use crate::{connection::*, result::Result, router::*, server::*};
use async_trait::async_trait;
use kaspa_core::task::service::{AsyncService, AsyncServiceError, AsyncServiceFuture};
use kaspa_rpc_core::api::ops::RpcApiOps;
use kaspa_rpc_service::service::RpcCoreService;
use std::sync::Arc;
use workflow_log::*;
use workflow_rpc::server::prelude::*;
pub use workflow_rpc::server::Encoding as WrpcEncoding;
pub struct Options {
pub listen_address: String,
pub grpc_proxy_address: Option<String>,
pub verbose: bool,
}
impl Default for Options {
fn default() -> Self {
Options { listen_address: "127.0.0.1:17110".to_owned(), verbose: false, grpc_proxy_address: None }
}
}
pub struct KaspaRpcHandler {
pub server: Server,
pub options: Arc<Options>,
}
impl KaspaRpcHandler {
pub fn new(
tasks: usize,
encoding: WrpcEncoding,
core_service: Option<Arc<RpcCoreService>>,
options: Arc<Options>,
) -> KaspaRpcHandler {
KaspaRpcHandler { server: Server::new(tasks, encoding, core_service, options.clone()), options }
}
}
#[async_trait]
impl RpcHandler for KaspaRpcHandler {
type Context = Connection;
async fn connect(self: Arc<Self>, _peer: &SocketAddr) -> WebSocketResult<()> {
Ok(())
}
async fn handshake(
self: Arc<Self>,
peer: &SocketAddr,
_sender: &mut WebSocketSender,
_receiver: &mut WebSocketReceiver,
messenger: Arc<Messenger>,
) -> WebSocketResult<Connection> {
let connection = self.server.connect(peer, messenger).await.map_err(|err| err.to_string())?;
Ok(connection)
}
async fn disconnect(self: Arc<Self>, ctx: Self::Context, _result: WebSocketResult<()>) {
self.server.disconnect(ctx).await;
}
}
pub struct WrpcService {
options: Arc<Options>,
server: RpcServer,
rpc_handler: Arc<KaspaRpcHandler>,
}
impl WrpcService {
pub fn new(tasks: usize, core_service: Option<Arc<RpcCoreService>>, encoding: &Encoding, options: Options) -> Self {
let options = Arc::new(options);
let rpc_handler = Arc::new(KaspaRpcHandler::new(tasks, *encoding, core_service, options.clone()));
let router = Arc::new(Router::new(rpc_handler.server.clone()));
let server = RpcServer::new_with_encoding::<Server, Connection, RpcApiOps, Id64>(
*encoding,
rpc_handler.clone(),
router.interface.clone(),
);
WrpcService { options, server, rpc_handler }
}
async fn run(self: Arc<Self>) -> Result<()> {
self.rpc_handler.server.start();
let addr = &self.options.listen_address;
log_info!("wRPC server is listening on {}", addr);
self.server.listen(addr).await?;
Ok(())
}
}
const WRPC_SERVER: &str = "WRPC_SERVER";
impl AsyncService for WrpcService {
fn ident(self: Arc<Self>) -> &'static str {
WRPC_SERVER
}
fn start(self: Arc<Self>) -> AsyncServiceFuture {
Box::pin(async move { self.run().await.map_err(|err| AsyncServiceError::Service(format!("wRPC error: `{err}`"))) })
}
fn signal_exit(self: Arc<Self>) {
self.server.stop().unwrap_or_else(|err| log_trace!("wRPC unable to signal shutdown: `{err}`"));
}
fn stop(self: Arc<Self>) -> AsyncServiceFuture {
Box::pin(async move {
self.rpc_handler
.server
.stop()
.await
.map_err(|err| AsyncServiceError::Service(format!("Notification system error: `{err}`")))?;
self.server.join().await.map_err(|err| AsyncServiceError::Service(format!("wRPC error: `{err}`")))?;
Ok(())
})
}
}