Răsfoiți Sursa

darkfid/wallet: Implement RPC queries for multiple rows.

parazyd 3 ani în urmă
părinte
comite
82d907dbe3
2 a modificat fișierele cu 97 adăugiri și 0 ștergeri
  1. 3 0
      bin/darkfid/src/main.rs
  2. 94 0
      bin/darkfid/src/rpc_wallet.rs

+ 3 - 0
bin/darkfid/src/main.rs

@@ -226,6 +226,9 @@ impl RequestHandler for Darkfid {
             Some("wallet.query_row_single") => {
                 return self.wallet_query_row_single(req.id, params).await
             }
+            Some("wallet.query_row_multi") => {
+                return self.wallet_query_row_multi(req.id, params).await
+            }
             // ==============
             // Invalid method
             // ==============

+ 94 - 0
bin/darkfid/src/rpc_wallet.rs

@@ -128,6 +128,100 @@ impl Darkfid {
         JsonResponse::new(json!(ret), id).into()
     }
 
+    // RPCAPI:
+    // Attempts to query for all available rows in a given table.
+    // The parameters given contain paired metadata so we know how to decode the SQL data.
+    // They're the same as above in `wallet.query_row_single`.
+    // If there are any values found, they will be returned in a paired array. If not, an
+    // empty array will be returned.
+    //
+    // --> {"jsonrpc": "2.0", "method": "wallet.query_row_multi", "params": [...], "id": 1}
+    // <-- {"jsonrpc": "2.0", "result": [["va", "lu"], ["es", "es"], ...], "id": 1}
+    pub async fn wallet_query_row_multi(&self, id: Value, params: &[Value]) -> JsonResult {
+        // We need at least 3 params for something we want to fetch, and we want them in pairs.
+        // Also the first param (the query) should be a String.
+        if params.len() < 3 || params[1..].len() % 2 != 0 || !params[0].is_string() {
+            return JsonError::new(InvalidParams, None, id).into()
+        }
+
+        // The remaining pairs should be typed properly too
+        let mut types: Vec<QueryType> = vec![];
+        let mut names: Vec<&str> = vec![];
+        for pair in params[1..].chunks(2) {
+            if !pair[0].is_u64() || !pair[1].is_string() {
+                return JsonError::new(InvalidParams, None, id).into()
+            }
+
+            let typ = pair[0].as_u64().unwrap();
+            if typ >= QueryType::Last as u64 {
+                return JsonError::new(InvalidParams, None, id).into()
+            }
+
+            types.push((typ as u8).into());
+            names.push(pair[1].as_str().unwrap());
+        }
+
+        // Get a wallet connection
+        let mut conn = match self.wallet.conn.acquire().await {
+            Ok(v) => v,
+            Err(e) => {
+                error!("[RPC] wallet.query_row_multi: Failed to acquire wallet connection: {}", e);
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+
+        // Execute the query and see if we find any rows
+        let rows = match sqlx::query(params[0].as_str().unwrap()).fetch_all(&mut conn).await {
+            Ok(v) => v,
+            Err(e) => {
+                error!("[RPC] wallet.query_row_multi: Failed to execute SQL query: {}", e);
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+
+        debug!("[RPC] wallet.query_row_multi: Found {} rows", rows.len());
+
+        // Try to decode whatever we've found
+        let mut ret: Vec<Vec<Value>> = vec![];
+
+        for row in rows {
+            let mut row_ret: Vec<Value> = vec![];
+            for (typ, col) in types.iter().zip(names.clone()) {
+                match typ {
+                    QueryType::Integer => {
+                        let value: i32 = match row.try_get(col) {
+                            Ok(v) => v,
+                            Err(e) => {
+                                error!("[RPC] wallet.query_row_multi: {}", e);
+                                return JsonError::new(ParseError, None, id).into()
+                            }
+                        };
+
+                        row_ret.push(json!(value));
+                    }
+
+                    QueryType::Blob => {
+                        let value: Vec<u8> = match row.try_get(col) {
+                            Ok(v) => v,
+                            Err(e) => {
+                                error!("[RPC] wallet.query_row_multi: {}", e);
+                                return JsonError::new(ParseError, None, id).into()
+                            }
+                        };
+
+                        row_ret.push(json!(value));
+                    }
+
+                    _ => unreachable!(),
+                }
+            }
+
+            ret.push(row_ret);
+        }
+
+        JsonResponse::new(json!(ret), id).into()
+    }
+
     // RPCAPI:
     // Executes an arbitrary SQL query on the wallet, and returns `true` on success.
     // `params[1..]` can optionally be provided in pairs like in `wallet.query_row_single`.