use serde::{Deserialize, Serialize};
pub const PROTOCOL_V1: u32 = 1;
#[derive(Serialize, Deserialize, schemars::JsonSchema, Debug, Clone)]
pub struct HandshakeParams {
pub client: String,
pub client_version: String,
pub protocol: Vec<u32>,
#[serde(default)]
pub features: Vec<String>,
}
#[derive(Serialize, Deserialize, schemars::JsonSchema, Debug, Clone)]
pub struct HandshakeResult {
pub protocol: u32,
pub agent_version: String,
pub features: Vec<String>,
pub session: HandshakeSession,
}
#[derive(Serialize, Deserialize, schemars::JsonSchema, Debug, Clone)]
pub struct HandshakeSession {
pub user: String,
pub session_id: u32,
pub pc_id: String,
}
pub mod features {
pub const PUSH_NOTIFICATIONS: &str = "push.notifications";
pub const PUSH_JOBS: &str = "push.jobs";
pub const PUSH_STATE: &str = "push.state";
pub const SUPPORT_DIAGNOSTICS: &str = "support.diagnostics";
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn handshake_params_round_trips_through_json() {
let p = HandshakeParams {
client: "kanade-client".into(),
client_version: "0.1.0".into(),
protocol: vec![PROTOCOL_V1],
features: vec![
features::PUSH_NOTIFICATIONS.into(),
features::PUSH_JOBS.into(),
features::PUSH_STATE.into(),
],
};
let json = serde_json::to_string(&p).unwrap();
let back: HandshakeParams = serde_json::from_str(&json).unwrap();
assert_eq!(back.client, "kanade-client");
assert_eq!(back.client_version, "0.1.0");
assert_eq!(back.protocol, vec![PROTOCOL_V1]);
assert!(back.features.contains(&"push.notifications".to_string()));
}
#[test]
fn handshake_params_accepts_missing_features() {
let wire = r#"{"client":"kanade-client","client_version":"0.0.1","protocol":[1]}"#;
let p: HandshakeParams = serde_json::from_str(wire).unwrap();
assert!(p.features.is_empty());
}
#[test]
fn handshake_result_spec_example_decodes() {
let wire = r#"{
"protocol": 1,
"agent_version": "0.4.0",
"features": ["push.notifications","push.jobs","push.state","support.diagnostics"],
"session": {"user":"DOMAIN\\alice","session_id":2,"pc_id":"PC1234"}
}"#;
let r: HandshakeResult = serde_json::from_str(wire).expect("decode");
assert_eq!(r.protocol, 1);
assert_eq!(r.agent_version, "0.4.0");
assert_eq!(r.features.len(), 4);
assert_eq!(r.session.user, "DOMAIN\\alice");
assert_eq!(r.session.session_id, 2);
assert_eq!(r.session.pc_id, "PC1234");
}
#[test]
fn handshake_protocol_negotiation_supports_multiple_versions() {
let wire = r#"{"client":"c","client_version":"0.0.1","protocol":[1,2,3]}"#;
let p: HandshakeParams = serde_json::from_str(wire).unwrap();
assert_eq!(p.protocol, vec![1, 2, 3]);
}
}