dchatd/
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
19use async_trait::async_trait;
20use darkfi::{net::P2pPtr, system::StoppableTaskPtr};
21use log::debug;
22use smol::lock::MutexGuard;
23use std::collections::HashSet;
24
25use darkfi::rpc::{
26    jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResponse, JsonResult},
27    p2p_method::HandlerP2p,
28    server::RequestHandler,
29    util::JsonValue,
30};
31
32use crate::{dchatmsg::DchatMsg, Dchat};
33
34#[async_trait]
35impl 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
57impl 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
121impl HandlerP2p for Dchat {
122    fn p2p(&self) -> P2pPtr {
123        self.p2p.clone()
124    }
125}