openvcs_core/
host.rs

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