forked from 1b-agent/opencadstudio-upstream
Snapshot: V4 plugin API and host integration
This commit is contained in:
1 parent
448869ac35
commit
29c41a4041
36 files changed
+5463
-253
No files matched your search
@@ -0,0 +1,127 @@
|
||||
//! V4 wire frames and envelope types.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::host::{HostNotification, PluginNotification};
|
||||
use crate::ipc::protocol::{HostRequest, HostResponse, PluginRequest, PluginResponse};
|
||||
|
||||
/// Protocol version carried in the V4 handshake.
|
||||
pub const V4_PROTOCOL_VERSION: u32 = 4;
|
||||
|
||||
/// Best-effort notification envelope carrying an optional command correlation
|
||||
/// ID in addition to the typed payload.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NotificationEnvelope<T> {
|
||||
pub command_id: Option<u64>,
|
||||
pub payload: T,
|
||||
}
|
||||
|
||||
/// Messages sent from the host to the plugin runner on the V4 socket.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum HostToPluginV4 {
|
||||
Request { id: u64, payload: HostRequest },
|
||||
Response { id: u64, payload: PluginResponse },
|
||||
Notification(NotificationEnvelope<HostNotification>),
|
||||
}
|
||||
|
||||
/// Messages sent from the plugin runner to the host on the V4 socket.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PluginToHostV4 {
|
||||
Request { id: u64, payload: PluginRequest },
|
||||
Response { id: u64, payload: HostResponse },
|
||||
Notification(NotificationEnvelope<PluginNotification>),
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "host"))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::host::LogLevel;
|
||||
|
||||
#[test]
|
||||
fn v4_frame_roundtrip() {
|
||||
let frame = HostToPluginV4::Notification(NotificationEnvelope {
|
||||
command_id: Some(7),
|
||||
payload: HostNotification::InputLine {
|
||||
line: "hello".to_string(),
|
||||
},
|
||||
});
|
||||
let bytes = bincode::serialize(&frame).unwrap();
|
||||
let got: HostToPluginV4 = bincode::deserialize(&bytes).unwrap();
|
||||
match got {
|
||||
HostToPluginV4::Notification(env) => {
|
||||
assert_eq!(env.command_id, Some(7));
|
||||
assert_eq!(
|
||||
env.payload,
|
||||
HostNotification::InputLine {
|
||||
line: "hello".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
other => panic!("unexpected: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_notification_roundtrip() {
|
||||
let frame = PluginToHostV4::Notification(NotificationEnvelope {
|
||||
command_id: None,
|
||||
payload: PluginNotification::Log {
|
||||
level: LogLevel::Info,
|
||||
text: "hi".to_string(),
|
||||
},
|
||||
});
|
||||
let bytes = bincode::serialize(&frame).unwrap();
|
||||
let got: PluginToHostV4 = bincode::deserialize(&bytes).unwrap();
|
||||
match got {
|
||||
PluginToHostV4::Notification(env) => {
|
||||
assert_eq!(env.command_id, None);
|
||||
assert_eq!(
|
||||
env.payload,
|
||||
PluginNotification::Log {
|
||||
level: LogLevel::Info,
|
||||
text: "hi".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
other => panic!("unexpected: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_notification_deserializes_as_unknown() {
|
||||
// Build a payload with an unknown discriminant (99) followed by some
|
||||
// bytes. The custom deserializer should return Unknown(raw_bytes).
|
||||
let mut payload = vec![99u8];
|
||||
bincode::serialize_into(&mut payload, &"future".to_string()).unwrap();
|
||||
let envelope = NotificationEnvelope {
|
||||
command_id: Some(1),
|
||||
payload: HostNotification::Unknown(payload.clone()),
|
||||
};
|
||||
let frame = HostToPluginV4::Notification(envelope);
|
||||
let bytes = bincode::serialize(&frame).unwrap();
|
||||
let got: HostToPluginV4 = bincode::deserialize(&bytes).unwrap();
|
||||
match got {
|
||||
HostToPluginV4::Notification(env) => match env.payload {
|
||||
HostNotification::Unknown(raw) => {
|
||||
assert_eq!(raw[0], 99);
|
||||
}
|
||||
other => panic!("expected Unknown, got {other:?}"),
|
||||
},
|
||||
other => panic!("unexpected: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v3_runner_handshake_token_roundtrips_after_tokenv4() {
|
||||
use crate::ipc::protocol::RunnerHandshake;
|
||||
let original = RunnerHandshake::Token("abc".to_string());
|
||||
let bytes = bincode::serialize(&original).unwrap();
|
||||
let got: RunnerHandshake = bincode::deserialize(&bytes).unwrap();
|
||||
match got {
|
||||
RunnerHandshake::Token(s) => assert_eq!(s, "abc"),
|
||||
other => panic!("unexpected: {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user