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}