1use crate::commands::builtin::{InitRPC, ManifestRPC};
5use crate::commands::types::{CLNConf, RPCHookInfo, RPCMethodInfo};
6use crate::commands::RPCCommand;
7use crate::errors::PluginError;
8use crate::types::{LogLevel, RpcOption};
9use clightningrpc_common::json_utils::{add_str, init_payload, init_success_response};
10use clightningrpc_common::types::Request;
11use serde_json::Value;
12use std::collections::{HashMap, HashSet};
13use std::string::String;
14use std::sync::Arc;
15use std::{io, io::Write};
16
17#[cfg(feature = "log")]
18pub use log::*;
19
20#[derive(Clone)]
21#[allow(dead_code)]
22pub struct Plugin<T>
23where
24 T: 'static + Clone,
26{
27 pub state: T,
28 pub option: HashMap<String, RpcOption>,
31 pub rpc_method: HashMap<String, Box<dyn RPCCommand<T>>>,
34 pub rpc_info: HashSet<RPCMethodInfo>,
37 pub rpc_hook: HashMap<String, Box<dyn RPCCommand<T>>>,
39 pub hook_info: HashSet<RPCHookInfo>,
42 pub rpc_notification: HashMap<String, Box<dyn RPCCommand<T>>>,
44 pub dynamic: bool,
47 pub configuration: Option<CLNConf>,
49 on_init: Option<Arc<dyn Fn(&mut Plugin<T>) -> Value>>,
51}
52
53#[cfg(feature = "log")]
54pub struct Log;
55
56#[cfg(feature = "log")]
57impl log::Log for Log {
58 fn enabled(&self, _: &Metadata) -> bool {
59 true
60 }
61
62 fn log(&self, record: &Record) {
63 if self.enabled(record.metadata()) {
64 let level: LogLevel = record.level().into();
65 let msg = record.args();
66
67 let mut writer = io::stdout();
68 let mut payload = init_payload();
69 add_str(&mut payload, "level", &level.to_string());
70 add_str(&mut payload, "message", &format!("{msg}"));
71 let request = Request {
72 id: None,
73 jsonrpc: "2.0".to_owned(),
74 method: "log".to_owned(),
75 params: payload,
76 };
77 writer
78 .write_all(serde_json::to_string(&request).unwrap().as_bytes())
79 .unwrap();
80 writer.flush().unwrap();
81 }
82 }
83
84 fn flush(&self) {}
85}
86
87impl<'a, T: 'a + Clone> Plugin<T> {
88 pub fn new(state: T, dynamic: bool) -> Self {
89 Plugin {
90 state,
91 option: HashMap::new(),
92 rpc_method: HashMap::new(),
93 rpc_info: HashSet::new(),
94 rpc_hook: HashMap::new(),
95 hook_info: HashSet::new(),
96 rpc_notification: HashMap::new(),
97 dynamic,
98 configuration: None,
99 on_init: None,
100 }
101 }
102
103 pub fn on_init<C: 'static>(&'a mut self, callback: C) -> Self
104 where
105 C: Fn(&mut Plugin<T>) -> Value,
106 {
107 self.on_init = Some(Arc::new(callback));
108 self.clone()
109 }
110
111 pub fn log(&self, level: LogLevel, msg: &str) {
112 let mut writer = io::stdout();
113 let mut payload = init_payload();
114 add_str(&mut payload, "level", &level.to_string());
115 add_str(&mut payload, "message", msg);
116 let request = Request {
117 id: None,
118 jsonrpc: "2.0".to_owned(),
119 method: "log".to_owned(),
120 params: payload,
121 };
122 writer
123 .write_all(serde_json::to_string(&request).unwrap().as_bytes())
124 .unwrap();
125 writer.flush().unwrap();
126 }
127
128 pub fn add_opt(
130 &mut self,
131 name: &str,
132 opt_type: &str,
133 def_val: Option<String>,
134 description: &str,
135 deprecated: bool,
136 ) -> &mut Self {
137 self.option.insert(
138 name.to_owned(),
139 RpcOption {
140 name: name.to_string(),
141 opt_typ: opt_type.to_string(),
142 default: def_val,
143 description: description.to_string(),
144 deprecated,
145 value: None,
146 },
147 );
148 self
149 }
150
151 pub fn get_opt<R: for<'de> serde::de::Deserialize<'de>>(
153 &self,
154 name: &str,
155 ) -> Result<R, PluginError> {
156 let opt = self.option.get(name).unwrap();
157 Ok(opt.value())
158 }
159
160 pub fn add_rpc_method<F: 'static>(
162 &'a mut self,
163 name: &str,
164 usage: &str,
165 description: &str,
166 callback: F,
167 ) -> Self
168 where
169 F: RPCCommand<T> + 'static,
170 {
171 self.rpc_method.insert(name.to_owned(), Box::new(callback));
172 self.rpc_info.insert(RPCMethodInfo {
173 name: name.to_string(),
174 usage: usage.to_string(),
175 description: description.to_string(),
176 long_description: description.to_string(),
177 deprecated: false,
178 });
179 self.clone()
180 }
181
182 fn call_rpc_method(
183 &'a mut self,
184 name: &str,
185 params: serde_json::Value,
186 ) -> Result<serde_json::Value, PluginError> {
187 let command = self.rpc_method.get(name).unwrap().clone();
188 command.call(self, params)
189 }
190
191 fn handle_notification(&'a mut self, name: &str, params: serde_json::Value) {
192 let notification = self.rpc_notification.get(name).unwrap().clone();
193 if let Err(json_res) = notification.call(self, params) {
194 self.log(
195 LogLevel::Debug,
196 format!("Notification end with and error: {json_res}").as_str(),
197 );
198 }
199 }
200
201 pub fn register_hook<F: 'static>(
202 &'a mut self,
203 hook_name: &str,
204 before: Option<Vec<String>>,
205 after: Option<Vec<String>>,
206 callback: F,
207 ) -> Self
208 where
209 F: RPCCommand<T> + 'static,
210 {
211 self.rpc_hook
212 .insert(hook_name.to_owned(), Box::new(callback));
213 self.hook_info.insert(RPCHookInfo {
214 name: hook_name.to_owned(),
215 before,
216 after,
217 });
218 self.clone()
219 }
220
221 pub fn register_notification<F: 'static>(&mut self, name: &str, callback: F) -> Self
222 where
223 F: 'static + RPCCommand<T> + Clone,
224 {
225 self.rpc_notification
226 .insert(name.to_owned(), Box::new(callback));
227 self.clone()
228 }
229
230 fn write_respose(
231 &mut self,
232 result: &Result<serde_json::Value, PluginError>,
233 response: &mut serde_json::Value,
234 ) {
235 match result {
236 Ok(json_resp) => response["result"] = json_resp.to_owned(),
237 Err(json_err) => {
238 let err_resp = serde_json::to_value(json_err).unwrap();
239 response["error"] = err_resp;
240 }
241 }
242 }
243
244 pub fn start(mut self) {
245 let reader = io::stdin();
246 let mut writer = io::stdout();
247 let mut buffer = String::new();
248 #[cfg(feature = "log")]
249 {
250 let _ = log::set_logger(&Log {}).map(|()| log::set_max_level(LevelFilter::Trace));
251 }
252 self.rpc_method
253 .insert("getmanifest".to_owned(), Box::new(ManifestRPC {}));
254 self.rpc_method.insert(
255 "init".to_owned(),
256 Box::new(InitRPC::<T> {
257 on_init: self.on_init.clone(),
258 }),
259 );
260 loop {
264 let _ = reader.read_line(&mut buffer);
265 let req_str = buffer.to_string();
266 if req_str.trim().is_empty() {
267 continue;
268 }
269 buffer.clear();
270 let request: Request<serde_json::Value> = serde_json::from_str(&req_str).unwrap();
271 if let Some(id) = request.id {
272 let response = self.call_rpc_method(&request.method, request.params);
274 let mut rpc_response = init_success_response(id);
275 self.write_respose(&response, &mut rpc_response);
276 writer
277 .write_all(serde_json::to_string(&rpc_response).unwrap().as_bytes())
278 .unwrap();
279 writer.flush().unwrap();
280 } else {
281 self.handle_notification(&request.method, request.params);
284 }
285 }
286 }
287}