]> nmode's Git Repositories - signal-cli/blobdiff - client/src/main.rs
Switch to jsonrpsee
[signal-cli] / client / src / main.rs
index 1ad8dbcfffffafbe21cdec9badac240f0ec5783c..f4ab67f93afc3b7b332d279f1d665a6e0a2992ea 100644 (file)
@@ -1,46 +1,64 @@
-use clap::StructOpt;
-use jsonrpc_client_transports::{RpcError, TypedSubscriptionStream};
-use jsonrpc_core::{futures_util::StreamExt, Value};
 use std::{path::PathBuf, time::Duration};
+
+use clap::Parser;
+use cli::Cli;
+use jsonrpsee::core::client::{Subscription, SubscriptionClientT};
+use jsonrpsee::core::Error as RpcError;
+use serde_json::Value;
 use tokio::{select, time::sleep};
 
 use crate::cli::{GroupPermission, LinkState};
+use crate::jsonrpc::RpcClient;
 
 mod cli;
-#[allow(clippy::too_many_arguments)]
+#[allow(non_snake_case, clippy::too_many_arguments)]
 mod jsonrpc;
-mod tcp;
+mod transports;
 
 const DEFAULT_TCP: &str = "127.0.0.1:7583";
 const DEFAULT_SOCKET_SUFFIX: &str = "signal-cli/socket";
+const DEFAULT_HTTP: &str = "http://localhost:8080/api/v1/rpc";
 
 #[tokio::main]
 async fn main() -> Result<(), anyhow::Error> {
     let cli = cli::Cli::parse();
 
-    let client = connect(&cli)
-        .await
-        .map_err(|e| anyhow::anyhow!("Failed to connect to socket: {e}"))?;
+    let result = connect(cli).await;
 
-    let result = match cli.command {
+    match result {
+        Ok(Value::Null) => {}
+        Ok(v) => println!("{v}"),
+        Err(e) => return Err(anyhow::anyhow!("JSON-RPC command failed: {e:?}")),
+    }
+    Ok(())
+}
+
+async fn handle_command(
+    cli: Cli,
+    client: impl SubscriptionClientT + Sync,
+) -> Result<Value, RpcError> {
+    match cli.command {
         cli::CliCommands::Receive { timeout } => {
-            let mut stream = client
-                .subscribe_receive(cli.account)
-                .map_err(|e| anyhow::anyhow!("JSON-RPC command failed: {:?}", e))?;
+            let mut stream = client.subscribe_receive(cli.account).await?;
 
             {
                 while let Some(v) = stream_next(timeout, &mut stream).await {
-                    let v = v.map_err(|e| anyhow::anyhow!("JSON-RPC command failed: {:?}", e))?;
+                    let v = v?;
                     println!("{v}");
                 }
             }
-            return Ok(());
+            Ok(Value::Null)
         }
         cli::CliCommands::AddDevice { uri } => client.add_device(cli.account, uri).await,
         cli::CliCommands::Block {
             recipient,
             group_id,
         } => client.block(cli.account, recipient, group_id).await,
+        cli::CliCommands::DeleteLocalAccountData { ignore_registered } => {
+            client
+                .delete_local_account_data(cli.account, ignore_registered)
+                .await
+        }
         cli::CliCommands::GetUserStatus { recipient } => {
             client.get_user_status(cli.account, recipient).await
         }
@@ -49,15 +67,27 @@ async fn main() -> Result<(), anyhow::Error> {
             let url = client
                 .start_link(cli.account)
                 .await
-                .map_err(|e| anyhow::anyhow!("JSON-RPC command startLink failed: {e:?}",))?
+                .map_err(|e| RpcError::Custom(format!("JSON-RPC command startLink failed: {e:?}")))?
                 .device_link_uri;
             println!("{}", url);
             client.finish_link(url, name).await
         }
         cli::CliCommands::ListAccounts => client.list_accounts().await,
-        cli::CliCommands::ListContacts => client.list_contacts(cli.account).await,
+        cli::CliCommands::ListContacts {
+            recipient,
+            all_recipients,
+            blocked,
+            name,
+        } => {
+            client
+                .list_contacts(cli.account, recipient, all_recipients, blocked, name)
+                .await
+        }
         cli::CliCommands::ListDevices => client.list_devices(cli.account).await,
-        cli::CliCommands::ListGroups { detailed: _ } => client.list_groups(cli.account).await,
+        cli::CliCommands::ListGroups {
+            detailed: _,
+            group_id,
+        } => client.list_groups(cli.account, group_id).await,
         cli::CliCommands::ListIdentities { number } => {
             client.list_identities(cli.account, number).await
         }
@@ -110,6 +140,8 @@ async fn main() -> Result<(), anyhow::Error> {
             quote_message,
             quote_mention,
             sticker,
+            story_timestamp,
+            story_author,
         } => {
             client
                 .send(
@@ -126,10 +158,21 @@ async fn main() -> Result<(), anyhow::Error> {
                     quote_message,
                     quote_mention,
                     sticker,
+                    story_timestamp,
+                    story_author,
                 )
                 .await
         }
         cli::CliCommands::SendContacts => client.send_contacts(cli.account).await,
+        cli::CliCommands::SendPaymentNotification {
+            recipient,
+            receipt,
+            note,
+        } => {
+            client
+                .send_payment_notification(cli.account, recipient, receipt, note)
+                .await
+        }
         cli::CliCommands::SendReaction {
             recipient,
             group_id,
@@ -138,6 +181,7 @@ async fn main() -> Result<(), anyhow::Error> {
             target_author,
             target_timestamp,
             remove,
+            story,
         } => {
             client
                 .send_reaction(
@@ -149,6 +193,7 @@ async fn main() -> Result<(), anyhow::Error> {
                     target_author,
                     target_timestamp,
                     remove,
+                    story,
                 )
                 .await
         }
@@ -243,6 +288,8 @@ async fn main() -> Result<(), anyhow::Error> {
             remove_member,
             admin,
             remove_admin,
+            ban,
+            unban,
             reset_link,
             link,
             set_permission_add_member,
@@ -261,6 +308,8 @@ async fn main() -> Result<(), anyhow::Error> {
                     remove_member,
                     admin,
                     remove_admin,
+                    ban,
+                    unban,
                     reset_link,
                     link.map(|link| match link {
                         LinkState::Enabled => "enabled".to_owned(),
@@ -288,6 +337,7 @@ async fn main() -> Result<(), anyhow::Error> {
             family_name,
             about,
             about_emoji,
+            mobile_coin_address,
             avatar,
             remove_avatar,
         } => {
@@ -298,6 +348,7 @@ async fn main() -> Result<(), anyhow::Error> {
                     family_name,
                     about,
                     about_emoji,
+                    mobile_coin_address,
                     avatar,
                     remove_avatar,
                 )
@@ -311,18 +362,28 @@ async fn main() -> Result<(), anyhow::Error> {
             pin,
         } => client.verify(cli.account, verification_code, pin).await,
         cli::CliCommands::Version => client.version().await,
-    };
-
-    result
-        .map(|v| println!("{v}"))
-        .map_err(|e| anyhow::anyhow!("JSON-RPC command failed: {e:?}",))?;
-    Ok(())
+    }
 }
 
-async fn connect(cli: &cli::Cli) -> Result<jsonrpc::SignalCliClient, RpcError> {
-    if let Some(tcp) = cli.json_rpc_tcp {
+async fn connect(cli: Cli) -> Result<Value, RpcError> {
+    if let Some(http) = &cli.json_rpc_http {
+        let uri = if let Some(uri) = http {
+            uri
+        } else {
+            DEFAULT_HTTP
+        };
+        let client = jsonrpc::connect_http(uri)
+            .await
+            .map_err(|e| RpcError::Custom(format!("Failed to connect to socket: {e}")))?;
+
+        handle_command(cli, client).await
+    } else if let Some(tcp) = cli.json_rpc_tcp {
         let socket_addr = tcp.unwrap_or_else(|| DEFAULT_TCP.parse().unwrap());
-        jsonrpc::connect_tcp(socket_addr).await
+        let client = jsonrpc::connect_tcp(socket_addr)
+            .await
+            .map_err(|e| RpcError::Custom(format!("Failed to connect to socket: {e}")))?;
+
+        handle_command(cli, client).await
     } else {
         let socket_path = cli
             .json_rpc_socket
@@ -336,13 +397,17 @@ async fn connect(cli: &cli::Cli) -> Result<jsonrpc::SignalCliClient, RpcError> {
                 })
             })
             .unwrap_or_else(|| ("/run".to_owned() + DEFAULT_SOCKET_SUFFIX).into());
-        jsonrpc::connect_unix(socket_path).await
+        let client = jsonrpc::connect_unix(socket_path)
+            .await
+            .map_err(|e| RpcError::Custom(format!("Failed to connect to socket: {e}")))?;
+
+        handle_command(cli, client).await
     }
 }
 
 async fn stream_next(
     timeout: f64,
-    stream: &mut TypedSubscriptionStream<Value>,
+    stream: &mut Subscription<Value>,
 ) -> Option<Result<Value, RpcError>> {
     if timeout < 0.0 {
         stream.next().await