#![allow(deprecated)]
use crate::module::{
add_alert_rpc_methods, add_chain_rpc_methods, add_debug_rpc_methods,
add_experiment_rpc_methods, add_indexer_rpc_methods, add_integration_test_rpc_methods,
add_miner_rpc_methods, add_net_rpc_methods, add_pool_rpc_methods, add_rich_indexer_rpc_methods,
add_stats_rpc_methods, add_subscription_rpc_methods, AlertRpcImpl, ChainRpcImpl, DebugRpcImpl,
ExperimentRpcImpl, IndexerRpcImpl, IntegrationTestRpcImpl, MinerRpcImpl, NetRpcImpl,
PoolRpcImpl, RichIndexerRpcImpl, StatsRpcImpl, SubscriptionRpcImpl,
};
use crate::{IoHandler, RPCError};
use ckb_app_config::{DBConfig, IndexerConfig, RpcConfig};
use ckb_chain::chain::ChainController;
use ckb_indexer::IndexerService;
use ckb_indexer_sync::{new_secondary_db, PoolService};
use ckb_network::NetworkController;
use ckb_network_alert::{notifier::Notifier as AlertNotifier, verifier::Verifier as AlertVerifier};
use ckb_pow::Pow;
use ckb_rich_indexer::RichIndexerService;
use ckb_shared::shared::Shared;
use ckb_sync::SyncShared;
use ckb_types::packed::Script;
use ckb_util::Mutex;
use jsonrpc_core::{MetaIoHandler, RemoteProcedure};
use jsonrpc_utils::pub_sub::Session;
use std::sync::Arc;
const DEPRECATED_RPC_PREFIX: &str = "deprecated.";
#[doc(hidden)]
pub struct ServiceBuilder<'a> {
config: &'a RpcConfig,
io_handler: IoHandler,
}
macro_rules! set_rpc_module_methods {
($self:ident, $name:expr, $check:ident, $add_methods:ident, $methods:expr) => {{
let mut meta_io = MetaIoHandler::default();
$add_methods(&mut meta_io, $methods);
if $self.config.$check() {
$self.add_methods(meta_io);
} else {
$self.update_disabled_methods($name, meta_io);
}
$self
}};
}
impl<'a> ServiceBuilder<'a> {
pub fn new(config: &'a RpcConfig) -> Self {
Self {
config,
io_handler: IoHandler::with_compatibility(jsonrpc_core::Compatibility::V2),
}
}
pub fn enable_chain(mut self, shared: Shared) -> Self {
let methods = ChainRpcImpl { shared };
set_rpc_module_methods!(self, "Chain", chain_enable, add_chain_rpc_methods, methods)
}
pub fn enable_pool(
mut self,
shared: Shared,
extra_well_known_lock_scripts: Vec<Script>,
extra_well_known_type_scripts: Vec<Script>,
) -> Self {
let methods = PoolRpcImpl::new(
shared,
extra_well_known_lock_scripts,
extra_well_known_type_scripts,
);
set_rpc_module_methods!(self, "Pool", pool_enable, add_pool_rpc_methods, methods)
}
pub fn enable_miner(
mut self,
shared: Shared,
network_controller: NetworkController,
chain: ChainController,
enable: bool,
) -> Self {
let mut meta_io = MetaIoHandler::default();
let methods = MinerRpcImpl {
shared,
chain,
network_controller,
};
add_miner_rpc_methods(&mut meta_io, methods);
if enable && self.config.miner_enable() {
self.add_methods(meta_io);
} else {
self.update_disabled_methods("Miner", meta_io);
}
self
}
pub fn enable_net(
mut self,
network_controller: NetworkController,
sync_shared: Arc<SyncShared>,
) -> Self {
let methods = NetRpcImpl {
network_controller,
sync_shared,
};
set_rpc_module_methods!(self, "Net", net_enable, add_net_rpc_methods, methods)
}
pub fn enable_stats(
mut self,
shared: Shared,
alert_notifier: Arc<Mutex<AlertNotifier>>,
) -> Self {
let methods = StatsRpcImpl {
shared,
alert_notifier,
};
set_rpc_module_methods!(self, "Stats", stats_enable, add_stats_rpc_methods, methods)
}
pub fn enable_experiment(mut self, shared: Shared) -> Self {
let methods = ExperimentRpcImpl { shared };
set_rpc_module_methods!(
self,
"Experiment",
experiment_enable,
add_experiment_rpc_methods,
methods
)
}
pub fn enable_integration_test(
mut self,
shared: Shared,
network_controller: NetworkController,
chain: ChainController,
) -> Self {
if self.config.integration_test_enable() {
assert_eq!(
shared.consensus().pow,
Pow::Dummy,
"Only run integration test on Dummy PoW chain"
);
}
let methods = IntegrationTestRpcImpl {
shared: shared.clone(),
network_controller,
chain,
};
set_rpc_module_methods!(
self,
"IntegrationTest",
integration_test_enable,
add_integration_test_rpc_methods,
methods
)
}
pub fn enable_alert(
mut self,
alert_verifier: Arc<AlertVerifier>,
alert_notifier: Arc<Mutex<AlertNotifier>>,
network_controller: NetworkController,
) -> Self {
let methods = AlertRpcImpl::new(alert_verifier, alert_notifier, network_controller);
set_rpc_module_methods!(self, "Alert", alert_enable, add_alert_rpc_methods, methods)
}
pub fn enable_debug(mut self) -> Self {
let methods = DebugRpcImpl {};
set_rpc_module_methods!(self, "Debug", debug_enable, add_debug_rpc_methods, methods)
}
pub fn enable_indexer(
mut self,
shared: Shared,
db_config: &DBConfig,
indexer_config: &IndexerConfig,
) -> Self {
let ckb_secondary_db = new_secondary_db(db_config, &indexer_config.into());
let pool_service =
PoolService::new(indexer_config.index_tx_pool, shared.async_handle().clone());
if self.config.indexer_enable() {
let mut indexer = IndexerService::new(
ckb_secondary_db.clone(),
pool_service.clone(),
indexer_config,
shared.async_handle().clone(),
);
indexer.spawn_poll(shared.notify_controller().clone());
if indexer_config.index_tx_pool {
indexer.index_tx_pool(shared.notify_controller().clone());
}
let indexer_handle = indexer.handle();
let methods = IndexerRpcImpl::new(indexer_handle);
self = set_rpc_module_methods!(
self,
"Indexer",
indexer_enable,
add_indexer_rpc_methods,
methods
);
}
if self.config.rich_indexer_enable() {
let mut rich_indexer = RichIndexerService::new(
ckb_secondary_db,
pool_service,
indexer_config,
shared.async_handle().clone(),
);
rich_indexer.spawn_poll(shared.notify_controller().clone());
if indexer_config.index_tx_pool {
rich_indexer.index_tx_pool(shared.notify_controller().clone());
}
let rich_indexer_handle = rich_indexer.async_handle();
let rich_indexer_methods = RichIndexerRpcImpl::new(rich_indexer_handle);
self = set_rpc_module_methods!(
self,
"RichIndexer",
rich_indexer_enable,
add_rich_indexer_rpc_methods,
rich_indexer_methods
)
}
self
}
pub fn enable_subscription(&mut self, shared: Shared) {
if self.config.subscription_enable() {
let methods = SubscriptionRpcImpl::new(
shared.notify_controller().clone(),
shared.async_handle().clone(),
);
let mut meta_io = MetaIoHandler::default();
add_subscription_rpc_methods(&mut meta_io, methods);
self.add_methods(meta_io);
}
}
fn add_methods<I>(&mut self, rpc_methods: I)
where
I: IntoIterator<Item = (String, RemoteProcedure<Option<Session>>)>,
{
let enable_deprecated_rpc = self.config.enable_deprecated_rpc;
self.io_handler
.extend_with(rpc_methods.into_iter().map(|(name, method)| {
if let Some(striped_method_name) = name.strip_prefix(DEPRECATED_RPC_PREFIX) {
(
striped_method_name.to_owned(),
if enable_deprecated_rpc {
method
} else {
RemoteProcedure::Method(Arc::new(|_param, _meta| async {
Err(RPCError::rpc_method_is_deprecated())
}))
},
)
} else {
(name, method)
}
}));
}
fn update_disabled_methods<I, M>(&mut self, module: &str, rpc_methods: I)
where
I: IntoIterator<Item = (String, M)>,
{
rpc_methods.into_iter().for_each(|(name, _method)| {
let error = Err(RPCError::rpc_module_is_disabled(module));
self.io_handler.add_sync_method(
name.split(DEPRECATED_RPC_PREFIX)
.collect::<Vec<&str>>()
.last()
.unwrap(),
move |_param| error.clone(),
)
});
}
pub fn build(self) -> IoHandler {
let mut io_handler = self.io_handler;
io_handler.add_method("ping", |_| async { Ok("pong".into()) });
io_handler
}
}