diff --git a/.ci/docker-compose-file/docker-compose-gcp-emulator.yaml b/.ci/docker-compose-file/docker-compose-gcp-emulator.yaml new file mode 100644 index 000000000..1f68e05d4 --- /dev/null +++ b/.ci/docker-compose-file/docker-compose-gcp-emulator.yaml @@ -0,0 +1,23 @@ +version: '3.9' + +services: + gcp_emulator: + container_name: gcp_emulator + image: gcr.io/google.com/cloudsdktool/google-cloud-cli:435.0.1-emulators + restart: always + expose: + - "8085" + # ports: + # - "8085:8085" + networks: + - emqx_bridge + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8085"] + interval: 30s + timeout: 5s + retries: 4 + command: + - bash + - "-c" + - | + gcloud beta emulators pubsub start --project=emqx-pubsub --host-port=0.0.0.0:8085 --impersonate-service-account test@emqx.iam.gserviceaccount.com diff --git a/.ci/docker-compose-file/toxiproxy.json b/.ci/docker-compose-file/toxiproxy.json index 8695acde9..87878ac92 100644 --- a/.ci/docker-compose-file/toxiproxy.json +++ b/.ci/docker-compose-file/toxiproxy.json @@ -149,5 +149,11 @@ "listen": "0.0.0.0:19100", "upstream": "minio-tls:9100", "enabled": true + }, + { + "name": "gcp_emulator", + "listen": "0.0.0.0:8085", + "upstream": "gcp_emulator:8085", + "enabled": true } ] diff --git a/apps/emqx/test/emqx_static_checks_data/5.0.bpapi b/apps/emqx/test/emqx_static_checks_data/5.0.bpapi index 64dfac537..040fbee19 100644 --- a/apps/emqx/test/emqx_static_checks_data/5.0.bpapi +++ b/apps/emqx/test/emqx_static_checks_data/5.0.bpapi @@ -1 +1 @@ -#{api => #{{emqx_gateway_cm,1} => #{calls => [{{emqx_gateway_cm_proto_v1,cast,['GwName','ClientId','ChanPid','Req']},{emqx_gateway_cm,do_cast,['GwName','ClientId','ChanPid','Req']}},{{emqx_gateway_cm_proto_v1,call,['GwName','ClientId','ChanPid','Req']},{emqx_gateway_cm,do_call,['GwName','ClientId','ChanPid','Req']}},{{emqx_gateway_cm_proto_v1,call,['GwName','ClientId','ChanPid','Req','Timeout']},{emqx_gateway_cm,do_call,['GwName','ClientId','ChanPid','Req','Timeout']}},{{emqx_gateway_cm_proto_v1,takeover_session,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_takeover_session,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,get_chann_conn_mod,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_get_chann_conn_mod,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,kick_session,['GwName','Action','ClientId','ChanPid']},{emqx_gateway_cm,do_kick_session,['GwName','Action','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,set_chan_stats,['GwName','ClientId','ChanPid','Stats']},{emqx_gateway_cm,do_set_chan_stats,['GwName','ClientId','ChanPid','Stats']}},{{emqx_gateway_cm_proto_v1,get_chan_stats,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_get_chan_stats,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,set_chan_info,['GwName','ClientId','ChanPid','Infos']},{emqx_gateway_cm,do_set_chan_info,['GwName','ClientId','ChanPid','Infos']}},{{emqx_gateway_cm_proto_v1,get_chan_info,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_get_chan_info,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,lookup_by_clientid,['Nodes','GwName','ClientId']},{emqx_gateway_cm,do_lookup_by_clientid,['GwName','ClientId']}}],casts => []},{emqx_authn,1} => #{calls => [{{emqx_authn_proto_v1,lookup_from_all_nodes,['Nodes','ChainName','AuthenticatorID']},{emqx_authn_api,lookup_from_local_node,['ChainName','AuthenticatorID']}}],casts => []},{emqx_bridge,4} => #{calls => [{{emqx_bridge_proto_v4,get_metrics_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,get_metrics_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,start_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,start_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,list_bridges_on_nodes,['Nodes']},{emqx_bridge,list,[]}}],casts => []},{emqx_gateway_api_listeners,1} => #{calls => [{{emqx_gateway_api_listeners_proto_v1,listeners_cluster_status,['Nodes','Listeners']},{emqx_gateway_api_listeners,do_listeners_cluster_status,['Listeners']}}],casts => []},{emqx_slow_subs,1} => #{calls => [{{emqx_slow_subs_proto_v1,get_history,['Nodes']},{emqx_slow_subs_api,get_history,[]}},{{emqx_slow_subs_proto_v1,clear_history,['Nodes']},{emqx_slow_subs,clear_history,[]}}],casts => []},{emqx_license,1} => #{calls => [{{emqx_license_proto_v1,remote_connection_counts,['Nodes']},{emqx_license_resources,local_connection_count,[]}}],casts => []},{emqx_exhook,1} => #{calls => [{{emqx_exhook_proto_v1,server_hooks_metrics,['Nodes','Name']},{emqx_exhook_mgr,server_hooks_metrics,['Name']}},{{emqx_exhook_proto_v1,server_info,['Nodes','Name']},{emqx_exhook_mgr,server_info,['Name']}},{{emqx_exhook_proto_v1,all_servers_info,['Nodes']},{emqx_exhook_mgr,all_servers_info,[]}}],casts => []},{emqx_cm,1} => #{calls => [{{emqx_cm_proto_v1,kick_session,['Action','ClientId','ChanPid']},{emqx_cm,do_kick_session,['Action','ClientId','ChanPid']}},{{emqx_cm_proto_v1,takeover_session,['ClientId','ChanPid']},{emqx_cm,takeover_session,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,get_chann_conn_mod,['ClientId','ChanPid']},{emqx_cm,do_get_chann_conn_mod,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,get_chan_info,['ClientId','ChanPid']},{emqx_cm,do_get_chan_info,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,get_chan_stats,['ClientId','ChanPid']},{emqx_cm,do_get_chan_stats,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,lookup_client,['Node','Key']},{emqx_cm,lookup_client,['Key']}},{{emqx_cm_proto_v1,kickout_client,['Node','ClientId']},{emqx_cm,kick_session,['ClientId']}}],casts => []},{emqx_license,2} => #{calls => [{{emqx_license_proto_v2,remote_connection_counts,['Nodes']},{emqx_license_resources,local_connection_count,[]}}],casts => []},{emqx_retainer,1} => #{calls => [{{emqx_retainer_proto_v1,wait_dispatch_complete,['Nodes','Timeout']},{emqx_retainer_dispatcher,wait_dispatch_complete,['Timeout']}}],casts => []},{emqx_node_rebalance,1} => #{calls => [{{emqx_node_rebalance_proto_v1,disconnected_session_counts,['Nodes']},{emqx_node_rebalance,disconnected_session_count,[]}},{{emqx_node_rebalance_proto_v1,disable_rebalance_agent,['Nodes','OwnerPid']},{emqx_node_rebalance_agent,disable,['OwnerPid']}},{{emqx_node_rebalance_proto_v1,enable_rebalance_agent,['Nodes','OwnerPid']},{emqx_node_rebalance_agent,enable,['OwnerPid']}},{{emqx_node_rebalance_proto_v1,session_counts,['Nodes']},{emqx_node_rebalance,session_count,[]}},{{emqx_node_rebalance_proto_v1,connection_counts,['Nodes']},{emqx_node_rebalance,connection_count,[]}},{{emqx_node_rebalance_proto_v1,evict_sessions,['Nodes','Count','RecipientNodes','ConnState']},{emqx_eviction_agent,evict_sessions,['Count','RecipientNodes','ConnState']}},{{emqx_node_rebalance_proto_v1,evict_connections,['Nodes','Count']},{emqx_eviction_agent,evict_connections,['Count']}},{{emqx_node_rebalance_proto_v1,available_nodes,['Nodes']},{emqx_node_rebalance,is_node_available,[]}}],casts => []},{emqx_broker,1} => #{calls => [{{emqx_broker_proto_v1,list_subscriptions_via_topic,['Node','Topic']},{emqx_broker,subscriptions_via_topic,['Topic']}},{{emqx_broker_proto_v1,list_client_subscriptions,['Node','ClientId']},{emqx_broker,subscriptions,['ClientId']}},{{emqx_broker_proto_v1,forward,['Node','Topic','Delivery']},{emqx_broker,dispatch,['Topic','Delivery']}}],casts => [{{emqx_broker_proto_v1,forward_async,['Node','Topic','Delivery']},{emqx_broker,dispatch,['Topic','Delivery']}}]},{emqx_topic_metrics,1} => #{calls => [{{emqx_topic_metrics_proto_v1,reset,['Nodes','Topic']},{emqx_topic_metrics,reset,['Topic']}},{{emqx_topic_metrics_proto_v1,reset,['Nodes']},{emqx_topic_metrics,reset,[]}},{{emqx_topic_metrics_proto_v1,metrics,['Nodes','Topic']},{emqx_topic_metrics,metrics,['Topic']}},{{emqx_topic_metrics_proto_v1,metrics,['Nodes']},{emqx_topic_metrics,metrics,[]}}],casts => []},{emqx_resource,1} => #{calls => [{{emqx_resource_proto_v1,reset_metrics,['ResId']},{emqx_resource,reset_metrics_local,['ResId']}},{{emqx_resource_proto_v1,remove,['ResId']},{emqx_resource,remove_local,['ResId']}},{{emqx_resource_proto_v1,recreate,['ResId','ResourceType','Config','Opts']},{emqx_resource,recreate_local,['ResId','ResourceType','Config','Opts']}},{{emqx_resource_proto_v1,create_dry_run,['ResourceType','Config']},{emqx_resource,create_dry_run_local,['ResourceType','Config']}},{{emqx_resource_proto_v1,create,['ResId','Group','ResourceType','Config','Opts']},{emqx_resource,create_local,['ResId','Group','ResourceType','Config','Opts']}}],casts => []},{emqx_bridge,1} => #{calls => [{{emqx_bridge_proto_v1,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,list_bridges,['Node']},{emqx_bridge,list,[]}}],casts => []},{emqx_mgmt_trace,1} => #{calls => [{{emqx_mgmt_trace_proto_v1,read_trace_file,['Node','Name','Position','Limit']},{emqx_mgmt_api_trace,read_trace_file,['Name','Position','Limit']}},{{emqx_mgmt_trace_proto_v1,trace_file,['Nodes','File']},{emqx_trace,trace_file,['File']}},{{emqx_mgmt_trace_proto_v1,get_trace_size,['Nodes']},{emqx_mgmt_api_trace,get_trace_size,[]}}],casts => []},{emqx_ft_storage_fs_reader,1} => #{calls => [{{emqx_ft_storage_fs_reader_proto_v1,read,['Node','Pid','Bytes']},{emqx_ft_storage_fs_reader,read,['Pid','Bytes']}}],casts => []},{emqx_bridge,2} => #{calls => [{{emqx_bridge_proto_v2,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,start_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,start_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,list_bridges,['Node']},{emqx_bridge,list,[]}}],casts => []},{emqx_eviction_agent,1} => #{calls => [{{emqx_eviction_agent_proto_v1,evict_session_channel,['Node','ClientId','ConnInfo','ClientInfo']},{emqx_eviction_agent,evict_session_channel,['ClientId','ConnInfo','ClientInfo']}}],casts => []},{emqx_node_rebalance_api,1} => #{calls => [{{emqx_node_rebalance_api_proto_v1,node_rebalance_stop,['Node']},{emqx_node_rebalance,stop,[]}},{{emqx_node_rebalance_api_proto_v1,node_rebalance_start,['Node','Opts']},{emqx_node_rebalance,start,['Opts']}},{{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_stop,['Node']},{emqx_node_rebalance_evacuation,stop,[]}},{{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_start,['Node','Opts']},{emqx_node_rebalance_evacuation,start,['Opts']}}],casts => []},{emqx,1} => #{calls => [{{emqx_proto_v1,delete_all_deactivated_alarms,['Node']},{emqx_alarm,delete_all_deactivated_alarms,[]}},{{emqx_proto_v1,deactivate_alarm,['Node','Name']},{emqx_alarm,deactivate,['Name']}},{{emqx_proto_v1,clean_pem_cache,['Node']},{ssl_pem_cache,clear,[]}},{{emqx_proto_v1,clean_authz_cache,['Node']},{emqx_authz_cache,drain_cache,[]}},{{emqx_proto_v1,clean_authz_cache,['Node','ClientId']},{emqx_authz_cache,drain_cache,['ClientId']}},{{emqx_proto_v1,get_metrics,['Node']},{emqx_metrics,all,[]}},{{emqx_proto_v1,get_stats,['Node']},{emqx_stats,getstats,[]}},{{emqx_proto_v1,get_alarms,['Node','Type']},{emqx_alarm,get_alarms,['Type']}},{{emqx_proto_v1,is_running,['Node']},{emqx,is_running,[]}}],casts => []},{emqx_shared_sub,1} => #{calls => [{{emqx_shared_sub_proto_v1,dispatch_with_ack,['Pid','Group','Topic','Msg','Timeout']},{emqx_shared_sub,do_dispatch_with_ack,['Pid','Group','Topic','Msg']}}],casts => [{{emqx_shared_sub_proto_v1,send,['Node','Pid','Topic','Msg']},{erlang,send,['Pid','Msg']}}]},{emqx_management,1} => #{calls => [{{emqx_management_proto_v1,get_full_config,['Node']},{emqx_mgmt_api_configs,get_full_config,[]}},{{emqx_management_proto_v1,call_client,['Node','ClientId','Req']},{emqx_mgmt,do_call_client,['ClientId','Req']}},{{emqx_management_proto_v1,unsubscribe,['Node','ClientId','Topic']},{emqx_mgmt,do_unsubscribe,['ClientId','Topic']}},{{emqx_management_proto_v1,subscribe,['Node','ClientId','TopicTables']},{emqx_mgmt,do_subscribe,['ClientId','TopicTables']}},{{emqx_management_proto_v1,list_listeners,['Node']},{emqx_mgmt_api_listeners,do_list_listeners,[]}},{{emqx_management_proto_v1,list_subscriptions,['Node']},{emqx_mgmt,do_list_subscriptions,[]}},{{emqx_management_proto_v1,broker_info,['Node']},{emqx_mgmt,broker_info,[]}},{{emqx_management_proto_v1,node_info,['Node']},{emqx_mgmt,node_info,[]}}],casts => []},{emqx_persistent_session,1} => #{calls => [{{emqx_persistent_session_proto_v1,resume_end,['Nodes','Pid','SessionID']},{emqx_session_router,resume_end,['Pid','SessionID']}},{{emqx_persistent_session_proto_v1,resume_begin,['Nodes','Pid','SessionID']},{emqx_session_router,resume_begin,['Pid','SessionID']}}],casts => []},{emqx_bridge,3} => #{calls => [{{emqx_bridge_proto_v3,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,start_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,start_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,list_bridges_on_nodes,['Nodes']},{emqx_bridge,list,[]}},{{emqx_bridge_proto_v3,list_bridges,['Node']},{emqx_bridge,list,[]}}],casts => []},{emqx_mgmt_api_plugins,1} => #{calls => [{{emqx_mgmt_api_plugins_proto_v1,ensure_action,['Name','Action']},{emqx_mgmt_api_plugins,ensure_action,['Name','Action']}},{{emqx_mgmt_api_plugins_proto_v1,delete_package,['Name']},{emqx_mgmt_api_plugins,delete_package,['Name']}},{{emqx_mgmt_api_plugins_proto_v1,describe_package,['Name']},{emqx_mgmt_api_plugins,describe_package,['Name']}},{{emqx_mgmt_api_plugins_proto_v1,install_package,['Filename','Bin']},{emqx_mgmt_api_plugins,install_package,['Filename','Bin']}},{{emqx_mgmt_api_plugins_proto_v1,get_plugins,[]},{emqx_mgmt_api_plugins,get_plugins,[]}}],casts => []},{emqx_mgmt_trace,2} => #{calls => [{{emqx_mgmt_trace_proto_v2,read_trace_file,['Node','Name','Position','Limit']},{emqx_mgmt_api_trace,read_trace_file,['Name','Position','Limit']}},{{emqx_mgmt_trace_proto_v2,trace_file_detail,['Nodes','File']},{emqx_trace,trace_file_detail,['File']}},{{emqx_mgmt_trace_proto_v2,trace_file,['Nodes','File']},{emqx_trace,trace_file,['File']}},{{emqx_mgmt_trace_proto_v2,get_trace_size,['Nodes']},{emqx_mgmt_api_trace,get_trace_size,[]}}],casts => []},{emqx_gateway_http,1} => #{calls => [{{emqx_gateway_http_proto_v1,get_cluster_status,['Nodes','GwName']},{emqx_gateway_http,gateway_status,['GwName']}}],casts => []},{emqx_node_rebalance_status,1} => #{calls => [{{emqx_node_rebalance_status_proto_v1,evacuation_status,['Nodes']},{emqx_node_rebalance_status,evacuation_status,[]}},{{emqx_node_rebalance_status_proto_v1,rebalance_status,['Nodes']},{emqx_node_rebalance_status,rebalance_status,[]}},{{emqx_node_rebalance_status_proto_v1,local_status,['Node']},{emqx_node_rebalance_status,local_status,[]}}],casts => []},{emqx_authz,1} => #{calls => [{{emqx_authz_proto_v1,lookup_from_all_nodes,['Nodes','Type']},{emqx_authz_api_sources,lookup_from_local_node,['Type']}}],casts => []},{emqx_plugins,1} => #{calls => [{{emqx_plugins_proto_v1,get_tar,['Node','NameVsn','Timeout']},{emqx_plugins,get_tar,['NameVsn']}}],casts => []},{emqx_ft_storage_exporter_fs,1} => #{calls => [{{emqx_ft_storage_exporter_fs_proto_v1,read_export_file,['Node','Filepath','CallerPid']},{emqx_ft_storage_exporter_fs_proxy,read_export_file_local,['Filepath','CallerPid']}},{{emqx_ft_storage_exporter_fs_proto_v1,list_exports,['Nodes','Query']},{emqx_ft_storage_exporter_fs_proxy,list_exports_local,['Query']}}],casts => []},{emqx_prometheus,1} => #{calls => [{{emqx_prometheus_proto_v1,stop,['Nodes']},{emqx_prometheus,do_stop,[]}},{{emqx_prometheus_proto_v1,start,['Nodes']},{emqx_prometheus,do_start,[]}}],casts => []},{emqx,2} => #{calls => [{{emqx_proto_v2,delete_all_deactivated_alarms,['Node']},{emqx_alarm,delete_all_deactivated_alarms,[]}},{{emqx_proto_v2,deactivate_alarm,['Node','Name']},{emqx_alarm,deactivate,['Name']}},{{emqx_proto_v2,clean_pem_cache,['Node']},{ssl_pem_cache,clear,[]}},{{emqx_proto_v2,clean_authz_cache,['Node']},{emqx_authz_cache,drain_cache,[]}},{{emqx_proto_v2,clean_authz_cache,['Node','ClientId']},{emqx_authz_cache,drain_cache,['ClientId']}},{{emqx_proto_v2,get_metrics,['Node']},{emqx_metrics,all,[]}},{{emqx_proto_v2,get_stats,['Node']},{emqx_stats,getstats,[]}},{{emqx_proto_v2,get_alarms,['Node','Type']},{emqx_alarm,get_alarms,['Type']}},{{emqx_proto_v2,are_running,['Nodes']},{emqx,is_running,[]}},{{emqx_proto_v2,is_running,['Node']},{emqx,is_running,[]}}],casts => []},{emqx_delayed,1} => #{calls => [{{emqx_delayed_proto_v1,delete_delayed_message,['Node','Id']},{emqx_delayed,delete_delayed_message,['Id']}},{{emqx_delayed_proto_v1,get_delayed_message,['Node','Id']},{emqx_delayed,get_delayed_message,['Id']}}],casts => []},{emqx_conf,2} => #{calls => [{{emqx_conf_proto_v2,get_override_config_file,['Nodes']},{emqx_conf_app,get_override_config_file,[]}},{{emqx_conf_proto_v2,reset,['Node','KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,reset,['KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,remove_config,['Node','KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,remove_config,['KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,update,['Node','KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v2,update,['KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v2,get_all,['KeyPath']},{emqx_conf,get_node_and_config,['KeyPath']}},{{emqx_conf_proto_v2,get_config,['Node','KeyPath','Default']},{emqx,get_config,['KeyPath','Default']}},{{emqx_conf_proto_v2,get_config,['Node','KeyPath']},{emqx,get_config,['KeyPath']}},{{emqx_conf_proto_v2,sync_data_from_node,['Node']},{emqx_conf_app,sync_data_from_node,[]}}],casts => []},{emqx_plugin_libs,1} => #{calls => [{{emqx_plugin_libs_proto_v1,get_metrics,['Node','HandlerName','MetricId']},{emqx_metrics_worker,get_metrics,['HandlerName','MetricId']}}],casts => []},{emqx_management,2} => #{calls => [{{emqx_management_proto_v2,get_full_config,['Node']},{emqx_mgmt_api_configs,get_full_config,[]}},{{emqx_management_proto_v2,call_client,['Node','ClientId','Req']},{emqx_mgmt,do_call_client,['ClientId','Req']}},{{emqx_management_proto_v2,unsubscribe,['Node','ClientId','Topic']},{emqx_mgmt,do_unsubscribe,['ClientId','Topic']}},{{emqx_management_proto_v2,subscribe,['Node','ClientId','TopicTables']},{emqx_mgmt,do_subscribe,['ClientId','TopicTables']}},{{emqx_management_proto_v2,list_listeners,['Node']},{emqx_mgmt_api_listeners,do_list_listeners,[]}},{{emqx_management_proto_v2,list_subscriptions,['Node']},{emqx_mgmt,do_list_subscriptions,[]}},{{emqx_management_proto_v2,broker_info,['Node']},{emqx_mgmt,broker_info,[]}},{{emqx_management_proto_v2,node_info,['Node']},{emqx_mgmt,node_info,[]}},{{emqx_management_proto_v2,unsubscribe_batch,['Node','ClientId','Topics']},{emqx_mgmt,do_unsubscribe_batch,['ClientId','Topics']}}],casts => []},{emqx_cm,2} => #{calls => [{{emqx_cm_proto_v2,kick_session,['Action','ClientId','ChanPid']},{emqx_cm,do_kick_session,['Action','ClientId','ChanPid']}},{{emqx_cm_proto_v2,takeover_finish,['ConnMod','ChanPid']},{emqx_cm,takeover_finish,['ConnMod','ChanPid']}},{{emqx_cm_proto_v2,takeover_session,['ClientId','ChanPid']},{emqx_cm,takeover_session,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,get_chann_conn_mod,['ClientId','ChanPid']},{emqx_cm,do_get_chann_conn_mod,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,get_chan_info,['ClientId','ChanPid']},{emqx_cm,do_get_chan_info,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,get_chan_stats,['ClientId','ChanPid']},{emqx_cm,do_get_chan_stats,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,lookup_client,['Node','Key']},{emqx_cm,lookup_client,['Key']}},{{emqx_cm_proto_v2,kickout_client,['Node','ClientId']},{emqx_cm,kick_session,['ClientId']}}],casts => []},{emqx_conf,1} => #{calls => [{{emqx_conf_proto_v1,get_override_config_file,['Nodes']},{emqx_conf_app,get_override_config_file,[]}},{{emqx_conf_proto_v1,reset,['Node','KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,reset,['KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,remove_config,['Node','KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,remove_config,['KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,update,['Node','KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v1,update,['KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v1,get_all,['KeyPath']},{emqx_conf,get_node_and_config,['KeyPath']}},{{emqx_conf_proto_v1,get_config,['Node','KeyPath','Default']},{emqx,get_config,['KeyPath','Default']}},{{emqx_conf_proto_v1,get_config,['Node','KeyPath']},{emqx,get_config,['KeyPath']}}],casts => []},{emqx_ft_storage_fs,1} => #{calls => [{{emqx_ft_storage_fs_proto_v1,list_assemblers,['Nodes','Transfer']},{emqx_ft_storage_fs_proxy,lookup_local_assembler,['Transfer']}},{{emqx_ft_storage_fs_proto_v1,pread,['Node','Transfer','Frag','Offset','Size']},{emqx_ft_storage_fs_proxy,pread_local,['Transfer','Frag','Offset','Size']}},{{emqx_ft_storage_fs_proto_v1,multilist,['Nodes','Transfer','What']},{emqx_ft_storage_fs_proxy,list_local,['Transfer','What']}}],casts => []},{emqx_mgmt_cluster,1} => #{calls => [{{emqx_mgmt_cluster_proto_v1,invite_node,['Node','Self']},{emqx_mgmt_api_cluster,join,['Self']}}],casts => []},{emqx_management,3} => #{calls => [{{emqx_management_proto_v3,get_full_config,['Node']},{emqx_mgmt_api_configs,get_full_config,[]}},{{emqx_management_proto_v3,call_client,['Node','ClientId','Req']},{emqx_mgmt,do_call_client,['ClientId','Req']}},{{emqx_management_proto_v3,unsubscribe,['Node','ClientId','Topic']},{emqx_mgmt,do_unsubscribe,['ClientId','Topic']}},{{emqx_management_proto_v3,subscribe,['Node','ClientId','TopicTables']},{emqx_mgmt,do_subscribe,['ClientId','TopicTables']}},{{emqx_management_proto_v3,list_listeners,['Node']},{emqx_mgmt_api_listeners,do_list_listeners,[]}},{{emqx_management_proto_v3,list_subscriptions,['Node']},{emqx_mgmt,do_list_subscriptions,[]}},{{emqx_management_proto_v3,broker_info,['Nodes']},{emqx_mgmt,broker_info,[]}},{{emqx_management_proto_v3,node_info,['Nodes']},{emqx_mgmt,node_info,[]}},{{emqx_management_proto_v3,unsubscribe_batch,['Node','ClientId','Topics']},{emqx_mgmt,do_unsubscribe_batch,['ClientId','Topics']}}],casts => []},{emqx_telemetry,1} => #{calls => [{{emqx_telemetry_proto_v1,get_cluster_uuid,['Node']},{emqx_telemetry,get_cluster_uuid,[]}},{{emqx_telemetry_proto_v1,get_node_uuid,['Node']},{emqx_telemetry,get_node_uuid,[]}}],casts => []},{emqx_node_rebalance_evacuation,1} => #{calls => [{{emqx_node_rebalance_evacuation_proto_v1,available_nodes,['Nodes']},{emqx_node_rebalance_evacuation,is_node_available,[]}}],casts => []},{emqx_retainer,2} => #{calls => [{{emqx_retainer_proto_v2,active_mnesia_indices,['Nodes']},{emqx_retainer_mnesia,active_indices,[]}},{{emqx_retainer_proto_v2,wait_dispatch_complete,['Nodes','Timeout']},{emqx_retainer_dispatcher,wait_dispatch_complete,['Timeout']}}],casts => []},{emqx_rule_engine,1} => #{calls => [{{emqx_rule_engine_proto_v1,reset_metrics,['RuleId']},{emqx_rule_engine,reset_metrics_for_rule,['RuleId']}}],casts => []},{emqx_dashboard,1} => #{calls => [{{emqx_dashboard_proto_v1,current_rate,['Node']},{emqx_dashboard_monitor,current_rate,['Node']}},{{emqx_dashboard_proto_v1,do_sample,['Node','Latest']},{emqx_dashboard_monitor,do_sample,['Node','Latest']}}],casts => []}},release => "5.0",signatures => #{{emqx_bridge_proto_v2,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,remove_config,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_alarm,deactivate,1} => {any,[any]},{emqx_cm,do_get_chan_info,2} => {any,[any,any]},{emqx_ft_storage_fs_proxy,pread_local,4} => {any,[any,any,any,any]},{emqx_node_rebalance_status,evacuation_status,0} => {{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[enabled],unknown},{c,map,{[{{c,atom,[conn_evict_rate],unknown},mandatory,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[current_conns],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[current_sessions],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[initial_conns],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[initial_sessions],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[migrate_to],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[server_reference],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[sess_evict_rate],unknown},mandatory,{c,number,{int_rng,1,pos_inf},integer}}],none,none},unknown}],{2,{c,atom,[enabled],unknown}}},none,none,none],unknown}],{2,any}},[]},{emqx_bridge_proto_v4,start_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_cm_proto_v1,lookup_client,2} => {any,[{c,atom,any,unknown},{c,tuple_set,[{2,[{c,tuple,[{c,atom,[clientid],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[clientid],unknown}}},{c,tuple,[{c,atom,[username],unknown},{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[username],unknown}}}]}],unknown}]},{emqx_bridge_proto_v3,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,update,3} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_plugins,get_tar,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,binary,[8,0],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown}]},{emqx_broker,subscriptions_via_topic,1} => {{c,list,[any,{c,nil,[],unknown}],unknown},[any]},{emqx_cm,takeover_session,2} => {{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,tuple,[{c,atom,any,unknown},any],{2,any}},{c,nil,[],unknown}],unknown},none,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[expired],unknown},{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[any,any,any],{3,any}}}],unknown},{c,tuple,[any,any,any,any,any,any,any,any,any,any,any],{11,any}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}}],{2,{c,atom,[expired],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},{c,tuple,[{c,atom,[persistent],unknown},{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[any,any,any],{3,any}}}],unknown},{c,tuple,[any,any,any,any,any,any,any,any,any,any,any],{11,any}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}}],{2,{c,atom,[persistent],unknown}}}]},{3,[{c,tuple,[{c,atom,[ok],unknown},{c,list,[any,{c,nil,[],unknown}],unknown},any],{3,{c,atom,[ok],unknown}}}]},{4,[{c,tuple,[{c,atom,[living],unknown},{c,atom,any,unknown},{c,identifier,[pid],unknown},{c,union,[none,none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[any,any,any],{3,any}}}],unknown},{c,tuple,[any,any,any,any,any,any,any,any,any,any,any],{11,any}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}},none,none,none],unknown}],{4,{c,atom,[living],unknown}}}]}],unknown},none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_bridge_proto_v4,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_resource_proto_v1,create,5} => {any,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,dynamic,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_bridge_proto_v2,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v3,broker_info,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_metrics,all,0} => {{c,list,[{c,tuple,[any,{c,number,any,integer}],{2,any}},{c,nil,[],unknown}],unknown},[]},{emqx_node_rebalance_status_proto_v1,evacuation_status,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_exhook_mgr,all_servers_info,0} => {any,[]},{emqx_alarm,get_alarms,1} => {any,[{c,atom,[activated,all,deactivated],unknown}]},{emqx_plugin_libs_proto_v1,get_metrics,3} => {any,[{c,atom,any,unknown},{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_exhook_proto_v1,all_servers_info,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{ssl_pem_cache,clear,0} => {any,[]},{emqx_resource,remove_local,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,binary,[8,0],unknown}]},{emqx_bridge_proto_v4,start_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge,list,0} => {any,[]},{emqx_retainer_proto_v1,wait_dispatch_complete,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_node_rebalance,stop,0} => {any,[]},{emqx_mgmt_api_cluster,join,1} => {any,[any]},{emqx_node_rebalance_evacuation_proto_v1,available_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_prometheus,do_stop,0} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found,restarting,running,simple_one_for_one],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[]},{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_start,2} => {any,[{c,atom,any,unknown},{c,map,{[{{c,atom,[conn_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[migrate_to],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[server_reference],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[sess_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_takeover],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}}],none,none},unknown}]},{emqx_telemetry_proto_v1,get_node_uuid,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v2,kickout_client,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_management_proto_v3,node_info,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_conf,get_node_and_config,1} => {{c,tuple,[{c,atom,any,unknown},any],{2,any}},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_gateway_cm_proto_v1,cast,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_node_rebalance,connection_count,0} => {{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},[]},{emqx_node_rebalance_status,local_status,0} => {{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[evacuation],unknown},{c,map,{[{{c,atom,[connection_eviction_rate],unknown},mandatory,any},{{c,atom,[connection_goal],unknown},mandatory,{c,number,{int_set,[0]},integer}},{{c,atom,[session_eviction_rate],unknown},mandatory,any},{{c,atom,[session_goal],unknown},mandatory,{c,number,{int_set,[0]},integer}},{{c,atom,[session_recipients],unknown},mandatory,any},{{c,atom,[state],unknown},mandatory,any},{{c,atom,[stats],unknown},mandatory,{c,map,{[{{c,atom,[current_connected],unknown},mandatory,any},{{c,atom,[current_sessions],unknown},mandatory,any},{{c,atom,[initial_connected],unknown},mandatory,any},{{c,atom,[initial_sessions],unknown},mandatory,any}],none,none},unknown}}],none,none},unknown}],{2,{c,atom,[evacuation],unknown}}},{c,tuple,[{c,atom,[rebalance],unknown},{c,map,{[],{c,atom,[connection_eviction_rate,connection_goal,coordinator_node,disconnected_session_goal,recipients,session_eviction_rate,state,stats],unknown},any},unknown}],{2,{c,atom,[rebalance],unknown}}}]}],unknown},none,none,none],unknown},[]},{emqx,is_running,0} => {{c,atom,[false,true],unknown},[]},{emqx_conf_proto_v1,reset,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_resource,create_dry_run_local,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,atom,any,unknown},any]},{emqx_management_proto_v3,call_client,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_cm_proto_v2,takeover_session,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_conf_app,sync_data_from_node,0} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,binary,[8,0],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[]},{emqx_conf_proto_v1,get_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown},any]},{emqx_proto_v1,is_running,1} => {any,[{c,atom,any,unknown}]},{emqx_exhook_mgr,server_info,1} => {any,[any]},{emqx_cm_proto_v2,get_chann_conn_mod,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_conf_proto_v2,get_override_config_file,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_management_proto_v1,broker_info,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v1,list_bridges,1} => {any,[{c,atom,any,unknown}]},{emqx_mgmt_api_plugins,describe_package,1} => {{c,tuple,[{c,atom,any,unknown},{c,list,[{c,map,{[],any,any},unknown},{c,nil,[],unknown}],unknown}],{2,any}},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_api_plugins_proto_v1,ensure_action,2} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,atom,[restart,start,stop],unknown}]},{emqx_gateway_cm,do_call,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_slow_subs_proto_v1,clear_history,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v3,list_bridges_on_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_gateway_cm_proto_v1,get_chan_info,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_cm_proto_v2,get_chan_stats,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_rule_engine_proto_v1,reset_metrics,1} => {any,[{c,binary,[8,0],unknown}]},{emqx_resource_proto_v1,reset_metrics,1} => {any,[{c,binary,[8,0],unknown}]},{emqx_gateway_cm,do_takeover_session,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx,remove_config,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown}},{{c,atom,[post_config_update],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[raw_config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_management_proto_v3,unsubscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_cm_proto_v1,get_chann_conn_mod,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_metrics_worker,get_metrics,2} => {{c,map,{[{{c,atom,[counters],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},mandatory,{c,map,{[],any,any},unknown}}],none,none},unknown},[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_mgmt_api_plugins,install_package,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_api_listeners_proto_v1,listeners_cluster_status,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,list,[any,{c,nil,[],unknown}],unknown}]},{emqx_topic_metrics_proto_v1,reset,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_management_proto_v3,unsubscribe_batch,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,binary,[8,0],unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_configs,get_full_config,0} => {{c,map,{[],any,any},unknown},[]},{emqx_management_proto_v2,list_listeners,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm,do_get_chan_stats,3} => {any,[any,any,any]},{emqx_node_rebalance_evacuation,is_node_available,0} => {{c,atom,any,unknown},[]},{emqx_ft_storage_exporter_fs_proto_v1,read_export_file,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_mgmt_trace_proto_v1,read_trace_file,4} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_exhook_proto_v1,server_hooks_metrics,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},any]},{emqx_proto_v2,get_metrics,1} => {any,[{c,atom,any,unknown}]},{emqx_conf_proto_v2,update,3} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_topic_metrics,metrics,0} => {{c,list,[{c,map,{[{{c,atom,[create_time],unknown},mandatory,any},{{c,atom,[metrics],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[reset_time],unknown},optional,any},{{c,atom,[topic],unknown},mandatory,any}],none,none},unknown},{c,nil,[],unknown}],unknown},[]},{emqx_bridge_proto_v3,start_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_delayed,get_delayed_message,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[delayed_interval],unknown},mandatory,any},{{c,atom,[delayed_remaining],unknown},mandatory,{c,number,any,integer}},{{c,atom,[expected_at],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[from_clientid],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[from_username],unknown},mandatory,any},{{c,atom,[msgid],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[node],unknown},mandatory,any},{{c,atom,[payload],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[publish_at],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[qos],unknown},mandatory,any},{{c,atom,[topic],unknown},mandatory,{c,binary,[8,0],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[any]},{emqx_proto_v1,clean_authz_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_proto_v2,clean_authz_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_mgmt,do_unsubscribe_batch,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[channel_not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[unsubscribe],unknown},{c,list,[{c,tuple,[any,any],{2,any}},{c,nil,[],unknown}],unknown}],{2,{c,atom,[unsubscribe],unknown}}}]}],unknown},[any,any]},{emqx_mgmt_api_plugins_proto_v1,describe_package,1} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,remove_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_cm_proto_v2,kick_session,3} => {any,[{c,atom,[discard,kick],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_mgmt_trace_proto_v2,read_trace_file,4} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_gateway_cm,do_lookup_by_clientid,2} => {{c,list,[any,{c,nil,[],unknown}],unknown},[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,none],unknown},any]},{emqx_management_proto_v2,list_subscriptions,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v3,get_full_config,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v1,call_client,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx,update_config,3} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown}},{{c,atom,[post_config_update],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[raw_config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_mgmt_trace_proto_v2,trace_file,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_http,gateway_status,1} => {{c,map,{[{{c,atom,[current_connections],unknown},optional,any},{{c,atom,[max_connections],unknown},optional,{c,number,{int_set,[0]},integer}},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[status],unknown},mandatory,{c,atom,[running,stopped,unloaded],unknown}}],none,none},unknown},[{c,atom,any,unknown}]},{emqx_ft_storage_fs_proto_v1,list_assemblers,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}}]},{emqx_dashboard_monitor,current_rate,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[badrpc],unknown},any],{2,{c,atom,[badrpc],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,atom,any,unknown}]},{emqx_mgmt_api_listeners,do_list_listeners,0} => {{c,map,{[],{c,binary,"( ",unknown},{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,map,{[],any,any},unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},unknown},[]},{emqx_resource,create_local,5} => {{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[callback_mode],unknown},mandatory,{c,atom,[always_sync,async_if_possible],unknown}},{{c,atom,[config],unknown},mandatory,any},{{c,atom,[error],unknown},mandatory,any},{{c,atom,[id],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[query_mode],unknown},mandatory,{c,atom,[async,dynamic,sync],unknown}},{{c,atom,[state],unknown},mandatory,any},{{c,atom,[status],unknown},mandatory,{c,atom,[connected,connecting,disconnected,stopped],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}},[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,dynamic,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_management_proto_v2,node_info,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm_proto_v1,get_chann_conn_mod,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_management_proto_v2,broker_info,1} => {any,[{c,atom,any,unknown}]},{emqx_broker,dispatch,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[no_subscribers,not_running],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,number,{int_rng,0,pos_inf},integer}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[delivery],unknown},{c,identifier,[pid],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[any,any,any,any],{4,any}}]},{8,[{c,tuple,[any,any,any,any,any,any,any,any],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}],{3,{c,atom,[delivery],unknown}}}]},{emqx_conf_proto_v1,get_override_config_file,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_session_router,resume_begin,2} => {any,[{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_proto_v2,get_stats,1} => {any,[{c,atom,any,unknown}]},{emqx_slow_subs_proto_v1,get_history,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_trace_proto_v2,get_trace_size,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_ft_storage_fs_proxy,lookup_local_assembler,1} => {any,[any]},{emqx_telemetry,get_node_uuid,0} => {any,[]},{emqx_license_proto_v2,remote_connection_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v1,get_metrics,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v2,lookup_client,2} => {any,[{c,atom,any,unknown},{c,tuple_set,[{2,[{c,tuple,[{c,atom,[clientid],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[clientid],unknown}}},{c,tuple,[{c,atom,[username],unknown},{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[username],unknown}}}]}],unknown}]},{emqx_delayed_proto_v1,delete_delayed_message,2} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_node_rebalance_agent,disable,1} => {any,[any]},{emqx_bridge_resource,start,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v2,reset,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_ft_storage_fs_reader,read,2} => {any,[{c,identifier,[pid],unknown},{c,number,{int_rng,1,pos_inf},integer}]},{emqx_cm_proto_v2,takeover_finish,2} => {any,[{c,atom,any,unknown},{c,identifier,[pid],unknown}]},{emqx_trace,trace_file,1} => {{c,tuple_set,[{3,[{c,tuple,[{c,atom,[error],unknown},{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},{c,atom,any,unknown}],{3,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},{c,binary,[8,0],unknown}],{3,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v1,list_subscriptions,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance_proto_v1,session_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v1,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v2,get_config,2} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v1,get_stats,1} => {any,[{c,atom,any,unknown}]},{emqx_ft_storage_fs_proto_v1,pread,5} => {any,[{c,atom,any,unknown},{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}},{c,map,{[{{c,atom,[fragment],unknown},mandatory,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[filemeta],unknown},{c,map,{[{{c,atom,[checksum],unknown},optional,{c,tuple,[{c,atom,any,unknown},{c,binary,[8,0],unknown}],{2,any}}},{{c,atom,[expire_at],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[name],unknown},mandatory,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown}},{{c,atom,[segments_ttl],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[user_data],unknown},optional,{c,union,[{c,atom,[false,null,true],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,[false,null,true],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown},{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,{c,map,{[],{c,binary,[8,0],unknown},{c,union,[{c,atom,[false,null,true],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[filemeta],unknown}}},{c,tuple,[{c,atom,[segment],unknown},{c,map,{[{{c,atom,[offset],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[size],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}],{2,{c,atom,[segment],unknown}}}]}],unknown}},{{c,atom,[path],unknown},mandatory,{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[size],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[timestamp],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_conf_proto_v2,get_all,1} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_authz_cache,drain_cache,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_conf_proto_v2,sync_data_from_node,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance_evacuation,start,1} => {any,[{c,map,{[],any,any},unknown}]},{emqx_prometheus_proto_v1,start,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt,do_unsubscribe,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[channel_not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[unsubscribe],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[],any,any},unknown}],{2,any}},{c,nil,[],unknown}],nonempty}],{2,{c,atom,[unsubscribe],unknown}}}]}],unknown},[any,any]},{emqx_ft_storage_exporter_fs_proto_v1,list_exports,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,map,{[{{c,atom,[following],unknown},optional,{c,var,'_LocalCursor',unknown}},{{c,atom,[limit],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[transfer],unknown},optional,{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}}}],none,none},unknown}]},{emqx_cm,do_get_chan_stats,2} => {any,[any,any]},{emqx_ft_storage_exporter_fs_proxy,list_exports_local,1} => {any,[any]},{emqx_node_rebalance,start,1} => {any,[{c,map,{[],any,any},unknown}]},{emqx_bridge_proto_v4,list_bridges_on_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_license_proto_v1,remote_connection_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_cm_proto_v1,takeover_session,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_bridge_proto_v4,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_slow_subs,clear_history,0} => {any,[]},{emqx_mgmt_api_plugins_proto_v1,get_plugins,0} => {any,[]},{emqx_management_proto_v2,get_full_config,1} => {any,[{c,atom,any,unknown}]},{emqx_proto_v2,is_running,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm_proto_v1,set_chan_stats,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},{c,list,[{c,tuple,[{c,atom,any,unknown},any],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_bridge_api,lookup_from_local_node,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v3,list_listeners,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v2,unsubscribe_batch,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,binary,[8,0],unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v4,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_trace_proto_v1,trace_file,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_resource,restart,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_delayed,delete_delayed_message,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[any]},{emqx_mgmt_api_trace,get_trace_size,0} => {{c,map,{[],any,any},unknown},[]},{emqx_shared_sub,do_dispatch_with_ack,4} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,identifier,[pid,port],unknown},any,any,{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}]},{emqx,reset_config,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown}},{{c,atom,[post_config_update],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[raw_config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any]},{emqx_authn_api,lookup_from_local_node,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[not_found_resource],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,any}}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,tuple,[{c,atom,any,unknown},{c,atom,[connected,connecting,disconnected,stopped],unknown},{c,map,{[{{c,atom,[counters],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},mandatory,{c,map,{[],any,any},unknown}}],none,none},unknown},{c,map,{[{{c,atom,[counters],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},optional,{c,map,{[],any,any},unknown}}],none,none},unknown}],{4,any}}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_management_proto_v1,unsubscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_management_proto_v2,call_client,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_persistent_session_proto_v1,resume_end,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_conf_proto_v2,remove_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_proto_v2,deactivate_alarm,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_node_rebalance,session_count,0} => {{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},[]},{emqx_topic_metrics_proto_v1,metrics,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_plugins_proto_v1,delete_package,1} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_persistent_session_proto_v1,resume_begin,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_proto_v1,clean_authz_cache,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_bridge_api,get_metrics_from_local_node,2} => {{c,map,{[{{c,atom,[dropped],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.expired'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.other'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.queue_full'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.resource_not_found'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.resource_stopped'],unknown},mandatory,{c,number,any,integer}},{{c,atom,[failed],unknown},mandatory,{c,number,any,integer}},{{c,atom,[inflight],unknown},mandatory,any},{{c,atom,[late_reply],unknown},mandatory,{c,number,any,integer}},{{c,atom,[matched],unknown},mandatory,{c,number,any,integer}},{{c,atom,[queuing],unknown},mandatory,any},{{c,atom,[rate],unknown},mandatory,any},{{c,atom,[rate_last5m],unknown},mandatory,any},{{c,atom,[rate_max],unknown},mandatory,any},{{c,atom,[received],unknown},mandatory,{c,number,any,integer}},{{c,atom,[retried],unknown},mandatory,{c,number,any,integer}},{{c,atom,[success],unknown},mandatory,{c,number,any,integer}}],none,none},unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_delayed_proto_v1,get_delayed_message,2} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_shared_sub_proto_v1,send,4} => {any,[{c,atom,any,unknown},{c,identifier,[pid],unknown},{c,binary,[8,0],unknown},any]},{emqx_eviction_agent,evict_sessions,3} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[disabled],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[any,{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},any]},{emqx_management_proto_v1,node_info,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v3,subscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[{{c,atom,[nl],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[qos],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[rap],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[rh],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[share],unknown},optional,{c,binary,[8,0],unknown}}],{c,atom,any,unknown},any},unknown}],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_topic_metrics_proto_v1,reset,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,binary,[8,0],unknown}]},{emqx_node_rebalance_agent,enable,1} => {any,[any]},{emqx_mgmt_trace_proto_v1,get_trace_size,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_node_rebalance_status,rebalance_status,0} => {{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[enabled],unknown},{c,map,{[],any,any},unknown}],{2,{c,atom,[enabled],unknown}}},none,none,none],unknown}],{2,any}},[]},{emqx_license_resources,local_connection_count,0} => {any,[]},{emqx_cm,lookup_client,1} => {{c,list,[any,{c,nil,[],unknown}],unknown},[{c,tuple_set,[{2,[{c,tuple,[{c,atom,[clientid],unknown},any],{2,{c,atom,[clientid],unknown}}},{c,tuple,[{c,atom,[username],unknown},any],{2,{c,atom,[username],unknown}}}]}],unknown}]},{emqx_management_proto_v2,subscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[{{c,atom,[nl],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[qos],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[rap],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[rh],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[share],unknown},optional,{c,binary,[8,0],unknown}}],{c,atom,any,unknown},any},unknown}],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_cm,kick_session,1} => {{c,atom,[ok],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_cm_proto_v1,kick_session,3} => {any,[{c,atom,[discard,kick],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_dashboard_proto_v1,current_rate,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v3,start_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_ft_storage_fs_reader_proto_v1,read,3} => {any,[{c,atom,any,unknown},{c,identifier,[pid],unknown},{c,number,{int_rng,1,pos_inf},integer}]},{emqx_plugins_proto_v1,get_tar,3} => {any,[{c,atom,any,unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_bridge_proto_v2,start_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_resource,recreate_local,4} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found,updating_to_incorrect_resource_type],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[callback_mode],unknown},mandatory,{c,atom,[always_sync,async_if_possible],unknown}},{{c,atom,[config],unknown},mandatory,any},{{c,atom,[error],unknown},mandatory,any},{{c,atom,[id],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[query_mode],unknown},mandatory,{c,atom,[async,dynamic,sync],unknown}},{{c,atom,[state],unknown},mandatory,any},{{c,atom,[status],unknown},mandatory,{c,atom,[connected,connecting,disconnected,stopped],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,dynamic,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_topic_metrics_proto_v1,metrics,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,binary,[8,0],unknown}]},{emqx_bridge_resource,stop,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt,do_call_client,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_exhook_proto_v1,server_info,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},any]},{emqx_retainer_mnesia,active_indices,0} => {{c,tuple,[any,any],{2,any}},[]},{emqx_prometheus_proto_v1,stop,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v1,get_alarms,2} => {any,[{c,atom,any,unknown},{c,atom,[activated,all,deactivated],unknown}]},{emqx_dashboard_proto_v1,do_sample,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,1,pos_inf},integer},none,none,none,none],unknown}]},{emqx_telemetry,get_cluster_uuid,0} => {any,[]},{emqx_bridge_proto_v2,list_bridges,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance_proto_v1,evict_connections,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_conf_proto_v1,update,4} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_stop,1} => {any,[{c,atom,any,unknown}]},{emqx_broker_proto_v1,list_client_subscriptions,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_broker_proto_v1,forward_async,3} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[delivery],unknown},{c,identifier,[pid],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}],{3,{c,atom,[delivery],unknown}}}]},{emqx_cm_proto_v1,kickout_client,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_mgmt,do_subscribe,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[channel_not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[subscribe],unknown},any],{2,{c,atom,[subscribe],unknown}}}]}],unknown},[any,any]},{emqx_conf_app,get_override_config_file,0} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,map,{[{{c,atom,[msg],unknown},mandatory,any},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}}],none,none},unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}}]}],unknown},[]},{emqx_gateway_cm,do_cast,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_management_proto_v1,subscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[{{c,atom,[nl],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[qos],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[rap],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[rh],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[share],unknown},optional,{c,binary,[8,0],unknown}}],{c,atom,any,unknown},any},unknown}],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_plugins,delete_package,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_api_plugins_proto_v1,install_package,2} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_resource_proto_v1,recreate,4} => {any,[{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,dynamic,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_authz_cache,drain_cache,0} => {{c,atom,[ok],unknown},[]},{emqx_mgmt_api_plugins,ensure_action,2} => {{c,atom,[ok],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,atom,[restart,start,stop],unknown}]},{emqx_broker_proto_v1,list_subscriptions_via_topic,2} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_trace,trace_file_detail,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,map,{[{{c,atom,[file],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[node],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[reason],unknown},mandatory,{c,atom,any,unknown}}],none,none},unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[mtime],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},{c,tuple,[{c,tuple,[any,any,any],{3,any}},{c,tuple,[any,any,any],{3,any}}],{2,any}},none,none,none],unknown}},{{c,atom,[node],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[size],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_proto_v1,delete_all_deactivated_alarms,1} => {any,[{c,atom,any,unknown}]},{emqx_prometheus,do_start,0} => {{c,atom,[ok],unknown},[]},{emqx_gateway_cm,do_kick_session,4} => {{c,atom,[ok],unknown},[{c,atom,any,unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_ft_storage_fs_proto_v1,multilist,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}},{c,atom,[fragment,result],unknown}]},{emqx_telemetry_proto_v1,get_cluster_uuid,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance,is_node_available,0} => {{c,atom,any,unknown},[]},{emqx_retainer_proto_v2,active_mnesia_indices,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v4,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_proto_v3,list_bridges,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm,do_get_chan_info,3} => {{c,union,[{c,atom,[undefined],unknown},none,none,none,none,none,none,none,none,{c,map,{[{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}}],any,any},unknown}],unknown},[any,any,any]},{emqx_node_rebalance_status_proto_v1,rebalance_status,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_node_rebalance_proto_v1,disable_rebalance_agent,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown}]},{emqx_rule_engine,reset_metrics_for_rule,1} => {{c,atom,[ok],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_authz_proto_v1,lookup_from_all_nodes,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown}]},{emqx_proto_v1,clean_pem_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_conf_proto_v1,get_config,2} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_management_proto_v1,get_full_config,1} => {any,[{c,atom,any,unknown}]},{emqx_topic_metrics,reset,1} => {any,[any]},{emqx_node_rebalance_proto_v1,available_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v2,clean_pem_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v4,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,reset,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_broker,subscriptions,1} => {{c,list,[{c,tuple,[any,any],{2,any}},{c,nil,[],unknown}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,{c,identifier,[pid],unknown},none,none,none,none,none,none],unknown}]},{emqx_mgmt,do_list_subscriptions,0} => {none,[]},{emqx_eviction_agent_proto_v1,evict_session_channel,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[{{c,atom,[clean_start],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[clientid],unknown},optional,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[conn_mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[conn_props],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[connected],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[connected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[disconnected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[expiry_interval],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[keepalive],unknown},optional,{c,number,{int_rng,0,1114111},integer}},{{c,atom,[peercert],unknown},mandatory,{c,union,[{c,atom,[nossl,undefined],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,none,none,{c,tuple,any,{any,any}},none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[peername],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[proto_name],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[receive_maximum],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[sockname],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[socktype],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,map,{[{{c,atom,[anonymous],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[auth_result],unknown},optional,{c,atom,[bad_authentication_method,bad_clientid_or_password,bad_username_or_password,banned,client_identifier_not_valid,not_authorized,server_busy,server_unavailable,success],unknown}},{{c,atom,[clientid],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[cn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[dn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[is_bridge],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[is_superuser],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[mountpoint],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[password],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[peerhost],unknown},mandatory,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[protocol],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[sockport],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[username],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[ws_cookie],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[zone],unknown},mandatory,{c,atom,any,unknown}}],{c,atom,any,unknown},any},unknown}]},{emqx_gateway_cm,do_set_chan_stats,4} => {{c,atom,[false,true],unknown},[any,any,any,any]},{emqx_retainer_dispatcher,wait_dispatch_complete,1} => {{c,atom,[ok],unknown},[any]},{emqx_conf_proto_v2,update,4} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_bridge_proto_v3,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_cm_proto_v1,get_chan_stats,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_ft_storage_exporter_fs_proxy,read_export_file_local,2} => {any,[any,any]},{emqx_conf_proto_v2,remove_config,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_stats,getstats,0} => {{c,list,[{c,tuple,any,{any,any}},{c,nil,[],unknown}],unknown},[]},{emqx_mgmt,node_info,0} => {{c,map,{[{{c,atom,[connections],unknown},mandatory,any},{{c,atom,[edition],unknown},mandatory,{c,binary,[0,80],unknown}},{{c,atom,[load1],unknown},optional,{c,number,any,float}},{{c,atom,[load15],unknown},optional,{c,number,any,float}},{{c,atom,[load5],unknown},optional,{c,number,any,float}},{{c,atom,[log_path],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[max_fds],unknown},mandatory,any},{{c,atom,[memory_total],unknown},mandatory,{c,number,any,unknown}},{{c,atom,[memory_used],unknown},mandatory,{c,number,any,integer}},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[node_status],unknown},mandatory,{c,atom,[running],unknown}},{{c,atom,[otp_release],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[process_available],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[process_used],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[role],unknown},mandatory,{c,atom,[core,replicant],unknown}},{{c,atom,[sys_path],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[uptime],unknown},mandatory,any},{{c,atom,[version],unknown},mandatory,{c,binary,[8,0],unknown}}],none,none},unknown},[]},{emqx_gateway_cm_proto_v1,kick_session,4} => {any,[{c,atom,any,unknown},{c,atom,[discard,kick],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_node_rebalance_api_proto_v1,node_rebalance_stop,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v2,get_chan_info,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_authn_proto_v1,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_cm,takeover_finish,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[noproc,timeout,unexpected_exception],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,union,[none,none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[{c,atom,[inflight],unknown},{c,number,{int_rng,1,pos_inf},integer},{c,opaque,[{opaque,gb_trees,tree,[any,any],{c,tuple,[any,any],{2,any}}}],unknown}],{3,{c,atom,[inflight],unknown}}}}],unknown},{c,tuple,[{c,atom,[mqueue],unknown},{c,atom,[false,true],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer},{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,none,none,none,{c,map,{[],any,any},unknown}],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,any,integer},none,none,none,none],unknown},{c,tuple_set,[{2,[{c,tuple,[any,any],{2,any}}]},{4,[{c,tuple,[any,any,any,any],{4,any}}]}],unknown},{c,tuple,[any,any,any],{3,any}},{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}],{11,{c,atom,[mqueue],unknown}}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}},none,none,none],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},none,none,none],unknown},[{c,atom,any,unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm_proto_v1,call,5} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any,{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_mgmt,broker_info,0} => {{c,map,{[{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[node_status],unknown},mandatory,{c,atom,[running],unknown}},{{c,atom,[otp_release],unknown},mandatory,{c,binary,[8,0],unknown}}],any,any},unknown},[]},{emqx_resource,reset_metrics_local,1} => {{c,atom,[ok],unknown},[{c,binary,[8,0],unknown}]},{emqx_cm,do_kick_session,3} => {{c,atom,[ok],unknown},[any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm,do_get_chann_conn_mod,3} => {any,[any,any,any]},{emqx_conf_proto_v2,get_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown},any]},{emqx_resource_proto_v1,remove,1} => {any,[{c,binary,[8,0],unknown}]},{emqx_topic_metrics,reset,0} => {any,[]},{emqx_bridge_proto_v3,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_slow_subs_api,get_history,0} => {{c,list,[{c,map,{[{{c,atom,[clientid],unknown},mandatory,any},{{c,atom,[last_update_time],unknown},mandatory,any},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[timespan],unknown},mandatory,any},{{c,atom,[topic],unknown},mandatory,any}],none,none},unknown},{c,nil,[],unknown}],unknown},[]},{emqx_node_rebalance_proto_v1,evict_sessions,4} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,[connected,connecting,disconnected,idle,reauthenticating],unknown}]},{emqx,get_config,1} => {any,[{c,list,[any,{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v1,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_proto_v2,start_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_authz_api_sources,lookup_from_local_node,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[not_found_resource],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,any}}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,tuple,[{c,atom,any,unknown},{c,atom,[connected,connecting,disconnected,stopped],unknown},{c,map,{[{{c,atom,[counters],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},mandatory,{c,map,{[],any,any},unknown}}],none,none},unknown},{c,map,{[{{c,atom,[counters],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},optional,{c,map,{[],any,any},unknown}}],none,none},unknown}],{4,any}}],{2,{c,atom,[ok],unknown}}}]}],unknown},[any]},{emqx_gateway_cm_proto_v1,set_chan_info,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},{c,map,{[],{c,atom,any,unknown},any},unknown}]},{emqx_eviction_agent,evict_session_channel,3} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,{c,identifier,[pid],unknown},none,none,none,none,none,none],unknown}],{2,{c,atom,[ok],unknown}}}]},{3,[{c,tuple,[{c,atom,[ok],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,{c,identifier,[pid],unknown},none,none,none,none,none,none],unknown},any],{3,{c,atom,[ok],unknown}}}]}],unknown},[any,{c,map,{[{{c,atom,[clean_start],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[clientid],unknown},optional,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[conn_mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[conn_props],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[connected],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[connected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[disconnected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[expiry_interval],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[keepalive],unknown},optional,{c,number,{int_rng,0,1114111},integer}},{{c,atom,[peercert],unknown},optional,{c,union,[{c,atom,[nossl,undefined],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,none,none,{c,tuple,any,{any,any}},none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[peername],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[proto_name],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[receive_maximum],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[sockname],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[socktype],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,map,{[{{c,atom,[anonymous],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[auth_result],unknown},optional,{c,atom,[bad_authentication_method,bad_clientid_or_password,bad_username_or_password,banned,client_identifier_not_valid,not_authorized,server_busy,server_unavailable,success],unknown}},{{c,atom,[clientid],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[cn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[dn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[is_bridge],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[is_superuser],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[mountpoint],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[password],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[peerhost],unknown},mandatory,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[protocol],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[sockport],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[username],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[ws_cookie],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[zone],unknown},mandatory,{c,atom,any,unknown}}],{c,atom,any,unknown},any},unknown}]},{emqx_bridge_proto_v1,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_node_rebalance_proto_v1,enable_rebalance_agent,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown}]},{emqx_node_rebalance_proto_v1,connection_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_plugins,get_plugins,0} => {{c,tuple,[{c,atom,any,unknown},{c,list,[{c,map,{[],any,any},unknown},{c,nil,[],unknown}],unknown}],{2,any}},[]},{emqx_proto_v2,clean_authz_cache,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_bridge_proto_v3,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_api_trace,read_trace_file,3} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[eof],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}],{2,{c,atom,[eof],unknown}}},{c,tuple,[{c,atom,[error],unknown},{c,union,[{c,atom,any,unknown},none,none,none,none,none,{c,tuple,[{c,atom,[no_translation],unknown},{c,atom,[unicode],unknown},{c,atom,[latin1],unknown}],{3,{c,atom,[no_translation],unknown}}},none,none,none],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,binary,[8,0],unknown},any,any]},{emqx_gateway_cm,do_set_chan_info,4} => {{c,atom,[false,true],unknown},[any,any,any,any]},{emqx_resource_proto_v1,create_dry_run,2} => {any,[{c,atom,any,unknown},any]},{emqx_broker_proto_v1,forward,3} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[delivery],unknown},{c,identifier,[pid],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}],{3,{c,atom,[delivery],unknown}}}]},{emqx_node_rebalance_evacuation,stop,0} => {any,[]},{emqx_bridge_proto_v1,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v2,unsubscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_gateway_api_listeners,do_listeners_cluster_status,1} => {{c,map,{[],any,any},unknown},[{c,list,[any,{c,nil,[],unknown}],unknown}]},{emqx_proto_v2,are_running,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_retainer_proto_v2,wait_dispatch_complete,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_bridge_proto_v3,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_node_rebalance_api_proto_v1,node_rebalance_start,2} => {any,[{c,atom,any,unknown},{c,map,{[{{c,atom,[abs_conn_threshold],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[abs_sess_threshold],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[conn_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[nodes],unknown},optional,{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}},{{c,atom,[rel_conn_threshold],unknown},optional,{c,number,any,unknown}},{{c,atom,[rel_sess_threshold],unknown},optional,{c,number,any,unknown}},{{c,atom,[sess_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_health_check],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_takeover],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}}],none,none},unknown}]},{emqx,get_config,2} => {any,[any,any]},{emqx_mgmt_trace_proto_v2,trace_file_detail,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_proto_v2,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_shared_sub_proto_v1,dispatch_with_ack,5} => {any,[{c,identifier,[pid],unknown},any,{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_gateway_http_proto_v1,get_cluster_status,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown}]},{emqx_management_proto_v3,list_subscriptions,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v1,get_chan_stats,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm_proto_v1,takeover_session,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_conf_proto_v2,reset,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_node_rebalance_proto_v1,disconnected_session_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{erlang,send,2} => {any,[any,any]},{emqx_cm_proto_v1,get_chan_info,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm_proto_v1,call,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_eviction_agent,evict_connections,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[disabled],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[any]},{emqx_dashboard_monitor,do_sample,2} => {any,[{c,atom,any,unknown},any]},{emqx_session_router,resume_end,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,list,[{c,tuple,any,{any,any}},{c,nil,[],unknown}],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_node_rebalance,disconnected_session_count,0} => {{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},[]},{emqx_proto_v2,delete_all_deactivated_alarms,1} => {any,[{c,atom,any,unknown}]},{emqx_cm,do_get_chann_conn_mod,2} => {any,[any,any]},{emqx_exhook_mgr,server_hooks_metrics,1} => {any,[any]},{emqx_node_rebalance_status_proto_v1,local_status,1} => {any,[{c,atom,any,unknown}]},{emqx_alarm,delete_all_deactivated_alarms,0} => {any,[]},{emqx_proto_v1,deactivate_alarm,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_bridge_proto_v1,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_cluster_proto_v1,invite_node,2} => {any,[{c,atom,any,unknown},{c,atom,any,unknown}]},{emqx_topic_metrics,metrics,1} => {{c,union,[none,none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[topic_not_found],unknown}],{2,{c,atom,[error],unknown}}},none,none,{c,map,{[{{c,atom,[create_time],unknown},mandatory,any},{{c,atom,[metrics],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[reset_time],unknown},optional,any},{{c,atom,[topic],unknown},mandatory,any}],none,none},unknown}],unknown},[any]},{emqx_bridge_proto_v4,get_metrics_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_proto_v2,get_alarms,2} => {any,[{c,atom,any,unknown},{c,atom,[activated,all,deactivated],unknown}]},{emqx_bridge_proto_v2,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_cm,do_call,5} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any,any]},{emqx_management_proto_v1,list_listeners,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v2,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_ft_storage_fs_proxy,list_local,2} => {any,[any,any]},{emqx_gateway_cm_proto_v1,lookup_by_clientid,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,get_all,1} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]}}}. +#{api => #{{emqx_gateway_cm,1} => #{calls => [{{emqx_gateway_cm_proto_v1,cast,['GwName','ClientId','ChanPid','Req']},{emqx_gateway_cm,do_cast,['GwName','ClientId','ChanPid','Req']}},{{emqx_gateway_cm_proto_v1,call,['GwName','ClientId','ChanPid','Req']},{emqx_gateway_cm,do_call,['GwName','ClientId','ChanPid','Req']}},{{emqx_gateway_cm_proto_v1,call,['GwName','ClientId','ChanPid','Req','Timeout']},{emqx_gateway_cm,do_call,['GwName','ClientId','ChanPid','Req','Timeout']}},{{emqx_gateway_cm_proto_v1,takeover_session,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_takeover_session,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,get_chann_conn_mod,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_get_chann_conn_mod,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,kick_session,['GwName','Action','ClientId','ChanPid']},{emqx_gateway_cm,do_kick_session,['GwName','Action','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,set_chan_stats,['GwName','ClientId','ChanPid','Stats']},{emqx_gateway_cm,do_set_chan_stats,['GwName','ClientId','ChanPid','Stats']}},{{emqx_gateway_cm_proto_v1,get_chan_stats,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_get_chan_stats,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,set_chan_info,['GwName','ClientId','ChanPid','Infos']},{emqx_gateway_cm,do_set_chan_info,['GwName','ClientId','ChanPid','Infos']}},{{emqx_gateway_cm_proto_v1,get_chan_info,['GwName','ClientId','ChanPid']},{emqx_gateway_cm,do_get_chan_info,['GwName','ClientId','ChanPid']}},{{emqx_gateway_cm_proto_v1,lookup_by_clientid,['Nodes','GwName','ClientId']},{emqx_gateway_cm,do_lookup_by_clientid,['GwName','ClientId']}}],casts => []},{emqx_authn,1} => #{calls => [{{emqx_authn_proto_v1,lookup_from_all_nodes,['Nodes','ChainName','AuthenticatorID']},{emqx_authn_api,lookup_from_local_node,['ChainName','AuthenticatorID']}}],casts => []},{emqx_bridge,4} => #{calls => [{{emqx_bridge_proto_v4,get_metrics_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,get_metrics_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,start_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,start_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v4,list_bridges_on_nodes,['Nodes']},{emqx_bridge,list,[]}}],casts => []},{emqx_gateway_api_listeners,1} => #{calls => [{{emqx_gateway_api_listeners_proto_v1,listeners_cluster_status,['Nodes','Listeners']},{emqx_gateway_api_listeners,do_listeners_cluster_status,['Listeners']}}],casts => []},{emqx_slow_subs,1} => #{calls => [{{emqx_slow_subs_proto_v1,get_history,['Nodes']},{emqx_slow_subs_api,get_history,[]}},{{emqx_slow_subs_proto_v1,clear_history,['Nodes']},{emqx_slow_subs,clear_history,[]}}],casts => []},{emqx_license,1} => #{calls => [{{emqx_license_proto_v1,remote_connection_counts,['Nodes']},{emqx_license_resources,local_connection_count,[]}}],casts => []},{emqx_exhook,1} => #{calls => [{{emqx_exhook_proto_v1,server_hooks_metrics,['Nodes','Name']},{emqx_exhook_mgr,server_hooks_metrics,['Name']}},{{emqx_exhook_proto_v1,server_info,['Nodes','Name']},{emqx_exhook_mgr,server_info,['Name']}},{{emqx_exhook_proto_v1,all_servers_info,['Nodes']},{emqx_exhook_mgr,all_servers_info,[]}}],casts => []},{emqx_cm,1} => #{calls => [{{emqx_cm_proto_v1,kick_session,['Action','ClientId','ChanPid']},{emqx_cm,do_kick_session,['Action','ClientId','ChanPid']}},{{emqx_cm_proto_v1,takeover_session,['ClientId','ChanPid']},{emqx_cm,takeover_session,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,get_chann_conn_mod,['ClientId','ChanPid']},{emqx_cm,do_get_chann_conn_mod,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,get_chan_info,['ClientId','ChanPid']},{emqx_cm,do_get_chan_info,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,get_chan_stats,['ClientId','ChanPid']},{emqx_cm,do_get_chan_stats,['ClientId','ChanPid']}},{{emqx_cm_proto_v1,lookup_client,['Node','Key']},{emqx_cm,lookup_client,['Key']}},{{emqx_cm_proto_v1,kickout_client,['Node','ClientId']},{emqx_cm,kick_session,['ClientId']}}],casts => []},{emqx_license,2} => #{calls => [{{emqx_license_proto_v2,remote_connection_counts,['Nodes']},{emqx_license_resources,local_connection_count,[]}}],casts => []},{emqx_retainer,1} => #{calls => [{{emqx_retainer_proto_v1,wait_dispatch_complete,['Nodes','Timeout']},{emqx_retainer_dispatcher,wait_dispatch_complete,['Timeout']}}],casts => []},{emqx_node_rebalance,1} => #{calls => [{{emqx_node_rebalance_proto_v1,disconnected_session_counts,['Nodes']},{emqx_node_rebalance,disconnected_session_count,[]}},{{emqx_node_rebalance_proto_v1,disable_rebalance_agent,['Nodes','OwnerPid']},{emqx_node_rebalance_agent,disable,['OwnerPid']}},{{emqx_node_rebalance_proto_v1,enable_rebalance_agent,['Nodes','OwnerPid']},{emqx_node_rebalance_agent,enable,['OwnerPid']}},{{emqx_node_rebalance_proto_v1,session_counts,['Nodes']},{emqx_node_rebalance,session_count,[]}},{{emqx_node_rebalance_proto_v1,connection_counts,['Nodes']},{emqx_node_rebalance,connection_count,[]}},{{emqx_node_rebalance_proto_v1,evict_sessions,['Nodes','Count','RecipientNodes','ConnState']},{emqx_eviction_agent,evict_sessions,['Count','RecipientNodes','ConnState']}},{{emqx_node_rebalance_proto_v1,evict_connections,['Nodes','Count']},{emqx_eviction_agent,evict_connections,['Count']}},{{emqx_node_rebalance_proto_v1,available_nodes,['Nodes']},{emqx_node_rebalance,is_node_available,[]}}],casts => []},{emqx_broker,1} => #{calls => [{{emqx_broker_proto_v1,list_subscriptions_via_topic,['Node','Topic']},{emqx_broker,subscriptions_via_topic,['Topic']}},{{emqx_broker_proto_v1,list_client_subscriptions,['Node','ClientId']},{emqx_broker,subscriptions,['ClientId']}},{{emqx_broker_proto_v1,forward,['Node','Topic','Delivery']},{emqx_broker,dispatch,['Topic','Delivery']}}],casts => [{{emqx_broker_proto_v1,forward_async,['Node','Topic','Delivery']},{emqx_broker,dispatch,['Topic','Delivery']}}]},{emqx_topic_metrics,1} => #{calls => [{{emqx_topic_metrics_proto_v1,reset,['Nodes','Topic']},{emqx_topic_metrics,reset,['Topic']}},{{emqx_topic_metrics_proto_v1,reset,['Nodes']},{emqx_topic_metrics,reset,[]}},{{emqx_topic_metrics_proto_v1,metrics,['Nodes','Topic']},{emqx_topic_metrics,metrics,['Topic']}},{{emqx_topic_metrics_proto_v1,metrics,['Nodes']},{emqx_topic_metrics,metrics,[]}}],casts => []},{emqx_resource,1} => #{calls => [{{emqx_resource_proto_v1,reset_metrics,['ResId']},{emqx_resource,reset_metrics_local,['ResId']}},{{emqx_resource_proto_v1,remove,['ResId']},{emqx_resource,remove_local,['ResId']}},{{emqx_resource_proto_v1,recreate,['ResId','ResourceType','Config','Opts']},{emqx_resource,recreate_local,['ResId','ResourceType','Config','Opts']}},{{emqx_resource_proto_v1,create_dry_run,['ResourceType','Config']},{emqx_resource,create_dry_run_local,['ResourceType','Config']}},{{emqx_resource_proto_v1,create,['ResId','Group','ResourceType','Config','Opts']},{emqx_resource,create_local,['ResId','Group','ResourceType','Config','Opts']}}],casts => []},{emqx_bridge,1} => #{calls => [{{emqx_bridge_proto_v1,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v1,list_bridges,['Node']},{emqx_bridge,list,[]}}],casts => []},{emqx_mgmt_trace,1} => #{calls => [{{emqx_mgmt_trace_proto_v1,read_trace_file,['Node','Name','Position','Limit']},{emqx_mgmt_api_trace,read_trace_file,['Name','Position','Limit']}},{{emqx_mgmt_trace_proto_v1,trace_file,['Nodes','File']},{emqx_trace,trace_file,['File']}},{{emqx_mgmt_trace_proto_v1,get_trace_size,['Nodes']},{emqx_mgmt_api_trace,get_trace_size,[]}}],casts => []},{emqx_ft_storage_fs_reader,1} => #{calls => [{{emqx_ft_storage_fs_reader_proto_v1,read,['Node','Pid','Bytes']},{emqx_ft_storage_fs_reader,read,['Pid','Bytes']}}],casts => []},{emqx_bridge,2} => #{calls => [{{emqx_bridge_proto_v2,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,start_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,start_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v2,list_bridges,['Node']},{emqx_bridge,list,[]}}],casts => []},{emqx_eviction_agent,1} => #{calls => [{{emqx_eviction_agent_proto_v1,evict_session_channel,['Node','ClientId','ConnInfo','ClientInfo']},{emqx_eviction_agent,evict_session_channel,['ClientId','ConnInfo','ClientInfo']}}],casts => []},{emqx_node_rebalance_api,1} => #{calls => [{{emqx_node_rebalance_api_proto_v1,node_rebalance_stop,['Node']},{emqx_node_rebalance,stop,[]}},{{emqx_node_rebalance_api_proto_v1,node_rebalance_start,['Node','Opts']},{emqx_node_rebalance,start,['Opts']}},{{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_stop,['Node']},{emqx_node_rebalance_evacuation,stop,[]}},{{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_start,['Node','Opts']},{emqx_node_rebalance_evacuation,start,['Opts']}}],casts => []},{emqx,1} => #{calls => [{{emqx_proto_v1,delete_all_deactivated_alarms,['Node']},{emqx_alarm,delete_all_deactivated_alarms,[]}},{{emqx_proto_v1,deactivate_alarm,['Node','Name']},{emqx_alarm,deactivate,['Name']}},{{emqx_proto_v1,clean_pem_cache,['Node']},{ssl_pem_cache,clear,[]}},{{emqx_proto_v1,clean_authz_cache,['Node']},{emqx_authz_cache,drain_cache,[]}},{{emqx_proto_v1,clean_authz_cache,['Node','ClientId']},{emqx_authz_cache,drain_cache,['ClientId']}},{{emqx_proto_v1,get_metrics,['Node']},{emqx_metrics,all,[]}},{{emqx_proto_v1,get_stats,['Node']},{emqx_stats,getstats,[]}},{{emqx_proto_v1,get_alarms,['Node','Type']},{emqx_alarm,get_alarms,['Type']}},{{emqx_proto_v1,is_running,['Node']},{emqx,is_running,[]}}],casts => []},{emqx_shared_sub,1} => #{calls => [{{emqx_shared_sub_proto_v1,dispatch_with_ack,['Pid','Group','Topic','Msg','Timeout']},{emqx_shared_sub,do_dispatch_with_ack,['Pid','Group','Topic','Msg']}}],casts => [{{emqx_shared_sub_proto_v1,send,['Node','Pid','Topic','Msg']},{erlang,send,['Pid','Msg']}}]},{emqx_management,1} => #{calls => [{{emqx_management_proto_v1,get_full_config,['Node']},{emqx_mgmt_api_configs,get_full_config,[]}},{{emqx_management_proto_v1,call_client,['Node','ClientId','Req']},{emqx_mgmt,do_call_client,['ClientId','Req']}},{{emqx_management_proto_v1,unsubscribe,['Node','ClientId','Topic']},{emqx_mgmt,do_unsubscribe,['ClientId','Topic']}},{{emqx_management_proto_v1,subscribe,['Node','ClientId','TopicTables']},{emqx_mgmt,do_subscribe,['ClientId','TopicTables']}},{{emqx_management_proto_v1,list_listeners,['Node']},{emqx_mgmt_api_listeners,do_list_listeners,[]}},{{emqx_management_proto_v1,list_subscriptions,['Node']},{emqx_mgmt,do_list_subscriptions,[]}},{{emqx_management_proto_v1,broker_info,['Node']},{emqx_mgmt,broker_info,[]}},{{emqx_management_proto_v1,node_info,['Node']},{emqx_mgmt,node_info,[]}}],casts => []},{emqx_persistent_session,1} => #{calls => [{{emqx_persistent_session_proto_v1,resume_end,['Nodes','Pid','SessionID']},{emqx_session_router,resume_end,['Pid','SessionID']}},{{emqx_persistent_session_proto_v1,resume_begin,['Nodes','Pid','SessionID']},{emqx_session_router,resume_begin,['Pid','SessionID']}}],casts => []},{emqx_bridge,3} => #{calls => [{{emqx_bridge_proto_v3,lookup_from_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_api,lookup_from_local_node,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,stop_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,start_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,restart_bridges_to_all_nodes,['Nodes','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,stop_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,stop,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,start_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,start,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,restart_bridge_to_node,['Node','BridgeType','BridgeName']},{emqx_bridge_resource,restart,['BridgeType','BridgeName']}},{{emqx_bridge_proto_v3,list_bridges_on_nodes,['Nodes']},{emqx_bridge,list,[]}},{{emqx_bridge_proto_v3,list_bridges,['Node']},{emqx_bridge,list,[]}}],casts => []},{emqx_mgmt_api_plugins,1} => #{calls => [{{emqx_mgmt_api_plugins_proto_v1,ensure_action,['Name','Action']},{emqx_mgmt_api_plugins,ensure_action,['Name','Action']}},{{emqx_mgmt_api_plugins_proto_v1,delete_package,['Name']},{emqx_mgmt_api_plugins,delete_package,['Name']}},{{emqx_mgmt_api_plugins_proto_v1,describe_package,['Name']},{emqx_mgmt_api_plugins,describe_package,['Name']}},{{emqx_mgmt_api_plugins_proto_v1,install_package,['Filename','Bin']},{emqx_mgmt_api_plugins,install_package,['Filename','Bin']}},{{emqx_mgmt_api_plugins_proto_v1,get_plugins,[]},{emqx_mgmt_api_plugins,get_plugins,[]}}],casts => []},{emqx_mgmt_trace,2} => #{calls => [{{emqx_mgmt_trace_proto_v2,read_trace_file,['Node','Name','Position','Limit']},{emqx_mgmt_api_trace,read_trace_file,['Name','Position','Limit']}},{{emqx_mgmt_trace_proto_v2,trace_file_detail,['Nodes','File']},{emqx_trace,trace_file_detail,['File']}},{{emqx_mgmt_trace_proto_v2,trace_file,['Nodes','File']},{emqx_trace,trace_file,['File']}},{{emqx_mgmt_trace_proto_v2,get_trace_size,['Nodes']},{emqx_mgmt_api_trace,get_trace_size,[]}}],casts => []},{emqx_gateway_http,1} => #{calls => [{{emqx_gateway_http_proto_v1,get_cluster_status,['Nodes','GwName']},{emqx_gateway_http,gateway_status,['GwName']}}],casts => []},{emqx_node_rebalance_status,1} => #{calls => [{{emqx_node_rebalance_status_proto_v1,evacuation_status,['Nodes']},{emqx_node_rebalance_status,evacuation_status,[]}},{{emqx_node_rebalance_status_proto_v1,rebalance_status,['Nodes']},{emqx_node_rebalance_status,rebalance_status,[]}},{{emqx_node_rebalance_status_proto_v1,local_status,['Node']},{emqx_node_rebalance_status,local_status,[]}}],casts => []},{emqx_authz,1} => #{calls => [{{emqx_authz_proto_v1,lookup_from_all_nodes,['Nodes','Type']},{emqx_authz_api_sources,lookup_from_local_node,['Type']}}],casts => []},{emqx_plugins,1} => #{calls => [{{emqx_plugins_proto_v1,get_tar,['Node','NameVsn','Timeout']},{emqx_plugins,get_tar,['NameVsn']}}],casts => []},{emqx_ft_storage_exporter_fs,1} => #{calls => [{{emqx_ft_storage_exporter_fs_proto_v1,read_export_file,['Node','Filepath','CallerPid']},{emqx_ft_storage_exporter_fs_proxy,read_export_file_local,['Filepath','CallerPid']}},{{emqx_ft_storage_exporter_fs_proto_v1,list_exports,['Nodes','Query']},{emqx_ft_storage_exporter_fs_proxy,list_exports_local,['Query']}}],casts => []},{emqx_prometheus,1} => #{calls => [{{emqx_prometheus_proto_v1,stop,['Nodes']},{emqx_prometheus,do_stop,[]}},{{emqx_prometheus_proto_v1,start,['Nodes']},{emqx_prometheus,do_start,[]}}],casts => []},{emqx,2} => #{calls => [{{emqx_proto_v2,delete_all_deactivated_alarms,['Node']},{emqx_alarm,delete_all_deactivated_alarms,[]}},{{emqx_proto_v2,deactivate_alarm,['Node','Name']},{emqx_alarm,deactivate,['Name']}},{{emqx_proto_v2,clean_pem_cache,['Node']},{ssl_pem_cache,clear,[]}},{{emqx_proto_v2,clean_authz_cache,['Node']},{emqx_authz_cache,drain_cache,[]}},{{emqx_proto_v2,clean_authz_cache,['Node','ClientId']},{emqx_authz_cache,drain_cache,['ClientId']}},{{emqx_proto_v2,get_metrics,['Node']},{emqx_metrics,all,[]}},{{emqx_proto_v2,get_stats,['Node']},{emqx_stats,getstats,[]}},{{emqx_proto_v2,get_alarms,['Node','Type']},{emqx_alarm,get_alarms,['Type']}},{{emqx_proto_v2,are_running,['Nodes']},{emqx,is_running,[]}},{{emqx_proto_v2,is_running,['Node']},{emqx,is_running,[]}}],casts => []},{emqx_delayed,1} => #{calls => [{{emqx_delayed_proto_v1,delete_delayed_message,['Node','Id']},{emqx_delayed,delete_delayed_message,['Id']}},{{emqx_delayed_proto_v1,get_delayed_message,['Node','Id']},{emqx_delayed,get_delayed_message,['Id']}}],casts => []},{emqx_conf,2} => #{calls => [{{emqx_conf_proto_v2,get_override_config_file,['Nodes']},{emqx_conf_app,get_override_config_file,[]}},{{emqx_conf_proto_v2,reset,['Node','KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,reset,['KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,remove_config,['Node','KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,remove_config,['KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v2,update,['Node','KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v2,update,['KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v2,get_all,['KeyPath']},{emqx_conf,get_node_and_config,['KeyPath']}},{{emqx_conf_proto_v2,get_config,['Node','KeyPath','Default']},{emqx,get_config,['KeyPath','Default']}},{{emqx_conf_proto_v2,get_config,['Node','KeyPath']},{emqx,get_config,['KeyPath']}},{{emqx_conf_proto_v2,sync_data_from_node,['Node']},{emqx_conf_app,sync_data_from_node,[]}}],casts => []},{emqx_plugin_libs,1} => #{calls => [{{emqx_plugin_libs_proto_v1,get_metrics,['Node','HandlerName','MetricId']},{emqx_metrics_worker,get_metrics,['HandlerName','MetricId']}}],casts => []},{emqx_management,2} => #{calls => [{{emqx_management_proto_v2,get_full_config,['Node']},{emqx_mgmt_api_configs,get_full_config,[]}},{{emqx_management_proto_v2,call_client,['Node','ClientId','Req']},{emqx_mgmt,do_call_client,['ClientId','Req']}},{{emqx_management_proto_v2,unsubscribe,['Node','ClientId','Topic']},{emqx_mgmt,do_unsubscribe,['ClientId','Topic']}},{{emqx_management_proto_v2,subscribe,['Node','ClientId','TopicTables']},{emqx_mgmt,do_subscribe,['ClientId','TopicTables']}},{{emqx_management_proto_v2,list_listeners,['Node']},{emqx_mgmt_api_listeners,do_list_listeners,[]}},{{emqx_management_proto_v2,list_subscriptions,['Node']},{emqx_mgmt,do_list_subscriptions,[]}},{{emqx_management_proto_v2,broker_info,['Node']},{emqx_mgmt,broker_info,[]}},{{emqx_management_proto_v2,node_info,['Node']},{emqx_mgmt,node_info,[]}},{{emqx_management_proto_v2,unsubscribe_batch,['Node','ClientId','Topics']},{emqx_mgmt,do_unsubscribe_batch,['ClientId','Topics']}}],casts => []},{emqx_cm,2} => #{calls => [{{emqx_cm_proto_v2,kick_session,['Action','ClientId','ChanPid']},{emqx_cm,do_kick_session,['Action','ClientId','ChanPid']}},{{emqx_cm_proto_v2,takeover_finish,['ConnMod','ChanPid']},{emqx_cm,takeover_finish,['ConnMod','ChanPid']}},{{emqx_cm_proto_v2,takeover_session,['ClientId','ChanPid']},{emqx_cm,takeover_session,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,get_chann_conn_mod,['ClientId','ChanPid']},{emqx_cm,do_get_chann_conn_mod,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,get_chan_info,['ClientId','ChanPid']},{emqx_cm,do_get_chan_info,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,get_chan_stats,['ClientId','ChanPid']},{emqx_cm,do_get_chan_stats,['ClientId','ChanPid']}},{{emqx_cm_proto_v2,lookup_client,['Node','Key']},{emqx_cm,lookup_client,['Key']}},{{emqx_cm_proto_v2,kickout_client,['Node','ClientId']},{emqx_cm,kick_session,['ClientId']}}],casts => []},{emqx_conf,1} => #{calls => [{{emqx_conf_proto_v1,get_override_config_file,['Nodes']},{emqx_conf_app,get_override_config_file,[]}},{{emqx_conf_proto_v1,reset,['Node','KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,reset,['KeyPath','Opts']},{emqx,reset_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,remove_config,['Node','KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,remove_config,['KeyPath','Opts']},{emqx,remove_config,['KeyPath','Opts']}},{{emqx_conf_proto_v1,update,['Node','KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v1,update,['KeyPath','UpdateReq','Opts']},{emqx,update_config,['KeyPath','UpdateReq','Opts']}},{{emqx_conf_proto_v1,get_all,['KeyPath']},{emqx_conf,get_node_and_config,['KeyPath']}},{{emqx_conf_proto_v1,get_config,['Node','KeyPath','Default']},{emqx,get_config,['KeyPath','Default']}},{{emqx_conf_proto_v1,get_config,['Node','KeyPath']},{emqx,get_config,['KeyPath']}}],casts => []},{emqx_ft_storage_fs,1} => #{calls => [{{emqx_ft_storage_fs_proto_v1,list_assemblers,['Nodes','Transfer']},{emqx_ft_storage_fs_proxy,lookup_local_assembler,['Transfer']}},{{emqx_ft_storage_fs_proto_v1,pread,['Node','Transfer','Frag','Offset','Size']},{emqx_ft_storage_fs_proxy,pread_local,['Transfer','Frag','Offset','Size']}},{{emqx_ft_storage_fs_proto_v1,multilist,['Nodes','Transfer','What']},{emqx_ft_storage_fs_proxy,list_local,['Transfer','What']}}],casts => []},{emqx_mgmt_cluster,1} => #{calls => [{{emqx_mgmt_cluster_proto_v1,invite_node,['Node','Self']},{emqx_mgmt_api_cluster,join,['Self']}}],casts => []},{emqx_management,3} => #{calls => [{{emqx_management_proto_v3,get_full_config,['Node']},{emqx_mgmt_api_configs,get_full_config,[]}},{{emqx_management_proto_v3,call_client,['Node','ClientId','Req']},{emqx_mgmt,do_call_client,['ClientId','Req']}},{{emqx_management_proto_v3,unsubscribe,['Node','ClientId','Topic']},{emqx_mgmt,do_unsubscribe,['ClientId','Topic']}},{{emqx_management_proto_v3,subscribe,['Node','ClientId','TopicTables']},{emqx_mgmt,do_subscribe,['ClientId','TopicTables']}},{{emqx_management_proto_v3,list_listeners,['Node']},{emqx_mgmt_api_listeners,do_list_listeners,[]}},{{emqx_management_proto_v3,list_subscriptions,['Node']},{emqx_mgmt,do_list_subscriptions,[]}},{{emqx_management_proto_v3,broker_info,['Nodes']},{emqx_mgmt,broker_info,[]}},{{emqx_management_proto_v3,node_info,['Nodes']},{emqx_mgmt,node_info,[]}},{{emqx_management_proto_v3,unsubscribe_batch,['Node','ClientId','Topics']},{emqx_mgmt,do_unsubscribe_batch,['ClientId','Topics']}}],casts => []},{emqx_telemetry,1} => #{calls => [{{emqx_telemetry_proto_v1,get_cluster_uuid,['Node']},{emqx_telemetry,get_cluster_uuid,[]}},{{emqx_telemetry_proto_v1,get_node_uuid,['Node']},{emqx_telemetry,get_node_uuid,[]}}],casts => []},{emqx_node_rebalance_evacuation,1} => #{calls => [{{emqx_node_rebalance_evacuation_proto_v1,available_nodes,['Nodes']},{emqx_node_rebalance_evacuation,is_node_available,[]}}],casts => []},{emqx_retainer,2} => #{calls => [{{emqx_retainer_proto_v2,active_mnesia_indices,['Nodes']},{emqx_retainer_mnesia,active_indices,[]}},{{emqx_retainer_proto_v2,wait_dispatch_complete,['Nodes','Timeout']},{emqx_retainer_dispatcher,wait_dispatch_complete,['Timeout']}}],casts => []},{emqx_rule_engine,1} => #{calls => [{{emqx_rule_engine_proto_v1,reset_metrics,['RuleId']},{emqx_rule_engine,reset_metrics_for_rule,['RuleId']}}],casts => []},{emqx_dashboard,1} => #{calls => [{{emqx_dashboard_proto_v1,current_rate,['Node']},{emqx_dashboard_monitor,current_rate,['Node']}},{{emqx_dashboard_proto_v1,do_sample,['Node','Latest']},{emqx_dashboard_monitor,do_sample,['Node','Latest']}}],casts => []}},release => "5.0",signatures => #{{emqx_bridge_proto_v2,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,remove_config,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_alarm,deactivate,1} => {any,[any]},{emqx_cm,do_get_chan_info,2} => {any,[any,any]},{emqx_ft_storage_fs_proxy,pread_local,4} => {any,[any,any,any,any]},{emqx_node_rebalance_status,evacuation_status,0} => {{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[enabled],unknown},{c,map,{[{{c,atom,[conn_evict_rate],unknown},mandatory,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[current_conns],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[current_sessions],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[initial_conns],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[initial_sessions],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[migrate_to],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[server_reference],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[sess_evict_rate],unknown},mandatory,{c,number,{int_rng,1,pos_inf},integer}}],none,none},unknown}],{2,{c,atom,[enabled],unknown}}},none,none,none],unknown}],{2,any}},[]},{emqx_bridge_proto_v4,start_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_cm_proto_v1,lookup_client,2} => {any,[{c,atom,any,unknown},{c,tuple_set,[{2,[{c,tuple,[{c,atom,[clientid],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[clientid],unknown}}},{c,tuple,[{c,atom,[username],unknown},{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[username],unknown}}}]}],unknown}]},{emqx_bridge_proto_v3,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,update,3} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_plugins,get_tar,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,binary,[8,0],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown}]},{emqx_broker,subscriptions_via_topic,1} => {{c,list,[any,{c,nil,[],unknown}],unknown},[any]},{emqx_cm,takeover_session,2} => {{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,tuple,[{c,atom,any,unknown},any],{2,any}},{c,nil,[],unknown}],unknown},none,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[expired],unknown},{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[any,any,any],{3,any}}}],unknown},{c,tuple,[any,any,any,any,any,any,any,any,any,any,any],{11,any}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}}],{2,{c,atom,[expired],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},{c,tuple,[{c,atom,[persistent],unknown},{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[any,any,any],{3,any}}}],unknown},{c,tuple,[any,any,any,any,any,any,any,any,any,any,any],{11,any}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}}],{2,{c,atom,[persistent],unknown}}}]},{3,[{c,tuple,[{c,atom,[ok],unknown},{c,list,[any,{c,nil,[],unknown}],unknown},any],{3,{c,atom,[ok],unknown}}}]},{4,[{c,tuple,[{c,atom,[living],unknown},{c,atom,any,unknown},{c,identifier,[pid],unknown},{c,union,[none,none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[any,any,any],{3,any}}}],unknown},{c,tuple,[any,any,any,any,any,any,any,any,any,any,any],{11,any}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}},none,none,none],unknown}],{4,{c,atom,[living],unknown}}}]}],unknown},none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_bridge_proto_v4,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_resource_proto_v1,create,5} => {any,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,no_queries,simple_async,simple_sync,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_bridge_proto_v2,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v3,broker_info,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_metrics,all,0} => {{c,list,[{c,tuple,[any,{c,number,any,integer}],{2,any}},{c,nil,[],unknown}],unknown},[]},{emqx_node_rebalance_status_proto_v1,evacuation_status,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_exhook_mgr,all_servers_info,0} => {any,[]},{emqx_alarm,get_alarms,1} => {any,[{c,atom,[activated,all,deactivated],unknown}]},{emqx_plugin_libs_proto_v1,get_metrics,3} => {any,[{c,atom,any,unknown},{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_exhook_proto_v1,all_servers_info,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{ssl_pem_cache,clear,0} => {any,[]},{emqx_resource,remove_local,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,binary,[8,0],unknown}]},{emqx_bridge_proto_v4,start_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge,list,0} => {any,[]},{emqx_retainer_proto_v1,wait_dispatch_complete,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_node_rebalance,stop,0} => {any,[]},{emqx_mgmt_api_cluster,join,1} => {any,[any]},{emqx_node_rebalance_evacuation_proto_v1,available_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_prometheus,do_stop,0} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found,restarting,running,simple_one_for_one],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[]},{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_start,2} => {any,[{c,atom,any,unknown},{c,map,{[{{c,atom,[conn_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[migrate_to],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[server_reference],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[sess_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_takeover],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}}],none,none},unknown}]},{emqx_telemetry_proto_v1,get_node_uuid,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v2,kickout_client,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_management_proto_v3,node_info,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_conf,get_node_and_config,1} => {{c,tuple,[{c,atom,any,unknown},any],{2,any}},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_gateway_cm_proto_v1,cast,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_node_rebalance,connection_count,0} => {{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},[]},{emqx_node_rebalance_status,local_status,0} => {{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[evacuation],unknown},{c,map,{[{{c,atom,[connection_eviction_rate],unknown},mandatory,any},{{c,atom,[connection_goal],unknown},mandatory,{c,number,{int_set,[0]},integer}},{{c,atom,[session_eviction_rate],unknown},mandatory,any},{{c,atom,[session_goal],unknown},mandatory,{c,number,{int_set,[0]},integer}},{{c,atom,[session_recipients],unknown},mandatory,any},{{c,atom,[state],unknown},mandatory,any},{{c,atom,[stats],unknown},mandatory,{c,map,{[{{c,atom,[current_connected],unknown},mandatory,any},{{c,atom,[current_sessions],unknown},mandatory,any},{{c,atom,[initial_connected],unknown},mandatory,any},{{c,atom,[initial_sessions],unknown},mandatory,any}],none,none},unknown}}],none,none},unknown}],{2,{c,atom,[evacuation],unknown}}},{c,tuple,[{c,atom,[rebalance],unknown},{c,map,{[],{c,atom,[connection_eviction_rate,connection_goal,coordinator_node,disconnected_session_goal,recipients,session_eviction_rate,state,stats],unknown},any},unknown}],{2,{c,atom,[rebalance],unknown}}}]}],unknown},none,none,none],unknown},[]},{emqx,is_running,0} => {{c,atom,[false,true],unknown},[]},{emqx_conf_proto_v1,reset,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_resource,create_dry_run_local,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,atom,any,unknown},any]},{emqx_management_proto_v3,call_client,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_cm_proto_v2,takeover_session,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_conf_app,sync_data_from_node,0} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,binary,[8,0],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[]},{emqx_conf_proto_v1,get_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown},any]},{emqx_proto_v1,is_running,1} => {any,[{c,atom,any,unknown}]},{emqx_exhook_mgr,server_info,1} => {any,[any]},{emqx_cm_proto_v2,get_chann_conn_mod,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_conf_proto_v2,get_override_config_file,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_management_proto_v1,broker_info,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v1,list_bridges,1} => {any,[{c,atom,any,unknown}]},{emqx_mgmt_api_plugins,describe_package,1} => {{c,tuple,[{c,atom,any,unknown},{c,list,[{c,map,{[],any,any},unknown},{c,nil,[],unknown}],unknown}],{2,any}},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_api_plugins_proto_v1,ensure_action,2} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,atom,[restart,start,stop],unknown}]},{emqx_gateway_cm,do_call,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_slow_subs_proto_v1,clear_history,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v3,list_bridges_on_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_gateway_cm_proto_v1,get_chan_info,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_cm_proto_v2,get_chan_stats,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_rule_engine_proto_v1,reset_metrics,1} => {any,[{c,binary,[8,0],unknown}]},{emqx_resource_proto_v1,reset_metrics,1} => {any,[{c,binary,[8,0],unknown}]},{emqx_gateway_cm,do_takeover_session,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx,remove_config,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown}},{{c,atom,[post_config_update],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[raw_config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_management_proto_v3,unsubscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_cm_proto_v1,get_chann_conn_mod,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_metrics_worker,get_metrics,2} => {{c,map,{[{{c,atom,[counters],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},mandatory,{c,map,{[],any,any},unknown}}],none,none},unknown},[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_mgmt_api_plugins,install_package,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_api_listeners_proto_v1,listeners_cluster_status,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,list,[any,{c,nil,[],unknown}],unknown}]},{emqx_topic_metrics_proto_v1,reset,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_management_proto_v3,unsubscribe_batch,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,binary,[8,0],unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_configs,get_full_config,0} => {{c,map,{[],any,any},unknown},[]},{emqx_management_proto_v2,list_listeners,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm,do_get_chan_stats,3} => {any,[any,any,any]},{emqx_node_rebalance_evacuation,is_node_available,0} => {{c,atom,any,unknown},[]},{emqx_ft_storage_exporter_fs_proto_v1,read_export_file,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_mgmt_trace_proto_v1,read_trace_file,4} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_exhook_proto_v1,server_hooks_metrics,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},any]},{emqx_proto_v2,get_metrics,1} => {any,[{c,atom,any,unknown}]},{emqx_conf_proto_v2,update,3} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_topic_metrics,metrics,0} => {{c,list,[{c,map,{[{{c,atom,[create_time],unknown},mandatory,any},{{c,atom,[metrics],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[reset_time],unknown},optional,any},{{c,atom,[topic],unknown},mandatory,any}],none,none},unknown},{c,nil,[],unknown}],unknown},[]},{emqx_bridge_proto_v3,start_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_delayed,get_delayed_message,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[delayed_interval],unknown},mandatory,any},{{c,atom,[delayed_remaining],unknown},mandatory,{c,number,any,integer}},{{c,atom,[expected_at],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[from_clientid],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[from_username],unknown},mandatory,any},{{c,atom,[msgid],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[node],unknown},mandatory,any},{{c,atom,[payload],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[publish_at],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[qos],unknown},mandatory,any},{{c,atom,[topic],unknown},mandatory,{c,binary,[8,0],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[any]},{emqx_proto_v1,clean_authz_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_proto_v2,clean_authz_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_mgmt,do_unsubscribe_batch,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[channel_not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[unsubscribe],unknown},{c,list,[{c,tuple,[any,any],{2,any}},{c,nil,[],unknown}],unknown}],{2,{c,atom,[unsubscribe],unknown}}}]}],unknown},[any,any]},{emqx_mgmt_api_plugins_proto_v1,describe_package,1} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,remove_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_cm_proto_v2,kick_session,3} => {any,[{c,atom,[discard,kick],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_mgmt_trace_proto_v2,read_trace_file,4} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_gateway_cm,do_lookup_by_clientid,2} => {{c,list,[any,{c,nil,[],unknown}],unknown},[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,none],unknown},any]},{emqx_management_proto_v2,list_subscriptions,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v3,get_full_config,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v1,call_client,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx,update_config,3} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown}},{{c,atom,[post_config_update],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[raw_config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_mgmt_trace_proto_v2,trace_file,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_http,gateway_status,1} => {{c,map,{[{{c,atom,[current_connections],unknown},optional,any},{{c,atom,[max_connections],unknown},optional,{c,number,{int_set,[0]},integer}},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[status],unknown},mandatory,{c,atom,[running,stopped,unloaded],unknown}}],none,none},unknown},[{c,atom,any,unknown}]},{emqx_ft_storage_fs_proto_v1,list_assemblers,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}}]},{emqx_dashboard_monitor,current_rate,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[badrpc],unknown},any],{2,{c,atom,[badrpc],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,atom,any,unknown}]},{emqx_mgmt_api_listeners,do_list_listeners,0} => {{c,map,{[],{c,binary,"( ",unknown},{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,map,{[],any,any},unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},unknown},[]},{emqx_resource,create_local,5} => {{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[callback_mode],unknown},mandatory,{c,atom,[always_sync,async_if_possible],unknown}},{{c,atom,[config],unknown},mandatory,any},{{c,atom,[error],unknown},mandatory,any},{{c,atom,[id],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[query_mode],unknown},mandatory,{c,atom,[async,no_queries,simple_async,simple_sync,sync],unknown}},{{c,atom,[state],unknown},mandatory,any},{{c,atom,[status],unknown},mandatory,{c,atom,[connected,connecting,disconnected,stopped],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}},[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,no_queries,simple_async,simple_sync,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_management_proto_v2,node_info,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm_proto_v1,get_chann_conn_mod,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_management_proto_v2,broker_info,1} => {any,[{c,atom,any,unknown}]},{emqx_broker,dispatch,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[no_subscribers,not_running],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,number,{int_rng,0,pos_inf},integer}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[delivery],unknown},{c,identifier,[pid],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[any,any,any,any],{4,any}}]},{8,[{c,tuple,[any,any,any,any,any,any,any,any],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}],{3,{c,atom,[delivery],unknown}}}]},{emqx_conf_proto_v1,get_override_config_file,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_session_router,resume_begin,2} => {any,[{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_proto_v2,get_stats,1} => {any,[{c,atom,any,unknown}]},{emqx_slow_subs_proto_v1,get_history,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_trace_proto_v2,get_trace_size,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_ft_storage_fs_proxy,lookup_local_assembler,1} => {any,[any]},{emqx_telemetry,get_node_uuid,0} => {any,[]},{emqx_license_proto_v2,remote_connection_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v1,get_metrics,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v2,lookup_client,2} => {any,[{c,atom,any,unknown},{c,tuple_set,[{2,[{c,tuple,[{c,atom,[clientid],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[clientid],unknown}}},{c,tuple,[{c,atom,[username],unknown},{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,{c,atom,[username],unknown}}}]}],unknown}]},{emqx_delayed_proto_v1,delete_delayed_message,2} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_node_rebalance_agent,disable,1} => {any,[any]},{emqx_bridge_resource,start,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v2,reset,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_ft_storage_fs_reader,read,2} => {any,[{c,identifier,[pid],unknown},{c,number,{int_rng,1,pos_inf},integer}]},{emqx_cm_proto_v2,takeover_finish,2} => {any,[{c,atom,any,unknown},{c,identifier,[pid],unknown}]},{emqx_trace,trace_file,1} => {{c,tuple_set,[{3,[{c,tuple,[{c,atom,[error],unknown},{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},{c,atom,any,unknown}],{3,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},{c,binary,[8,0],unknown}],{3,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v1,list_subscriptions,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance_proto_v1,session_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v1,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v2,get_config,2} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v1,get_stats,1} => {any,[{c,atom,any,unknown}]},{emqx_ft_storage_fs_proto_v1,pread,5} => {any,[{c,atom,any,unknown},{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}},{c,map,{[{{c,atom,[fragment],unknown},mandatory,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[filemeta],unknown},{c,map,{[{{c,atom,[checksum],unknown},optional,{c,tuple,[{c,atom,any,unknown},{c,binary,[8,0],unknown}],{2,any}}},{{c,atom,[expire_at],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[name],unknown},mandatory,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown}},{{c,atom,[segments_ttl],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[user_data],unknown},optional,{c,union,[{c,atom,[false,null,true],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,[false,null,true],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown},{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,{c,map,{[],{c,binary,[8,0],unknown},{c,union,[{c,atom,[false,null,true],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,any,unknown},none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[filemeta],unknown}}},{c,tuple,[{c,atom,[segment],unknown},{c,map,{[{{c,atom,[offset],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[size],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}],{2,{c,atom,[segment],unknown}}}]}],unknown}},{{c,atom,[path],unknown},mandatory,{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[size],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[timestamp],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_conf_proto_v2,get_all,1} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_authz_cache,drain_cache,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_conf_proto_v2,sync_data_from_node,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance_evacuation,start,1} => {any,[{c,map,{[],any,any},unknown}]},{emqx_prometheus_proto_v1,start,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt,do_unsubscribe,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[channel_not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[unsubscribe],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[],any,any},unknown}],{2,any}},{c,nil,[],unknown}],nonempty}],{2,{c,atom,[unsubscribe],unknown}}}]}],unknown},[any,any]},{emqx_ft_storage_exporter_fs_proto_v1,list_exports,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,map,{[{{c,atom,[following],unknown},optional,{c,var,'_LocalCursor',unknown}},{{c,atom,[limit],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[transfer],unknown},optional,{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}}}],none,none},unknown}]},{emqx_cm,do_get_chan_stats,2} => {any,[any,any]},{emqx_ft_storage_exporter_fs_proxy,list_exports_local,1} => {any,[any]},{emqx_node_rebalance,start,1} => {any,[{c,map,{[],any,any},unknown}]},{emqx_bridge_proto_v4,list_bridges_on_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_license_proto_v1,remote_connection_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_cm_proto_v1,takeover_session,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_bridge_proto_v4,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_slow_subs,clear_history,0} => {any,[]},{emqx_mgmt_api_plugins_proto_v1,get_plugins,0} => {any,[]},{emqx_management_proto_v2,get_full_config,1} => {any,[{c,atom,any,unknown}]},{emqx_proto_v2,is_running,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm_proto_v1,set_chan_stats,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},{c,list,[{c,tuple,[{c,atom,any,unknown},any],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_bridge_api,lookup_from_local_node,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v3,list_listeners,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v2,unsubscribe_batch,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,binary,[8,0],unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v4,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_trace_proto_v1,trace_file,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_resource,restart,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_delayed,delete_delayed_message,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[any]},{emqx_mgmt_api_trace,get_trace_size,0} => {{c,map,{[],any,any},unknown},[]},{emqx_shared_sub,do_dispatch_with_ack,4} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,identifier,[pid,port],unknown},any,any,{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}]},{emqx,reset_config,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,atom,any,unknown},any},unknown}],unknown}},{{c,atom,[post_config_update],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[raw_config],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,{c,map,{[],{c,binary,[8,0],unknown},any},unknown}],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any]},{emqx_authn_api,lookup_from_local_node,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[not_found_resource],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,any}}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,tuple,[{c,atom,any,unknown},{c,atom,[connected,connecting,disconnected,stopped],unknown},{c,map,{[{{c,atom,[counters],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},mandatory,{c,map,{[],any,any},unknown}}],none,none},unknown},{c,map,{[{{c,atom,[counters],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},optional,{c,map,{[],any,any},unknown}}],none,none},unknown}],{4,any}}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_management_proto_v1,unsubscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_management_proto_v2,call_client,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_persistent_session_proto_v1,resume_end,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_conf_proto_v2,remove_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_proto_v2,deactivate_alarm,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_node_rebalance,session_count,0} => {{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},[]},{emqx_topic_metrics_proto_v1,metrics,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_plugins_proto_v1,delete_package,1} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_persistent_session_proto_v1,resume_begin,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_proto_v1,clean_authz_cache,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_bridge_api,get_metrics_from_local_node,2} => {{c,map,{[{{c,atom,[dropped],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.expired'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.other'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.queue_full'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.resource_not_found'],unknown},mandatory,{c,number,any,integer}},{{c,atom,['dropped.resource_stopped'],unknown},mandatory,{c,number,any,integer}},{{c,atom,[failed],unknown},mandatory,{c,number,any,integer}},{{c,atom,[inflight],unknown},mandatory,any},{{c,atom,[late_reply],unknown},mandatory,{c,number,any,integer}},{{c,atom,[matched],unknown},mandatory,{c,number,any,integer}},{{c,atom,[queuing],unknown},mandatory,any},{{c,atom,[rate],unknown},mandatory,any},{{c,atom,[rate_last5m],unknown},mandatory,any},{{c,atom,[rate_max],unknown},mandatory,any},{{c,atom,[received],unknown},mandatory,{c,number,any,integer}},{{c,atom,[retried],unknown},mandatory,{c,number,any,integer}},{{c,atom,[success],unknown},mandatory,{c,number,any,integer}}],none,none},unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_delayed_proto_v1,get_delayed_message,2} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_shared_sub_proto_v1,send,4} => {any,[{c,atom,any,unknown},{c,identifier,[pid],unknown},{c,binary,[8,0],unknown},any]},{emqx_eviction_agent,evict_sessions,3} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[disabled],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[any,{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},any]},{emqx_management_proto_v1,node_info,1} => {any,[{c,atom,any,unknown}]},{emqx_management_proto_v3,subscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[{{c,atom,[nl],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[qos],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[rap],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[rh],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[share],unknown},optional,{c,binary,[8,0],unknown}}],{c,atom,any,unknown},any},unknown}],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_topic_metrics_proto_v1,reset,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,binary,[8,0],unknown}]},{emqx_node_rebalance_agent,enable,1} => {any,[any]},{emqx_mgmt_trace_proto_v1,get_trace_size,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_node_rebalance_status,rebalance_status,0} => {{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[enabled],unknown},{c,map,{[],any,any},unknown}],{2,{c,atom,[enabled],unknown}}},none,none,none],unknown}],{2,any}},[]},{emqx_license_resources,local_connection_count,0} => {any,[]},{emqx_cm,lookup_client,1} => {{c,list,[any,{c,nil,[],unknown}],unknown},[{c,tuple_set,[{2,[{c,tuple,[{c,atom,[clientid],unknown},any],{2,{c,atom,[clientid],unknown}}},{c,tuple,[{c,atom,[username],unknown},any],{2,{c,atom,[username],unknown}}}]}],unknown}]},{emqx_management_proto_v2,subscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[{{c,atom,[nl],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[qos],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[rap],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[rh],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[share],unknown},optional,{c,binary,[8,0],unknown}}],{c,atom,any,unknown},any},unknown}],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_cm,kick_session,1} => {{c,atom,[ok],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_cm_proto_v1,kick_session,3} => {any,[{c,atom,[discard,kick],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_dashboard_proto_v1,current_rate,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v3,start_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_ft_storage_fs_reader_proto_v1,read,3} => {any,[{c,atom,any,unknown},{c,identifier,[pid],unknown},{c,number,{int_rng,1,pos_inf},integer}]},{emqx_plugins_proto_v1,get_tar,3} => {any,[{c,atom,any,unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_bridge_proto_v2,start_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_resource,recreate_local,4} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[not_found,updating_to_incorrect_resource_type],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[callback_mode],unknown},mandatory,{c,atom,[always_sync,async_if_possible],unknown}},{{c,atom,[config],unknown},mandatory,any},{{c,atom,[error],unknown},mandatory,any},{{c,atom,[id],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[query_mode],unknown},mandatory,{c,atom,[async,no_queries,simple_async,simple_sync,sync],unknown}},{{c,atom,[state],unknown},mandatory,any},{{c,atom,[status],unknown},mandatory,{c,atom,[connected,connecting,disconnected,stopped],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,no_queries,simple_async,simple_sync,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_topic_metrics_proto_v1,metrics,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,binary,[8,0],unknown}]},{emqx_bridge_resource,stop,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt,do_call_client,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},any]},{emqx_exhook_proto_v1,server_info,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},any]},{emqx_retainer_mnesia,active_indices,0} => {{c,tuple,[any,any],{2,any}},[]},{emqx_prometheus_proto_v1,stop,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v1,get_alarms,2} => {any,[{c,atom,any,unknown},{c,atom,[activated,all,deactivated],unknown}]},{emqx_dashboard_proto_v1,do_sample,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,1,pos_inf},integer},none,none,none,none],unknown}]},{emqx_telemetry,get_cluster_uuid,0} => {any,[]},{emqx_bridge_proto_v2,list_bridges,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance_proto_v1,evict_connections,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,pos_inf},integer}]},{emqx_conf_proto_v1,update,4} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_node_rebalance_api_proto_v1,node_rebalance_evacuation_stop,1} => {any,[{c,atom,any,unknown}]},{emqx_broker_proto_v1,list_client_subscriptions,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_broker_proto_v1,forward_async,3} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[delivery],unknown},{c,identifier,[pid],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}],{3,{c,atom,[delivery],unknown}}}]},{emqx_cm_proto_v1,kickout_client,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_mgmt,do_subscribe,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[channel_not_found],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[subscribe],unknown},any],{2,{c,atom,[subscribe],unknown}}}]}],unknown},[any,any]},{emqx_conf_app,get_override_config_file,0} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,map,{[{{c,atom,[msg],unknown},mandatory,any},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}}],none,none},unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}}]}],unknown},[]},{emqx_gateway_cm,do_cast,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_management_proto_v1,subscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,list,[{c,tuple,[{c,binary,[8,0],unknown},{c,map,{[{{c,atom,[nl],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[qos],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[rap],unknown},mandatory,{c,number,{int_set,[0,1]},integer}},{{c,atom,[rh],unknown},mandatory,{c,number,{int_set,[0,1,2]},integer}},{{c,atom,[share],unknown},optional,{c,binary,[8,0],unknown}}],{c,atom,any,unknown},any},unknown}],{2,any}},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_plugins,delete_package,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_api_plugins_proto_v1,install_package,2} => {any,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_resource_proto_v1,recreate,4} => {any,[{c,binary,[8,0],unknown},{c,atom,any,unknown},any,{c,map,{[{{c,atom,[auto_restart_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[auto_retry_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[batch_size],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[batch_time],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[health_check_interval],unknown},optional,{c,number,any,integer}},{{c,atom,[health_check_timeout],unknown},optional,{c,number,any,integer}},{{c,atom,[inflight_window],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[max_buffer_bytes],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[query_mode],unknown},optional,{c,atom,[async,no_queries,simple_async,simple_sync,sync],unknown}},{{c,atom,[resume_interval],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[start_after_created],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[start_timeout],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_for_resource_ready],unknown},optional,{c,number,any,integer}},{{c,atom,[worker_pool_size],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}}],none,none},unknown}]},{emqx_authz_cache,drain_cache,0} => {{c,atom,[ok],unknown},[]},{emqx_mgmt_api_plugins,ensure_action,2} => {{c,atom,[ok],unknown},[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,atom,[restart,start,stop],unknown}]},{emqx_broker_proto_v1,list_subscriptions_via_topic,2} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_trace,trace_file_detail,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,map,{[{{c,atom,[file],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[node],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[reason],unknown},mandatory,{c,atom,any,unknown}}],none,none},unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,map,{[{{c,atom,[mtime],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},{c,tuple,[{c,tuple,[any,any,any],{3,any}},{c,tuple,[any,any,any],{3,any}}],{2,any}},none,none,none],unknown}},{{c,atom,[node],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[size],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}}],none,none},unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_proto_v1,delete_all_deactivated_alarms,1} => {any,[{c,atom,any,unknown}]},{emqx_prometheus,do_start,0} => {{c,atom,[ok],unknown},[]},{emqx_gateway_cm,do_kick_session,4} => {{c,atom,[ok],unknown},[{c,atom,any,unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_ft_storage_fs_proto_v1,multilist,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,tuple,[{c,binary,[8,0],unknown},{c,binary,[8,0],unknown}],{2,any}},{c,atom,[fragment,result],unknown}]},{emqx_telemetry_proto_v1,get_cluster_uuid,1} => {any,[{c,atom,any,unknown}]},{emqx_node_rebalance,is_node_available,0} => {{c,atom,any,unknown},[]},{emqx_retainer_proto_v2,active_mnesia_indices,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v4,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_proto_v3,list_bridges,1} => {any,[{c,atom,any,unknown}]},{emqx_gateway_cm,do_get_chan_info,3} => {{c,union,[{c,atom,[undefined],unknown},none,none,none,none,none,none,none,none,{c,map,{[{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}}],any,any},unknown}],unknown},[any,any,any]},{emqx_node_rebalance_status_proto_v1,rebalance_status,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_node_rebalance_proto_v1,disable_rebalance_agent,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown}]},{emqx_rule_engine,reset_metrics_for_rule,1} => {{c,atom,[ok],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_authz_proto_v1,lookup_from_all_nodes,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown}]},{emqx_proto_v1,clean_pem_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_conf_proto_v1,get_config,2} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]},{emqx_management_proto_v1,get_full_config,1} => {any,[{c,atom,any,unknown}]},{emqx_topic_metrics,reset,1} => {any,[any]},{emqx_node_rebalance_proto_v1,available_nodes,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_proto_v2,clean_pem_cache,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v4,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,reset,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_broker,subscriptions,1} => {{c,list,[{c,tuple,[any,any],{2,any}},{c,nil,[],unknown}],unknown},[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,{c,identifier,[pid],unknown},none,none,none,none,none,none],unknown}]},{emqx_mgmt,do_list_subscriptions,0} => {none,[]},{emqx_eviction_agent_proto_v1,evict_session_channel,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[{{c,atom,[clean_start],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[clientid],unknown},optional,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[conn_mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[conn_props],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[connected],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[connected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[disconnected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[expiry_interval],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[keepalive],unknown},optional,{c,number,{int_rng,0,1114111},integer}},{{c,atom,[peercert],unknown},mandatory,{c,union,[{c,atom,[nossl,undefined],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,none,none,{c,tuple,any,{any,any}},none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[peername],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[proto_name],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[receive_maximum],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[sockname],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[socktype],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,map,{[{{c,atom,[anonymous],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[auth_result],unknown},optional,{c,atom,[bad_authentication_method,bad_clientid_or_password,bad_username_or_password,banned,client_identifier_not_valid,not_authorized,server_busy,server_unavailable,success],unknown}},{{c,atom,[clientid],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[cn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[dn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[is_bridge],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[is_superuser],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[mountpoint],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[password],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[peerhost],unknown},mandatory,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[protocol],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[sockport],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[username],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[ws_cookie],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[zone],unknown},mandatory,{c,atom,any,unknown}}],{c,atom,any,unknown},any},unknown}]},{emqx_gateway_cm,do_set_chan_stats,4} => {{c,atom,[false,true],unknown},[any,any,any,any]},{emqx_retainer_dispatcher,wait_dispatch_complete,1} => {{c,atom,[ok],unknown},[any]},{emqx_conf_proto_v2,update,4} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},any,{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_bridge_proto_v3,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_cm_proto_v1,get_chan_stats,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_ft_storage_exporter_fs_proxy,read_export_file_local,2} => {any,[any,any]},{emqx_conf_proto_v2,remove_config,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_stats,getstats,0} => {{c,list,[{c,tuple,any,{any,any}},{c,nil,[],unknown}],unknown},[]},{emqx_mgmt,node_info,0} => {{c,map,{[{{c,atom,[connections],unknown},mandatory,any},{{c,atom,[edition],unknown},mandatory,{c,binary,[0,80],unknown}},{{c,atom,[load1],unknown},optional,{c,number,any,float}},{{c,atom,[load15],unknown},optional,{c,number,any,float}},{{c,atom,[load5],unknown},optional,{c,number,any,float}},{{c,atom,[log_path],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[max_fds],unknown},mandatory,any},{{c,atom,[memory_total],unknown},mandatory,{c,number,any,unknown}},{{c,atom,[memory_used],unknown},mandatory,{c,number,any,integer}},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[node_status],unknown},mandatory,{c,atom,[running],unknown}},{{c,atom,[otp_release],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[process_available],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[process_used],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[role],unknown},mandatory,{c,atom,[core,replicant],unknown}},{{c,atom,[sys_path],unknown},mandatory,{c,binary,[8,0],unknown}},{{c,atom,[uptime],unknown},mandatory,any},{{c,atom,[version],unknown},mandatory,{c,binary,[8,0],unknown}}],none,none},unknown},[]},{emqx_gateway_cm_proto_v1,kick_session,4} => {any,[{c,atom,any,unknown},{c,atom,[discard,kick],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_node_rebalance_api_proto_v1,node_rebalance_stop,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v2,get_chan_info,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_authn_proto_v1,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown},{c,binary,[8,0],unknown}]},{emqx_cm,takeover_finish,2} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,atom,[noproc,timeout,unexpected_exception],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,union,[none,none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,{c,tuple,[{c,atom,[session],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[0,128],unknown},{c,atom,[false,true],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,atom,[false,true],unknown},{c,opaque,[{opaque,emqx_inflight,inflight,[],{c,tuple,[{c,atom,[inflight],unknown},{c,number,{int_rng,1,pos_inf},integer},{c,opaque,[{opaque,gb_trees,tree,[any,any],{c,tuple,[any,any],{2,any}}}],unknown}],{3,{c,atom,[inflight],unknown}}}}],unknown},{c,tuple,[{c,atom,[mqueue],unknown},{c,atom,[false,true],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer},{c,number,{int_rng,0,pos_inf},integer},{c,union,[{c,atom,[disabled],unknown},none,none,none,none,none,none,none,none,{c,map,{[],any,any},unknown}],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,any,integer},none,none,none,none],unknown},{c,tuple_set,[{2,[{c,tuple,[any,any],{2,any}}]},{4,[{c,tuple,[any,any,any,any],{4,any}}]}],unknown},{c,tuple,[any,any,any],{3,any}},{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}],{11,{c,atom,[mqueue],unknown}}},{c,number,{int_rng,1,1114111},integer},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,map,{[],any,any},unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown},{c,number,{int_rng,1,pos_inf},integer}],{15,{c,atom,[session],unknown}}},none,none,none],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},none,none,none],unknown},[{c,atom,any,unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm_proto_v1,call,5} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any,{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_mgmt,broker_info,0} => {{c,map,{[{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[node_status],unknown},mandatory,{c,atom,[running],unknown}},{{c,atom,[otp_release],unknown},mandatory,{c,binary,[8,0],unknown}}],any,any},unknown},[]},{emqx_resource,reset_metrics_local,1} => {{c,atom,[ok],unknown},[{c,binary,[8,0],unknown}]},{emqx_cm,do_kick_session,3} => {{c,atom,[ok],unknown},[any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm,do_get_chann_conn_mod,3} => {any,[any,any,any]},{emqx_conf_proto_v2,get_config,3} => {any,[{c,atom,any,unknown},{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown},any]},{emqx_resource_proto_v1,remove,1} => {any,[{c,binary,[8,0],unknown}]},{emqx_topic_metrics,reset,0} => {any,[]},{emqx_bridge_proto_v3,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_slow_subs_api,get_history,0} => {{c,list,[{c,map,{[{{c,atom,[clientid],unknown},mandatory,any},{{c,atom,[last_update_time],unknown},mandatory,any},{{c,atom,[node],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[timespan],unknown},mandatory,any},{{c,atom,[topic],unknown},mandatory,any}],none,none},unknown},{c,nil,[],unknown}],unknown},[]},{emqx_node_rebalance_proto_v1,evict_sessions,4} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,pos_inf},integer},{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,[connected,connecting,disconnected,idle,reauthenticating],unknown}]},{emqx,get_config,1} => {any,[{c,list,[any,{c,nil,[],unknown}],unknown}]},{emqx_bridge_proto_v1,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_proto_v2,start_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_authz_api_sources,lookup_from_local_node,1} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},{c,tuple,[{c,atom,any,unknown},{c,union,[{c,atom,[not_found_resource],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}],{2,any}}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,tuple,[{c,atom,any,unknown},{c,atom,[connected,connecting,disconnected,stopped],unknown},{c,map,{[{{c,atom,[counters],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},mandatory,{c,map,{[],any,any},unknown}}],none,none},unknown},{c,map,{[{{c,atom,[counters],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[gauges],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[rate],unknown},optional,{c,map,{[],any,any},unknown}},{{c,atom,[slides],unknown},optional,{c,map,{[],any,any},unknown}}],none,none},unknown}],{4,any}}],{2,{c,atom,[ok],unknown}}}]}],unknown},[any]},{emqx_gateway_cm_proto_v1,set_chan_info,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},{c,map,{[],{c,atom,any,unknown},any},unknown}]},{emqx_eviction_agent,evict_session_channel,3} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,{c,identifier,[pid],unknown},none,none,none,none,none,none],unknown}],{2,{c,atom,[ok],unknown}}}]},{3,[{c,tuple,[{c,atom,[ok],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,{c,identifier,[pid],unknown},none,none,none,none,none,none],unknown},any],{3,{c,atom,[ok],unknown}}}]}],unknown},[any,{c,map,{[{{c,atom,[clean_start],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[clientid],unknown},optional,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[conn_mod],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[conn_props],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[connected],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[connected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[disconnected_at],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[expiry_interval],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[keepalive],unknown},optional,{c,number,{int_rng,0,1114111},integer}},{{c,atom,[peercert],unknown},optional,{c,union,[{c,atom,[nossl,undefined],unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,none,none,{c,tuple,any,{any,any}},none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[peername],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[proto_name],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[receive_maximum],unknown},optional,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[sockname],unknown},mandatory,{c,tuple,[{c,union,[{c,atom,[local,undefined,unspec],unknown},none,none,none,none,none,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown},none,none,none],unknown},any],{2,any}}},{{c,atom,[socktype],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,map,{[{{c,atom,[anonymous],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[auth_result],unknown},optional,{c,atom,[bad_authentication_method,bad_clientid_or_password,bad_username_or_password,banned,client_identifier_not_valid,not_authorized,server_busy,server_unavailable,success],unknown}},{{c,atom,[clientid],unknown},mandatory,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[cn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[dn],unknown},optional,{c,binary,[8,0],unknown}},{{c,atom,[is_bridge],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[is_superuser],unknown},mandatory,{c,atom,[false,true],unknown}},{{c,atom,[mountpoint],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[password],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[peerhost],unknown},mandatory,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[protocol],unknown},mandatory,{c,atom,any,unknown}},{{c,atom,[sockport],unknown},mandatory,{c,number,{int_rng,0,pos_inf},integer}},{{c,atom,[username],unknown},mandatory,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}},{{c,atom,[ws_cookie],unknown},optional,{c,union,[{c,atom,[undefined],unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}},{{c,atom,[zone],unknown},mandatory,{c,atom,any,unknown}}],{c,atom,any,unknown},any},unknown}]},{emqx_bridge_proto_v1,stop_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_node_rebalance_proto_v1,enable_rebalance_agent,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,identifier,[pid],unknown}]},{emqx_node_rebalance_proto_v1,connection_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_mgmt_api_plugins,get_plugins,0} => {{c,tuple,[{c,atom,any,unknown},{c,list,[{c,map,{[],any,any},unknown},{c,nil,[],unknown}],unknown}],{2,any}},[]},{emqx_proto_v2,clean_authz_cache,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_bridge_proto_v3,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_api_trace,read_trace_file,3} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[eof],unknown},{c,union,[{c,atom,[undefined],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}],{2,{c,atom,[eof],unknown}}},{c,tuple,[{c,atom,[error],unknown},{c,union,[{c,atom,any,unknown},none,none,none,none,none,{c,tuple,[{c,atom,[no_translation],unknown},{c,atom,[unicode],unknown},{c,atom,[latin1],unknown}],{3,{c,atom,[no_translation],unknown}}},none,none,none],unknown}],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,1114111},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,binary,[8,0],unknown},any,any]},{emqx_gateway_cm,do_set_chan_info,4} => {{c,atom,[false,true],unknown},[any,any,any,any]},{emqx_resource_proto_v1,create_dry_run,2} => {any,[{c,atom,any,unknown},any]},{emqx_broker_proto_v1,forward,3} => {any,[{c,atom,any,unknown},{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[delivery],unknown},{c,identifier,[pid],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}}],{3,{c,atom,[delivery],unknown}}}]},{emqx_node_rebalance_evacuation,stop,0} => {any,[]},{emqx_bridge_proto_v1,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_management_proto_v2,unsubscribe,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,binary,[8,0],unknown}]},{emqx_gateway_api_listeners,do_listeners_cluster_status,1} => {{c,map,{[],any,any},unknown},[{c,list,[any,{c,nil,[],unknown}],unknown}]},{emqx_proto_v2,are_running,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{emqx_retainer_proto_v2,wait_dispatch_complete,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_bridge_proto_v3,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_node_rebalance_api_proto_v1,node_rebalance_start,2} => {any,[{c,atom,any,unknown},{c,map,{[{{c,atom,[abs_conn_threshold],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[abs_sess_threshold],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[conn_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[nodes],unknown},optional,{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}},{{c,atom,[rel_conn_threshold],unknown},optional,{c,number,any,unknown}},{{c,atom,[rel_sess_threshold],unknown},optional,{c,number,any,unknown}},{{c,atom,[sess_evict_rate],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_health_check],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}},{{c,atom,[wait_takeover],unknown},optional,{c,number,{int_rng,1,pos_inf},integer}}],none,none},unknown}]},{emqx,get_config,2} => {any,[any,any]},{emqx_mgmt_trace_proto_v2,trace_file_detail,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[{c,atom,any,unknown},none,none,none,{c,list,[any,{c,nil,[],unknown}],unknown},{c,number,{int_rng,0,1114111},integer},none,none,none,none],unknown},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_bridge_proto_v2,stop_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_shared_sub_proto_v1,dispatch_with_ack,5} => {any,[{c,identifier,[pid],unknown},any,{c,binary,[8,0],unknown},{c,tuple,[{c,atom,[message],unknown},{c,binary,[8,0],unknown},any,{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,map,{[],{c,atom,any,unknown},{c,atom,[false,true],unknown}},unknown},{c,map,{[{{c,atom,[allow_publish],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[peerhost],unknown},optional,{c,tuple_set,[{4,[{c,tuple,[{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer},{c,number,{int_rng,0,255},integer}],{4,any}}]},{8,[{c,tuple,[{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer},{c,number,{int_rng,0,1114111},integer}],{8,any}}]}],unknown}},{{c,atom,[properties],unknown},optional,{c,map,{[],{c,atom,any,unknown},any},unknown}},{{c,atom,[proto_ver],unknown},optional,{c,union,[none,{c,binary,[8,0],unknown},none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}},{{c,atom,[protocol],unknown},optional,{c,atom,any,unknown}},{{c,atom,[username],unknown},optional,{c,union,[{c,atom,[undefined],unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}}],{c,atom,any,unknown},any},unknown},{c,binary,[8,0],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,list,[any,{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},{c,number,{int_rng,0,255},integer},none,none,none,none],unknown},{c,union,[none,{c,binary,[8,0],unknown},none,none,{c,nil,[],unknown},none,none,none,none,none],unknown}],unknown},none,none,none,none,none],unknown},{c,number,any,integer},any],{10,{c,atom,[message],unknown}}},{c,union,[{c,atom,[infinity],unknown},none,none,none,none,{c,number,{int_rng,0,pos_inf},integer},none,none,none,none],unknown}]},{emqx_gateway_http_proto_v1,get_cluster_status,2} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown}]},{emqx_management_proto_v3,list_subscriptions,1} => {any,[{c,atom,any,unknown}]},{emqx_cm_proto_v1,get_chan_stats,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm_proto_v1,takeover_session,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_conf_proto_v2,reset,2} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],nonempty},{c,map,{[{{c,atom,[override_to],unknown},optional,{c,atom,[cluster,local],unknown}},{{c,atom,[persistent],unknown},optional,{c,atom,[false,true],unknown}},{{c,atom,[rawconf_with_defaults],unknown},optional,{c,atom,[false,true],unknown}}],none,none},unknown}]},{emqx_node_rebalance_proto_v1,disconnected_session_counts,1} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown}]},{erlang,send,2} => {any,[any,any]},{emqx_cm_proto_v1,get_chan_info,2} => {any,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown}]},{emqx_gateway_cm_proto_v1,call,4} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any]},{emqx_eviction_agent,evict_connections,1} => {{c,union,[{c,atom,[ok],unknown},none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[disabled],unknown}],{2,{c,atom,[error],unknown}}},none,none,none],unknown},[any]},{emqx_dashboard_monitor,do_sample,2} => {any,[{c,atom,any,unknown},any]},{emqx_session_router,resume_end,2} => {{c,tuple_set,[{2,[{c,tuple,[{c,atom,[error],unknown},any],{2,{c,atom,[error],unknown}}},{c,tuple,[{c,atom,[ok],unknown},{c,list,[{c,tuple,any,{any,any}},{c,nil,[],unknown}],unknown}],{2,{c,atom,[ok],unknown}}}]}],unknown},[{c,identifier,[pid],unknown},{c,binary,[8,0],unknown}]},{emqx_node_rebalance,disconnected_session_count,0} => {{c,tuple,[{c,atom,[ok],unknown},any],{2,{c,atom,[ok],unknown}}},[]},{emqx_proto_v2,delete_all_deactivated_alarms,1} => {any,[{c,atom,any,unknown}]},{emqx_cm,do_get_chann_conn_mod,2} => {any,[any,any]},{emqx_exhook_mgr,server_hooks_metrics,1} => {any,[any]},{emqx_node_rebalance_status_proto_v1,local_status,1} => {any,[{c,atom,any,unknown}]},{emqx_alarm,delete_all_deactivated_alarms,0} => {any,[]},{emqx_proto_v1,deactivate_alarm,2} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_bridge_proto_v1,restart_bridge_to_node,3} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_mgmt_cluster_proto_v1,invite_node,2} => {any,[{c,atom,any,unknown},{c,atom,any,unknown}]},{emqx_topic_metrics,metrics,1} => {{c,union,[none,none,none,none,none,none,{c,tuple,[{c,atom,[error],unknown},{c,atom,[topic_not_found],unknown}],{2,{c,atom,[error],unknown}}},none,none,{c,map,{[{{c,atom,[create_time],unknown},mandatory,any},{{c,atom,[metrics],unknown},mandatory,{c,map,{[],any,any},unknown}},{{c,atom,[reset_time],unknown},optional,any},{{c,atom,[topic],unknown},mandatory,any}],none,none},unknown}],unknown},[any]},{emqx_bridge_proto_v4,get_metrics_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_proto_v2,get_alarms,2} => {any,[{c,atom,any,unknown},{c,atom,[activated,all,deactivated],unknown}]},{emqx_bridge_proto_v2,lookup_from_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_gateway_cm,do_call,5} => {any,[{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown},{c,identifier,[pid],unknown},any,any]},{emqx_management_proto_v1,list_listeners,1} => {any,[{c,atom,any,unknown}]},{emqx_bridge_proto_v2,restart_bridges_to_all_nodes,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown}]},{emqx_ft_storage_fs_proxy,list_local,2} => {any,[any,any]},{emqx_gateway_cm_proto_v1,lookup_by_clientid,3} => {any,[{c,list,[{c,atom,any,unknown},{c,nil,[],unknown}],unknown},{c,atom,any,unknown},{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,none,none,none,none,none,none],unknown}]},{emqx_conf_proto_v1,get_all,1} => {any,[{c,list,[{c,union,[{c,atom,any,unknown},{c,binary,[8,0],unknown},none,none,{c,list,[{c,number,{int_rng,0,255},integer},{c,nil,[],unknown}],unknown},none,none,none,none,none],unknown},{c,nil,[],unknown}],unknown}]}}}. diff --git a/apps/emqx_bridge/src/emqx_bridge_resource.erl b/apps/emqx_bridge/src/emqx_bridge_resource.erl index b19b7139f..db8669f49 100644 --- a/apps/emqx_bridge/src/emqx_bridge_resource.erl +++ b/apps/emqx_bridge/src/emqx_bridge_resource.erl @@ -54,7 +54,9 @@ (TYPE) =:= <<"mqtt">> ). -define(IS_INGRESS_BRIDGE(TYPE), - (TYPE) =:= <<"kafka_consumer">> orelse ?IS_BI_DIR_BRIDGE(TYPE) + (TYPE) =:= <<"kafka_consumer">> orelse + (TYPE) =:= <<"gcp_pubsub_consumer">> orelse + ?IS_BI_DIR_BRIDGE(TYPE) ). -if(?EMQX_RELEASE_EDITION == ee). diff --git a/apps/emqx_bridge_gcp_pubsub/docker-ct b/apps/emqx_bridge_gcp_pubsub/docker-ct new file mode 100644 index 000000000..e08426b9c --- /dev/null +++ b/apps/emqx_bridge_gcp_pubsub/docker-ct @@ -0,0 +1,2 @@ +toxiproxy +gcp_emulator diff --git a/apps/emqx_bridge_gcp_pubsub/rebar.config b/apps/emqx_bridge_gcp_pubsub/rebar.config index 2fd264fc0..10b89a449 100644 --- a/apps/emqx_bridge_gcp_pubsub/rebar.config +++ b/apps/emqx_bridge_gcp_pubsub/rebar.config @@ -1,9 +1,26 @@ %% -*- mode: erlang; -*- -{erl_opts, [debug_info]}. -{deps, [ {emqx_connector, {path, "../../apps/emqx_connector"}} - , {emqx_resource, {path, "../../apps/emqx_resource"}} - , {emqx_bridge, {path, "../../apps/emqx_bridge"}} - ]}. +{erl_opts, [ + warn_unused_vars, + warn_shadow_vars, + warn_unused_import, + warn_obsolete_guard, + warnings_as_errors, + debug_info +]}. +{deps, [ + {emqx_connector, {path, "../../apps/emqx_connector"}}, + {emqx_resource, {path, "../../apps/emqx_resource"}}, + {emqx_bridge, {path, "../../apps/emqx_bridge"}} +]}. + +{xref_checks, [ + undefined_function_calls, + undefined_functions, + locals_not_used, + deprecated_function_calls, + warnings_as_errors, + deprecated_functions +]}. {shell, [ {apps, [emqx_bridge_gcp_pubsub]} diff --git a/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub.erl b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub.erl index 1bd21ce5c..81aa729e4 100644 --- a/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub.erl +++ b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub.erl @@ -7,7 +7,7 @@ -include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl"). --import(hoconsc, [mk/2, enum/1, ref/2]). +-import(hoconsc, [mk/2, enum/1]). %% hocon_schema API -export([ @@ -39,11 +39,22 @@ namespace() -> roots() -> []. -fields("config") -> +fields("config_producer") -> emqx_bridge_schema:common_bridge_fields() ++ emqx_resource_schema:fields("resource_opts") ++ - fields(bridge_config); -fields(bridge_config) -> + fields(connector_config) ++ fields(producer); +fields("config_consumer") -> + emqx_bridge_schema:common_bridge_fields() ++ + [ + {resource_opts, + mk( + ref("consumer_resource_opts"), + #{required => true, desc => ?DESC(emqx_resource_schema, "creation_opts")} + )} + ] ++ + fields(connector_config) ++ + [{consumer, mk(ref(consumer), #{required => true, desc => ?DESC(consumer_opts)})}]; +fields(connector_config) -> [ {connect_timeout, sc( @@ -88,6 +99,20 @@ fields(bridge_config) -> desc => ?DESC("request_timeout") } )}, + {service_account_json, + sc( + service_account_json(), + #{ + required => true, + validator => fun ?MODULE:service_account_json_validator/1, + converter => fun ?MODULE:service_account_json_converter/1, + sensitive => true, + desc => ?DESC("service_account_json") + } + )} + ]; +fields(producer) -> + [ {payload_template, sc( binary(), @@ -110,28 +135,88 @@ fields(bridge_config) -> required => true, desc => ?DESC("pubsub_topic") } + )} + ]; +fields(consumer) -> + [ + {ack_retry_interval, + mk( + emqx_schema:timeout_duration_ms(), + #{ + default => <<"5s">>, + importance => ?IMPORTANCE_HIDDEN + } )}, - {service_account_json, - sc( - service_account_json(), + {pull_max_messages, + mk( + pos_integer(), + #{default => 100, desc => ?DESC("consumer_pull_max_messages")} + )}, + {consumer_workers_per_topic, + mk( + pos_integer(), + #{ + default => 1, + importance => ?IMPORTANCE_HIDDEN + } + )}, + {topic_mapping, + mk( + hoconsc:array(ref(consumer_topic_mapping)), #{ required => true, - validator => fun ?MODULE:service_account_json_validator/1, - converter => fun ?MODULE:service_account_json_converter/1, - sensitive => true, - desc => ?DESC("service_account_json") + validator => fun consumer_topic_mapping_validator/1, + desc => ?DESC("consumer_topic_mapping") } )} ]; -fields("get") -> - emqx_bridge_schema:status_fields() ++ fields("post"); -fields("post") -> - [type_field(), name_field() | fields("config")]; -fields("put") -> - fields("config"). +fields(consumer_topic_mapping) -> + [ + {pubsub_topic, mk(binary(), #{required => true, desc => ?DESC(consumer_pubsub_topic)})}, + {mqtt_topic, mk(binary(), #{required => true, desc => ?DESC(consumer_mqtt_topic)})}, + {qos, mk(emqx_schema:qos(), #{default => 0, desc => ?DESC(consumer_mqtt_qos)})}, + {payload_template, + mk( + string(), + #{default => <<"${.}">>, desc => ?DESC(consumer_mqtt_payload)} + )} + ]; +fields("consumer_resource_opts") -> + ResourceFields = emqx_resource_schema:fields("creation_opts"), + SupportedFields = [ + auto_restart_interval, + health_check_interval, + request_ttl, + resume_interval, + worker_pool_size + ], + lists:filter( + fun({Field, _Sc}) -> lists:member(Field, SupportedFields) end, + ResourceFields + ); +fields("get_producer") -> + emqx_bridge_schema:status_fields() ++ fields("post_producer"); +fields("post_producer") -> + [type_field_producer(), name_field() | fields("config_producer")]; +fields("put_producer") -> + fields("config_producer"); +fields("get_consumer") -> + emqx_bridge_schema:status_fields() ++ fields("post_consumer"); +fields("post_consumer") -> + [type_field_consumer(), name_field() | fields("config_consumer")]; +fields("put_consumer") -> + fields("config_consumer"). -desc("config") -> +desc("config_producer") -> ?DESC("desc_config"); +desc("config_consumer") -> + ?DESC("desc_config"); +desc("consumer_resource_opts") -> + ?DESC(emqx_resource_schema, "creation_opts"); +desc(consumer_topic_mapping) -> + ?DESC("consumer_topic_mapping"); +desc(consumer) -> + ?DESC("consumer"); desc(_) -> undefined. @@ -139,13 +224,19 @@ conn_bridge_examples(Method) -> [ #{ <<"gcp_pubsub">> => #{ - summary => <<"GCP PubSub Bridge">>, - value => values(Method) + summary => <<"GCP PubSub Producer Bridge">>, + value => values(producer, Method) + } + }, + #{ + <<"gcp_pubsub_consumer">> => #{ + summary => <<"GCP PubSub Consumer Bridge">>, + value => values(consumer, Method) } } ]. -values(_Method) -> +values(producer, _Method) -> #{ pubsub_topic => <<"mytopic">>, service_account_json => @@ -173,17 +264,71 @@ values(_Method) -> <<"https://oauth2.googleapis.com/token">>, type => <<"service_account">> } + }; +values(consumer, _Method) -> + #{ + connect_timeout => <<"15s">>, + consumer => + #{ + pull_max_messages => 100, + topic_mapping => [ + #{ + pubsub_topic => <<"pubsub-topic-1">>, + mqtt_topic => <<"mqtt/topic/1">>, + qos => 1, + payload_template => <<"${.}">> + }, + #{ + pubsub_topic => <<"pubsub-topic-2">>, + mqtt_topic => <<"mqtt/topic/2">>, + qos => 2, + payload_template => + <<"v = ${.value}, a = ${.attributes}, o = ${.ordering_key}">> + } + ] + }, + resource_opts => #{request_ttl => <<"20s">>}, + service_account_json => + #{ + auth_provider_x509_cert_url => + <<"https://www.googleapis.com/oauth2/v1/certs">>, + auth_uri => + <<"https://accounts.google.com/o/oauth2/auth">>, + client_email => + <<"test@myproject.iam.gserviceaccount.com">>, + client_id => <<"123812831923812319190">>, + client_x509_cert_url => + << + "https://www.googleapis.com/robot/v1/" + "metadata/x509/test%40myproject.iam.gserviceaccount.com" + >>, + private_key => + << + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvQI..." + >>, + private_key_id => <<"kid">>, + project_id => <<"myproject">>, + token_uri => + <<"https://oauth2.googleapis.com/token">>, + type => <<"service_account">> + } }. %%------------------------------------------------------------------------------------------------- %% Helper fns %%------------------------------------------------------------------------------------------------- +ref(Name) -> hoconsc:ref(?MODULE, Name). + sc(Type, Meta) -> hoconsc:mk(Type, Meta). -type_field() -> +type_field_producer() -> {type, mk(enum([gcp_pubsub]), #{required => true, desc => ?DESC("desc_type")})}. +type_field_consumer() -> + {type, mk(enum([gcp_pubsub_consumer]), #{required => true, desc => ?DESC("desc_type")})}. + name_field() -> {name, mk(binary(), #{required => true, desc => ?DESC("desc_name")})}. @@ -225,3 +370,16 @@ service_account_json_converter(Map) when is_map(Map) -> maps:with(ExpectedKeys, Map); service_account_json_converter(Val) -> Val. + +consumer_topic_mapping_validator(_TopicMapping = []) -> + {error, "There must be at least one GCP PubSub-MQTT topic mapping"}; +consumer_topic_mapping_validator(TopicMapping = [_ | _]) -> + NumEntries = length(TopicMapping), + PubSubTopics = [KT || #{<<"pubsub_topic">> := KT} <- TopicMapping], + DistinctPubSubTopics = length(lists:usort(PubSubTopics)), + case DistinctPubSubTopics =:= NumEntries of + true -> + ok; + false -> + {error, "GCP PubSub topics must not be repeated in a bridge"} + end. diff --git a/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_connector.erl b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_client.erl similarity index 55% rename from apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_connector.erl rename to apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_client.erl index f61817095..f2fa87d38 100644 --- a/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_connector.erl +++ b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_client.erl @@ -2,9 +2,7 @@ %% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved. %%-------------------------------------------------------------------- --module(emqx_bridge_gcp_pubsub_connector). - --behaviour(emqx_resource). +-module(emqx_bridge_gcp_pubsub_client). -include_lib("jose/include/jose_jwk.hrl"). -include_lib("emqx_connector/include/emqx_connector_tables.hrl"). @@ -13,74 +11,79 @@ -include_lib("emqx/include/logger.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -%% `emqx_resource' API +%% API -export([ - callback_mode/0, - on_start/2, - on_stop/2, - on_query/3, - on_query_async/4, - on_batch_query/3, - on_batch_query_async/4, - on_get_status/2 + start/2, + stop/1, + query_sync/2, + query_async/3, + get_status/1 ]). -export([reply_delegator/3]). +-export([get_topic/2]). + +-export([get_jwt_authorization_header/1]). + -type service_account_json() :: emqx_bridge_gcp_pubsub:service_account_json(). +-type project_id() :: binary(). -type config() :: #{ connect_timeout := emqx_schema:duration_ms(), max_retries := non_neg_integer(), - pubsub_topic := binary(), resource_opts := #{request_ttl := infinity | emqx_schema:duration_ms(), any() => term()}, service_account_json := service_account_json(), any() => term() }. --type state() :: #{ +-opaque state() :: #{ connect_timeout := timer:time(), jwt_config := emqx_connector_jwt:jwt_config(), max_retries := non_neg_integer(), - payload_template := emqx_placeholder:tmpl_token(), pool_name := binary(), - project_id := binary(), - pubsub_topic := binary(), + project_id := project_id(), request_ttl := infinity | timer:time() }. -type headers() :: [{binary(), iodata()}]. -type body() :: iodata(). -type status_code() :: 100..599. +-type method() :: get | post | put | patch. +-type path() :: binary(). +-type prepared_request() :: {method(), path(), body()}. +-type topic() :: binary(). + +-export_type([ + service_account_json/0, + state/0, + headers/0, + body/0, + status_code/0, + project_id/0, + topic/0 +]). -define(DEFAULT_PIPELINE_SIZE, 100). %%------------------------------------------------------------------------------------------------- -%% emqx_resource API +%% API %%------------------------------------------------------------------------------------------------- -callback_mode() -> async_if_possible. - --spec on_start(resource_id(), config()) -> {ok, state()} | {error, term()}. -on_start( +-spec start(resource_id(), config()) -> {ok, state()} | {error, term()}. +start( ResourceId, #{ connect_timeout := ConnectTimeout, max_retries := MaxRetries, - payload_template := PayloadTemplate, pool_size := PoolSize, - pubsub_topic := PubSubTopic, resource_opts := #{request_ttl := RequestTTL} } = Config ) -> - ?SLOG(info, #{ - msg => "starting_gcp_pubsub_bridge", - connector => ResourceId, - config => Config - }), - %% emulating the emulator behavior - %% https://cloud.google.com/pubsub/docs/emulator - HostPort = os:getenv("PUBSUB_EMULATOR_HOST", "pubsub.googleapis.com:443"), + {Transport, HostPort} = get_transport(), #{hostname := Host, port := Port} = emqx_schema:parse_server(HostPort, #{default_port => 443}), PoolType = random, - Transport = tls, - TransportOpts = emqx_tls_lib:to_client_opts(#{enable => true, verify => verify_none}), + TransportOpts = + case Transport of + tls -> emqx_tls_lib:to_client_opts(#{enable => true, verify => verify_none}); + tcp -> [] + end, NTransportOpts = emqx_utils:ipv6_probe(TransportOpts), PoolOpts = [ {host, Host}, @@ -91,7 +94,7 @@ on_start( {pool_size, PoolSize}, {transport, Transport}, {transport_opts, NTransportOpts}, - {enable_pipelining, maps:get(enable_pipelining, Config, ?DEFAULT_PIPELINE_SIZE)} + {enable_pipelining, maps:get(pipelining, Config, ?DEFAULT_PIPELINE_SIZE)} ], #{ jwt_config := JWTConfig, @@ -101,10 +104,8 @@ on_start( connect_timeout => ConnectTimeout, jwt_config => JWTConfig, max_retries => MaxRetries, - payload_template => emqx_placeholder:preproc_tmpl(PayloadTemplate), pool_name => ResourceId, project_id => ProjectId, - pubsub_topic => PubSubTopic, request_ttl => RequestTTL }, ?tp( @@ -130,8 +131,8 @@ on_start( {error, Reason} end. --spec on_stop(resource_id(), state()) -> ok | {error, term()}. -on_stop(ResourceId, _State) -> +-spec stop(resource_id()) -> ok | {error, term()}. +stop(ResourceId) -> ?tp(gcp_pubsub_stop, #{resource_id => ResourceId}), ?SLOG(info, #{ msg => "stopping_gcp_pubsub_bridge", @@ -147,73 +148,41 @@ on_stop(ResourceId, _State) -> Error end. --spec on_query( - resource_id(), - {send_message, map()}, +-spec query_sync( + {prepared_request, prepared_request()}, state() ) -> - {ok, status_code(), headers()} - | {ok, status_code(), headers(), body()} - | {error, {recoverable_error, term()}} - | {error, term()}. -on_query(ResourceId, {send_message, Selected}, State) -> - Requests = [{send_message, Selected}], + {ok, map()} | {error, {recoverable_error, term()} | term()}. +query_sync({prepared_request, PreparedRequest = {_Method, _Path, _Body}}, State) -> + PoolName = maps:get(pool_name, State), ?TRACE( "QUERY_SYNC", "gcp_pubsub_received", - #{requests => Requests, connector => ResourceId, state => State} + #{requests => PreparedRequest, connector => PoolName, state => State} ), - do_send_requests_sync(State, Requests, ResourceId). + do_send_requests_sync(State, {prepared_request, PreparedRequest}). --spec on_query_async( - resource_id(), - {send_message, map()}, +-spec query_async( + {prepared_request, prepared_request()}, {ReplyFun :: function(), Args :: list()}, state() ) -> {ok, pid()}. -on_query_async(ResourceId, {send_message, Selected}, ReplyFunAndArgs, State) -> - Requests = [{send_message, Selected}], - ?TRACE( - "QUERY_ASYNC", - "gcp_pubsub_received", - #{requests => Requests, connector => ResourceId, state => State} - ), - do_send_requests_async(State, Requests, ReplyFunAndArgs, ResourceId). - --spec on_batch_query( - resource_id(), - [{send_message, map()}], - state() +query_async( + {prepared_request, PreparedRequest = {_Method, _Path, _Body}}, + ReplyFunAndArgs, + State ) -> - {ok, status_code(), headers()} - | {ok, status_code(), headers(), body()} - | {error, {recoverable_error, term()}} - | {error, term()}. -on_batch_query(ResourceId, Requests, State) -> - ?TRACE( - "QUERY_SYNC", - "gcp_pubsub_received", - #{requests => Requests, connector => ResourceId, state => State} - ), - do_send_requests_sync(State, Requests, ResourceId). - --spec on_batch_query_async( - resource_id(), - [{send_message, map()}], - {ReplyFun :: function(), Args :: list()}, - state() -) -> {ok, pid()}. -on_batch_query_async(ResourceId, Requests, ReplyFunAndArgs, State) -> + PoolName = maps:get(pool_name, State), ?TRACE( "QUERY_ASYNC", "gcp_pubsub_received", - #{requests => Requests, connector => ResourceId, state => State} + #{requests => PreparedRequest, connector => PoolName, state => State} ), - do_send_requests_async(State, Requests, ReplyFunAndArgs, ResourceId). + do_send_requests_async(State, {prepared_request, PreparedRequest}, ReplyFunAndArgs). --spec on_get_status(resource_id(), state()) -> connected | disconnected. -on_get_status(ResourceId, #{connect_timeout := Timeout} = State) -> - case do_get_status(ResourceId, Timeout) of +-spec get_status(state()) -> connected | disconnected. +get_status(#{connect_timeout := Timeout, pool_name := PoolName} = State) -> + case do_get_status(PoolName, Timeout) of true -> connected; false -> @@ -224,6 +193,19 @@ on_get_status(ResourceId, #{connect_timeout := Timeout} = State) -> disconnected end. +%%------------------------------------------------------------------------------------------------- +%% API +%%------------------------------------------------------------------------------------------------- + +-spec get_topic(topic(), state()) -> {ok, map()} | {error, term()}. +get_topic(Topic, ConnectorState) -> + #{project_id := ProjectId} = ConnectorState, + Method = get, + Path = <<"/v1/projects/", ProjectId/binary, "/topics/", Topic/binary>>, + Body = <<>>, + PreparedRequest = {prepared_request, {Method, Path, Body}}, + query_sync(PreparedRequest, ConnectorState). + %%------------------------------------------------------------------------------------------------- %% Helper fns %%------------------------------------------------------------------------------------------------- @@ -286,28 +268,6 @@ parse_jwt_config(ResourceId, #{ project_id => ProjectId }. --spec encode_payload(state(), Selected :: map()) -> #{data := binary()}. -encode_payload(_State = #{payload_template := PayloadTemplate}, Selected) -> - Interpolated = - case PayloadTemplate of - [] -> emqx_utils_json:encode(Selected); - _ -> emqx_placeholder:proc_tmpl(PayloadTemplate, Selected) - end, - #{data => base64:encode(Interpolated)}. - --spec to_pubsub_request([#{data := binary()}]) -> binary(). -to_pubsub_request(Payloads) -> - emqx_utils_json:encode(#{messages => Payloads}). - --spec publish_path(state()) -> binary(). -publish_path( - _State = #{ - project_id := ProjectId, - pubsub_topic := PubSubTopic - } -) -> - <<"/v1/projects/", ProjectId/binary, "/topics/", PubSubTopic/binary, ":publish">>. - -spec get_jwt_authorization_header(emqx_connector_jwt:jwt_config()) -> [{binary(), binary()}]. get_jwt_authorization_header(JWTConfig) -> JWT = emqx_connector_jwt:ensure_jwt(JWTConfig), @@ -315,16 +275,11 @@ get_jwt_authorization_header(JWTConfig) -> -spec do_send_requests_sync( state(), - [{send_message, map()}], - resource_id() + {prepared_request, prepared_request()} ) -> - {ok, status_code(), headers()} - | {ok, status_code(), headers(), body()} - | {error, {recoverable_error, term()}} - | {error, term()}. -do_send_requests_sync(State, Requests, ResourceId) -> + {ok, map()} | {error, {recoverable_error, term()} | term()}. +do_send_requests_sync(State, {prepared_request, {Method, Path, Body}}) -> #{ - jwt_config := JWTConfig, pool_name := PoolName, max_retries := MaxRetries, request_ttl := RequestTTL @@ -332,192 +287,125 @@ do_send_requests_sync(State, Requests, ResourceId) -> ?tp( gcp_pubsub_bridge_do_send_requests, #{ + request => {prepared_request, {Method, Path, Body}}, query_mode => sync, - resource_id => ResourceId, - requests => Requests + resource_id => PoolName } ), - Headers = get_jwt_authorization_header(JWTConfig), - Payloads = - lists:map( - fun({send_message, Selected}) -> - encode_payload(State, Selected) - end, - Requests - ), - Body = to_pubsub_request(Payloads), - Path = publish_path(State), - Method = post, - Request = {Path, Headers, Body}, - case - ehttpc:request( - PoolName, - Method, - Request, - RequestTTL, - MaxRetries - ) - of - {error, Reason} when - Reason =:= econnrefused; - %% this comes directly from `gun'... - Reason =:= {closed, "The connection was lost."}; - Reason =:= timeout - -> - ?tp( - warning, - gcp_pubsub_request_failed, - #{ - reason => Reason, - query_mode => sync, - recoverable_error => true, - connector => ResourceId - } - ), - {error, {recoverable_error, Reason}}; - {error, Reason} = Result -> - ?tp( - error, - gcp_pubsub_request_failed, - #{ - reason => Reason, - query_mode => sync, - recoverable_error => false, - connector => ResourceId - } - ), - Result; - {ok, StatusCode, _} = Result when StatusCode >= 200 andalso StatusCode < 300 -> - ?tp( - gcp_pubsub_response, - #{ - response => Result, - query_mode => sync, - connector => ResourceId - } - ), - Result; - {ok, StatusCode, _, _} = Result when StatusCode >= 200 andalso StatusCode < 300 -> - ?tp( - gcp_pubsub_response, - #{ - response => Result, - query_mode => sync, - connector => ResourceId - } - ), - Result; - {ok, StatusCode, RespHeaders} = _Result -> - ?tp( - gcp_pubsub_response, - #{ - response => _Result, - query_mode => sync, - connector => ResourceId - } - ), - ?SLOG(error, #{ - msg => "gcp_pubsub_error_response", - request => Request, - connector => ResourceId, - status_code => StatusCode - }), - {error, #{status_code => StatusCode, headers => RespHeaders}}; - {ok, StatusCode, RespHeaders, RespBody} = _Result -> - ?tp( - gcp_pubsub_response, - #{ - response => _Result, - query_mode => sync, - connector => ResourceId - } - ), - ?SLOG(error, #{ - msg => "gcp_pubsub_error_response", - request => Request, - connector => ResourceId, - status_code => StatusCode - }), - {error, #{status_code => StatusCode, headers => RespHeaders, body => RespBody}} - end. + Request = to_ehttpc_request(State, Method, Path, Body), + Response = ehttpc:request( + PoolName, + Method, + Request, + RequestTTL, + MaxRetries + ), + handle_response(Response, PoolName, _QueryMode = sync). -spec do_send_requests_async( state(), - [{send_message, map()}], - {ReplyFun :: function(), Args :: list()}, - resource_id() + {prepared_request, prepared_request()}, + {ReplyFun :: function(), Args :: list()} ) -> {ok, pid()}. -do_send_requests_async(State, Requests, ReplyFunAndArgs, ResourceId) -> +do_send_requests_async( + State, {prepared_request, {Method, Path, Body}}, ReplyFunAndArgs +) -> #{ - jwt_config := JWTConfig, pool_name := PoolName, request_ttl := RequestTTL } = State, ?tp( gcp_pubsub_bridge_do_send_requests, #{ + request => {prepared_request, {Method, Path, Body}}, query_mode => async, - resource_id => ResourceId, - requests => Requests + resource_id => PoolName } ), - Headers = get_jwt_authorization_header(JWTConfig), - Payloads = - lists:map( - fun({send_message, Selected}) -> - encode_payload(State, Selected) - end, - Requests - ), - Body = to_pubsub_request(Payloads), - Path = publish_path(State), - Method = post, - Request = {Path, Headers, Body}, + Request = to_ehttpc_request(State, Method, Path, Body), Worker = ehttpc_pool:pick_worker(PoolName), ok = ehttpc:request_async( Worker, Method, Request, RequestTTL, - {fun ?MODULE:reply_delegator/3, [ResourceId, ReplyFunAndArgs]} + {fun ?MODULE:reply_delegator/3, [PoolName, ReplyFunAndArgs]} ), {ok, Worker}. +to_ehttpc_request(State, Method, Path, Body) -> + #{jwt_config := JWTConfig} = State, + Headers = get_jwt_authorization_header(JWTConfig), + case {Method, Body} of + {get, <<>>} -> {Path, Headers}; + _ -> {Path, Headers, Body} + end. + +-spec handle_response(term(), resource_id(), sync | async) -> {ok, map()} | {error, term()}. +handle_response(Result, ResourceId, QueryMode) -> + case Result of + {error, Reason} -> + ?tp( + gcp_pubsub_request_failed, + #{ + reason => Reason, + query_mode => QueryMode, + connector => ResourceId + } + ), + {error, Reason}; + {ok, StatusCode, RespHeaders} when StatusCode >= 200 andalso StatusCode < 300 -> + ?tp( + gcp_pubsub_response, + #{ + response => Result, + query_mode => QueryMode, + connector => ResourceId + } + ), + {ok, #{status_code => StatusCode, headers => RespHeaders}}; + {ok, StatusCode, RespHeaders, RespBody} when + StatusCode >= 200 andalso StatusCode < 300 + -> + ?tp( + gcp_pubsub_response, + #{ + response => Result, + query_mode => QueryMode, + connector => ResourceId + } + ), + {ok, #{status_code => StatusCode, headers => RespHeaders, body => RespBody}}; + {ok, StatusCode, RespHeaders} = _Result -> + ?tp( + gcp_pubsub_response, + #{ + response => _Result, + query_mode => QueryMode, + connector => ResourceId + } + ), + {error, #{status_code => StatusCode, headers => RespHeaders}}; + {ok, StatusCode, RespHeaders, RespBody} = _Result -> + ?tp( + gcp_pubsub_response, + #{ + response => _Result, + query_mode => QueryMode, + connector => ResourceId + } + ), + {error, #{status_code => StatusCode, headers => RespHeaders, body => RespBody}} + end. + -spec reply_delegator( resource_id(), {ReplyFun :: function(), Args :: list()}, term() | {error, econnrefused | timeout | term()} ) -> ok. -reply_delegator(_ResourceId, ReplyFunAndArgs, Result) -> - case Result of - {error, Reason} when - Reason =:= econnrefused; - %% this comes directly from `gun'... - Reason =:= {closed, "The connection was lost."}; - Reason =:= timeout - -> - ?tp( - gcp_pubsub_request_failed, - #{ - reason => Reason, - query_mode => async, - recoverable_error => true, - connector => _ResourceId - } - ), - Result1 = {error, {recoverable_error, Reason}}, - emqx_resource:apply_reply_fun(ReplyFunAndArgs, Result1); - _ -> - ?tp( - gcp_pubsub_response, - #{ - response => Result, - query_mode => async, - connector => _ResourceId - } - ), - emqx_resource:apply_reply_fun(ReplyFunAndArgs, Result) - end. +reply_delegator(ResourceId, ReplyFunAndArgs, Response) -> + Result = handle_response(Response, ResourceId, _QueryMode = async), + emqx_resource:apply_reply_fun(ReplyFunAndArgs, Result). -spec do_get_status(resource_id(), timer:time()) -> boolean(). do_get_status(ResourceId, Timeout) -> @@ -546,3 +434,16 @@ do_get_status(ResourceId, Timeout) -> exit:timeout -> false end. + +-spec get_transport() -> {tls | tcp, string()}. +get_transport() -> + %% emulating the emulator behavior + %% https://cloud.google.com/pubsub/docs/emulator + case os:getenv("PUBSUB_EMULATOR_HOST") of + false -> + {tls, "pubsub.googleapis.com:443"}; + HostPort0 -> + %% The emulator is plain HTTP... + Transport0 = persistent_term:get({?MODULE, transport}, tcp), + {Transport0, HostPort0} + end. diff --git a/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_consumer_worker.erl b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_consumer_worker.erl new file mode 100644 index 000000000..bb9e75a9c --- /dev/null +++ b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_consumer_worker.erl @@ -0,0 +1,568 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%%-------------------------------------------------------------------- + +-module(emqx_bridge_gcp_pubsub_consumer_worker). + +-behaviour(ecpool_worker). +-behaviour(gen_server). + +-include_lib("emqx/include/logger.hrl"). +-include_lib("snabbkaffe/include/snabbkaffe.hrl"). + +%% `ecpool_worker' API +-export([connect/1, health_check/1]). + +%% `gen_server' API +-export([ + init/1, + handle_info/2, + handle_cast/2, + handle_call/3, + handle_continue/2, + terminate/2 +]). + +-export([get_subscription/1]). +-export([reply_delegator/3, pull_async/1, process_pull_response/2, ensure_subscription/1]). + +-type subscription_id() :: binary(). +-type bridge_name() :: atom() | binary(). +-type ack_id() :: binary(). +-type config() :: #{ + ack_retry_interval := emqx_schema:timeout_duration_ms(), + client := emqx_bridge_gcp_pubsub_client:state(), + ecpool_worker_id => non_neg_integer(), + hookpoint := binary(), + instance_id := binary(), + mqtt_config => emqx_bridge_gcp_pubsub_impl_consumer:mqtt_config(), + project_id := emqx_bridge_gcp_pubsub_client:project_id(), + pull_max_messages := non_neg_integer(), + subscription_id => subscription_id(), + topic => emqx_bridge_gcp_pubsub_client:topic() +}. +-type state() :: #{ + ack_retry_interval := emqx_schema:timeout_duration_ms(), + ack_timer := undefined | reference(), + async_workers := #{pid() => reference()}, + client := emqx_bridge_gcp_pubsub_client:state(), + ecpool_worker_id := non_neg_integer(), + hookpoint := binary(), + instance_id := binary(), + mqtt_config => emqx_bridge_gcp_pubsub_impl_consumer:mqtt_config(), + pending_acks => [ack_id()], + project_id := emqx_bridge_gcp_pubsub_client:project_id(), + pull_max_messages := non_neg_integer(), + pull_timer := undefined | reference(), + subscription_id => subscription_id(), + topic => emqx_bridge_gcp_pubsub_client:topic() +}. +-type decoded_message() :: map(). + +-define(HEALTH_CHECK_TIMEOUT, 10_000). +-define(OPTVAR_SUB_OK(PID), {?MODULE, PID}). +-define(PULL_INTERVAL, 5_000). + +%%------------------------------------------------------------------------------------------------- +%% API used by `reply_delegator' +%%------------------------------------------------------------------------------------------------- + +-spec pull_async(pid()) -> ok. +pull_async(WorkerPid) -> + gen_server:cast(WorkerPid, pull_async). + +-spec process_pull_response(pid(), binary()) -> ok. +process_pull_response(WorkerPid, RespBody) -> + gen_server:cast(WorkerPid, {process_pull_response, RespBody}). + +-spec ensure_subscription(pid()) -> ok. +ensure_subscription(WorkerPid) -> + gen_server:cast(WorkerPid, ensure_subscription). + +-spec reply_delegator(pid(), binary(), {ok, map()} | {error, timeout | term()}) -> ok. +reply_delegator(WorkerPid, InstanceId, Result) -> + case Result of + {error, timeout} -> + ?MODULE:pull_async(WorkerPid); + {error, Reason} -> + ?SLOG(warning, #{ + msg => "gcp_pubsub_consumer_worker_pull_error", + instance_id => InstanceId, + reason => Reason + }), + case Reason of + #{status_code := 409} -> + %% the subscription was not found; deleted?! + ?MODULE:ensure_subscription(WorkerPid); + _ -> + ?MODULE:pull_async(WorkerPid) + end; + {ok, #{status_code := 200, body := RespBody}} -> + ?MODULE:process_pull_response(WorkerPid, RespBody) + end. + +%%------------------------------------------------------------------------------------------------- +%% Debugging API +%%------------------------------------------------------------------------------------------------- + +-spec get_subscription(pid()) -> {ok, map()} | {error, term()}. +get_subscription(WorkerPid) -> + gen_server:call(WorkerPid, get_subscription, 5_000). + +%%------------------------------------------------------------------------------------------------- +%% `ecpool' health check +%%------------------------------------------------------------------------------------------------- + +-spec health_check(pid()) -> boolean(). +health_check(WorkerPid) -> + case optvar:read(?OPTVAR_SUB_OK(WorkerPid), ?HEALTH_CHECK_TIMEOUT) of + {ok, _} -> + true; + timeout -> + false + end. + +%%------------------------------------------------------------------------------------------------- +%% `emqx_resource' API +%%------------------------------------------------------------------------------------------------- + +connect(Opts0) -> + Opts = maps:from_list(Opts0), + #{ + ack_retry_interval := AckRetryInterval, + bridge_name := BridgeName, + client := Client, + ecpool_worker_id := WorkerId, + hookpoint := Hookpoint, + instance_id := InstanceId, + project_id := ProjectId, + pull_max_messages := PullMaxMessages, + topic_mapping := TopicMapping + } = Opts, + TopicMappingList = lists:keysort(1, maps:to_list(TopicMapping)), + Index = 1 + (WorkerId rem map_size(TopicMapping)), + {Topic, MQTTConfig} = lists:nth(Index, TopicMappingList), + Config = #{ + ack_retry_interval => AckRetryInterval, + %% Note: the `client' value here must be immutable and not changed by the + %% bridge during `on_get_status', since we have handed it over to the pull + %% workers. + client => Client, + hookpoint => Hookpoint, + instance_id => InstanceId, + mqtt_config => MQTTConfig, + project_id => ProjectId, + pull_max_messages => PullMaxMessages, + topic => Topic, + subscription_id => subscription_id(BridgeName, Topic) + }, + start_link(Config). + +%%------------------------------------------------------------------------------------------------- +%% `gen_server' API +%%------------------------------------------------------------------------------------------------- + +-spec init(config()) -> {ok, state(), {continue, ensure_subscription}}. +init(Config) -> + process_flag(trap_exit, true), + State = Config#{ + ack_timer => undefined, + async_workers => #{}, + pending_acks => [], + pull_timer => undefined + }, + {ok, State, {continue, ensure_subscription}}. + +handle_continue(ensure_subscription, State0) -> + case ensure_subscription_exists(State0) of + ok -> + #{instance_id := InstanceId} = State0, + ?tp( + debug, + "gcp_pubsub_consumer_worker_subscription_ready", + #{instance_id => InstanceId} + ), + ?MODULE:pull_async(self()), + optvar:set(?OPTVAR_SUB_OK(self()), subscription_ok), + {noreply, State0}; + error -> + %% FIXME: add delay if topic does not exist?! + %% retry + {noreply, State0, {continue, ensure_subscription}} + end. + +handle_call(get_subscription, _From, State0) -> + Res = do_get_subscription(State0), + {reply, Res, State0}; +handle_call(_Request, _From, State0) -> + {reply, {error, unknown_call}, State0}. + +handle_cast(pull_async, State0) -> + State = do_pull_async(State0), + {noreply, State}; +handle_cast({process_pull_response, RespBody}, State0) -> + State = do_process_pull_response(State0, RespBody), + {noreply, State}; +handle_cast(ensure_subscription, State0) -> + {noreply, State0, {continue, ensure_subscription}}; +handle_cast(_Request, State0) -> + {noreply, State0}. + +handle_info({timeout, TRef, ack}, State0 = #{ack_timer := TRef}) -> + State1 = acknowledge(State0), + State = ensure_ack_timer(State1), + {noreply, State}; +handle_info({timeout, TRef, pull}, State0 = #{pull_timer := TRef}) -> + State1 = State0#{pull_timer := undefined}, + State2 = do_pull_async(State1), + State = ensure_pull_timer(State2), + {noreply, State}; +handle_info( + {'DOWN', _Ref, process, AsyncWorkerPid, _Reason}, State0 = #{async_workers := Workers0} +) when + is_map_key(AsyncWorkerPid, Workers0) +-> + Workers = maps:remove(AsyncWorkerPid, Workers0), + State1 = State0#{async_workers := Workers}, + State = do_pull_async(State1), + {noreply, State}; +handle_info(Msg, State0) -> + #{ + instance_id := InstanceId, + topic := Topic + } = State0, + ?SLOG(debug, #{ + msg => "gcp_pubsub_consumer_worker_unexpected_message", + unexpected_msg => Msg, + instance_id => InstanceId, + topic => Topic + }), + {noreply, State0}. + +terminate(_Reason, _State) -> + optvar:unset(?OPTVAR_SUB_OK(self())), + ok. + +%%------------------------------------------------------------------------------------------------- +%% Internal fns +%%------------------------------------------------------------------------------------------------- + +-spec start_link(config()) -> gen_server:start_ret(). +start_link(Config) -> + gen_server:start_link(?MODULE, Config, []). + +-spec ensure_ack_timer(state()) -> state(). +ensure_ack_timer(State = #{pending_acks := []}) -> + State; +ensure_ack_timer(State = #{ack_timer := TRef}) when is_reference(TRef) -> + State; +ensure_ack_timer(State = #{ack_retry_interval := AckRetryInterval}) -> + State#{ack_timer := emqx_utils:start_timer(AckRetryInterval, ack)}. + +-spec ensure_pull_timer(state()) -> state(). +ensure_pull_timer(State = #{pull_timer := TRef}) when is_reference(TRef) -> + State; +ensure_pull_timer(State) -> + State#{pull_timer := emqx_utils:start_timer(?PULL_INTERVAL, pull)}. + +-spec ensure_subscription_exists(state()) -> ok | error. +ensure_subscription_exists(State) -> + #{ + client := Client, + instance_id := InstanceId, + subscription_id := SubscriptionId, + topic := Topic + } = State, + Method = put, + Path = path(State, create), + Body = body(State, create), + PreparedRequest = {prepared_request, {Method, Path, Body}}, + Res = emqx_bridge_gcp_pubsub_client:query_sync(PreparedRequest, Client), + case Res of + {error, #{status_code := 409}} -> + %% already exists + ?SLOG(debug, #{ + msg => "gcp_pubsub_consumer_worker_subscription_already_exists", + instance_id => InstanceId, + topic => Topic, + subscription_id => SubscriptionId + }), + Method1 = patch, + Path1 = path(State, create), + Body1 = body(State, patch_subscription), + PreparedRequest1 = {prepared_request, {Method1, Path1, Body1}}, + Res1 = emqx_bridge_gcp_pubsub_client:query_sync(PreparedRequest1, Client), + ?SLOG(debug, #{ + msg => "gcp_pubsub_consumer_worker_subscription_patch", + instance_id => InstanceId, + topic => Topic, + subscription_id => SubscriptionId, + result => Res1 + }), + ok; + {ok, #{status_code := 200}} -> + ?SLOG(debug, #{ + msg => "gcp_pubsub_consumer_worker_subscription_created", + instance_id => InstanceId, + topic => Topic, + subscription_id => SubscriptionId + }), + ok; + {error, Reason} -> + ?SLOG(error, #{ + msg => "gcp_pubsub_consumer_worker_subscription_error", + instance_id => InstanceId, + topic => Topic, + reason => Reason + }), + error + end. + +%% We use async requests so that this process will be more responsive to system messages. +do_pull_async(State) -> + #{ + client := Client, + instance_id := InstanceId + } = State, + Method = post, + Path = path(State, pull), + Body = body(State, pull), + PreparedRequest = {prepared_request, {Method, Path, Body}}, + ReplyFunAndArgs = {fun ?MODULE:reply_delegator/3, [self(), InstanceId]}, + {ok, AsyncWorkerPid} = emqx_bridge_gcp_pubsub_client:query_async( + PreparedRequest, + ReplyFunAndArgs, + Client + ), + ensure_async_worker_monitored(State, AsyncWorkerPid). + +-spec ensure_async_worker_monitored(state(), pid()) -> state(). +ensure_async_worker_monitored(State = #{async_workers := Workers0}, AsyncWorkerPid) -> + case is_map_key(AsyncWorkerPid, Workers0) of + true -> + State; + false -> + Ref = monitor(process, AsyncWorkerPid), + Workers = Workers0#{AsyncWorkerPid => Ref}, + State#{async_workers := Workers} + end. + +-spec do_process_pull_response(state(), binary()) -> state(). +do_process_pull_response(State0, RespBody) -> + Messages = decode_response(RespBody), + AckIds = lists:map(fun(Msg) -> handle_message(State0, Msg) end, Messages), + State1 = maps:update_with(pending_acks, fun(AckIds0) -> AckIds0 ++ AckIds end, State0), + State2 = acknowledge(State1), + pull_async(self()), + ensure_ack_timer(State2). + +-spec acknowledge(state()) -> state(). +acknowledge(State0 = #{pending_acks := []}) -> + State0; +acknowledge(State0) -> + State1 = State0#{ack_timer := undefined}, + #{ + client := Client, + pending_acks := AckIds + } = State1, + Method = post, + Path = path(State1, ack), + Body = body(State1, ack, #{ack_ids => AckIds}), + PreparedRequest = {prepared_request, {Method, Path, Body}}, + Res = emqx_bridge_gcp_pubsub_client:query_sync(PreparedRequest, Client), + case Res of + {error, Reason} -> + ?SLOG(warning, #{msg => "gcp_pubsub_consumer_worker_ack_error", reason => Reason}), + State1; + {ok, #{status_code := 200}} -> + ?tp(gcp_pubsub_consumer_worker_acknowledged, #{ack_ids => AckIds}), + State1#{pending_acks := []}; + {ok, Details} -> + ?SLOG(warning, #{msg => "gcp_pubsub_consumer_worker_ack_error", details => Details}), + State1 + end. + +do_get_subscription(State) -> + #{ + client := Client + } = State, + Method = get, + Path = path(State, get_subscription), + Body = body(State, get_subscription), + PreparedRequest = {prepared_request, {Method, Path, Body}}, + Res = emqx_bridge_gcp_pubsub_client:query_sync(PreparedRequest, Client), + case Res of + {error, Reason} -> + ?SLOG(warning, #{ + msg => "gcp_pubsub_consumer_worker_get_subscription_error", + reason => Reason + }), + {error, Reason}; + {ok, #{status_code := 200, body := RespBody}} -> + DecodedBody = emqx_utils_json:decode(RespBody, [return_maps]), + {ok, DecodedBody}; + {ok, Details} -> + ?SLOG(warning, #{ + msg => "gcp_pubsub_consumer_worker_get_subscription_unexpected_response", + details => Details + }), + {error, Details} + end. + +-spec subscription_id(bridge_name(), emqx_bridge_gcp_pubsub_client:topic()) -> subscription_id(). +subscription_id(BridgeName0, Topic) -> + %% The real GCP PubSub accepts colons in subscription names, but its emulator + %% doesn't... We currently validate bridge names to not include that character. The + %% exception is the prefix from the probe API. + BridgeName1 = to_bin(BridgeName0), + BridgeName = binary:replace(BridgeName1, <<":">>, <<"-">>), + to_bin(uri_string:quote(<<"emqx-sub-", BridgeName/binary, "-", Topic/binary>>)). + +-spec path(state(), pull | create | ack | get_subscription) -> binary(). +path(State, Type) -> + #{ + client := #{project_id := ProjectId}, + subscription_id := SubscriptionId + } = State, + SubscriptionResource = subscription_resource(ProjectId, SubscriptionId), + case Type of + pull -> + <<"/v1/", SubscriptionResource/binary, ":pull">>; + create -> + <<"/v1/", SubscriptionResource/binary>>; + ack -> + <<"/v1/", SubscriptionResource/binary, ":acknowledge">>; + get_subscription -> + <<"/v1/", SubscriptionResource/binary>> + end. + +-spec body(state(), pull | create | patch_subscription | get_subscription) -> binary(). +body(State, pull) -> + #{pull_max_messages := PullMaxMessages} = State, + emqx_utils_json:encode(#{<<"maxMessages">> => PullMaxMessages}); +body(State, create) -> + #{ + ack_retry_interval := AckRetryInterval, + project_id := ProjectId, + topic := PubSubTopic + } = State, + TopicResource = <<"projects/", ProjectId/binary, "/topics/", PubSubTopic/binary>>, + AckDeadlineSeconds = 5 + erlang:convert_time_unit(AckRetryInterval, millisecond, second), + JSON = #{ + <<"topic">> => TopicResource, + <<"ackDeadlineSeconds">> => AckDeadlineSeconds + }, + emqx_utils_json:encode(JSON); +body(State, patch_subscription) -> + #{ + ack_retry_interval := AckRetryInterval, + project_id := ProjectId, + topic := PubSubTopic, + subscription_id := SubscriptionId + } = State, + TopicResource = <<"projects/", ProjectId/binary, "/topics/", PubSubTopic/binary>>, + SubscriptionResource = subscription_resource(ProjectId, SubscriptionId), + AckDeadlineSeconds = 5 + erlang:convert_time_unit(AckRetryInterval, millisecond, second), + JSON = #{ + <<"subscription">> => + #{ + <<"ackDeadlineSeconds">> => AckDeadlineSeconds, + <<"name">> => SubscriptionResource, + <<"topic">> => TopicResource + }, + %% topic is immutable; don't add it here. + <<"updateMask">> => <<"ackDeadlineSeconds">> + }, + emqx_utils_json:encode(JSON); +body(_State, get_subscription) -> + <<>>. + +-spec body(state(), ack, map()) -> binary(). +body(_State, ack, Opts) -> + #{ack_ids := AckIds} = Opts, + JSON = #{<<"ackIds">> => AckIds}, + emqx_utils_json:encode(JSON). + +-spec subscription_resource(emqx_bridge_gcp_pubsub_client:project_id(), subscription_id()) -> + binary(). +subscription_resource(ProjectId, SubscriptionId) -> + <<"projects/", ProjectId/binary, "/subscriptions/", SubscriptionId/binary>>. + +-spec decode_response(binary()) -> [decoded_message()]. +decode_response(RespBody) -> + case emqx_utils_json:decode(RespBody, [return_maps]) of + #{<<"receivedMessages">> := Msgs0} -> + lists:map( + fun(Msg0 = #{<<"message">> := InnerMsg0}) -> + InnerMsg = emqx_utils_maps:update_if_present( + <<"data">>, fun base64:decode/1, InnerMsg0 + ), + Msg0#{<<"message">> := InnerMsg} + end, + Msgs0 + ); + #{} -> + [] + end. + +-spec handle_message(state(), decoded_message()) -> [ack_id()]. +handle_message(State, #{<<"ackId">> := AckId, <<"message">> := InnerMsg} = _Message) -> + ?tp( + debug, + "gcp_pubsub_consumer_worker_handle_message", + #{message_id => maps:get(<<"messageId">>, InnerMsg), message => _Message, ack_id => AckId} + ), + #{ + instance_id := InstanceId, + hookpoint := Hookpoint, + mqtt_config := #{ + payload_template := PayloadTemplate, + qos := MQTTQoS, + mqtt_topic := MQTTTopic + }, + topic := Topic + } = State, + #{ + <<"messageId">> := MessageId, + <<"publishTime">> := PublishTime + } = InnerMsg, + FullMessage0 = #{ + message_id => MessageId, + publish_time => PublishTime, + topic => Topic + }, + FullMessage = + lists:foldl( + fun({FromKey, ToKey}, Acc) -> + add_if_present(FromKey, InnerMsg, ToKey, Acc) + end, + FullMessage0, + [ + {<<"data">>, value}, + {<<"attributes">>, attributes}, + {<<"orderingKey">>, ordering_key} + ] + ), + Payload = render(FullMessage, PayloadTemplate), + MQTTMessage = emqx_message:make(InstanceId, MQTTQoS, MQTTTopic, Payload), + _ = emqx:publish(MQTTMessage), + emqx:run_hook(Hookpoint, [FullMessage]), + emqx_resource_metrics:received_inc(InstanceId), + AckId. + +-spec add_if_present(any(), map(), any(), map()) -> map(). +add_if_present(FromKey, Message, ToKey, Map) -> + case maps:get(FromKey, Message, undefined) of + undefined -> + Map; + Value -> + Map#{ToKey => Value} + end. + +render(FullMessage, PayloadTemplate) -> + Opts = #{return => full_binary}, + emqx_placeholder:proc_tmpl(PayloadTemplate, FullMessage, Opts). + +to_bin(A) when is_atom(A) -> atom_to_binary(A); +to_bin(L) when is_list(L) -> iolist_to_binary(L); +to_bin(B) when is_binary(B) -> B. diff --git a/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_impl_consumer.erl b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_impl_consumer.erl new file mode 100644 index 000000000..88b57be1e --- /dev/null +++ b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_impl_consumer.erl @@ -0,0 +1,201 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%%-------------------------------------------------------------------- + +-module(emqx_bridge_gcp_pubsub_impl_consumer). + +-behaviour(emqx_resource). + +%% `emqx_resource' API +-export([ + callback_mode/0, + query_mode/1, + on_start/2, + on_stop/2, + on_get_status/2 +]). + +-include_lib("emqx/include/logger.hrl"). +-include_lib("snabbkaffe/include/snabbkaffe.hrl"). +-include_lib("emqx_resource/include/emqx_resource.hrl"). + +-type mqtt_config() :: #{ + mqtt_topic := emqx_types:topic(), + qos := emqx_types:qos(), + payload_template := string() +}. +-type config() :: #{ + connect_timeout := emqx_schema:duration_ms(), + max_retries := non_neg_integer(), + pool_size := non_neg_integer(), + resource_opts := #{request_ttl := infinity | emqx_schema:duration_ms(), any() => term()}, + service_account_json := emqx_bridge_gcp_pubsub_client:service_account_json(), + any() => term() +}. +-type state() :: #{ + client := emqx_bridge_gcp_pubsub_client:state() +}. + +-export_type([mqtt_config/0]). + +-define(AUTO_RECONNECT_S, 2). + +%%------------------------------------------------------------------------------------------------- +%% `emqx_resource' API +%%------------------------------------------------------------------------------------------------- + +-spec callback_mode() -> callback_mode(). +callback_mode() -> async_if_possible. + +-spec query_mode(any()) -> query_mode(). +query_mode(_Config) -> no_queries. + +-spec on_start(resource_id(), config()) -> {ok, state()} | {error, term()}. +on_start(InstanceId, Config) -> + case emqx_bridge_gcp_pubsub_client:start(InstanceId, Config) of + {ok, Client} -> + start_consumers(InstanceId, Client, Config); + Error -> + Error + end. + +-spec on_stop(resource_id(), state()) -> ok | {error, term()}. +on_stop(InstanceId, _State) -> + ok = stop_consumers(InstanceId), + emqx_bridge_gcp_pubsub_client:stop(InstanceId). + +-spec on_get_status(resource_id(), state()) -> connected | disconnected. +on_get_status(InstanceId, _State) -> + %% Note: do *not* alter the `client' value here. It must be immutable, since + %% we have handed it over to the pull workers. + case + emqx_resource_pool:health_check_workers( + InstanceId, + fun emqx_bridge_gcp_pubsub_consumer_worker:health_check/1 + ) + of + true -> connected; + false -> connecting + end. + +%%------------------------------------------------------------------------------------------------- +%% Internal fns +%%------------------------------------------------------------------------------------------------- + +start_consumers(InstanceId, Client, Config) -> + #{ + bridge_name := BridgeName, + consumer := ConsumerConfig0, + hookpoint := Hookpoint, + service_account_json := #{project_id := ProjectId} + } = Config, + ConsumerConfig1 = maps:update_with(topic_mapping, fun convert_topic_mapping/1, ConsumerConfig0), + TopicMapping = maps:get(topic_mapping, ConsumerConfig1), + ConsumerWorkersPerTopic = maps:get(consumer_workers_per_topic, ConsumerConfig1), + PoolSize = map_size(TopicMapping) * ConsumerWorkersPerTopic, + ConsumerConfig = ConsumerConfig1#{ + auto_reconnect => ?AUTO_RECONNECT_S, + bridge_name => BridgeName, + client => Client, + hookpoint => Hookpoint, + instance_id => InstanceId, + pool_size => PoolSize, + project_id => ProjectId + }, + ConsumerOpts = maps:to_list(ConsumerConfig), + %% FIXME: mark as unhealthy if topics do not exist! + case validate_pubsub_topics(TopicMapping, Client) of + ok -> + ok; + error -> + _ = emqx_bridge_gcp_pubsub_client:stop(InstanceId), + throw( + "GCP PubSub topics are invalid. Please check the logs, check if the " + "topic exists in GCP and if the service account has permissions to use them." + ) + end, + case + emqx_resource_pool:start(InstanceId, emqx_bridge_gcp_pubsub_consumer_worker, ConsumerOpts) + of + ok -> + State = #{ + client => Client, + pool_name => InstanceId + }, + {ok, State}; + {error, Reason} -> + _ = emqx_bridge_gcp_pubsub_client:stop(InstanceId), + {error, Reason} + end. + +stop_consumers(InstanceId) -> + _ = log_when_error( + fun() -> + ok = emqx_resource_pool:stop(InstanceId) + end, + #{ + msg => "failed_to_stop_pull_worker_pool", + instance_id => InstanceId + } + ), + ok. + +convert_topic_mapping(TopicMappingList) -> + lists:foldl( + fun(Fields, Acc) -> + #{ + pubsub_topic := PubSubTopic, + mqtt_topic := MQTTTopic, + qos := QoS, + payload_template := PayloadTemplate0 + } = Fields, + PayloadTemplate = emqx_placeholder:preproc_tmpl(PayloadTemplate0), + Acc#{ + PubSubTopic => #{ + payload_template => PayloadTemplate, + mqtt_topic => MQTTTopic, + qos => QoS + } + } + end, + #{}, + TopicMappingList + ). + +validate_pubsub_topics(TopicMapping, Client) -> + PubSubTopics = maps:keys(TopicMapping), + do_validate_pubsub_topics(Client, PubSubTopics). + +do_validate_pubsub_topics(Client, [Topic | Rest]) -> + case check_for_topic_existence(Topic, Client) of + ok -> + do_validate_pubsub_topics(Client, Rest); + {error, _} -> + error + end; +do_validate_pubsub_topics(_Client, []) -> + %% we already validate that the mapping is not empty in the config schema. + ok. + +check_for_topic_existence(Topic, Client) -> + Res = emqx_bridge_gcp_pubsub_client:get_topic(Topic, Client), + case Res of + {ok, _} -> + ok; + {error, #{status_code := 404}} -> + {error, not_found}; + {error, Details} -> + ?tp(warning, "gcp_pubsub_consumer_check_topic_error", Details), + {error, Details} + end. + +log_when_error(Fun, Log) -> + try + Fun() + catch + C:E -> + ?SLOG(error, Log#{ + exception => C, + reason => E + }) + end. diff --git a/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_impl_producer.erl b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_impl_producer.erl new file mode 100644 index 000000000..d2469160b --- /dev/null +++ b/apps/emqx_bridge_gcp_pubsub/src/emqx_bridge_gcp_pubsub_impl_producer.erl @@ -0,0 +1,287 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%%-------------------------------------------------------------------- + +-module(emqx_bridge_gcp_pubsub_impl_producer). + +-include_lib("emqx/include/logger.hrl"). +-include_lib("emqx_resource/include/emqx_resource.hrl"). +-include_lib("snabbkaffe/include/snabbkaffe.hrl"). + +-type config() :: #{ + connect_timeout := emqx_schema:duration_ms(), + max_retries := non_neg_integer(), + pubsub_topic := binary(), + resource_opts := #{request_ttl := infinity | emqx_schema:duration_ms(), any() => term()}, + service_account_json := emqx_bridge_gcp_pubsub_client:service_account_json(), + any() => term() +}. +-type state() :: #{ + client := emqx_bridge_gcp_pubsub_client:state(), + payload_template := emqx_placeholder:tmpl_token(), + project_id := emqx_bridge_gcp_pubsub_client:project_id(), + pubsub_topic := binary() +}. +-type headers() :: emqx_bridge_gcp_pubsub_client:headers(). +-type body() :: emqx_bridge_gcp_pubsub_client:body(). +-type status_code() :: emqx_bridge_gcp_pubsub_client:status_code(). + +%% `emqx_resource' API +-export([ + callback_mode/0, + query_mode/1, + on_start/2, + on_stop/2, + on_query/3, + on_query_async/4, + on_batch_query/3, + on_batch_query_async/4, + on_get_status/2 +]). + +-export([reply_delegator/2]). + +%%------------------------------------------------------------------------------------------------- +%% `emqx_resource' API +%%------------------------------------------------------------------------------------------------- + +callback_mode() -> async_if_possible. + +query_mode(_Config) -> async. + +-spec on_start(resource_id(), config()) -> {ok, state()} | {error, term()}. +on_start(InstanceId, Config) -> + ?SLOG(info, #{ + msg => "starting_gcp_pubsub_bridge", + config => Config + }), + #{ + payload_template := PayloadTemplate, + pubsub_topic := PubSubTopic, + service_account_json := #{project_id := ProjectId} + } = Config, + case emqx_bridge_gcp_pubsub_client:start(InstanceId, Config) of + {ok, Client} -> + State = #{ + client => Client, + payload_template => emqx_placeholder:preproc_tmpl(PayloadTemplate), + project_id => ProjectId, + pubsub_topic => PubSubTopic + }, + {ok, State}; + Error -> + Error + end. + +-spec on_stop(resource_id(), state()) -> ok | {error, term()}. +on_stop(InstanceId, _State) -> + emqx_bridge_gcp_pubsub_client:stop(InstanceId). + +-spec on_get_status(resource_id(), state()) -> connected | disconnected. +on_get_status(_InstanceId, #{client := Client} = _State) -> + emqx_bridge_gcp_pubsub_client:get_status(Client). + +-spec on_query( + resource_id(), + {send_message, map()}, + state() +) -> + {ok, map()} + | {error, {recoverable_error, term()}} + | {error, term()}. +on_query(ResourceId, {send_message, Selected}, State) -> + Requests = [{send_message, Selected}], + ?TRACE( + "QUERY_SYNC", + "gcp_pubsub_received", + #{requests => Requests, connector => ResourceId, state => State} + ), + do_send_requests_sync(State, Requests, ResourceId). + +-spec on_query_async( + resource_id(), + {send_message, map()}, + {ReplyFun :: function(), Args :: list()}, + state() +) -> {ok, pid()}. +on_query_async(ResourceId, {send_message, Selected}, ReplyFunAndArgs, State) -> + Requests = [{send_message, Selected}], + ?TRACE( + "QUERY_ASYNC", + "gcp_pubsub_received", + #{requests => Requests, connector => ResourceId, state => State} + ), + do_send_requests_async(State, Requests, ReplyFunAndArgs). + +-spec on_batch_query( + resource_id(), + [{send_message, map()}], + state() +) -> + {ok, map()} + | {error, {recoverable_error, term()}} + | {error, term()}. +on_batch_query(ResourceId, Requests, State) -> + ?TRACE( + "QUERY_SYNC", + "gcp_pubsub_received", + #{requests => Requests, connector => ResourceId, state => State} + ), + do_send_requests_sync(State, Requests, ResourceId). + +-spec on_batch_query_async( + resource_id(), + [{send_message, map()}], + {ReplyFun :: function(), Args :: list()}, + state() +) -> {ok, pid()}. +on_batch_query_async(ResourceId, Requests, ReplyFunAndArgs, State) -> + ?TRACE( + "QUERY_ASYNC", + "gcp_pubsub_received", + #{requests => Requests, connector => ResourceId, state => State} + ), + do_send_requests_async(State, Requests, ReplyFunAndArgs). + +%%------------------------------------------------------------------------------------------------- +%% Helper fns +%%------------------------------------------------------------------------------------------------- + +-spec do_send_requests_sync( + state(), + [{send_message, map()}], + resource_id() +) -> + {ok, status_code(), headers()} + | {ok, status_code(), headers(), body()} + | {error, {recoverable_error, term()}} + | {error, term()}. +do_send_requests_sync(State, Requests, InstanceId) -> + #{client := Client} = State, + Payloads = + lists:map( + fun({send_message, Selected}) -> + encode_payload(State, Selected) + end, + Requests + ), + Body = to_pubsub_request(Payloads), + Path = publish_path(State), + Method = post, + Request = {prepared_request, {Method, Path, Body}}, + Result = emqx_bridge_gcp_pubsub_client:query_sync(Request, Client), + QueryMode = sync, + handle_result(Result, Request, QueryMode, InstanceId). + +-spec do_send_requests_async( + state(), + [{send_message, map()}], + {ReplyFun :: function(), Args :: list()} +) -> {ok, pid()}. +do_send_requests_async(State, Requests, ReplyFunAndArgs0) -> + #{client := Client} = State, + Payloads = + lists:map( + fun({send_message, Selected}) -> + encode_payload(State, Selected) + end, + Requests + ), + Body = to_pubsub_request(Payloads), + Path = publish_path(State), + Method = post, + Request = {prepared_request, {Method, Path, Body}}, + ReplyFunAndArgs = {fun ?MODULE:reply_delegator/2, [ReplyFunAndArgs0]}, + emqx_bridge_gcp_pubsub_client:query_async( + Request, ReplyFunAndArgs, Client + ). + +-spec encode_payload(state(), Selected :: map()) -> #{data := binary()}. +encode_payload(_State = #{payload_template := PayloadTemplate}, Selected) -> + Interpolated = + case PayloadTemplate of + [] -> emqx_utils_json:encode(Selected); + _ -> emqx_placeholder:proc_tmpl(PayloadTemplate, Selected) + end, + #{data => base64:encode(Interpolated)}. + +-spec to_pubsub_request([#{data := binary()}]) -> binary(). +to_pubsub_request(Payloads) -> + emqx_utils_json:encode(#{messages => Payloads}). + +-spec publish_path(state()) -> binary(). +publish_path( + _State = #{ + project_id := ProjectId, + pubsub_topic := PubSubTopic + } +) -> + <<"/v1/projects/", ProjectId/binary, "/topics/", PubSubTopic/binary, ":publish">>. + +handle_result({error, Reason}, _Request, QueryMode, ResourceId) when + Reason =:= econnrefused; + %% this comes directly from `gun'... + Reason =:= {closed, "The connection was lost."}; + Reason =:= timeout +-> + ?tp( + warning, + gcp_pubsub_request_failed, + #{ + reason => Reason, + query_mode => QueryMode, + recoverable_error => true, + connector => ResourceId + } + ), + {error, {recoverable_error, Reason}}; +handle_result( + {error, #{status_code := StatusCode, body := RespBody}} = Result, + Request, + _QueryMode, + ResourceId +) -> + ?SLOG(error, #{ + msg => "gcp_pubsub_error_response", + request => emqx_connector_http:redact_request(Request), + connector => ResourceId, + status_code => StatusCode, + resp_body => RespBody + }), + Result; +handle_result({error, #{status_code := StatusCode}} = Result, Request, _QueryMode, ResourceId) -> + ?SLOG(error, #{ + msg => "gcp_pubsub_error_response", + request => emqx_connector_http:redact_request(Request), + connector => ResourceId, + status_code => StatusCode + }), + Result; +handle_result({error, Reason} = Result, _Request, QueryMode, ResourceId) -> + ?tp( + error, + gcp_pubsub_request_failed, + #{ + reason => Reason, + query_mode => QueryMode, + recoverable_error => false, + connector => ResourceId + } + ), + Result; +handle_result({ok, _} = Result, _Request, _QueryMode, _ResourceId) -> + Result. + +reply_delegator(ReplyFunAndArgs, Response) -> + case Response of + {error, Reason} when + Reason =:= econnrefused; + %% this comes directly from `gun'... + Reason =:= {closed, "The connection was lost."}; + Reason =:= timeout + -> + Result = {error, {recoverable_error, Reason}}, + emqx_resource:apply_reply_fun(ReplyFunAndArgs, Result); + _ -> + emqx_resource:apply_reply_fun(ReplyFunAndArgs, Response) + end. diff --git a/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_consumer_SUITE.erl b/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_consumer_SUITE.erl new file mode 100644 index 000000000..2e32f630a --- /dev/null +++ b/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_consumer_SUITE.erl @@ -0,0 +1,688 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%%-------------------------------------------------------------------- + +-module(emqx_bridge_gcp_pubsub_consumer_SUITE). + +-compile(nowarn_export_all). +-compile(export_all). + +-include_lib("eunit/include/eunit.hrl"). +-include_lib("common_test/include/ct.hrl"). +-include_lib("snabbkaffe/include/snabbkaffe.hrl"). +-include_lib("jose/include/jose_jwt.hrl"). +-include_lib("jose/include/jose_jws.hrl"). + +-define(BRIDGE_TYPE, gcp_pubsub_consumer). +-define(BRIDGE_TYPE_BIN, <<"gcp_pubsub_consumer">>). +-define(REPUBLISH_TOPIC, <<"republish/t">>). + +-import(emqx_common_test_helpers, [on_exit/1]). + +%%------------------------------------------------------------------------------ +%% CT boilerplate +%%------------------------------------------------------------------------------ + +all() -> + emqx_common_test_helpers:all(?MODULE). + +init_per_suite(Config) -> + GCPEmulatorHost = os:getenv("GCP_EMULATOR_HOST", "toxiproxy"), + GCPEmulatorPortStr = os:getenv("GCP_EMULATOR_PORT", "8085"), + GCPEmulatorPort = list_to_integer(GCPEmulatorPortStr), + ProxyHost = os:getenv("PROXY_HOST", "toxiproxy"), + ProxyPort = list_to_integer(os:getenv("PROXY_PORT", "8474")), + ProxyName = "gcp_emulator", + case emqx_common_test_helpers:is_tcp_server_available(GCPEmulatorHost, GCPEmulatorPort) of + true -> + emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), + ok = emqx_common_test_helpers:start_apps([emqx_conf]), + ok = emqx_connector_test_helpers:start_apps([ + emqx_resource, emqx_bridge, emqx_rule_engine + ]), + {ok, _} = application:ensure_all_started(emqx_connector), + emqx_mgmt_api_test_util:init_suite(), + HostPort = GCPEmulatorHost ++ ":" ++ GCPEmulatorPortStr, + true = os:putenv("PUBSUB_EMULATOR_HOST", HostPort), + Client = start_control_connector(), + [ + {proxy_name, ProxyName}, + {proxy_host, ProxyHost}, + {proxy_port, ProxyPort}, + {gcp_emulator_host, GCPEmulatorHost}, + {gcp_emulator_port, GCPEmulatorPort}, + {client, Client} + | Config + ]; + false -> + case os:getenv("IS_CI") of + "yes" -> + throw(no_gcp_emulator); + _ -> + {skip, no_gcp_emulator} + end + end. + +end_per_suite(Config) -> + Client = ?config(client, Config), + stop_control_connector(Client), + emqx_mgmt_api_test_util:end_suite(), + ok = emqx_common_test_helpers:stop_apps([emqx_conf]), + ok = emqx_connector_test_helpers:stop_apps([emqx_bridge, emqx_resource, emqx_rule_engine]), + _ = application:stop(emqx_connector), + os:unsetenv("PUBSUB_EMULATOR_HOST"), + ok. + +init_per_testcase(TestCase, Config) -> + common_init_per_testcase(TestCase, Config). + +common_init_per_testcase(TestCase, Config0) -> + ct:timetrap(timer:seconds(60)), + emqx_bridge_testlib:delete_all_bridges(), + emqx_config:delete_override_conf_files(), + ConsumerTopic = + << + (atom_to_binary(TestCase))/binary, + (integer_to_binary(erlang:unique_integer()))/binary + >>, + UniqueNum = integer_to_binary(erlang:unique_integer()), + MQTTTopic = proplists:get_value(mqtt_topic, Config0, <<"mqtt/topic/", UniqueNum/binary>>), + MQTTQoS = proplists:get_value(mqtt_qos, Config0, 0), + DefaultTopicMapping = [ + #{ + pubsub_topic => ConsumerTopic, + mqtt_topic => MQTTTopic, + qos => MQTTQoS, + payload_template => <<"${.}">> + } + ], + TopicMapping = proplists:get_value(topic_mapping, Config0, DefaultTopicMapping), + ServiceAccountJSON = + #{<<"project_id">> := ProjectId} = + emqx_bridge_gcp_pubsub_utils:generate_service_account_json(), + Config = [ + {consumer_topic, ConsumerTopic}, + {topic_mapping, TopicMapping}, + {service_account_json, ServiceAccountJSON}, + {project_id, ProjectId} + | Config0 + ], + {Name, ConfigString, ConsumerConfig} = consumer_config(TestCase, Config), + ensure_topics(Config), + ok = snabbkaffe:start_trace(), + [ + {consumer_name, Name}, + {consumer_config_string, ConfigString}, + {consumer_config, ConsumerConfig} + | Config + ]. + +end_per_testcase(_Testcase, Config) -> + case proplists:get_bool(skip_does_not_apply, Config) of + true -> + ok; + false -> + ProxyHost = ?config(proxy_host, Config), + ProxyPort = ?config(proxy_port, Config), + emqx_common_test_helpers:reset_proxy(ProxyHost, ProxyPort), + emqx_bridge_testlib:delete_all_bridges(), + emqx_common_test_helpers:call_janitor(60_000), + ok = snabbkaffe:stop(), + ok + end. + +%%------------------------------------------------------------------------------ +%% Helper fns +%%------------------------------------------------------------------------------ + +consumer_config(TestCase, Config) -> + UniqueNum = integer_to_binary(erlang:unique_integer()), + ConsumerTopic = ?config(consumer_topic, Config), + ServiceAccountJSON = ?config(service_account_json, Config), + Name = << + (atom_to_binary(TestCase))/binary, UniqueNum/binary + >>, + ServiceAccountJSONStr = emqx_utils_json:encode(ServiceAccountJSON), + MQTTTopic = proplists:get_value(mqtt_topic, Config, <<"mqtt/topic/", UniqueNum/binary>>), + MQTTQoS = proplists:get_value(mqtt_qos, Config, 0), + ConsumerWorkersPerTopic = proplists:get_value(consumer_workers_per_topic, Config, 1), + DefaultTopicMapping = [ + #{ + pubsub_topic => ConsumerTopic, + mqtt_topic => MQTTTopic, + qos => MQTTQoS, + payload_template => <<"${.}">> + } + ], + TopicMapping0 = proplists:get_value(topic_mapping, Config, DefaultTopicMapping), + TopicMappingStr = topic_mapping(TopicMapping0), + ConfigString = + io_lib:format( + "bridges.gcp_pubsub_consumer.~s {\n" + " enable = true\n" + %% gcp pubsub emulator doesn't do pipelining very well... + " pipelining = 1\n" + " connect_timeout = \"15s\"\n" + " service_account_json = ~s\n" + " consumer {\n" + " ack_retry_interval = \"5s\"\n" + " pull_max_messages = 10\n" + " consumer_workers_per_topic = ~b\n" + %% topic mapping + "~s" + " }\n" + " max_retries = 2\n" + " pipelining = 100\n" + " pool_size = 8\n" + " resource_opts {\n" + " health_check_interval = \"1s\"\n" + " request_ttl = \"15s\"\n" + " }\n" + "}\n", + [ + Name, + ServiceAccountJSONStr, + ConsumerWorkersPerTopic, + TopicMappingStr + ] + ), + {Name, ConfigString, parse_and_check(ConfigString, Name)}. + +parse_and_check(ConfigString, Name) -> + {ok, RawConf} = hocon:binary(ConfigString, #{format => map}), + TypeBin = ?BRIDGE_TYPE_BIN, + hocon_tconf:check_plain(emqx_bridge_schema, RawConf, #{required => false, atom_key => false}), + #{<<"bridges">> := #{TypeBin := #{Name := Config}}} = RawConf, + Config. + +topic_mapping(TopicMapping0) -> + Template0 = << + "{pubsub_topic = \"{{ pubsub_topic }}\"," + " mqtt_topic = \"{{ mqtt_topic }}\"," + " qos = {{ qos }}," + " payload_template = \"{{{ payload_template }}}\" }" + >>, + Template = bbmustache:parse_binary(Template0), + Entries = + lists:map( + fun(Params) -> + bbmustache:compile(Template, Params, [{key_type, atom}]) + end, + TopicMapping0 + ), + iolist_to_binary( + [ + " topic_mapping = [", + lists:join(<<",\n">>, Entries), + "]\n" + ] + ). + +ensure_topics(Config) -> + TopicMapping = ?config(topic_mapping, Config), + lists:foreach( + fun(#{pubsub_topic := T}) -> + ensure_topic(Config, T) + end, + TopicMapping + ). + +ensure_topic(Config, Topic) -> + ProjectId = ?config(project_id, Config), + Client = ?config(client, Config), + Method = put, + Path = <<"/v1/projects/", ProjectId/binary, "/topics/", Topic/binary>>, + Body = <<"{}">>, + Res = emqx_bridge_gcp_pubsub_client:query_sync( + {prepared_request, {Method, Path, Body}}, + Client + ), + case Res of + {ok, _} -> + ok; + {error, #{status_code := 409}} -> + %% already exists + ok + end, + ok. + +start_control_connector() -> + RawServiceAccount = emqx_bridge_gcp_pubsub_utils:generate_service_account_json(), + ServiceAccount = emqx_utils_maps:unsafe_atom_key_map(RawServiceAccount), + ConnectorConfig = + #{ + connect_timeout => 5_000, + max_retries => 0, + pool_size => 1, + resource_opts => #{request_ttl => 5_000}, + service_account_json => ServiceAccount + }, + PoolName = <<"control_connector">>, + {ok, Client} = emqx_bridge_gcp_pubsub_client:start(PoolName, ConnectorConfig), + Client. + +stop_control_connector(Client) -> + ok = emqx_bridge_gcp_pubsub_client:stop(Client), + ok. + +pubsub_publish(Config, Topic, Messages0) -> + Client = ?config(client, Config), + ProjectId = ?config(project_id, Config), + Method = post, + Path = <<"/v1/projects/", ProjectId/binary, "/topics/", Topic/binary, ":publish">>, + Messages = + lists:map( + fun(Msg) -> + emqx_utils_maps:update_if_present( + <<"data">>, + fun + (D) when is_binary(D) -> base64:encode(D); + (M) when is_map(M) -> base64:encode(emqx_utils_json:encode(M)) + end, + Msg + ) + end, + Messages0 + ), + Body = emqx_utils_json:encode(#{<<"messages">> => Messages}), + {ok, _} = emqx_bridge_gcp_pubsub_client:query_sync( + {prepared_request, {Method, Path, Body}}, + Client + ), + ok. + +create_bridge(Config) -> + create_bridge(Config, _Overrides = #{}). + +create_bridge(Config, Overrides) -> + Type = ?BRIDGE_TYPE_BIN, + Name = ?config(consumer_name, Config), + BridgeConfig0 = ?config(consumer_config, Config), + BridgeConfig = emqx_utils_maps:deep_merge(BridgeConfig0, Overrides), + emqx_bridge:create(Type, Name, BridgeConfig). + +create_bridge_api(Config) -> + create_bridge_api(Config, _Overrides = #{}). + +create_bridge_api(Config, Overrides) -> + TypeBin = ?BRIDGE_TYPE_BIN, + Name = ?config(consumer_name, Config), + BridgeConfig0 = ?config(consumer_config, Config), + BridgeConfig = emqx_utils_maps:deep_merge(BridgeConfig0, Overrides), + Params = BridgeConfig#{<<"type">> => TypeBin, <<"name">> => Name}, + Path = emqx_mgmt_api_test_util:api_path(["bridges"]), + AuthHeader = emqx_mgmt_api_test_util:auth_header_(), + Opts = #{return_all => true}, + ct:pal("creating bridge (via http): ~p", [Params]), + Res = + case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, Params, Opts) of + {ok, {Status, Headers, Body0}} -> + {ok, {Status, Headers, emqx_utils_json:decode(Body0, [return_maps])}}; + Error -> + Error + end, + ct:pal("bridge create result: ~p", [Res]), + Res. + +probe_bridge_api(Config) -> + TypeBin = ?BRIDGE_TYPE_BIN, + Name = ?config(consumer_name, Config), + ConsumerConfig = ?config(consumer_config, Config), + Params = ConsumerConfig#{<<"type">> => TypeBin, <<"name">> => Name}, + Path = emqx_mgmt_api_test_util:api_path(["bridges_probe"]), + AuthHeader = emqx_mgmt_api_test_util:auth_header_(), + Opts = #{return_all => true}, + ct:pal("probing bridge (via http): ~p", [Params]), + Res = + case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, Params, Opts) of + {ok, {{_, 204, _}, _Headers, _Body0} = Res0} -> {ok, Res0}; + Error -> Error + end, + ct:pal("bridge probe result: ~p", [Res]), + Res. + +start_and_subscribe_mqtt(Config) -> + TopicMapping = ?config(topic_mapping, Config), + {ok, C} = emqtt:start_link([{proto_ver, v5}]), + on_exit(fun() -> emqtt:stop(C) end), + {ok, _} = emqtt:connect(C), + lists:foreach( + fun(#{mqtt_topic := MQTTTopic}) -> + {ok, _, [2]} = emqtt:subscribe(C, MQTTTopic, _QoS = 2) + end, + TopicMapping + ), + ok. + +resource_id(Config) -> + Type = ?BRIDGE_TYPE_BIN, + Name = ?config(consumer_name, Config), + emqx_bridge_resource:resource_id(Type, Name). + +receive_published() -> + receive_published(#{}). + +receive_published(Opts0) -> + Default = #{n => 1, timeout => 20_000}, + Opts = maps:merge(Default, Opts0), + receive_published(Opts, []). + +receive_published(#{n := N, timeout := _Timeout}, Acc) when N =< 0 -> + {ok, lists:reverse(Acc)}; +receive_published(#{n := N, timeout := Timeout} = Opts, Acc) -> + receive + {publish, Msg0 = #{payload := Payload}} -> + Msg = + case emqx_utils_json:safe_decode(Payload, [return_maps]) of + {ok, Decoded} -> Msg0#{payload := Decoded}; + {error, _} -> Msg0 + end, + receive_published(Opts#{n := N - 1}, [Msg | Acc]) + after Timeout -> + {timeout, #{ + msgs_so_far => Acc, + mailbox => process_info(self(), messages), + expected_remaining => N + }} + end. + +create_rule_and_action_http(Config) -> + ConsumerName = ?config(consumer_name, Config), + BridgeId = emqx_bridge_resource:bridge_id(?BRIDGE_TYPE_BIN, ConsumerName), + ActionFn = <<(atom_to_binary(?MODULE))/binary, ":action_response">>, + Params = #{ + enable => true, + sql => <<"SELECT * FROM \"$bridges/", BridgeId/binary, "\"">>, + actions => + [ + #{ + <<"function">> => <<"republish">>, + <<"args">> => + #{ + <<"topic">> => ?REPUBLISH_TOPIC, + <<"payload">> => <<>>, + <<"qos">> => 0, + <<"retain">> => false, + <<"user_properties">> => <<"${headers}">> + } + }, + #{<<"function">> => ActionFn} + ] + }, + Path = emqx_mgmt_api_test_util:api_path(["rules"]), + AuthHeader = emqx_mgmt_api_test_util:auth_header_(), + ct:pal("rule action params: ~p", [Params]), + case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, Params) of + {ok, Res = #{<<"id">> := RuleId}} -> + on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end), + {ok, emqx_utils_json:decode(Res, [return_maps])}; + Error -> + Error + end. + +action_response(Selected, Envs, Args) -> + ?tp(action_response, #{ + selected => Selected, + envs => Envs, + args => Args + }), + ok. + +assert_non_received_metrics(BridgeName) -> + Metrics = emqx_bridge:get_metrics(?BRIDGE_TYPE, BridgeName), + #{counters := Counters0, gauges := Gauges} = Metrics, + Counters = maps:remove(received, Counters0), + ?assert(lists:all(fun(V) -> V == 0 end, maps:values(Counters)), #{metrics => Metrics}), + ?assert(lists:all(fun(V) -> V == 0 end, maps:values(Gauges)), #{metrics => Metrics}), + ok. + +%%------------------------------------------------------------------------------ +%% Trace properties +%%------------------------------------------------------------------------------ + +prop_pulled_only_once(Trace) -> + PulledIds = ?projection( + message_id, ?of_kind("gcp_pubsub_consumer_worker_handle_message", Trace) + ), + NumPulled = length(PulledIds), + UniqueNumPulled = sets:size(sets:from_list(PulledIds, [{version, 2}])), + ?assertEqual(UniqueNumPulled, NumPulled), + ok. + +prop_all_pulled_are_acked(Trace) -> + PulledAckIds = ?projection( + ack_id, ?of_kind("gcp_pubsub_consumer_worker_handle_message", Trace) + ), + AckedIds0 = ?projection(ack_ids, ?of_kind(gcp_pubsub_consumer_worker_acknowledged, Trace)), + AckedIds = lists:flatten(AckedIds0), + ?assertEqual( + sets:from_list(PulledAckIds, [{version, 2}]), + sets:from_list(AckedIds, [{version, 2}]) + ), + ok. + +%%------------------------------------------------------------------------------ +%% Testcases +%%------------------------------------------------------------------------------ + +t_consume_ok(Config) -> + BridgeName = ?config(consumer_name, Config), + TopicMapping = ?config(topic_mapping, Config), + ResourceId = resource_id(Config), + ?check_trace( + begin + start_and_subscribe_mqtt(Config), + ?assertMatch( + {{ok, _}, {ok, _}}, + ?wait_async_action( + create_bridge(Config), + #{?snk_kind := "gcp_pubsub_consumer_worker_subscription_ready"}, + 40_000 + ) + ), + [ + #{ + pubsub_topic := Topic, + mqtt_topic := MQTTTopic, + qos := QoS + } + ] = TopicMapping, + Payload0 = emqx_guid:to_hexstr(emqx_guid:gen()), + Messages0 = [ + #{ + <<"data">> => Data0 = #{<<"value">> => Payload0}, + <<"attributes">> => Attributes0 = #{<<"key">> => <<"value">>}, + <<"orderingKey">> => <<"some_ordering_key">> + } + ], + pubsub_publish(Config, Topic, Messages0), + {ok, Published0} = receive_published(), + EncodedData0 = emqx_utils_json:encode(Data0), + ?assertMatch( + [ + #{ + qos := QoS, + topic := MQTTTopic, + payload := + #{ + <<"attributes">> := Attributes0, + <<"message_id">> := MsgId, + <<"ordering_key">> := <<"some_ordering_key">>, + <<"publish_time">> := PubTime, + <<"topic">> := Topic, + <<"value">> := EncodedData0 + } + } + ] when is_binary(MsgId) andalso is_binary(PubTime), + Published0 + ), + %% no need to check return value; we check the property in + %% the check phase. this is just to give it a chance to do + %% so and avoid flakiness. should be fast. + ?block_until(#{?snk_kind := gcp_pubsub_consumer_worker_acknowledged}, 1_000), + ?retry( + _Interval = 200, + _NAttempts = 20, + ?assertEqual(1, emqx_resource_metrics:received_get(ResourceId)) + ), + + %% Batch with only data and only attributes + Payload1 = emqx_guid:to_hexstr(emqx_guid:gen()), + Messages1 = [ + #{<<"data">> => Data1 = #{<<"val">> => Payload1}}, + #{<<"attributes">> => Attributes1 = #{<<"other_key">> => <<"other_value">>}} + ], + pubsub_publish(Config, Topic, Messages1), + {ok, Published1} = receive_published(#{n => 2}), + EncodedData1 = emqx_utils_json:encode(Data1), + ?assertMatch( + [ + #{ + qos := QoS, + topic := MQTTTopic, + payload := + #{ + <<"message_id">> := _, + <<"publish_time">> := _, + <<"topic">> := Topic, + <<"value">> := EncodedData1 + } + }, + #{ + qos := QoS, + topic := MQTTTopic, + payload := + #{ + <<"attributes">> := Attributes1, + <<"message_id">> := _, + <<"publish_time">> := _, + <<"topic">> := Topic + } + } + ], + Published1 + ), + ?assertNotMatch( + [ + #{payload := #{<<"attributes">> := _, <<"ordering_key">> := _}}, + #{payload := #{<<"value">> := _, <<"ordering_key">> := _}} + ], + Published1 + ), + %% no need to check return value; we check the property in + %% the check phase. this is just to give it a chance to do + %% so and avoid flakiness. should be fast. + ?block_until( + #{?snk_kind := gcp_pubsub_consumer_worker_acknowledged, ack_ids := [_, _]}, 1_000 + ), + ?retry( + _Interval = 200, + _NAttempts = 20, + ?assertEqual(3, emqx_resource_metrics:received_get(ResourceId)) + ), + + %% Check that the bridge probe API doesn't leak atoms. + ProbeRes0 = probe_bridge_api(Config), + ?assertMatch({ok, {{_, 204, _}, _Headers, _Body}}, ProbeRes0), + AtomsBefore = erlang:system_info(atom_count), + %% Probe again; shouldn't have created more atoms. + ProbeRes1 = probe_bridge_api(Config), + ?assertMatch({ok, {{_, 204, _}, _Headers, _Body}}, ProbeRes1), + AtomsAfter = erlang:system_info(atom_count), + ?assertEqual(AtomsBefore, AtomsAfter), + + assert_non_received_metrics(BridgeName), + + ok + end, + [ + {"all pulled ack ids are acked", fun ?MODULE:prop_all_pulled_are_acked/1}, + {"all pulled message ids are unique", fun ?MODULE:prop_pulled_only_once/1} + ] + ), + ok. + +t_bridge_rule_action_source(Config) -> + BridgeName = ?config(consumer_name, Config), + TopicMapping = ?config(topic_mapping, Config), + ResourceId = resource_id(Config), + ?check_trace( + begin + ?assertMatch( + {{ok, _}, {ok, _}}, + ?wait_async_action( + create_bridge(Config), + #{?snk_kind := "gcp_pubsub_consumer_worker_subscription_ready"}, + 40_000 + ) + ), + {ok, _} = create_rule_and_action_http(Config), + + [#{pubsub_topic := PubSubTopic}] = TopicMapping, + {ok, C} = emqtt:start_link([{proto_ver, v5}]), + on_exit(fun() -> emqtt:stop(C) end), + {ok, _} = emqtt:connect(C), + {ok, _, [0]} = emqtt:subscribe(C, ?REPUBLISH_TOPIC), + + Payload0 = emqx_guid:to_hexstr(emqx_guid:gen()), + Messages0 = [ + #{ + <<"data">> => Data0 = #{<<"payload">> => Payload0}, + <<"attributes">> => Attributes0 = #{<<"key">> => <<"value">>} + } + ], + {_, {ok, _}} = + ?wait_async_action( + pubsub_publish(Config, PubSubTopic, Messages0), + #{?snk_kind := action_response}, + 5_000 + ), + Published0 = receive_published(), + EncodedData0 = emqx_utils_json:encode(Data0), + ?assertMatch( + {ok, [ + #{ + topic := ?REPUBLISH_TOPIC, + qos := 0, + payload := #{ + <<"event">> := <<"$bridges/", _/binary>>, + <<"message_id">> := _, + <<"metadata">> := #{<<"rule_id">> := _}, + <<"publish_time">> := _, + <<"topic">> := PubSubTopic, + <<"attributes">> := Attributes0, + <<"value">> := EncodedData0 + } + } + ]}, + Published0 + ), + ?retry( + _Interval = 200, + _NAttempts = 20, + ?assertEqual(1, emqx_resource_metrics:received_get(ResourceId)) + ), + + assert_non_received_metrics(BridgeName), + + #{payload => Payload0} + end, + [{"all pulled message ids are unique", fun ?MODULE:prop_pulled_only_once/1}] + ), + ok. + +%% TODO TEST: +%% * multi-topic mapping +%% * get status +%% * 2+ pull workers do not duplicate delivered messages +%% * inexistent topic +%% * connection cut then restored +%% * pull worker death +%% * async worker death mid-pull +%% * ensure subscription creation error +%% * cluster subscription +%% * connection down during pull +%% * connection down during ack +%% * topic deleted while consumer is running +%% * subscription deleted while consumer is running +%% * ensure client is terminated when bridge stops diff --git a/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_SUITE.erl b/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_producer_SUITE.erl similarity index 96% rename from apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_SUITE.erl rename to apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_producer_SUITE.erl index 4dd2682fb..67e4f52d1 100644 --- a/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_SUITE.erl +++ b/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_producer_SUITE.erl @@ -2,7 +2,7 @@ %% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved. %%-------------------------------------------------------------------- --module(emqx_bridge_gcp_pubsub_SUITE). +-module(emqx_bridge_gcp_pubsub_producer_SUITE). -compile(nowarn_export_all). -compile(export_all). @@ -38,13 +38,13 @@ groups() -> {group, sync_query}, {group, async_query} ], - ResourceGroups = [{group, gcp_pubsub}], + SyncTCs = MatrixTCs, + AsyncTCs = MatrixTCs -- only_sync_tests(), [ {with_batch, SynchronyGroups}, {without_batch, SynchronyGroups}, - {sync_query, ResourceGroups}, - {async_query, ResourceGroups}, - {gcp_pubsub, MatrixTCs} + {sync_query, SyncTCs}, + {async_query, AsyncTCs} ]. %% these should not be influenced by the batch/no @@ -66,11 +66,15 @@ single_config_tests() -> t_on_start_ehttpc_pool_already_started ]. +only_sync_tests() -> + [t_query_sync]. + init_per_suite(Config) -> ok = emqx_common_test_helpers:start_apps([emqx_conf]), ok = emqx_connector_test_helpers:start_apps([emqx_resource, emqx_bridge, emqx_rule_engine]), {ok, _} = application:ensure_all_started(emqx_connector), emqx_mgmt_api_test_util:init_suite(), + persistent_term:put({emqx_bridge_gcp_pubsub_client, transport}, tls), Config. end_per_suite(_Config) -> @@ -78,6 +82,7 @@ end_per_suite(_Config) -> ok = emqx_common_test_helpers:stop_apps([emqx_conf]), ok = emqx_connector_test_helpers:stop_apps([emqx_bridge, emqx_resource, emqx_rule_engine]), _ = application:stop(emqx_connector), + persistent_term:erase({emqx_bridge_gcp_pubsub_client, transport}), ok. init_per_group(sync_query, Config) -> @@ -273,7 +278,7 @@ gcp_pubsub_config(Config) -> PayloadTemplate = proplists:get_value(payload_template, Config, ""), PubSubTopic = proplists:get_value(pubsub_topic, Config, <<"mytopic">>), PipelineSize = proplists:get_value(pipeline_size, Config, 100), - ServiceAccountJSON = proplists:get_value(pubsub_topic, Config, generate_service_account_json()), + ServiceAccountJSON = emqx_bridge_gcp_pubsub_utils:generate_service_account_json(), ServiceAccountJSONStr = emqx_utils_json:encode(ServiceAccountJSON), GUID = emqx_guid:to_hexstr(emqx_guid:gen()), Name = <<(atom_to_binary(?MODULE))/binary, (GUID)/binary>>, @@ -321,32 +326,6 @@ parse_and_check(ConfigString, Name) -> #{<<"bridges">> := #{TypeBin := #{Name := Config}}} = RawConf, Config. -generate_service_account_json() -> - PrivateKeyPEM = generate_private_key_pem(), - service_account_json(PrivateKeyPEM). - -generate_private_key_pem() -> - PublicExponent = 65537, - Size = 2048, - Key = public_key:generate_key({rsa, Size, PublicExponent}), - DERKey = public_key:der_encode('PrivateKeyInfo', Key), - public_key:pem_encode([{'PrivateKeyInfo', DERKey, not_encrypted}]). - -service_account_json(PrivateKeyPEM) -> - #{ - <<"type">> => <<"service_account">>, - <<"project_id">> => <<"myproject">>, - <<"private_key_id">> => <<"kid">>, - <<"private_key">> => PrivateKeyPEM, - <<"client_email">> => <<"test@myproject.iam.gserviceaccount.com">>, - <<"client_id">> => <<"123812831923812319190">>, - <<"auth_uri">> => <<"https://accounts.google.com/o/oauth2/auth">>, - <<"token_uri">> => <<"https://oauth2.googleapis.com/token">>, - <<"auth_provider_x509_cert_url">> => <<"https://www.googleapis.com/oauth2/v1/certs">>, - <<"client_x509_cert_url">> => - <<"https://www.googleapis.com/robot/v1/metadata/x509/test%40myproject.iam.gserviceaccount.com">> - }. - metrics_mapping() -> #{ dropped => fun emqx_resource_metrics:dropped_get/1, @@ -1016,7 +995,7 @@ t_publish_timeout(Config) -> <<"pipelining">> => 1, <<"resource_opts">> => #{ <<"batch_size">> => 1, - <<"resume_interval">> => <<"15s">> + <<"resume_interval">> => <<"1s">> } }), {ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config), @@ -1068,7 +1047,7 @@ do_econnrefused_or_timeout_test(Config, Error) -> #{ ?snk_kind := gcp_pubsub_request_failed, query_mode := async, - recoverable_error := true + reason := econnrefused }, 15_000 ); @@ -1082,8 +1061,8 @@ do_econnrefused_or_timeout_test(Config, Error) -> emqx:publish(Message), {ok, _} = snabbkaffe:block_until( ?match_n_events(2, #{ - ?snk_kind := gcp_pubsub_response, - query_mode := async + ?snk_kind := handle_async_reply_expired, + expired := [_] }), _Timeout1 = 15_000 ) @@ -1104,7 +1083,7 @@ do_econnrefused_or_timeout_test(Config, Error) -> timeout -> ?assertMatch( [_, _ | _], - ?of_kind(gcp_pubsub_response, Trace) + ?of_kind(handle_async_reply_expired, Trace) ) end, ok @@ -1304,13 +1283,13 @@ t_unrecoverable_error(Config) -> {_, {ok, _}} = ?wait_async_action( emqx:publish(Message), - #{?snk_kind := gcp_pubsub_response}, + #{?snk_kind := gcp_pubsub_request_failed}, 5_000 ), fun(Trace) -> ?assertMatch( - [#{response := {error, killed}}], - ?of_kind(gcp_pubsub_response, Trace) + [#{reason := killed}], + ?of_kind(gcp_pubsub_request_failed, Trace) ), ok end @@ -1464,3 +1443,30 @@ t_on_start_ehttpc_pool_start_failure(Config) -> end ), ok. + +%% Usually not called, since the bridge has `async_if_possible' callback mode. +t_query_sync(Config) -> + BatchSize0 = ?config(batch_size, Config), + ServiceAccountJSON = ?config(service_account_json, Config), + BatchSize = min(2, BatchSize0), + Topic = <<"t/topic">>, + Payload = <<"payload">>, + ?check_trace( + emqx_common_test_helpers:with_mock( + emqx_bridge_gcp_pubsub_impl_producer, + callback_mode, + fun() -> always_sync end, + fun() -> + {ok, _} = create_bridge(Config), + {ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config), + on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end), + Message = emqx_message:make(Topic, Payload), + emqx_utils:pmap(fun(_) -> emqx:publish(Message) end, lists:seq(1, BatchSize)), + DecodedMessages = assert_http_request(ServiceAccountJSON), + ?assertEqual(BatchSize, length(DecodedMessages)), + ok + end + ), + [] + ), + ok. diff --git a/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_utils.erl b/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_utils.erl new file mode 100644 index 000000000..c3a516fb3 --- /dev/null +++ b/apps/emqx_bridge_gcp_pubsub/test/emqx_bridge_gcp_pubsub_utils.erl @@ -0,0 +1,34 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%%-------------------------------------------------------------------- + +-module(emqx_bridge_gcp_pubsub_utils). + +-compile(nowarn_export_all). +-compile(export_all). + +generate_service_account_json() -> + PrivateKeyPEM = generate_private_key_pem(), + service_account_json(PrivateKeyPEM). + +generate_private_key_pem() -> + PublicExponent = 65537, + Size = 2048, + Key = public_key:generate_key({rsa, Size, PublicExponent}), + DERKey = public_key:der_encode('PrivateKeyInfo', Key), + public_key:pem_encode([{'PrivateKeyInfo', DERKey, not_encrypted}]). + +service_account_json(PrivateKeyPEM) -> + #{ + <<"type">> => <<"service_account">>, + <<"project_id">> => <<"myproject">>, + <<"private_key_id">> => <<"kid">>, + <<"private_key">> => PrivateKeyPEM, + <<"client_email">> => <<"test@myproject.iam.gserviceaccount.com">>, + <<"client_id">> => <<"123812831923812319190">>, + <<"auth_uri">> => <<"https://accounts.google.com/o/oauth2/auth">>, + <<"token_uri">> => <<"https://oauth2.googleapis.com/token">>, + <<"auth_provider_x509_cert_url">> => <<"https://www.googleapis.com/oauth2/v1/certs">>, + <<"client_x509_cert_url">> => + <<"https://www.googleapis.com/robot/v1/metadata/x509/test%40myproject.iam.gserviceaccount.com">> + }. diff --git a/apps/emqx_connector/src/emqx_connector_http.erl b/apps/emqx_connector/src/emqx_connector_http.erl index ce8a1a1a5..22024f316 100644 --- a/apps/emqx_connector/src/emqx_connector_http.erl +++ b/apps/emqx_connector/src/emqx_connector_http.erl @@ -41,6 +41,9 @@ namespace/0 ]). +%% for other webhook-like connectors. +-export([redact_request/1]). + -export([validate_method/1, join_paths/2]). -type connect_timeout() :: emqx_schema:duration() | infinity. diff --git a/apps/emqx_resource/include/emqx_resource.hrl b/apps/emqx_resource/include/emqx_resource.hrl index 8e17ac15c..5d53234f7 100644 --- a/apps/emqx_resource/include/emqx_resource.hrl +++ b/apps/emqx_resource/include/emqx_resource.hrl @@ -22,7 +22,7 @@ -type resource_state() :: term(). -type resource_status() :: connected | disconnected | connecting | stopped. -type callback_mode() :: always_sync | async_if_possible. --type query_mode() :: async | sync | simple_async | simple_sync | dynamic. +-type query_mode() :: simple_sync | simple_async | sync | async | no_queries. -type result() :: term(). -type reply_fun() :: {fun((result(), Args :: term()) -> any()), Args :: term()} | undefined. -type query_opts() :: #{ diff --git a/apps/emqx_resource/src/emqx_resource.erl b/apps/emqx_resource/src/emqx_resource.erl index 7b0f387f5..cec1a6240 100644 --- a/apps/emqx_resource/src/emqx_resource.erl +++ b/apps/emqx_resource/src/emqx_resource.erl @@ -122,6 +122,7 @@ -export([apply_reply_fun/2]). -export_type([ + query_mode/0, resource_id/0, resource_data/0, resource_status/0 @@ -174,8 +175,7 @@ | {resource_status(), resource_state()} | {resource_status(), resource_state(), term()}. --callback query_mode(Config :: term()) -> - simple_sync | simple_async | sync | async | no_queries. +-callback query_mode(Config :: term()) -> query_mode(). -spec list_types() -> [module()]. list_types() -> @@ -415,9 +415,7 @@ call_stop(ResId, Mod, ResourceState) -> Res end). --spec query_mode(module(), term(), creation_opts()) -> - simple_sync | simple_async | sync | async | no_queries. - +-spec query_mode(module(), term(), creation_opts()) -> query_mode(). query_mode(Mod, Config, Opts) -> case erlang:function_exported(Mod, query_mode, 1) of true -> diff --git a/apps/emqx_utils/src/emqx_utils_maps.erl b/apps/emqx_utils/src/emqx_utils_maps.erl index d1caf1f1e..d49c90e53 100644 --- a/apps/emqx_utils/src/emqx_utils_maps.erl +++ b/apps/emqx_utils/src/emqx_utils_maps.erl @@ -32,7 +32,8 @@ deep_convert/3, diff_maps/2, best_effort_recursive_sum/3, - if_only_to_toggle_enable/2 + if_only_to_toggle_enable/2, + update_if_present/3 ]). -export_type([config_key/0, config_key_path/0]). @@ -293,3 +294,12 @@ if_only_to_toggle_enable(OldConf, Conf) -> {_, _, _} -> false end. + +%% Like `maps:update_with', but does nothing if key does not exist. +update_if_present(Key, Fun, Map) -> + case Map of + #{Key := Val} -> + Map#{Key := Fun(Val)}; + _ -> + Map + end. diff --git a/changes/ee/feat-11090.en.md b/changes/ee/feat-11090.en.md new file mode 100644 index 000000000..153dbac5f --- /dev/null +++ b/changes/ee/feat-11090.en.md @@ -0,0 +1 @@ +Implemented GCP PubSub Consumer data integration bridge. diff --git a/changes/ee/fix-11090.en.md b/changes/ee/fix-11090.en.md new file mode 100644 index 000000000..faef72ae3 --- /dev/null +++ b/changes/ee/fix-11090.en.md @@ -0,0 +1 @@ +Fixed a configuration that prevented the pipelining option from being correctly set for GCP PubSub Producer bridge. diff --git a/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge.erl b/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge.erl index 42e10179e..ab23cbc02 100644 --- a/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge.erl +++ b/lib-ee/emqx_ee_bridge/src/emqx_ee_bridge.erl @@ -16,7 +16,8 @@ api_schemas(Method) -> [ %% We need to map the `type' field of a request (binary) to a %% bridge schema module. - api_ref(emqx_bridge_gcp_pubsub, <<"gcp_pubsub">>, Method), + api_ref(emqx_bridge_gcp_pubsub, <<"gcp_pubsub">>, Method ++ "_producer"), + api_ref(emqx_bridge_gcp_pubsub, <<"gcp_pubsub_consumer">>, Method ++ "_consumer"), api_ref(emqx_bridge_kafka, <<"kafka_consumer">>, Method ++ "_consumer"), %% TODO: rename this to `kafka_producer' after alias support is added %% to hocon; keeping this as just `kafka' for backwards compatibility. @@ -91,7 +92,8 @@ resource_type(kafka_consumer) -> emqx_bridge_kafka_impl_consumer; resource_type(kafka) -> emqx_bridge_kafka_impl_producer; resource_type(cassandra) -> emqx_bridge_cassandra_connector; resource_type(hstreamdb) -> emqx_ee_connector_hstreamdb; -resource_type(gcp_pubsub) -> emqx_bridge_gcp_pubsub_connector; +resource_type(gcp_pubsub) -> emqx_bridge_gcp_pubsub_impl_producer; +resource_type(gcp_pubsub_consumer) -> emqx_bridge_gcp_pubsub_impl_consumer; resource_type(mongodb_rs) -> emqx_ee_connector_mongodb; resource_type(mongodb_sharded) -> emqx_ee_connector_mongodb; resource_type(mongodb_single) -> emqx_ee_connector_mongodb; @@ -125,14 +127,6 @@ fields(bridges) -> required => false } )}, - {gcp_pubsub, - mk( - hoconsc:map(name, ref(emqx_bridge_gcp_pubsub, "config")), - #{ - desc => <<"EMQX Enterprise Config">>, - required => false - } - )}, {mysql, mk( hoconsc:map(name, ref(emqx_ee_bridge_mysql, "config")), @@ -198,7 +192,8 @@ fields(bridges) -> required => false } )} - ] ++ kafka_structs() ++ pulsar_structs() ++ mongodb_structs() ++ influxdb_structs() ++ + ] ++ kafka_structs() ++ pulsar_structs() ++ gcp_pubsub_structs() ++ mongodb_structs() ++ + influxdb_structs() ++ redis_structs() ++ pgsql_structs() ++ clickhouse_structs() ++ sqlserver_structs() ++ rabbitmq_structs(). @@ -249,6 +244,26 @@ pulsar_structs() -> )} ]. +gcp_pubsub_structs() -> + [ + {gcp_pubsub, + mk( + hoconsc:map(name, ref(emqx_bridge_gcp_pubsub, "config_producer")), + #{ + desc => <<"EMQX Enterprise Config">>, + required => false + } + )}, + {gcp_pubsub_consumer, + mk( + hoconsc:map(name, ref(emqx_bridge_gcp_pubsub, "config_consumer")), + #{ + desc => <<"EMQX Enterprise Config">>, + required => false + } + )} + ]. + influxdb_structs() -> [ {Protocol, diff --git a/mix.exs b/mix.exs index dc4a4d545..d038bac49 100644 --- a/mix.exs +++ b/mix.exs @@ -49,7 +49,7 @@ defmodule EMQXUmbrella.MixProject do {:redbug, "2.0.8"}, {:covertool, github: "zmstone/covertool", tag: "2.0.4.1", override: true}, {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true}, - {:ehttpc, github: "emqx/ehttpc", tag: "0.4.10", override: true}, + {:ehttpc, github: "emqx/ehttpc", tag: "0.4.11", override: true}, {:gproc, github: "emqx/gproc", tag: "0.9.0.1", override: true}, {:jiffy, github: "emqx/jiffy", tag: "1.0.5", override: true}, {:cowboy, github: "emqx/cowboy", tag: "2.9.2", override: true}, diff --git a/rebar.config b/rebar.config index f41972d98..b4a8b7ea1 100644 --- a/rebar.config +++ b/rebar.config @@ -56,7 +56,7 @@ , {gpb, "4.19.7"} , {typerefl, {git, "https://github.com/ieQu1/typerefl", {tag, "0.9.1"}}} , {gun, {git, "https://github.com/emqx/gun", {tag, "1.3.9"}}} - , {ehttpc, {git, "https://github.com/emqx/ehttpc", {tag, "0.4.10"}}} + , {ehttpc, {git, "https://github.com/emqx/ehttpc", {tag, "0.4.11"}}} , {gproc, {git, "https://github.com/emqx/gproc", {tag, "0.9.0.1"}}} , {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}} , {cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.9.2"}}} diff --git a/rel/i18n/emqx_bridge_gcp_pubsub.hocon b/rel/i18n/emqx_bridge_gcp_pubsub.hocon index ca6b855dc..39c4b7417 100644 --- a/rel/i18n/emqx_bridge_gcp_pubsub.hocon +++ b/rel/i18n/emqx_bridge_gcp_pubsub.hocon @@ -71,4 +71,52 @@ When a GCP Service Account is created (as described in https://developers.google service_account_json.label: """GCP Service Account Credentials""" + consumer_opts { + desc: "Local MQTT publish and GCP PubSub consumer configs." + label: "GCP PubSub to MQTT" + } + + consumer_pull_max_messages { + desc: "The maximum number of messages to retrieve from GCP PubSub in a single pull request." + " The actual number may be less than the specified value." + label: "Maximum Messages to Pull" + } + + consumer_topic_mapping { + desc: "Defines the mapping between GCP PubSub topics and MQTT topics. Must contain at least one item." + label: "Topic Mapping" + } + + consumer_pubsub_topic { + desc: "GCP PubSub topic to consume from." + label: "GCP PubSub" + } + + consumer_mqtt_topic { + desc: "Local topic to which consumed GCP PubSub messages should be published to." + label: "MQTT Topic" + } + + consumer_mqtt_qos { + desc: "MQTT QoS used to publish messages consumed from GCP PubSub." + label: "QoS" + } + +consumer_mqtt_payload.desc: +"""The template for transforming the incoming GCP PubSub message. By default, it will use JSON format to serialize inputs from the GCP PubSub message. Available fields are: +message_id: the message ID assigned by GCP PubSub. +publish_time: message timestamp assigned by GCP PubSub. +topic: GCP PubSub topic. +value: the payload of the GCP PubSub message. Omitted if there's no payload. +attributes: an object containing string key-value pairs. Omitted if there are no attributes. +ordering_key: GCP PubSub message ordering key. Omitted if there's none.""" + +consumer_mqtt_payload.label: +"Payload Template" + + consumer { + desc: "GCP PubSub Consumer configuration." + label: "GCP PubSub Consumer" + } + } diff --git a/scripts/ct/run.sh b/scripts/ct/run.sh index 135eec919..01e6cf329 100755 --- a/scripts/ct/run.sh +++ b/scripts/ct/run.sh @@ -213,6 +213,9 @@ for dep in ${CT_DEPS}; do FILES+=( '.ci/docker-compose-file/docker-compose-minio-tcp.yaml' '.ci/docker-compose-file/docker-compose-minio-tls.yaml' ) ;; + gcp_emulator) + FILES+=( '.ci/docker-compose-file/docker-compose-gcp-emulator.yaml' ) + ;; *) echo "unknown_ct_dependency $dep" exit 1