gitdataai/libs/session/storage/format.rs
2026-04-15 09:08:09 +08:00

76 lines
2.3 KiB
Rust

use std::collections::HashMap;
use serde::ser::{Serialize, SerializeMap, Serializer};
use serde_json::{Map, Value};
use super::interface::SessionState;
const SESSION_STATE_FORMAT_VERSION: u8 = 1;
#[derive(Debug)]
struct StoredSessionStateRef<'a> {
state: &'a SessionState,
}
impl Serialize for StoredSessionStateRef<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(2))?;
map.serialize_entry("v", &SESSION_STATE_FORMAT_VERSION)?;
map.serialize_entry("state", self.state)?;
map.end()
}
}
pub(crate) fn serialize_session_state(
session_state: &SessionState,
) -> Result<String, anyhow::Error> {
let stored = StoredSessionStateRef {
state: session_state,
};
serde_json::to_string(&stored).map_err(anyhow::Error::new)
}
pub(crate) fn deserialize_session_state(value: &str) -> Result<SessionState, anyhow::Error> {
let value = serde_json::from_str::<Value>(value)?;
let Value::Object(mut obj) = value else {
anyhow::bail!("Session state is not a JSON object");
};
if matches!(obj.get("state"), Some(Value::Object(_))) {
if let Some(Value::Number(v)) = obj.get("v") {
let v = v
.as_u64()
.ok_or_else(|| anyhow::anyhow!("Invalid session state format version"))?;
let v = u8::try_from(v)
.map_err(|_| anyhow::anyhow!("Invalid session state format version"))?;
anyhow::ensure!(
v == SESSION_STATE_FORMAT_VERSION,
"Unsupported session state format version: {}",
v
);
let Some(Value::Object(state)) = obj.remove("state") else {
unreachable!("`state` was checked to be an object above");
};
return Ok(state);
}
}
if obj.values().all(Value::is_string) {
let legacy: HashMap<String, String> = serde_json::from_value(Value::Object(obj))?;
let mut migrated: Map<String, Value> = Map::new();
for (key, json_encoded) in legacy {
migrated.insert(key, serde_json::from_str::<Value>(&json_encoded)?);
}
return Ok(migrated);
}
Ok(obj)
}