radicle: Fix some serialization issues

For some inexplicable reason, deserializing doesn't work unless we use
our custom de-serializer for `LocalTime`.
This commit is contained in:
cloudhead 2023-11-15 14:36:27 +01:00
parent aa13f57e7d
commit ca557909c2
No known key found for this signature in database
3 changed files with 101 additions and 1 deletions

View File

@ -129,6 +129,7 @@ impl fmt::Display for State {
/// Repository sync status for our own refs.
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "status")]
#[serde(rename_all = "camelCase")]
pub enum SyncStatus {
/// We're in sync.
#[serde(rename_all = "camelCase")]
@ -447,7 +448,9 @@ impl Session {
pub struct Seed {
pub nid: NodeId,
pub addrs: Vec<KnownAddress>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub state: Option<State>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sync: Option<SyncStatus>,
}
@ -1100,9 +1103,26 @@ mod test {
.unwrap(),
"{\"error\":\"entity not found\"}"
);
json::from_str::<CommandResult<State>>(
&serde_json::to_string(&CommandResult::Okay(State::Connected {
since: LocalTime::now(),
ping: Default::default(),
fetching: Default::default(),
}))
.unwrap(),
)
.unwrap();
assert_matches!(
json::from_str::<CommandResult<State>>(
r#"{"connected":{"since":1699636852107,"fetching":[]}}"#
),
Ok(CommandResult::Okay(_))
);
assert_matches!(
json::from_str::<CommandResult<Seeds>>(
r#"[{"nid":"z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z","addrs":[],"state":{"connected":{"since":1699636852107,"fetching":[]}}}]"#
r#"[{"nid":"z6MksmpU5b1dS7oaqF2bHXhQi1DWy2hB7Mh9CuN7y1DN6QSz","addrs":[{"addr":"seed.radicle.xyz:8776","source":"peer","lastSuccess":1699983994234,"lastAttempt":1699983994000,"banned":false}],"state":{"connected":{"since":1699983994,"fetching":[]}}}]"#
),
Ok(CommandResult::Okay(_))
);

View File

@ -137,8 +137,10 @@ pub struct KnownAddress {
/// Address of the peer who sent us this address.
pub source: Source,
/// Last time this address was used to successfully connect to a peer.
#[serde(with = "crate::serde_ext::localtime::option::time")]
pub last_success: Option<LocalTime>,
/// Last time this address was tried.
#[serde(with = "crate::serde_ext::localtime::option::time")]
pub last_attempt: Option<LocalTime>,
/// Whether this address has been banned.
pub banned: bool,
@ -187,6 +189,7 @@ pub struct SyncedAt {
/// Head of `rad/sigrefs`.
pub oid: git_ext::Oid,
/// When these refs were synced.
#[serde(with = "crate::serde_ext::localtime::time")]
pub timestamp: LocalTime,
}

View File

@ -55,6 +55,34 @@ pub mod localtime {
}
}
pub mod option {
pub mod time {
use localtime::LocalTime;
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(value: &Option<LocalTime>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match value {
Some(time) => serializer.serialize_some(&time.as_secs()),
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<LocalTime>, D::Error>
where
D: Deserializer<'de>,
{
let option = Option::<u64>::deserialize(deserializer)?;
match option {
Some(seconds) => Ok(Some(LocalTime::from_secs(seconds))),
None => Ok(None),
}
}
}
}
pub mod duration {
use localtime::LocalDuration;
use serde::{Deserialize, Deserializer, Serializer};
@ -81,3 +109,52 @@ pub mod localtime {
pub fn is_default<T: Default + PartialEq>(t: &T) -> bool {
t == &T::default()
}
#[cfg(test)]
mod test {
use super::*;
use ::localtime::LocalTime;
#[test]
fn test_localtime() {
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
struct Test {
time: LocalTime,
}
let value = Test {
time: LocalTime::from_millis(1699636852107),
};
assert_eq!(
serde_json::from_str::<Test>(r#"{"time":1699636852107}"#).unwrap(),
value
);
assert_eq!(
serde_json::from_str::<Test>(serde_json::to_string(&value).unwrap().as_str()).unwrap(),
value
);
}
#[test]
// Tests serialization into seconds instead of milliseconds.
fn test_localtime_ext() {
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
struct Test {
#[serde(with = "localtime::time")]
time: LocalTime,
}
let value = Test {
time: LocalTime::from_secs(1699636852107),
};
assert_eq!(
serde_json::from_str::<Test>(r#"{"time":1699636852107}"#).unwrap(),
value
);
assert_eq!(
serde_json::from_str::<Test>(serde_json::to_string(&value).unwrap().as_str()).unwrap(),
value
);
}
}