/ example / dchat / dchatd / src / rpc.rs
rpc.rs
  1  /* This file is part of DarkFi (https://dark.fi)
  2   *
  3   * Copyright (C) 2020-2025 Dyne.org foundation
  4   *
  5   * This program is free software: you can redistribute it and/or modify
  6   * it under the terms of the GNU Affero General Public License as
  7   * published by the Free Software Foundation, either version 3 of the
  8   * License, or (at your option) any later version.
  9   *
 10   * This program is distributed in the hope that it will be useful,
 11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13   * GNU Affero General Public License for more details.
 14   *
 15   * You should have received a copy of the GNU Affero General Public License
 16   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17   */
 18  
 19  use async_trait::async_trait;
 20  use darkfi::{net::P2pPtr, system::StoppableTaskPtr};
 21  use smol::lock::MutexGuard;
 22  use std::collections::HashSet;
 23  use tracing::debug;
 24  
 25  use darkfi::rpc::{
 26      jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResponse, JsonResult},
 27      p2p_method::HandlerP2p,
 28      server::RequestHandler,
 29      util::JsonValue,
 30  };
 31  
 32  use crate::{dchatmsg::DchatMsg, Dchat};
 33  
 34  #[async_trait]
 35  impl RequestHandler<()> for Dchat {
 36      async fn handle_request(&self, req: JsonRequest) -> JsonResult {
 37          debug!(target: "dchat::rpc", "--> {}", req.stringify().unwrap());
 38  
 39          // ANCHOR: req_match
 40          match req.method.as_str() {
 41              "send" => self.send(req.id, req.params).await,
 42              "recv" => self.recv(req.id).await,
 43              "ping" => self.pong(req.id, req.params).await,
 44              "p2p.get_info" => self.p2p_get_info(req.id, req.params).await,
 45              "dnet.switch" => self.dnet_switch(req.id, req.params).await,
 46              "dnet.subscribe_events" => self.dnet_subscribe_events(req.id, req.params).await,
 47              _ => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
 48          }
 49          // ANCHOR_END: req_match
 50      }
 51  
 52      async fn connections_mut(&self) -> MutexGuard<'life0, HashSet<StoppableTaskPtr>> {
 53          self.rpc_connections.lock().await
 54      }
 55  }
 56  
 57  impl Dchat {
 58      // RPCAPI:
 59      // TODO
 60      // --> {"jsonrpc": "2.0", "method": "send", "params": [true], "id": 42}
 61      // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
 62      async fn send(&self, id: u16, params: JsonValue) -> JsonResult {
 63          let msg = params[0].get::<String>().unwrap().to_string();
 64          let dchatmsg = DchatMsg { msg };
 65          self.p2p.broadcast(&dchatmsg).await;
 66          JsonResponse::new(JsonValue::Boolean(true), id).into()
 67      }
 68  
 69      // RPCAPI:
 70      // TODO
 71      // --> {"jsonrpc": "2.0", "method": "inbox", "params": [true], "id": 42}
 72      // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
 73      async fn recv(&self, id: u16) -> JsonResult {
 74          let buffer = self.recv_msgs.lock().await;
 75          let msgs: Vec<JsonValue> =
 76              buffer.iter().map(|x| JsonValue::String(x.msg.clone())).collect();
 77          JsonResponse::new(JsonValue::Array(msgs), id).into()
 78      }
 79  
 80      // RPCAPI:
 81      // Activate or deactivate dnet in the P2P stack.
 82      // By sending `true`, dnet will be activated, and by sending `false` dnet will
 83      // be deactivated. Returns `true` on success.
 84      //
 85      // --> {"jsonrpc": "2.0", "method": "dnet_switch", "params": [true], "id": 42}
 86      // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
 87      async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
 88          let params = params.get::<Vec<JsonValue>>().unwrap();
 89          if params.len() != 1 || !params[0].is_bool() {
 90              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
 91          }
 92  
 93          let switch = params[0].get::<bool>().unwrap();
 94  
 95          if *switch {
 96              self.p2p.dnet_enable();
 97          } else {
 98              self.p2p.dnet_disable();
 99          }
100  
101          JsonResponse::new(JsonValue::Boolean(true), id).into()
102      }
103      //
104      // RPCAPI:
105      // Initializes a subscription to p2p dnet events.
106      // Once a subscription is established, `darkirc` will send JSON-RPC notifications of
107      // new network events to the subscriber.
108      //
109      // --> {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [], "id": 1}
110      // <-- {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [`event`]}
111      pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
112          let params = params.get::<Vec<JsonValue>>().unwrap();
113          if !params.is_empty() {
114              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
115          }
116  
117          self.dnet_sub.clone().into()
118      }
119  }
120  
121  impl HandlerP2p for Dchat {
122      fn p2p(&self) -> P2pPtr {
123          self.p2p.clone()
124      }
125  }