kaspa-grpc-server 0.0.4

Kaspa gRPC server
Documentation
use super::{handler::RequestHandler, handler_trait::Handler, interface::Interface, method::Method};
use crate::{
    connection::{Connection, IncomingRoute},
    connection_handler::ServerContext,
    error::GrpcServerError,
};
use kaspa_grpc_core::protowire::{kaspad_request::Payload, *};
use kaspa_grpc_core::{ops::KaspadPayloadOps, protowire::NotifyFinalityConflictResponseMessage};
use kaspa_notify::{scope::FinalityConflictResolvedScope, subscriber::SubscriptionManager};
use kaspa_rpc_macros::build_grpc_server_interface;

pub struct Factory {}

impl Factory {
    pub fn new_handler(
        rpc_op: KaspadPayloadOps,
        incoming_route: IncomingRoute,
        server_context: ServerContext,
        interface: &Interface,
        connection: Connection,
    ) -> Box<dyn Handler> {
        Box::new(RequestHandler::new(rpc_op, incoming_route, server_context, interface, connection))
    }

    pub fn new_interface(server_ctx: ServerContext) -> Interface {
        // The array as last argument in the macro call below must exactly match the full set of
        // KaspadPayloadOps variants.
        let mut interface = build_grpc_server_interface!(
            server_ctx.clone(),
            ServerContext,
            Connection,
            KaspadRequest,
            KaspadResponse,
            KaspadPayloadOps,
            [
                SubmitBlock,
                GetBlockTemplate,
                GetCurrentNetwork,
                GetBlock,
                GetBlocks,
                GetInfo,
                Shutdown,
                GetPeerAddresses,
                GetSink,
                GetMempoolEntry,
                GetMempoolEntries,
                GetConnectedPeerInfo,
                AddPeer,
                SubmitTransaction,
                GetSubnetwork,
                GetVirtualChainFromBlock,
                GetBlockCount,
                GetBlockDagInfo,
                ResolveFinalityConflict,
                GetHeaders,
                GetUtxosByAddresses,
                GetBalanceByAddress,
                GetBalancesByAddresses,
                GetSinkBlueScore,
                Ban,
                Unban,
                EstimateNetworkHashesPerSecond,
                GetMempoolEntriesByAddresses,
                GetCoinSupply,
                Ping,
                GetMetrics,
                GetServerInfo,
                GetSyncStatus,
                NotifyBlockAdded,
                NotifyNewBlockTemplate,
                NotifyFinalityConflict,
                NotifyUtxosChanged,
                NotifySinkBlueScoreChanged,
                NotifyPruningPointUtxoSetOverride,
                NotifyVirtualDaaScoreChanged,
                NotifyVirtualChainChanged,
                StopNotifyingUtxosChanged,
                StopNotifyingPruningPointUtxoSetOverride,
            ]
        );

        // Manually reimplementing the NotifyFinalityConflictRequest method so subscription
        // gets mirrored to FinalityConflictResolved notifications as well.
        let method: Method<ServerContext, Connection, KaspadRequest, KaspadResponse> =
            Method::new(|server_ctx: ServerContext, connection: Connection, request: KaspadRequest| {
                Box::pin(async move {
                    let mut response: KaspadResponse = match request.payload {
                        Some(Payload::NotifyFinalityConflictRequest(ref request)) => {
                            match kaspa_rpc_core::NotifyFinalityConflictRequest::try_from(request) {
                                Ok(request) => {
                                    let id = connection.get_or_register_listener_id();
                                    let command = request.command;
                                    let result =
                                        server_ctx.notifier.clone().execute_subscribe_command(id, request.into(), command).await.and(
                                            server_ctx
                                                .notifier
                                                .clone()
                                                .execute_subscribe_command(
                                                    id,
                                                    FinalityConflictResolvedScope::default().into(),
                                                    command,
                                                )
                                                .await,
                                        );
                                    NotifyFinalityConflictResponseMessage::from(result).into()
                                }
                                Err(err) => NotifyFinalityConflictResponseMessage::from(err).into(),
                            }
                        }
                        _ => {
                            return Err(GrpcServerError::InvalidRequestPayload);
                        }
                    };
                    response.id = request.id;
                    Ok(response)
                })
            });
        interface.replace_method(KaspadPayloadOps::NotifyFinalityConflict, method);

        interface
    }
}