mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 01:16:31 +03:00
fix(sync): ignore unknown sync items to provide forward compatibility
This commit is contained in:
87
src/sync.rs
87
src/sync.rs
@@ -52,10 +52,18 @@ pub(crate) enum SyncData {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub(crate) enum SyncDataOrUnknown {
|
||||||
|
SyncData(SyncData),
|
||||||
|
Unknown(serde_json::Value),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub(crate) struct SyncItem {
|
pub(crate) struct SyncItem {
|
||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
data: SyncData,
|
|
||||||
|
data: SyncDataOrUnknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -63,6 +71,12 @@ pub(crate) struct SyncItems {
|
|||||||
items: Vec<SyncItem>,
|
items: Vec<SyncItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SyncData> for SyncDataOrUnknown {
|
||||||
|
fn from(sync_data: SyncData) -> Self {
|
||||||
|
Self::SyncData(sync_data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
/// Adds an item to the list of items that should be synchronized to other devices.
|
/// Adds an item to the list of items that should be synchronized to other devices.
|
||||||
///
|
///
|
||||||
@@ -79,7 +93,10 @@ impl Context {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let item = SyncItem { timestamp, data };
|
let item = SyncItem {
|
||||||
|
timestamp,
|
||||||
|
data: data.into(),
|
||||||
|
};
|
||||||
let item = serde_json::to_string(&item)?;
|
let item = serde_json::to_string(&item)?;
|
||||||
self.sql
|
self.sql
|
||||||
.execute("INSERT INTO multi_device_sync (item) VALUES(?);", (item,))
|
.execute("INSERT INTO multi_device_sync (item) VALUES(?);", (item,))
|
||||||
@@ -242,9 +259,15 @@ impl Context {
|
|||||||
info!(self, "executing {} sync item(s)", items.items.len());
|
info!(self, "executing {} sync item(s)", items.items.len());
|
||||||
for item in &items.items {
|
for item in &items.items {
|
||||||
match &item.data {
|
match &item.data {
|
||||||
|
SyncDataOrUnknown::SyncData(data) => match data {
|
||||||
AddQrToken(token) => self.add_qr_token(token).await,
|
AddQrToken(token) => self.add_qr_token(token).await,
|
||||||
DeleteQrToken(token) => self.delete_qr_token(token).await,
|
DeleteQrToken(token) => self.delete_qr_token(token).await,
|
||||||
AlterChat { id, action } => self.sync_alter_chat(id, action).await,
|
AlterChat { id, action } => self.sync_alter_chat(id, action).await,
|
||||||
|
},
|
||||||
|
SyncDataOrUnknown::Unknown(data) => {
|
||||||
|
warn!(self, "Ignored unknown sync item: {data}.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.log_err(self)
|
.log_err(self)
|
||||||
.ok();
|
.ok();
|
||||||
@@ -383,48 +406,32 @@ mod tests {
|
|||||||
|
|
||||||
assert!(t.parse_sync_items(r#"{"badname":[]}"#.to_string()).is_err());
|
assert!(t.parse_sync_items(r#"{"badname":[]}"#.to_string()).is_err());
|
||||||
|
|
||||||
assert!(t.parse_sync_items(
|
for bad_item_example in [
|
||||||
r#"{"items":[{"timestamp":1631781316,"data":{"BadItem":{"invitenumber":"in","auth":"a","grpid":null}}}]}"#
|
r#"{"items":[{"timestamp":1631781316,"data":{"BadItem":{"invitenumber":"in","auth":"a","grpid":null}}}]}"#,
|
||||||
.to_string(),
|
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":123}}}]}"#, // `123` is invalid for `String`
|
||||||
)
|
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":true}}}]}"#, // `true` is invalid for `String`
|
||||||
.is_err());
|
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":[]}}}]}"#, // `[]` is invalid for `String`
|
||||||
|
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":{}}}}]}"#, // `{}` is invalid for `String`
|
||||||
assert!(t.parse_sync_items(
|
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","grpid":null}}}]}"#, // missing field
|
||||||
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":123}}}]}"#.to_string(),
|
r#"{"items":[{"timestamp":1631781316,"data":{"AlterChat":{"id":{"ContactAddr":"bob@example.net"},"action":"Burn"}}}]}"#, // Unknown enum value
|
||||||
)
|
] {
|
||||||
.is_err()); // `123` is invalid for `String`
|
let sync_items = t.parse_sync_items(bad_item_example.to_string()).unwrap();
|
||||||
|
assert_eq!(sync_items.items.len(), 1);
|
||||||
assert!(t.parse_sync_items(
|
assert!(matches!(sync_items.items[0].timestamp, 1631781316));
|
||||||
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":true}}}]}"#.to_string(),
|
assert!(matches!(
|
||||||
)
|
sync_items.items[0].data,
|
||||||
.is_err()); // `true` is invalid for `String`
|
SyncDataOrUnknown::Unknown(_)
|
||||||
|
));
|
||||||
assert!(t.parse_sync_items(
|
}
|
||||||
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":[]}}}]}"#.to_string(),
|
|
||||||
)
|
|
||||||
.is_err()); // `[]` is invalid for `String`
|
|
||||||
|
|
||||||
assert!(t.parse_sync_items(
|
|
||||||
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":{}}}}]}"#.to_string(),
|
|
||||||
)
|
|
||||||
.is_err()); // `{}` is invalid for `String`
|
|
||||||
|
|
||||||
assert!(t.parse_sync_items(
|
|
||||||
r#"{"items":[{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","grpid":null}}}]}"#.to_string(),
|
|
||||||
)
|
|
||||||
.is_err()); // missing field
|
|
||||||
|
|
||||||
assert!(t.parse_sync_items(
|
|
||||||
r#"{"items":[{"timestamp":1631781318,"data":{"AlterChat":{"id":{"ContactAddr":"bob@example.net"},"action":"Burn"}}}]}"#.to_string(),
|
|
||||||
)
|
|
||||||
.is_err()); // Unknown enum value
|
|
||||||
|
|
||||||
// Test enums inside items and SystemTime
|
// Test enums inside items and SystemTime
|
||||||
let sync_items = t.parse_sync_items(
|
let sync_items = t.parse_sync_items(
|
||||||
r#"{"items":[{"timestamp":1631781318,"data":{"AlterChat":{"id":{"ContactAddr":"bob@example.net"},"action":{"SetMuted":{"Until":{"secs_since_epoch":42,"nanos_since_epoch":999000000}}}}}}]}"#.to_string(),
|
r#"{"items":[{"timestamp":1631781318,"data":{"AlterChat":{"id":{"ContactAddr":"bob@example.net"},"action":{"SetMuted":{"Until":{"secs_since_epoch":42,"nanos_since_epoch":999000000}}}}}}]}"#.to_string(),
|
||||||
)?;
|
)?;
|
||||||
assert_eq!(sync_items.items.len(), 1);
|
assert_eq!(sync_items.items.len(), 1);
|
||||||
let AlterChat { id, action } = &sync_items.items.get(0).unwrap().data else {
|
let SyncDataOrUnknown::SyncData(AlterChat { id, action }) =
|
||||||
|
&sync_items.items.get(0).unwrap().data
|
||||||
|
else {
|
||||||
bail!("bad item");
|
bail!("bad item");
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -466,7 +473,9 @@ mod tests {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
assert_eq!(sync_items.items.len(), 1);
|
assert_eq!(sync_items.items.len(), 1);
|
||||||
if let AddQrToken(token) = &sync_items.items.get(0).unwrap().data {
|
if let SyncDataOrUnknown::SyncData(AddQrToken(token)) =
|
||||||
|
&sync_items.items.get(0).unwrap().data
|
||||||
|
{
|
||||||
assert_eq!(token.invitenumber, "in");
|
assert_eq!(token.invitenumber, "in");
|
||||||
assert_eq!(token.auth, "yip");
|
assert_eq!(token.auth, "yip");
|
||||||
assert_eq!(token.grpid, None);
|
assert_eq!(token.grpid, None);
|
||||||
|
|||||||
Reference in New Issue
Block a user