@@ -4,10 +4,11 @@ use std::sync::Arc;
44
55use async_compression:: tokio:: write:: GzipEncoder ;
66use futures:: { StreamExt , TryStreamExt } ;
7+ use log:: error;
78use sha1:: Digest ;
89use shvclient:: appnodes:: DOT_APP_METHODS ;
9- use shvclient:: clientnode:: { rpc_error_unknown_method_on_path , LsHandlerResult } ;
10- use shvclient:: clientnode:: { ResolvedRequest , StaticNode , METH_DIR , METH_LS } ;
10+ use shvclient:: clientnode:: { err_unresolved_request , LsHandlerResult , Method , RequestHandlerResult , UnresolvedRequest } ;
11+ use shvclient:: clientnode:: StaticNode ;
1112use shvclient:: shvproto:: RpcValue ;
1213use shvclient:: ClientCommandSender ;
1314use shvrpc:: metamethod:: { AccessLevel , MetaMethod } ;
@@ -105,10 +106,10 @@ fn path_contains_parent_dir_references(path: impl AsRef<str>) -> bool {
105106
106107async fn shvjournal_request_handler (
107108 path : String ,
108- method : String ,
109+ method : Method ,
109110 param : RpcValue ,
110111 app_state : Arc < State > ,
111- ) -> Result < ResolvedRequest , RpcError >
112+ ) -> RequestHandlerResult
112113{
113114 async fn get_journaldir_entries ( path : impl AsRef < Path > ) -> Result < ReadDirStream , RpcError > {
114115 Ok ( ReadDirStream :: new (
@@ -210,7 +211,7 @@ async fn shvjournal_request_handler(
210211
211212 if path_contains_parent_dir_references ( & path) {
212213 // Reject parent dir references
213- return Err ( rpc_error_unknown_method_on_path ( path , method ) ) ;
214+ return err_unresolved_request ( )
214215 }
215216 let is_shvjournal_root = & path == "_shvjournal" ;
216217 let path = path. replacen ( "_shvjournal" , & app_state. config . journal_dir , 1 ) ;
@@ -225,53 +226,56 @@ async fn shvjournal_request_handler(
225226 MetaMethod :: new_static ( METH_SYNC_INFO , 0 , AccessLevel :: Read , "String" , "Map" , & [ ] , "syncInfo - returns info about sites' sync status\n Optionally takes a string that filters the sites by prefix.\n \n Returns: a map where they is the path of the site and the value is a map with a status string and a last updated timestamp.\n " ) ,
226227 MetaMethod :: new_static ( METH_SANITIZE_LOG , 0 , AccessLevel :: Developer , "Null" , "String" , & [ ] , "" ) ,
227228 ] ;
228- match method. as_ref ( ) {
229- METH_DIR => return Ok ( ResolvedRequest :: dir ( METHODS ) ) ,
230- METH_LS => return Ok ( ResolvedRequest :: ls ( METHODS , async || {
229+ match method {
230+ Method :: Dir ( dir ) => return dir. resolve ( METHODS ) ,
231+ Method :: Ls ( ls ) => return ls . resolve ( METHODS , async || {
231232 journaldir_ls_handler ( get_journaldir_entries ( path) . await ?) . await
232- } ) ) ,
233- METH_LS_FILES => return Ok ( ResolvedRequest :: method ( METHODS , method, async || {
234- journaldir_lsfiles_handler ( get_journaldir_entries ( path) . await ?) . await
235- } ) ) ,
236- METH_LOG_SIZE_LIMIT => return Ok ( ResolvedRequest :: method ( METHODS , method, async move || Ok ( log_size_limit ( & app_state. config ) ) ) ) ,
237- METH_TOTAL_LOG_SIZE => return Ok ( ResolvedRequest :: method ( METHODS , method, async move || total_log_size ( & app_state. config )
233+ } ) ,
234+ Method :: Other ( m) => match m. method ( ) {
235+ METH_LS_FILES => return m. resolve ( METHODS , async || {
236+ journaldir_lsfiles_handler ( get_journaldir_entries ( path) . await ?) . await
237+ } ) ,
238+ METH_LOG_SIZE_LIMIT => return m. resolve ( METHODS , async move || Ok ( log_size_limit ( & app_state. config ) ) ) ,
239+ METH_TOTAL_LOG_SIZE => return m. resolve ( METHODS , async move || total_log_size ( & app_state. config )
238240 . await
239241 . map ( RpcValue :: from)
240- . map_err ( rpc_error_filesystem) )
241- ) ,
242- METH_LOG_USAGE => return Ok ( ResolvedRequest :: method ( METHODS , method, async move || total_log_size ( & app_state. config )
243- . await
244- . map ( |size| 100. * ( size as f64 ) / ( log_size_limit ( & app_state. config ) as f64 ) )
245- . map_err ( rpc_error_filesystem) )
246- ) ,
247- METH_SYNC_LOG => return Ok ( ResolvedRequest :: method ( METHODS , method, async move || sync_log_request_handler ( & param, app_state) . await ) ) ,
248- METH_SYNC_INFO => return Ok ( ResolvedRequest :: method ( METHODS , method, async move || Ok ( ( * app_state. sync_info . sites_sync_info . read ( ) . await ) . to_owned ( ) ) ) ) ,
249- METH_SANITIZE_LOG => return Ok ( ResolvedRequest :: method ( METHODS , method, async move || app_state. sync_cmd_tx
250- . send ( crate :: sync:: SyncCommand :: Cleanup )
251- . map ( |_| true )
252- . map_err ( |_| RpcError :: new ( RpcErrorCode :: InternalError , "Cannot send the command through the channel" ) )
253- ) ) ,
254- _ => return Err ( rpc_error_method_not_found ( ) ) ,
242+ . map_err ( rpc_error_filesystem)
243+ ) ,
244+ METH_LOG_USAGE => return m. resolve ( METHODS , async move || total_log_size ( & app_state. config )
245+ . await
246+ . map ( |size| 100. * ( size as f64 ) / ( log_size_limit ( & app_state. config ) as f64 ) )
247+ . map_err ( rpc_error_filesystem)
248+ ) ,
249+ METH_SYNC_LOG => return m. resolve ( METHODS , async move || sync_log_request_handler ( & param, app_state) . await ) ,
250+ METH_SYNC_INFO => return m. resolve ( METHODS , async move || Ok ( ( * app_state. sync_info . sites_sync_info . read ( ) . await ) . to_owned ( ) ) ) ,
251+ METH_SANITIZE_LOG => return m. resolve ( METHODS , async move || app_state. sync_cmd_tx
252+ . send ( crate :: sync:: SyncCommand :: Cleanup )
253+ . map ( |_| true )
254+ . map_err ( |_| RpcError :: new ( RpcErrorCode :: InternalError , "Cannot send the command through the channel" ) )
255+ ) ,
256+ _ => return err_unresolved_request ( ) ,
257+ }
255258 }
256259 }
257260
258261 // Probe the path on the fs. Prevent leaking FS info to unauthorized
259262 // users, do not return `rpc_error_filesystem`.
260263 let path_meta = tokio:: fs:: metadata ( & path)
261264 . await
262- . map_err ( |_| rpc_error_unknown_method_on_path ( & path, & method) ) ?;
265+ . inspect_err ( |err| error ! ( "Cannot read FS metadata, path: {path}, error: {err}" ) )
266+ . or ( Err ( UnresolvedRequest ) ) ?;
263267
264268 if path_meta. is_dir ( ) {
265269 const METHODS : & [ MetaMethod ] = & [ META_METHOD_LS_FILES ] ;
266- match method. as_str ( ) {
267- METH_DIR => Ok ( ResolvedRequest :: dir ( METHODS ) ) ,
268- METH_LS => Ok ( ResolvedRequest :: ls ( METHODS , async || {
270+ match method {
271+ Method :: Dir ( dir ) => dir. resolve ( METHODS ) ,
272+ Method :: Ls ( ls ) => ls . resolve ( METHODS , async || {
269273 journaldir_ls_handler ( get_journaldir_entries ( path) . await ?) . await
270- } ) ) ,
271- METH_LS_FILES => Ok ( ResolvedRequest :: method ( METHODS , method , async || {
274+ } ) ,
275+ Method :: Other ( m ) if m . method ( ) == METH_LS_FILES => m . resolve ( METHODS , async || {
272276 journaldir_lsfiles_handler ( get_journaldir_entries ( path) . await ?) . await
273- } ) ) ,
274- _ => Err ( rpc_error_method_not_found ( ) ) ,
277+ } ) ,
278+ _ => err_unresolved_request ( ) ,
275279 }
276280 } else if path_meta. is_file ( ) {
277281 const METHODS : & [ MetaMethod ] = & [
@@ -280,15 +284,18 @@ async fn shvjournal_request_handler(
280284 MetaMethod :: new_static ( METH_READ , 0 , AccessLevel :: Read , "Map" , "Blob" , & [ ] , "Parameters\n offset: file offset to start read, default is 0\n size: number of bytes to read starting on offset, default is till end of file\n " ) ,
281285 MetaMethod :: new_static ( METH_READ_COMPRESSED , 0 , AccessLevel :: Read , "Map" , "Blob" , & [ ] , "Parameters\n read() parameters\n compressionType: gzip (default) | qcompress" ) ,
282286 ] ;
283- match method. as_str ( ) {
284- METH_DIR => Ok ( ResolvedRequest :: dir ( METHODS ) ) ,
285- METH_LS => Ok ( ResolvedRequest :: ls ( METHODS , ls_empty) ) ,
286- _ => Ok ( ResolvedRequest :: method ( METHODS , method. clone ( ) , async move || {
287- journalfile_methods_handler ( & method, & path, path_meta. len ( ) , & param) . await
288- } ) ) ,
287+ match method {
288+ Method :: Dir ( dir) => dir. resolve ( METHODS ) ,
289+ Method :: Ls ( ls) => ls. resolve ( METHODS , ls_empty) ,
290+ Method :: Other ( m) => {
291+ let method = m. method ( ) . to_owned ( ) ;
292+ m. resolve ( METHODS , async move || {
293+ journalfile_methods_handler ( & method, & path, path_meta. len ( ) , & param) . await
294+ } )
295+ } ,
289296 }
290297 } else {
291- Err ( rpc_error_unknown_method_on_path ( path , method ) )
298+ err_unresolved_request ( )
292299 }
293300}
294301
@@ -562,20 +569,20 @@ pub(crate) async fn request_handler(
562569 rq : RpcMessage ,
563570 client_cmd_tx : ClientCommandSender ,
564571 app_state : Arc < State > ,
565- ) -> Result < ResolvedRequest , RpcError >
572+ ) -> RequestHandlerResult
566573{
567574 let path = rq. shv_path ( ) . map_or_else ( String :: new, String :: from) ;
568- let method = rq . method ( ) . map_or_else ( String :: new , String :: from ) ;
575+ let method = Method :: from_request ( & rq ) ;
569576 let param = rq. param ( ) . map_or_else ( RpcValue :: null, RpcValue :: clone) ;
570577
571578 match NodeType :: from_path ( & path) {
572579 NodeType :: DotApp => {
573- match method. as_str ( ) {
574- METH_DIR => Ok ( ResolvedRequest :: dir ( DOT_APP_METHODS ) ) ,
575- METH_LS => Ok ( ResolvedRequest :: ls ( DOT_APP_METHODS , ls_empty) ) ,
576- _ => Ok ( ResolvedRequest :: method_opt ( DOT_APP_METHODS , method , async move ||
577- DOT_APP_NODE . process_request ( rq, client_cmd_tx) . await
578- ) ) ,
580+ match method {
581+ Method :: Dir ( dir ) => dir. resolve ( DOT_APP_METHODS ) ,
582+ Method :: Ls ( ls ) => ls . resolve ( DOT_APP_METHODS , ls_empty) ,
583+ Method :: Other ( m ) => m . resolve_opt ( DOT_APP_METHODS , async move ||
584+ DOT_APP_NODE . process_request ( rq, client_cmd_tx) . await
585+ ) ,
579586 }
580587 }
581588 NodeType :: ShvJournal =>
@@ -585,11 +592,11 @@ pub(crate) async fn request_handler(
585592 MetaMethod :: new_static ( METH_GET , 0 , AccessLevel :: Developer , "String" , "RpcValue" , & [ ] , "" ) ,
586593 MetaMethod :: new_static ( METH_GET_CACHE , 0 , AccessLevel :: Developer , "Null" , "Map" , & [ ] , "" ) ,
587594 ] ;
588- match method. as_str ( ) {
589- METH_DIR => Ok ( ResolvedRequest :: dir ( METHODS ) ) ,
590- METH_LS => Ok ( ResolvedRequest :: ls ( METHODS , ls_empty) ) ,
591- METH_GET | METH_GET_CACHE => Ok ( ResolvedRequest :: method ( METHODS , method , async || Err :: < ( ) , _ > ( rpc_error_not_implemented ( ) ) ) ) ,
592- _ => Err ( rpc_error_method_not_found ( ) ) ,
595+ match method {
596+ Method :: Dir ( dir ) => dir. resolve ( METHODS ) ,
597+ Method :: Ls ( ls ) => ls . resolve ( METHODS , ls_empty) ,
598+ Method :: Other ( m ) if m . method ( ) == METH_GET || m . method ( ) == METH_GET_CACHE => m . resolve ( METHODS , async || Err :: < ( ) , _ > ( rpc_error_not_implemented ( ) ) ) ,
599+ _ => err_unresolved_request ( ) ,
593600 }
594601 }
595602 NodeType :: Root => {
@@ -607,9 +614,9 @@ pub(crate) async fn request_handler(
607614 // shvGitCommit
608615 // reloadSites (wr) -> Bool
609616 ] ;
610- match method. as_str ( ) {
611- METH_DIR => Ok ( ResolvedRequest :: dir ( METHODS ) ) ,
612- METH_LS => {
617+ match method {
618+ Method :: Dir ( dir ) => dir. resolve ( METHODS ) ,
619+ Method :: Ls ( ls ) => {
613620 let ls_handler = async move || {
614621 let mut nodes = vec ! [
615622 ".app" . to_string( ) ,
@@ -620,25 +627,27 @@ pub(crate) async fn request_handler(
620627 nodes. append ( & mut children_on_path ( & app_state. sites_data . read ( ) . await . sites_info , ROOT_PATH ) . unwrap_or_default ( ) ) ;
621628 Ok ( nodes)
622629 } ;
623- Ok ( ResolvedRequest :: ls ( METHODS , ls_handler) )
630+ ls. resolve ( METHODS , ls_handler)
631+ }
632+ Method :: Other ( m) => match m. method ( ) {
633+ METH_VERSION => m. resolve ( METHODS , async || Ok ( env ! ( "CARGO_PKG_VERSION" ) ) ) ,
634+ METH_UPTIME => m. resolve ( METHODS , async move || {
635+ Ok ( humantime:: format_duration ( std:: time:: Duration :: from_secs ( app_state. start_time . elapsed ( ) . as_secs ( ) ) ) . to_string ( ) )
636+ } ) ,
637+ METH_ALARM_LOG => m. resolve ( METHODS , async move || {
638+ let params = AlarmLogParams :: try_from ( param)
639+ . map_err ( |err| RpcError :: new ( RpcErrorCode :: InvalidParam , format ! ( "Wrong alarmLog parameters: {err}" ) ) ) ?;
640+ Ok ( alarmlog_impl ( & path, & params, app_state) . await )
641+ } ) ,
642+ _ => err_unresolved_request ( ) ,
624643 }
625- METH_VERSION => Ok ( ResolvedRequest :: method ( METHODS , method, async || Ok ( env ! ( "CARGO_PKG_VERSION" ) ) ) ) ,
626- METH_UPTIME => Ok ( ResolvedRequest :: method ( METHODS , method, async move || {
627- Ok ( humantime:: format_duration ( std:: time:: Duration :: from_secs ( app_state. start_time . elapsed ( ) . as_secs ( ) ) ) . to_string ( ) )
628- } ) ) ,
629- METH_ALARM_LOG => Ok ( ResolvedRequest :: method ( METHODS , method, async move || {
630- let params = AlarmLogParams :: try_from ( param)
631- . map_err ( |err| RpcError :: new ( RpcErrorCode :: InvalidParam , format ! ( "Wrong alarmLog parameters: {err}" ) ) ) ?;
632- Ok ( alarmlog_impl ( & path, & params, app_state) . await )
633- } ) ) ,
634- _ => Err ( rpc_error_method_not_found ( ) ) ,
635644 }
636645 }
637646 NodeType :: History => {
638647 let methods = {
639648 let sites_data = app_state. sites_data . read ( ) . await ;
640649 let is_site_path = children_on_path ( & sites_data. sites_info , & path)
641- . ok_or_else ( || rpc_error_unknown_method_on_path ( & path , & method ) ) ?
650+ . ok_or ( UnresolvedRequest ) ?
642651 . is_empty ( ) ;
643652 if is_site_path {
644653 let is_pushlog = sites_data. sites_info . get ( & path)
@@ -661,26 +670,23 @@ pub(crate) async fn request_handler(
661670 METHODS
662671 }
663672 } ;
664- match method. as_str ( ) {
665- METH_DIR => Ok ( ResolvedRequest :: dir ( methods) ) ,
666- METH_LS => {
667- Ok ( ResolvedRequest :: ls ( methods, async move || {
673+ match method {
674+ Method :: Dir ( dir ) => dir. resolve ( methods) ,
675+ Method :: Ls ( ls ) => {
676+ ls . resolve ( methods, async move || {
668677 let children = children_on_path ( & app_state. sites_data . read ( ) . await . sites_info , & path)
669678 . unwrap_or_else ( || panic ! ( "Children on path `{path}` should be Some after methods processing" ) ) ;
670679 Ok ( children)
671- } ) )
680+ } )
672681 }
673- _ => Ok ( ResolvedRequest :: method ( methods, method. clone ( ) , async move || {
674- match method. as_str ( ) {
675- METH_GET_LOG => getlog_handler_rq ( & path, & param, app_state) . await ,
676- METH_ALARM_TABLE => alarmtable_handler :: < CommonAlarm > ( & path, app_state) . await ,
677- METH_STATE_ALARM_TABLE => alarmtable_handler :: < StateAlarm > ( & path, app_state) . await ,
678- METH_ALARM_LOG => alarmlog_handler ( & path, & param, app_state) . await ,
679- METH_PUSH_LOG => pushlog_handler ( & path, param, app_state) . await ,
680- _ => Err ( rpc_error_method_not_found ( ) ) ,
681- }
682-
683- } ) ) ,
682+ Method :: Other ( m) => match m. method ( ) {
683+ METH_GET_LOG => m. resolve ( methods, async move || { getlog_handler_rq ( & path, & param, app_state) . await } ) ,
684+ METH_ALARM_TABLE => m. resolve ( methods, async move || { alarmtable_handler :: < CommonAlarm > ( & path, app_state) . await } ) ,
685+ METH_STATE_ALARM_TABLE => m. resolve ( methods, async move || { alarmtable_handler :: < StateAlarm > ( & path, app_state) . await } ) ,
686+ METH_ALARM_LOG => m. resolve ( methods, async move || { alarmlog_handler ( & path, & param, app_state) . await } ) ,
687+ METH_PUSH_LOG => m. resolve ( methods, async move || { pushlog_handler ( & path, param, app_state) . await } ) ,
688+ _ => err_unresolved_request ( ) ,
689+ } ,
684690 }
685691 }
686692 }
0 commit comments