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}