diff --git a/Cargo.toml b/Cargo.toml index b8f2d02..25e34a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shvbroker" -version = "3.1.2" +version = "3.1.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/bin/shvbroker.rs b/src/bin/shvbroker.rs index 74e7cf9..837280b 100644 --- a/src/bin/shvbroker.rs +++ b/src/bin/shvbroker.rs @@ -25,6 +25,9 @@ struct CliOpts { /// Allow writing to access database #[arg(short = 'b', long)] use_access_db: bool, + /// SHV2 compatibility mode + #[arg(long = "shv2")] + shv2_compatibility: bool, /// Verbose mode (module, .) #[arg(short = 'v', long = "verbose")] verbose: Option, @@ -35,6 +38,7 @@ pub(crate) fn main() -> shvrpc::Result<()> { let cli = CliOpts::augment_args(cli); let cli_matches = cli.get_matches(); let cli_use_access_db_set = cli_matches.try_get_one::("use_access_db").is_ok(); + let cli_shv2_set = cli_matches.try_get_one::("shv2_compatibility").is_ok(); let cli_opts = CliOpts::from_arg_matches(&cli_matches).map_err(|err| err.exit()).unwrap(); let mut logger = SimpleLogger::new(); @@ -48,7 +52,7 @@ pub(crate) fn main() -> shvrpc::Result<()> { logger.init().unwrap(); info!("====================================================="); - info!("{} starting", module_path!()); + info!("{}", module_path!()); info!("====================================================="); //trace!("trace message"); //debug!("debug message"); @@ -58,7 +62,7 @@ pub(crate) fn main() -> shvrpc::Result<()> { //log!(target: "RpcMsg", Level::Debug, "RPC message"); //log!(target: "Access", Level::Debug, "Access control message"); - let config = if let Some(config_file) = &cli_opts.config { + let mut config = if let Some(config_file) = &cli_opts.config { info!("Loading config file {config_file}"); match BrokerConfig::from_file(config_file) { Ok(config) => {config} @@ -80,6 +84,12 @@ pub(crate) fn main() -> shvrpc::Result<()> { info!("Using default config"); BrokerConfig::default() }; + if cli_shv2_set { + config.shv2_compatibility = cli_opts.shv2_compatibility; + } + if config.shv2_compatibility { + info!("Running in SHV2 compatibility mode"); + } let data_dir = cli_opts.data_directory.or(config.data_directory.clone()).unwrap_or("/tmp/shvbroker/data".to_owned()); let use_access_db = (cli_use_access_db_set && cli_opts.use_access_db) || config.use_access_db; let (access, sql_connection) = if use_access_db { @@ -104,6 +114,7 @@ pub(crate) fn main() -> shvrpc::Result<()> { if let Some(file) = cli_opts.write_config { write_config_to_file(&file, &config, &access)?; } + info!("-----------------------------------------------------"); task::block_on(shvbroker::brokerimpl::accept_loop(config, access, sql_connection)) } diff --git a/src/brokerimpl.rs b/src/brokerimpl.rs index c40c563..d6d3b6e 100644 --- a/src/brokerimpl.rs +++ b/src/brokerimpl.rs @@ -12,7 +12,7 @@ use shvrpc::rpcframe::RpcFrame; use shvrpc::rpcmessage::{PeerId, RpcError, RpcErrorCode, RqId, Tag}; use shvproto::{Map, MetaMap, RpcValue, rpcvalue}; use shvrpc::rpc::{Glob, ShvRI, SubscriptionParam}; -use crate::shvnode::{AppNode, BrokerAccessMountsNode, BrokerAccessRolesNode, BrokerAccessUsersNode, BrokerCurrentClientNode, BrokerNode, DIR_APP, DIR_BROKER, DIR_BROKER_ACCESS_MOUNTS, DIR_BROKER_ACCESS_ROLES, DIR_BROKER_ACCESS_USERS, DIR_BROKER_CURRENT_CLIENT, find_longest_prefix, METH_DIR, METH_SUBSCRIBE, process_local_dir_ls, ShvNode, ProcessRequestRetval}; +use crate::shvnode::{AppNode, BrokerAccessMountsNode, BrokerAccessRolesNode, BrokerAccessUsersNode, BrokerCurrentClientNode, BrokerNode, DIR_APP, DIR_BROKER, DIR_BROKER_ACCESS_MOUNTS, DIR_BROKER_ACCESS_ROLES, DIR_BROKER_ACCESS_USERS, DIR_BROKER_CURRENT_CLIENT, find_longest_prefix, METH_DIR, METH_SUBSCRIBE, process_local_dir_ls, ShvNode, ProcessRequestRetval, DIR_SHV2_BROKER_ETC_ACL_MOUNTS, DIR_SHV2_BROKER_ETC_ACL_USERS}; use shvrpc::util::{join_path, sha1_hash, split_glob_on_match}; use log::Level; use shvrpc::metamethod::{AccessLevel}; @@ -184,7 +184,7 @@ pub(crate) async fn broker_loop(broker: BrokerImpl) { pub async fn accept_loop(config: BrokerConfig, access: AccessConfig, sql_connection: Option) -> shvrpc::Result<()> { if let Some(address) = config.listen.tcp.clone() { - let broker_impl = BrokerImpl::new(access, sql_connection); + let broker_impl = BrokerImpl::new(&config, access, sql_connection); let broker_sender = broker_impl.command_sender.clone(); let parent_broker_peer_config = config.parent_broker.clone(); let broker_task = task::spawn(broker_loop(broker_impl)); @@ -732,7 +732,7 @@ fn split_mount_point(mount_point: &str) -> shvrpc::Result<(&str, &str)> { Ok((prefix, dir)) } impl BrokerImpl { - pub(crate) fn new(access: AccessConfig, sql_connection: Option) -> Self { + pub(crate) fn new(config: &BrokerConfig, access: AccessConfig, sql_connection: Option) -> Self { let (command_sender, command_receiver) = unbounded(); let mut role_access: HashMap> = Default::default(); for (name, role) in &access.roles { @@ -779,6 +779,10 @@ impl BrokerImpl { add_node(DIR_BROKER_ACCESS_MOUNTS, Box::new(BrokerAccessMountsNode::new())); add_node(DIR_BROKER_ACCESS_USERS, Box::new(BrokerAccessUsersNode::new())); add_node(DIR_BROKER_ACCESS_ROLES, Box::new(BrokerAccessRolesNode::new())); + if config.shv2_compatibility { + add_node(DIR_SHV2_BROKER_ETC_ACL_MOUNTS, Box::new(BrokerAccessMountsNode::new())); + add_node(DIR_SHV2_BROKER_ETC_ACL_USERS, Box::new(BrokerAccessUsersNode::new())); + } broker } pub(crate) async fn process_rpc_frame(&mut self, peer_id: PeerId, frame: RpcFrame) -> shvrpc::Result<()> { @@ -1232,7 +1236,7 @@ mod test { fn test_broker() { let config = BrokerConfig::default(); let access = config.access.clone(); - let broker = BrokerImpl::new(access, None); + let broker = BrokerImpl::new(&config, access, None); let roles = state_reader(&broker.state).flatten_roles("child-broker").unwrap(); assert_eq!(roles, vec!["child-broker", "device", "client", "ping", "subscribe", "browse"]); } diff --git a/src/config.rs b/src/config.rs index a3ecf4f..dcbf6ab 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,6 +10,8 @@ pub struct BrokerConfig { #[serde(default)] pub use_access_db: bool, #[serde(default)] + pub shv2_compatibility: bool, + #[serde(default)] pub data_directory: Option, #[serde(default)] pub parent_broker: ParentBrokerConfig, @@ -128,6 +130,7 @@ impl Default for BrokerConfig { Self { listen: Listen { tcp: Some("localhost:3755".to_string()), ssl: None }, use_access_db: false, + shv2_compatibility: false, data_directory: None, parent_broker: Default::default(), access: AccessConfig { diff --git a/src/shvnode.rs b/src/shvnode.rs index f1f941b..0768e6b 100644 --- a/src/shvnode.rs +++ b/src/shvnode.rs @@ -404,6 +404,11 @@ pub const DIR_BROKER_ACCESS_MOUNTS: &str = ".broker/access/mounts"; pub const DIR_BROKER_ACCESS_USERS: &str = ".broker/access/users"; pub const DIR_BROKER_ACCESS_ROLES: &str = ".broker/access/roles"; +pub const DIR_SHV2_BROKER_ETC_ACL_USERS: &str = ".broker/etc/acl/users"; +pub const DIR_SHV2_BROKER_ETC_ACL_ROLES: &str = ".broker/etc/acl/roles"; +pub const DIR_SHV2_BROKER_ETC_ACL_ACCESS: &str = ".broker/etc/acl/access"; +pub const DIR_SHV2_BROKER_ETC_ACL_MOUNTS: &str = ".broker/etc/acl/mounts"; + pub const METH_CLIENT_INFO: &str = "clientInfo"; pub const METH_MOUNTED_CLIENT_INFO: &str = "mountedClientInfo"; pub const METH_CLIENTS: &str = "clients"; diff --git a/src/test.rs b/src/test.rs index 1c96946..efa0da4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -53,7 +53,7 @@ async fn test_broker_loop() { let config = BrokerConfig::default(); let access = config.access.clone(); let sql = Connection::open_in_memory().unwrap(); - let broker = BrokerImpl::new(access, Some(sql)); + let broker = BrokerImpl::new(&config, access, Some(sql)); let broker_sender = broker.command_sender.clone(); let broker_task = task::spawn(crate::brokerimpl::broker_loop(broker)); @@ -217,7 +217,7 @@ async fn test_broker_loop() { async fn test_tunnel_loop() { let config = BrokerConfig::default(); let access = config.access.clone(); - let broker = BrokerImpl::new(access, None); + let broker = BrokerImpl::new(&config, access, None); let broker_sender = broker.command_sender.clone(); let broker_task = task::spawn(crate::brokerimpl::broker_loop(broker)); @@ -251,7 +251,7 @@ async fn test_tunnel_loop() { assert_eq!(tunid.err().unwrap().code, RpcErrorCode::MethodCallException); // service is running - // ncat -e /bin/cat -k -l 8888 + println!("To pass tests ensure that this is running: ncat -e /bin/cat -k -l 8888"); let param = Map::from([("host".to_string(), "localhost:8888".into())]); let tunid = call(".app/tunnel", "create", Some(param.into()), &call_ctx).await.unwrap(); assert!(tunid.is_string());