use std::path::PathBuf;
use algocline_core::TokenUsage;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "op", rename_all = "snake_case")]
pub enum PoolRequest {
Handshake {
version: String,
},
Run {
code: String,
ctx: Option<serde_json::Value>,
lib_paths: Vec<PathBuf>,
},
Continue {
sid: String,
response: String,
query_id: Option<String>,
usage: Option<TokenUsage>,
},
Status,
Shutdown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum PoolResponseData {
Handshake {
version: String,
},
Feed {
session_id: String,
feed_result: serde_json::Value,
},
Status {
has_session: bool,
session_id: Option<String>,
},
Shutdown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PoolResponse {
pub ok: bool,
pub data: Option<PoolResponseData>,
pub error: Option<String>,
}
impl PoolResponse {
pub fn success(data: PoolResponseData) -> Self {
Self {
ok: true,
data: Some(data),
error: None,
}
}
pub fn failure(error: impl Into<String>) -> Self {
Self {
ok: false,
data: None,
error: Some(error.into()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn handshake_request_roundtrip() {
let req = PoolRequest::Handshake {
version: "0.31.0".to_string(),
};
let json = serde_json::to_string(&req).expect("serialize");
assert!(!json.contains('\n'), "JSON line must not contain newlines");
assert!(json.contains("\"op\":\"handshake\""), "op field missing");
assert!(
json.contains("\"version\":\"0.31.0\""),
"version field missing"
);
let decoded: PoolRequest = serde_json::from_str(&json).expect("deserialize");
match decoded {
PoolRequest::Handshake { version } => {
assert_eq!(version, "0.31.0");
}
other => panic!("unexpected variant: {other:?}"),
}
}
#[test]
fn response_success_roundtrip() {
let resp = PoolResponse::success(PoolResponseData::Handshake {
version: "0.31.0".to_string(),
});
let json = serde_json::to_string(&resp).expect("serialize");
assert!(json.contains("\"ok\":true"), "ok flag missing");
let decoded: PoolResponse = serde_json::from_str(&json).expect("deserialize");
assert!(decoded.ok);
assert!(decoded.error.is_none());
match decoded.data {
Some(PoolResponseData::Handshake { version }) => {
assert_eq!(version, "0.31.0");
}
other => panic!("unexpected data: {other:?}"),
}
}
#[test]
fn response_failure_roundtrip() {
let resp = PoolResponse::failure("version mismatch");
let json = serde_json::to_string(&resp).expect("serialize");
assert!(json.contains("\"ok\":false"), "ok flag missing");
let decoded: PoolResponse = serde_json::from_str(&json).expect("deserialize");
assert!(!decoded.ok);
assert!(decoded.data.is_none());
assert_eq!(decoded.error.as_deref(), Some("version mismatch"));
}
}