RPC interface

Let's begin connecting dchat up to JSON-RPC using DarkFi's rpc module.

We'll start by defining a new struct called JsonRpcInterface that takes two values, an accept Url that will receive JSON-RPC requests, and a pointer to the p2p network.

pub struct JsonRpcInterface {
    pub addr: Url,
    pub p2p: net::P2pPtr,
}

We'll need to implement a trait called RequestHandler for the JsonRpcInterface. RequestHandler exposes a method called handle_request() which is a handle for processing incoming JSON-RPC requests. handle_request() takes a JsonRequest and returns a JsonResult. These types are defined inside jsonrpc.rs

This is JsonResult:

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum JsonResult {
    Response(JsonResponse),
    Error(JsonError),
    Notification(JsonNotification),
    Subscriber(JsonSubscriber),
}

This is JsonRequest:

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct JsonRequest {
    /// JSON-RPC version
    pub jsonrpc: Value,
    /// Request ID
    pub id: Value,
    /// Request method
    pub method: Value,
    /// Request parameters
    pub params: Value,
}

We'll use handle_request() to run a match statement on JsonRequest.method.

Running a match on method will allow us to branch out to functions that respond to methods received over JSON-RPC. We haven't implemented any methods yet, so for now let's just return a JsonError.

#[async_trait]
impl RequestHandler for JsonRpcInterface {
    async fn handle_request(&self, req: JsonRequest) -> JsonResult {
        if req.params.as_array().is_none() {
            return JsonError::new(ErrorCode::InvalidRequest, None, req.id).into()
        }

        debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());

        match req.method.as_str() {
            Some(_) | None => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
        }
    }
}