mirror of
https://github.com/chatmail/core.git
synced 2026-04-05 15:02:11 +03:00
Compare commits
1 Commits
v2.32.0
...
link2xt/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b06d31190 |
@@ -1175,6 +1175,24 @@ int dc_send_webxdc_status_update (dc_context_t* context, uint32_t msg_id, const
|
|||||||
*/
|
*/
|
||||||
char* dc_get_webxdc_status_updates (dc_context_t* context, uint32_t msg_id, uint32_t serial);
|
char* dc_get_webxdc_status_updates (dc_context_t* context, uint32_t msg_id, uint32_t serial);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces webxdc app with a new version.
|
||||||
|
*
|
||||||
|
* On the JavaScript side this API could be used like this:
|
||||||
|
* ```
|
||||||
|
* window.webxdc.replaceWebxdc(blob);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @memberof dc_context_t
|
||||||
|
* @param context The context object.
|
||||||
|
* @param msg_id The ID of the WebXDC message to be replaced.
|
||||||
|
* @param blob New blob to replace WebXDC with.
|
||||||
|
* @param n Blob size.
|
||||||
|
*/
|
||||||
|
void dc_replace_webxdc(dc_context_t* context, uint32_t msg_id, uint8_t *blob, size_t n);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a draft for a chat in the database.
|
* Save a draft for a chat in the database.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg};
|
|||||||
use deltachat::reaction::{get_msg_reactions, send_reaction, Reactions};
|
use deltachat::reaction::{get_msg_reactions, send_reaction, Reactions};
|
||||||
use deltachat::stock_str::StockMessage;
|
use deltachat::stock_str::StockMessage;
|
||||||
use deltachat::stock_str::StockStrings;
|
use deltachat::stock_str::StockStrings;
|
||||||
use deltachat::webxdc::StatusUpdateSerial;
|
use deltachat::webxdc::{replace_webxdc, StatusUpdateSerial};
|
||||||
use deltachat::*;
|
use deltachat::*;
|
||||||
use deltachat::{accounts::Accounts, log::LogExt};
|
use deltachat::{accounts::Accounts, log::LogExt};
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
@@ -1097,6 +1097,32 @@ pub unsafe extern "C" fn dc_get_webxdc_status_updates(
|
|||||||
.strdup()
|
.strdup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_replace_webxdc(
|
||||||
|
context: *mut dc_context_t,
|
||||||
|
msg_id: u32,
|
||||||
|
blob: *const u8,
|
||||||
|
n: libc::size_t,
|
||||||
|
) {
|
||||||
|
if context.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_replace_webxdc()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg_id = MsgId::new(msg_id);
|
||||||
|
let blob_slice = std::slice::from_raw_parts(blob, n);
|
||||||
|
|
||||||
|
let ctx = &*context;
|
||||||
|
|
||||||
|
block_on(async move {
|
||||||
|
replace_webxdc(ctx, msg_id, blob_slice)
|
||||||
|
.await
|
||||||
|
.context("Failed to replace WebXDC")
|
||||||
|
.log_err(ctx)
|
||||||
|
.ok();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_set_draft(
|
pub unsafe extern "C" fn dc_set_draft(
|
||||||
context: *mut dc_context_t,
|
context: *mut dc_context_t,
|
||||||
@@ -1539,14 +1565,10 @@ pub unsafe extern "C" fn dc_delete_chat(context: *mut dc_context_t, chat_id: u32
|
|||||||
}
|
}
|
||||||
let ctx = &*context;
|
let ctx = &*context;
|
||||||
|
|
||||||
block_on(async move {
|
block_on(ChatId::new(chat_id).delete(ctx))
|
||||||
ChatId::new(chat_id)
|
.context("Failed chat delete")
|
||||||
.delete(ctx)
|
.log_err(ctx)
|
||||||
.await
|
.ok();
|
||||||
.context("Failed chat delete")
|
|
||||||
.log_err(ctx)
|
|
||||||
.ok();
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
|
use crate::blob::BlobObject;
|
||||||
use crate::chat::Chat;
|
use crate::chat::Chat;
|
||||||
use crate::constants::Chattype;
|
use crate::constants::Chattype;
|
||||||
use crate::contact::ContactId;
|
use crate::contact::ContactId;
|
||||||
@@ -845,6 +846,35 @@ impl Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces WebXDC blob of existing message.
|
||||||
|
///
|
||||||
|
/// This API is supposed to be called from within a WebXDC to replace itself
|
||||||
|
/// e.g. with an updated or persistently reconfigured version.
|
||||||
|
pub async fn replace_webxdc(context: &Context, msg_id: MsgId, data: &[u8]) -> Result<()> {
|
||||||
|
let mut msg = Message::load_from_db(context, msg_id).await?;
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
msg.get_viewtype() == Viewtype::Webxdc,
|
||||||
|
"Message {msg_id} is not a WebXDC instance"
|
||||||
|
);
|
||||||
|
|
||||||
|
let blob = BlobObject::create(
|
||||||
|
context,
|
||||||
|
&msg.get_filename()
|
||||||
|
.context("Cannot get filename of exising WebXDC instance")?,
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("Failed to create WebXDC replacement blob")?;
|
||||||
|
|
||||||
|
let mut param = msg.param.clone();
|
||||||
|
param.set(Param::File, blob.as_name());
|
||||||
|
msg.param = param;
|
||||||
|
msg.update_param(context).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
@@ -2623,4 +2653,62 @@ sth_for_the = "future""#
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tests replacing WebXDC with a newer version.
|
||||||
|
///
|
||||||
|
/// Updates should be preserved after upgrading.
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_replace_webxdc() -> Result<()> {
|
||||||
|
let alice = TestContext::new_alice().await;
|
||||||
|
let bob = TestContext::new_bob().await;
|
||||||
|
|
||||||
|
// Alice sends WebXDC instance.
|
||||||
|
let alice_chat = alice.create_chat(&bob).await;
|
||||||
|
let mut alice_instance = create_webxdc_instance(
|
||||||
|
&alice,
|
||||||
|
"minimal.xdc",
|
||||||
|
include_bytes!("../test-data/webxdc/minimal.xdc"),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
alice_instance.set_text("user added text".to_string());
|
||||||
|
send_msg(&alice, alice_chat.id, &mut alice_instance).await?;
|
||||||
|
let alice_instance = alice.get_last_msg().await;
|
||||||
|
assert_eq!(alice_instance.get_text(), "user added text");
|
||||||
|
|
||||||
|
// Bob receives that instance.
|
||||||
|
let alice_sent_instance = alice.pop_sent_msg().await;
|
||||||
|
let bob_received_instance = bob.recv_msg(&alice_sent_instance).await;
|
||||||
|
assert_eq!(bob_received_instance.get_text(), "user added text");
|
||||||
|
|
||||||
|
// Alice sends WebXDC update.
|
||||||
|
alice
|
||||||
|
.send_webxdc_status_update(alice_instance.id, r#"{"payload": 1}"#, "Alice update")
|
||||||
|
.await?;
|
||||||
|
alice.flush_status_updates().await?;
|
||||||
|
let alice_sent_update = alice.pop_sent_msg().await;
|
||||||
|
bob.recv_msg(&alice_sent_update).await;
|
||||||
|
assert_eq!(
|
||||||
|
bob.get_webxdc_status_updates(bob_received_instance.id, StatusUpdateSerial(0))
|
||||||
|
.await?,
|
||||||
|
r#"[{"payload":1,"serial":1,"max_serial":1}]"#
|
||||||
|
);
|
||||||
|
|
||||||
|
// Bob replaces WebXDC.
|
||||||
|
replace_webxdc(
|
||||||
|
&bob,
|
||||||
|
bob_received_instance.id,
|
||||||
|
include_bytes!("../test-data/webxdc/with-minimal-manifest.xdc"),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("Failed to replace WebXDC")?;
|
||||||
|
|
||||||
|
// Updates are not modified.
|
||||||
|
assert_eq!(
|
||||||
|
bob.get_webxdc_status_updates(bob_received_instance.id, StatusUpdateSerial(0))
|
||||||
|
.await?,
|
||||||
|
r#"[{"payload":1,"serial":1,"max_serial":1}]"#
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user