Просмотр исходного кода

bin/darkfid: Port to new JSONRPC server implementation.

parazyd 4 лет назад
Родитель
Сommit
1b863922c8
5 измененных файлов с 74 добавлено и 94 удалено
  1. 11 0
      example/config/darkfid.toml
  2. 52 92
      src/bin/darkfid.rs
  3. 1 1
      src/bin/drk.rs
  4. 9 0
      src/cli/cli_config.rs
  5. 1 1
      src/rpc/jsonrpc.rs

+ 11 - 0
example/config/darkfid.toml

@@ -1,6 +1,17 @@
 connect_url = "127.0.0.1:3333"
 connect_url = "127.0.0.1:3333"
 subscriber_url = "127.0.0.1:4444"
 subscriber_url = "127.0.0.1:4444"
 cashier_url = "127.0.0.1:7777"
 cashier_url = "127.0.0.1:7777"
+# The URL where darkfid will bind it's RPC socket
 rpc_url = "127.0.0.1:8000"
 rpc_url = "127.0.0.1:8000"
+# Whether to listen with TLS or plain TCP
+use_tls = false
+# Path to DER-formatted PKCS#12 archive.
+# This can be created using openssl:
+# openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
+tls_identity_path = "~/.config/darkfi/darkfid_identity.pfx"
+# Password for the created identity
+tls_identity_password = "FOOBAR"
+# Path to darkfid log file
 log_path = "/tmp/darkfid_service_daemon.log"
 log_path = "/tmp/darkfid_service_daemon.log"
+# Wallet password
 password = "TEST_PASSWORD"
 password = "TEST_PASSWORD"

+ 52 - 92
src/bin/darkfid.rs

@@ -1,28 +1,26 @@
-use log::*;
-use std::fs;
 use std::path::PathBuf;
 use std::path::PathBuf;
+use std::sync::Arc;
 
 
+use async_trait::async_trait;
 use clap::clap_app;
 use clap::clap_app;
+use log::debug;
 use serde_json::{json, Value};
 use serde_json::{json, Value};
 use simplelog::{
 use simplelog::{
     CombinedLogger, Config as SimLogConfig, ConfigBuilder, LevelFilter, TermLogger, TerminalMode,
     CombinedLogger, Config as SimLogConfig, ConfigBuilder, LevelFilter, TermLogger, TerminalMode,
     WriteLogger,
     WriteLogger,
 };
 };
 
 
-use async_std::sync::Arc;
-use tokio::io::{AsyncReadExt, AsyncWriteExt};
-use tokio::net::TcpListener;
-
 use drk::{
 use drk::{
     cli::{Config, DarkfidConfig},
     cli::{Config, DarkfidConfig},
     rpc::{
     rpc::{
         jsonrpc::{error as jsonerr, request as jsonreq, response as jsonresp, send_request},
         jsonrpc::{error as jsonerr, request as jsonreq, response as jsonresp, send_request},
         jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
         jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
+        rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
     },
     },
     serial::serialize,
     serial::serialize,
     util::join_config_path,
     util::join_config_path,
     wallet::WalletDb,
     wallet::WalletDb,
-    Error, Result,
+    Result,
 };
 };
 
 
 #[derive(Clone)]
 #[derive(Clone)]
@@ -36,29 +34,15 @@ struct Darkfid {
     // spend_params:
     // spend_params:
 }
 }
 
 
-impl Darkfid {
-    fn new(verbose: bool, config_path: PathBuf) -> Result<Self> {
-        let config: DarkfidConfig = Config::<DarkfidConfig>::load(config_path)?;
-        let wallet_path = join_config_path(&PathBuf::from("walletdb.db"))?;
-        let wallet = WalletDb::new(&PathBuf::from(wallet_path.clone()), config.password.clone())?;
-        let file_contents = fs::read_to_string("token/solanatokenlist.json")?;
-        let tokenlist: Value = serde_json::from_str(&file_contents)?;
-
-        Ok(Self {
-            verbose,
-            config,
-            wallet,
-            tokenlist,
-        })
-    }
-
+#[async_trait]
+impl RequestHandler for Darkfid {
     // TODO: ServerError codes should be part of the lib.
     // TODO: ServerError codes should be part of the lib.
-    async fn handle_request(self, req: JsonRequest) -> JsonResult {
+    async fn handle_request(&self, req: JsonRequest) -> JsonResult {
         if req.params.as_array().is_none() {
         if req.params.as_array().is_none() {
             return JsonResult::Err(jsonerr(InvalidParams, None, req.id));
             return JsonResult::Err(jsonerr(InvalidParams, None, req.id));
         }
         }
 
 
-        debug!(target: "RPC", "--> {:#?}", serde_json::to_string(&req).unwrap());
+        debug!(target: "RPC", "--> {:?}", serde_json::to_string(&req).unwrap());
 
 
         match req.method.as_str() {
         match req.method.as_str() {
             Some("say_hello") => return self.say_hello(req.id, req.params).await,
             Some("say_hello") => return self.say_hello(req.id, req.params).await,
@@ -70,22 +54,38 @@ impl Darkfid {
             Some("deposit") => return self.deposit(req.id, req.params).await,
             Some("deposit") => return self.deposit(req.id, req.params).await,
             Some("withdraw") => return self.withdraw(req.id, req.params).await,
             Some("withdraw") => return self.withdraw(req.id, req.params).await,
             Some("transfer") => return self.transfer(req.id, req.params).await,
             Some("transfer") => return self.transfer(req.id, req.params).await,
-            Some(_) => {}
-            None => {}
+            Some(_) | None => {}
         };
         };
 
 
         return JsonResult::Err(jsonerr(MethodNotFound, None, req.id));
         return JsonResult::Err(jsonerr(MethodNotFound, None, req.id));
     }
     }
+}
+
+impl Darkfid {
+    fn new(verbose: bool, config_path: PathBuf) -> Result<Self> {
+        let config: DarkfidConfig = Config::<DarkfidConfig>::load(config_path)?;
+        let wallet_path = join_config_path(&PathBuf::from("walletdb.db"))?;
+        let wallet = WalletDb::new(&PathBuf::from(wallet_path.clone()), config.password.clone())?;
+        let file_contents = std::fs::read_to_string("token/solanatokenlist.json")?;
+        let tokenlist: Value = serde_json::from_str(&file_contents)?;
+
+        Ok(Self {
+            verbose,
+            config,
+            wallet,
+            tokenlist,
+        })
+    }
 
 
     // --> {"method": "say_hello", "params": []}
     // --> {"method": "say_hello", "params": []}
     // <-- {"result": "hello world"}
     // <-- {"result": "hello world"}
-    async fn say_hello(self, id: Value, _params: Value) -> JsonResult {
+    async fn say_hello(&self, id: Value, _params: Value) -> JsonResult {
         JsonResult::Resp(jsonresp(json!("hello world"), id))
         JsonResult::Resp(jsonresp(json!("hello world"), id))
     }
     }
 
 
     // --> {"method": "create_wallet", "params": []}
     // --> {"method": "create_wallet", "params": []}
     // <-- {"result": true}
     // <-- {"result": true}
-    async fn create_wallet(self, id: Value, _params: Value) -> JsonResult {
+    async fn create_wallet(&self, id: Value, _params: Value) -> JsonResult {
         match self.wallet.init_db() {
         match self.wallet.init_db() {
             Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
             Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
             Err(e) => {
             Err(e) => {
@@ -96,7 +96,7 @@ impl Darkfid {
 
 
     // --> {"method": "key_gen", "params": []}
     // --> {"method": "key_gen", "params": []}
     // <-- {"result": true}
     // <-- {"result": true}
-    async fn key_gen(self, id: Value, _params: Value) -> JsonResult {
+    async fn key_gen(&self, id: Value, _params: Value) -> JsonResult {
         match self.wallet.key_gen() {
         match self.wallet.key_gen() {
             Ok((_, _)) => return JsonResult::Resp(jsonresp(json!(true), id)),
             Ok((_, _)) => return JsonResult::Resp(jsonresp(json!(true), id)),
             Err(e) => {
             Err(e) => {
@@ -107,7 +107,7 @@ impl Darkfid {
 
 
     // --> {"method": "get_key", "params": []}
     // --> {"method": "get_key", "params": []}
     // <-- {"result": "vdNS7oBj7KvsMWWmo9r96SV4SqATLrGsH2a3PGpCfJC"}
     // <-- {"result": "vdNS7oBj7KvsMWWmo9r96SV4SqATLrGsH2a3PGpCfJC"}
-    async fn get_key(self, id: Value, _params: Value) -> JsonResult {
+    async fn get_key(&self, id: Value, _params: Value) -> JsonResult {
         match self.wallet.get_keypairs() {
         match self.wallet.get_keypairs() {
             Ok(v) => {
             Ok(v) => {
                 let pk = v[0].public;
                 let pk = v[0].public;
@@ -124,7 +124,7 @@ impl Darkfid {
     //      "params": [token],
     //      "params": [token],
     //      "id": 42}
     //      "id": 42}
     // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
     // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
-    async fn get_token_id(self, id: Value, params: Value) -> JsonResult {
+    async fn get_token_id(&self, id: Value, params: Value) -> JsonResult {
         let args = params.as_array().unwrap();
         let args = params.as_array().unwrap();
         let symbol = &args[0];
         let symbol = &args[0];
 
 
@@ -139,7 +139,7 @@ impl Darkfid {
     }
     }
 
 
     // TODO: proper error handling here
     // TODO: proper error handling here
-    fn search_id(self, symbol: &str) -> Value {
+    fn search_id(&self, symbol: &str) -> Value {
         debug!(target: "DARKFID", "SEARCHING FOR {}", symbol);
         debug!(target: "DARKFID", "SEARCHING FOR {}", symbol);
         let tokens = self.tokenlist["tokens"]
         let tokens = self.tokenlist["tokens"]
             .as_array()
             .as_array()
@@ -155,11 +155,11 @@ impl Darkfid {
 
 
     // --> {"jsonrpc": "2.0", "method": "features", "params": [], "id": 42}
     // --> {"jsonrpc": "2.0", "method": "features", "params": [], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": ["network": "btc", "sol"], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": ["network": "btc", "sol"], "id": 42}
-    async fn features(self, id: Value, _params: Value) -> JsonResult {
+    async fn features(&self, id: Value, _params: Value) -> JsonResult {
         // TODO: return a dictionary of features
         // TODO: return a dictionary of features
         let req = jsonreq(json!("features"), json!([]));
         let req = jsonreq(json!("features"), json!([]));
         let rep: JsonResult;
         let rep: JsonResult;
-        match send_request(self.config.cashier_url, json!(req)).await {
+        match send_request(&self.config.cashier_url, json!(req)).await {
             Ok(v) => rep = v,
             Ok(v) => rep = v,
             Err(e) => {
             Err(e) => {
                 return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id))
                 return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id))
@@ -179,7 +179,7 @@ impl Darkfid {
     // The publickey sent here is used so the cashier can know where to send
     // The publickey sent here is used so the cashier can know where to send
     // assets once the deposit is received.
     // assets once the deposit is received.
     // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
     // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
-    async fn deposit(self, id: Value, params: Value) -> JsonResult {
+    async fn deposit(&self, id: Value, params: Value) -> JsonResult {
         let args = params.as_array().unwrap();
         let args = params.as_array().unwrap();
         if args.len() != 2 {
         if args.len() != 2 {
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
@@ -216,7 +216,7 @@ impl Darkfid {
         // If not, an error is returned, and forwarded to the method caller.
         // If not, an error is returned, and forwarded to the method caller.
         let req = jsonreq(json!("deposit"), json!([network, token, pubkey]));
         let req = jsonreq(json!("deposit"), json!([network, token, pubkey]));
         let rep: JsonResult;
         let rep: JsonResult;
-        match send_request(self.config.cashier_url, json!(req)).await {
+        match send_request(&self.config.cashier_url, json!(req)).await {
             Ok(v) => rep = v,
             Ok(v) => rep = v,
             Err(e) => {
             Err(e) => {
                 return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id))
                 return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id))
@@ -230,7 +230,7 @@ impl Darkfid {
         }
         }
     }
     }
 
 
-    fn parse_token(self, token: &str) -> Value {
+    fn parse_token(&self, token: &str) -> Value {
         let vec: Vec<char> = token.chars().collect();
         let vec: Vec<char> = token.chars().collect();
         let mut counter = 0;
         let mut counter = 0;
         for c in vec {
         for c in vec {
@@ -254,7 +254,7 @@ impl Darkfid {
     // dark assets to the cashier's wallet. Following that, the cashier should return
     // dark assets to the cashier's wallet. Following that, the cashier should return
     // a transaction ID of them sending the funds that are requested for withdrawal.
     // a transaction ID of them sending the funds that are requested for withdrawal.
     // <-- {"result": "txID"}
     // <-- {"result": "txID"}
-    async fn withdraw(self, id: Value, params: Value) -> JsonResult {
+    async fn withdraw(&self, id: Value, params: Value) -> JsonResult {
         let args = params.as_array().unwrap();
         let args = params.as_array().unwrap();
         if args.len() != 4 {
         if args.len() != 4 {
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
             return JsonResult::Err(jsonerr(InvalidParams, None, id));
@@ -279,7 +279,7 @@ impl Darkfid {
 
 
     // --> {"method": "transfer", [dToken, address, amount]}
     // --> {"method": "transfer", [dToken, address, amount]}
     // <-- {"result": "txID"}
     // <-- {"result": "txID"}
-    async fn transfer(self, id: Value, _params: Value) -> JsonResult {
+    async fn transfer(&self, id: Value, _params: Value) -> JsonResult {
         return JsonResult::Err(jsonerr(
         return JsonResult::Err(jsonerr(
             ServerError(-32006),
             ServerError(-32006),
             Some("failed to transfer".to_string()),
             Some("failed to transfer".to_string()),
@@ -288,7 +288,7 @@ impl Darkfid {
     }
     }
 }
 }
 
 
-#[tokio::main]
+#[async_std::main]
 async fn main() -> Result<()> {
 async fn main() -> Result<()> {
     let args = clap_app!(darkfid =>
     let args = clap_app!(darkfid =>
         (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
         (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
@@ -303,11 +303,6 @@ async fn main() -> Result<()> {
         config_path = join_config_path(&PathBuf::from("darkfid.toml"))?;
         config_path = join_config_path(&PathBuf::from("darkfid.toml"))?;
     }
     }
 
 
-    let darkfid = Darkfid::new(args.clone().is_present("verbose"), config_path)?;
-    // TODO: TLS
-    let listener = TcpListener::bind(darkfid.clone().config.rpc_url).await?;
-    debug!(target: "RPC SERVER", "Listening on {}", darkfid.clone().config.rpc_url);
-
     let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
     let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
     let debug_level = if args.is_present("verbose") {
     let debug_level = if args.is_present("verbose") {
         LevelFilter::Debug
         LevelFilter::Debug
@@ -315,7 +310,16 @@ async fn main() -> Result<()> {
         LevelFilter::Off
         LevelFilter::Off
     };
     };
 
 
-    let log_path = darkfid.clone().config.log_path;
+    let dfi = Darkfid::new(args.is_present("verbose"), config_path)?;
+
+    let cfg = RpcServerConfig {
+        socket_addr: dfi.config.clone().rpc_url,
+        use_tls: dfi.config.use_tls,
+        identity_path: dfi.config.clone().tls_identity_path,
+        identity_pass: dfi.config.clone().tls_identity_password,
+    };
+
+    let log_path = &dfi.config.log_path;
     CombinedLogger::init(vec![
     CombinedLogger::init(vec![
         TermLogger::new(debug_level, logger_config, TerminalMode::Mixed).unwrap(),
         TermLogger::new(debug_level, logger_config, TerminalMode::Mixed).unwrap(),
         WriteLogger::new(
         WriteLogger::new(
@@ -326,51 +330,7 @@ async fn main() -> Result<()> {
     ])
     ])
     .unwrap();
     .unwrap();
 
 
-    loop {
-        debug!(target: "RPC SERVER", "waiting for client");
-
-        let (mut socket, _) = listener.accept().await?;
-        let darkfid = darkfid.clone();
-
-        debug!(target: "RPC SERVER", "accepted client");
-
-        tokio::spawn(async move {
-            let mut buf = [0; 2048];
-
-            loop {
-                let n = match socket.read(&mut buf).await {
-                    Ok(n) if n == 0 => {
-                        debug!(target: "RPC SERVER", "closed connection");
-                        return;
-                    }
-                    Ok(n) => n,
-                    Err(e) => {
-                        debug!(target: "RPC SERVER", "failed to read from socket; err = {:?}", e);
-                        return;
-                    }
-                };
-
-                let r: JsonRequest = match serde_json::from_slice(&buf[0..n]) {
-                    Ok(r) => r,
-                    Err(e) => {
-                        debug!(target: "RPC SERVER", "received invalid json; err = {:?}", e);
-                        return;
-                    }
-                };
-
-                let reply = darkfid.clone().handle_request(r).await;
-                let j = serde_json::to_string(&reply).unwrap();
-
-                debug!(target: "RPC", "<-- {:#?}", j);
-
-                // Write the data back
-                if let Err(e) = socket.write_all(j.as_bytes()).await {
-                    debug!(target: "RPC SERVER", "failed to write to socket; err = {:?}", e);
-                    return;
-                }
-            }
-        });
-    }
+    listen_and_serve(cfg, dfi).await
 }
 }
 
 
 mod tests {
 mod tests {

+ 1 - 1
src/bin/drk.rs

@@ -24,7 +24,7 @@ impl Drk {
     async fn request(&self, r: jsonrpc::JsonRequest) -> Result<Value> {
     async fn request(&self, r: jsonrpc::JsonRequest) -> Result<Value> {
         let reply: JsonResult;
         let reply: JsonResult;
         debug!(target: "DRK", "--> {:#?}", serde_json::to_string(&r)?);
         debug!(target: "DRK", "--> {:#?}", serde_json::to_string(&r)?);
-        match jsonrpc::send_request(self.url.clone(), json!(r)).await {
+        match jsonrpc::send_request(&self.url, json!(r)).await {
             Ok(v) => reply = v,
             Ok(v) => reply = v,
             Err(e) => return Err(e),
             Err(e) => return Err(e),
         }
         }

+ 9 - 0
src/cli/cli_config.rs

@@ -48,6 +48,15 @@ pub struct DarkfidConfig {
     #[serde(rename = "rpc_url")]
     #[serde(rename = "rpc_url")]
     pub rpc_url: String,
     pub rpc_url: String,
 
 
+    #[serde(rename = "use_tls")]
+    pub use_tls: bool,
+
+    #[serde(rename = "tls_identity_path")]
+    pub tls_identity_path: String,
+
+    #[serde(rename = "tls_identity_password")]
+    pub tls_identity_password: String,
+
     //TODO: reimplement this
     //TODO: reimplement this
     //#[serde(rename = "database_path")]
     //#[serde(rename = "database_path")]
     //pub database_path: String,
     //pub database_path: String,

+ 1 - 1
src/rpc/jsonrpc.rs

@@ -130,7 +130,7 @@ pub fn notification(m: Value, p: Value) -> JsonNotification {
     }
     }
 }
 }
 
 
-pub async fn send_request(url: String, data: Value) -> Result<JsonResult, Error> {
+pub async fn send_request(url: &str, data: Value) -> Result<JsonResult, Error> {
     // TODO: TLS
     // TODO: TLS
     let mut buf = [0; 2048];
     let mut buf = [0; 2048];
     let mut stream = TcpStream::connect(url).await?;
     let mut stream = TcpStream::connect(url).await?;