openvcs_core/
host.rs

1#![cfg(feature = "plugin-protocol")]
2
3use crate::plugin_protocol::RpcRequest;
4use crate::plugin_stdio::{PluginError, RequestIdState, call_host};
5use serde_json::Value;
6use std::collections::VecDeque;
7use std::io::{BufReader, LineWriter};
8use std::sync::{Arc, Mutex, OnceLock};
9use std::time::Duration;
10
11pub type HostStdout = LineWriter<std::io::Stdout>;
12pub type HostStdin = BufReader<std::io::Stdin>;
13
14#[derive(Clone)]
15struct HostContext {
16    out: Arc<Mutex<HostStdout>>,
17    stdin: Arc<Mutex<HostStdin>>,
18    queue: Arc<Mutex<VecDeque<RpcRequest>>>,
19    ids: Arc<Mutex<RequestIdState>>,
20    timeout: Duration,
21}
22
23static HOST: OnceLock<HostContext> = OnceLock::new();
24
25pub fn init_stdio_default(next_id: u64, timeout: Duration) {
26    let out = Arc::new(Mutex::new(LineWriter::new(std::io::stdout())));
27    let stdin = Arc::new(Mutex::new(BufReader::new(std::io::stdin())));
28    let queue = Arc::new(Mutex::new(VecDeque::new()));
29    let ids = Arc::new(Mutex::new(RequestIdState { next_id }));
30    init_default_stdio_host(out, stdin, queue, ids, timeout);
31}
32
33pub fn init_default_stdio_host(
34    out: Arc<Mutex<HostStdout>>,
35    stdin: Arc<Mutex<HostStdin>>,
36    queue: Arc<Mutex<VecDeque<RpcRequest>>>,
37    ids: Arc<Mutex<RequestIdState>>,
38    timeout: Duration,
39) {
40    let _ = HOST.set(HostContext {
41        out,
42        stdin,
43        queue,
44        ids,
45        timeout,
46    });
47}
48
49pub fn stdout() -> Result<&'static Arc<Mutex<HostStdout>>, PluginError> {
50    Ok(&HOST
51        .get()
52        .ok_or_else(|| PluginError::code("host.uninitialized", "host not initialized"))?
53        .out)
54}
55
56pub fn stdin() -> Result<&'static Arc<Mutex<HostStdin>>, PluginError> {
57    Ok(&HOST
58        .get()
59        .ok_or_else(|| PluginError::code("host.uninitialized", "host not initialized"))?
60        .stdin)
61}
62
63pub fn queue() -> Result<&'static Arc<Mutex<VecDeque<RpcRequest>>>, PluginError> {
64    Ok(&HOST
65        .get()
66        .ok_or_else(|| PluginError::code("host.uninitialized", "host not initialized"))?
67        .queue)
68}
69
70pub fn ids() -> Result<&'static Arc<Mutex<RequestIdState>>, PluginError> {
71    Ok(&HOST
72        .get()
73        .ok_or_else(|| PluginError::code("host.uninitialized", "host not initialized"))?
74        .ids)
75}
76
77pub fn call(method: &str, params: Value) -> Result<Value, PluginError> {
78    let ctx = HOST.get().ok_or_else(|| {
79        PluginError::code(
80            "host.uninitialized",
81            "host bridge not initialized (call init_default_stdio_host)",
82        )
83    })?;
84    call_host(
85        &ctx.out,
86        &ctx.stdin,
87        &ctx.queue,
88        &ctx.ids,
89        method,
90        params,
91        ctx.timeout,
92    )
93}