/ bin / darkirc / 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  use std::collections::HashSet;
 19  
 20  use async_trait::async_trait;
 21  use darkfi::{
 22      event_graph::util::recreate_from_replayer_log,
 23      net::P2pPtr,
 24      rpc::{
 25          jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResponse, JsonResult},
 26          p2p_method::HandlerP2p,
 27          server::RequestHandler,
 28          util::JsonValue,
 29      },
 30      system::StoppableTaskPtr,
 31  };
 32  use smol::lock::MutexGuard;
 33  use tracing::debug;
 34  
 35  use super::DarkIrc;
 36  
 37  #[async_trait]
 38  impl RequestHandler<()> for DarkIrc {
 39      async fn handle_request(&self, req: JsonRequest) -> JsonResult {
 40          debug!(target: "darkirc::rpc", "--> {}", req.stringify().unwrap());
 41  
 42          match req.method.as_str() {
 43              "ping" => self.pong(req.id, req.params).await,
 44              "dnet.switch" => self.dnet_switch(req.id, req.params).await,
 45              "dnet.subscribe_events" => self.dnet_subscribe_events(req.id, req.params).await,
 46              "p2p.get_info" => self.p2p_get_info(req.id, req.params).await,
 47  
 48              "deg.switch" => self.deg_switch(req.id, req.params).await,
 49              "deg.subscribe_events" => self.deg_subscribe_events(req.id, req.params).await,
 50              "eventgraph.get_info" => self.eg_get_info(req.id, req.params).await,
 51              "eventgraph.replay" => self.eg_rep_info(req.id, req.params).await,
 52  
 53              _ => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
 54          }
 55      }
 56  
 57      async fn connections_mut(&self) -> MutexGuard<'life0, HashSet<StoppableTaskPtr>> {
 58          self.rpc_connections.lock().await
 59      }
 60  }
 61  
 62  impl DarkIrc {
 63      // RPCAPI:
 64      // Activate or deactivate dnet in the P2P stack.
 65      // By sending `true`, dnet will be activated, and by sending `false` dnet
 66      // will be deactivated. Returns `true` on success.
 67      //
 68      // --> {"jsonrpc": "2.0", "method": "dnet.switch", "params": [true], "id": 42}
 69      // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
 70      async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
 71          let params = params.get::<Vec<JsonValue>>().unwrap();
 72          if params.len() != 1 || !params[0].is_bool() {
 73              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
 74          }
 75  
 76          let switch = params[0].get::<bool>().unwrap();
 77  
 78          if *switch {
 79              self.p2p.dnet_enable();
 80          } else {
 81              self.p2p.dnet_disable();
 82          }
 83  
 84          JsonResponse::new(JsonValue::Boolean(true), id).into()
 85      }
 86  
 87      // RPCAPI:
 88      // Initializes a subscription to p2p dnet events.
 89      // Once a subscription is established, `darkirc` will send JSON-RPC notifications of
 90      // new network events to the subscriber.
 91      //
 92      // --> {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [], "id": 1}
 93      // <-- {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [`event`]}
 94      pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
 95          let params = params.get::<Vec<JsonValue>>().unwrap();
 96          if !params.is_empty() {
 97              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
 98          }
 99  
100          self.dnet_sub.clone().into()
101      }
102  
103      // RPCAPI:
104      // Initializes a subscription to deg events.
105      // Once a subscription is established, apps using eventgraph will send JSON-RPC notifications of
106      // new eventgraph events to the subscriber.
107      //
108      // --> {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [], "id": 1}
109      // <-- {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [`event`]}
110      pub async fn deg_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
111          let params = params.get::<Vec<JsonValue>>().unwrap();
112          if !params.is_empty() {
113              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
114          }
115  
116          self.deg_sub.clone().into()
117      }
118  
119      // RPCAPI:
120      // Activate or deactivate deg in the EVENTGRAPH.
121      // By sending `true`, deg will be activated, and by sending `false` deg
122      // will be deactivated. Returns `true` on success.
123      //
124      // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
125      // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
126      async fn deg_switch(&self, id: u16, params: JsonValue) -> JsonResult {
127          let params = params.get::<Vec<JsonValue>>().unwrap();
128          if params.len() != 1 || !params[0].is_bool() {
129              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
130          }
131  
132          let switch = params[0].get::<bool>().unwrap();
133  
134          if *switch {
135              self.event_graph.deg_enable().await;
136          } else {
137              self.event_graph.deg_disable().await;
138          }
139  
140          JsonResponse::new(JsonValue::Boolean(true), id).into()
141      }
142  
143      // RPCAPI:
144      // Get EVENTGRAPH info.
145      //
146      // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
147      // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
148      async fn eg_get_info(&self, id: u16, params: JsonValue) -> JsonResult {
149          let params_ = params.get::<Vec<JsonValue>>().unwrap();
150          if !params_.is_empty() {
151              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
152          }
153  
154          self.event_graph.eventgraph_info(id, params).await
155      }
156  
157      // RPCAPI:
158      // Get replayed EVENTGRAPH info.
159      //
160      // --> {"jsonrpc": "2.0", "method": "eventgraph.replay", "params": ..., "id": 42}
161      // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
162      async fn eg_rep_info(&self, id: u16, params: JsonValue) -> JsonResult {
163          let params_ = params.get::<Vec<JsonValue>>().unwrap();
164          if !params_.is_empty() {
165              return JsonError::new(ErrorCode::InvalidParams, None, id).into()
166          }
167  
168          recreate_from_replayer_log(&self.replay_datastore).await
169      }
170  }
171  
172  impl HandlerP2p for DarkIrc {
173      fn p2p(&self) -> P2pPtr {
174          self.p2p.clone()
175      }
176  }