diff --git a/plugin/examples/foo_plugin.rs b/plugin/examples/foo_plugin.rs index 7f3469d..eb3a864 100644 --- a/plugin/examples/foo_plugin.rs +++ b/plugin/examples/foo_plugin.rs @@ -36,7 +36,7 @@ impl RPCCommand for OnChannelOpened { } fn main() { - let mut plugin = Plugin::::new(PluginState(()), true) + let plugin = Plugin::::new(PluginState(()), true) .add_rpc_method( "hello", "", diff --git a/plugin/src/commands/builtin.rs b/plugin/src/commands/builtin.rs index a957c53..e08bbb2 100644 --- a/plugin/src/commands/builtin.rs +++ b/plugin/src/commands/builtin.rs @@ -2,6 +2,8 @@ //! by core lightning in other to configure the plugin at startup. //! //! author: https://github.com/vincenzopalazzo +use std::collections::HashMap; + use crate::commands::{ types::{RPCHookInfo, RPCMethodInfo}, RPCCommand, @@ -12,6 +14,8 @@ use crate::types::RpcOption; use clightningrpc_common::json_utils::{add_bool, add_vec, init_payload}; use serde_json::Value; +use super::types::InitConf; + #[derive(Clone)] /// Type to define the manifest method and its attributes, used during plugin initialization pub struct ManifestRPC {} @@ -22,7 +26,7 @@ impl RPCCommand for ManifestRPC { add_vec::( &mut response, "options", - plugin.option.clone().into_iter().collect(), + plugin.option.clone().into_iter().map(|it| it.1).collect(), ); add_vec::( &mut response, @@ -51,10 +55,22 @@ pub struct InitRPC { pub(crate) on_init: Option<&'static OnInit>, } +impl InitRPC { + fn parse_option(&self, plugin: &mut Plugin, options: &HashMap) { + for option_name in options.keys() { + let option = options.get(option_name).unwrap(); + plugin.option.get_mut(option_name).unwrap().value = Some(option.to_owned()); + } + } +} + impl RPCCommand for InitRPC { fn call<'c>(&self, plugin: &mut Plugin, request: &'c Value) -> Result { let response = init_payload(); - plugin.conf = serde_json::from_value(request.to_owned()).unwrap(); + let init: InitConf = serde_json::from_value(request.to_owned()).unwrap(); + plugin.configuration = Some(init.configuration); + self.parse_option(plugin, &init.options); + if let Some(callback) = self.on_init { (*callback)(plugin); } diff --git a/plugin/src/commands/types.rs b/plugin/src/commands/types.rs index bddc53d..5d5537b 100644 --- a/plugin/src/commands/types.rs +++ b/plugin/src/commands/types.rs @@ -24,14 +24,14 @@ pub struct RPCHookInfo { #[derive(Deserialize, Clone)] /// Type to define attributes for the plugin's init method -pub struct InitConf { - pub options: serde_json::Value, - pub configuration: ConfFiled, +pub(crate) struct InitConf { + pub options: HashMap, + pub configuration: CLNConf, } #[derive(Deserialize, Clone)] /// Type to define the configuration options for the plugin's init method -pub struct ConfFiled { +pub struct CLNConf { #[serde(rename = "lightning-dir")] pub lightning_dir: String, #[serde(rename = "rpc-file")] diff --git a/plugin/src/plugin.rs b/plugin/src/plugin.rs index de24658..a713878 100644 --- a/plugin/src/plugin.rs +++ b/plugin/src/plugin.rs @@ -1,11 +1,9 @@ //! Core of the plugin API //! //! Unofficial API interface to develop plugin in Rust. -use crate::commands::{ - builtin::{InitRPC, ManifestRPC}, - types::{InitConf, RPCHookInfo, RPCMethodInfo}, - RPCCommand, -}; +use crate::commands::builtin::{InitRPC, ManifestRPC}; +use crate::commands::types::{CLNConf, RPCHookInfo, RPCMethodInfo}; +use crate::commands::RPCCommand; use crate::errors::PluginError; use crate::types::{LogLevel, RpcOption}; use clightningrpc_common::json_utils::{add_str, init_payload, init_success_response}; @@ -27,7 +25,7 @@ where pub state: T, /// all the option contained inside the /// hash map. - pub option: HashSet, + pub option: HashMap, /// all the options rpc method that the /// plugin need to support, included the builtin rpc method. pub rpc_method: HashMap>>, @@ -44,9 +42,9 @@ where /// mark a plugin as dynamic, in this way the plugin can be run /// from core lightning without stop the lightningd daemon pub dynamic: bool, - /// plugin configuration given by core lightning - pub conf: Option, - /// onInit callback called when the method on init is runned. + /// core lightning configuration sent with the init call. + pub configuration: Option, + /// onInit callback called when the method on init is ran. on_init: Option<&'static OnInit>, } @@ -54,14 +52,14 @@ impl<'a, T: 'a + Clone> Plugin { pub fn new(state: T, dynamic: bool) -> Self { Plugin { state, - option: HashSet::new(), + option: HashMap::new(), rpc_method: HashMap::new(), rpc_info: HashSet::new(), rpc_hook: HashMap::new(), hook_info: HashSet::new(), rpc_notification: HashMap::new(), dynamic, - conf: None, + configuration: None, on_init: None, } } @@ -93,6 +91,7 @@ impl<'a, T: 'a + Clone> Plugin { writer.flush().unwrap(); } + /// register the plugin option. pub fn add_opt( &mut self, name: &str, @@ -101,16 +100,29 @@ impl<'a, T: 'a + Clone> Plugin { description: &str, deprecated: bool, ) -> &mut Self { - self.option.insert(RpcOption { - name: name.to_string(), - opt_typ: opt_type.to_string(), - default: def_val, - description: description.to_string(), - deprecated, - }); + self.option.insert( + name.to_owned(), + RpcOption { + name: name.to_string(), + opt_typ: opt_type.to_string(), + default: def_val, + description: description.to_string(), + deprecated, + value: None, + }, + ); self } + /// get an option value that cln sent back to the plugin. + pub fn get_opt serde::de::Deserialize<'de>>( + &self, + name: &str, + ) -> Result { + let opt = self.option.get(name).unwrap(); + Ok(opt.value()) + } + // FIXME: adding the long description as parameter pub fn add_rpc_method( &'a mut self, @@ -195,7 +207,7 @@ impl<'a, T: 'a + Clone> Plugin { } } - pub fn start(&'a mut self) { + pub fn start(mut self) { let reader = io::stdin(); let mut writer = io::stdout(); let mut buffer = String::new(); @@ -220,7 +232,7 @@ impl<'a, T: 'a + Clone> Plugin { buffer.clear(); let request: Request = serde_json::from_str(&req_str).unwrap(); if let Some(id) = request.id { - // whe the id is specified this is a RPC or Hook, so we need to return a response + // when the id is specified this is a RPC or Hook, so we need to return a response let response = self.call_rpc_method(request.method, &request.params); let mut rpc_response = init_success_response(id); self.write_respose(&response, &mut rpc_response); diff --git a/plugin/src/types.rs b/plugin/src/types.rs index e2947e3..fef7a87 100644 --- a/plugin/src/types.rs +++ b/plugin/src/types.rs @@ -1,8 +1,9 @@ //! types use serde::{Deserialize, Serialize}; +use serde_json::Value; use std::fmt; -#[derive(Deserialize, Serialize, Clone, Eq, Hash, PartialEq)] +#[derive(Deserialize, Serialize, Clone)] pub struct RpcOption { /// option name that is specified by the /// core lightning user, like --foo @@ -18,6 +19,15 @@ pub struct RpcOption { pub description: String, /// if the filed is deprecated pub deprecated: bool, + /// The value specified by the user + pub value: Option, +} + +impl RpcOption { + pub fn value serde::de::Deserialize<'de>>(&self) -> T { + let value: T = serde_json::from_value(self.value.to_owned().unwrap()).unwrap(); + value + } } pub enum LogLevel {