Parcourir la source

Move message send/receive functions to shared

Rain il y a 1 mois
Parent
commit
40ebec68d4
7 fichiers modifiés avec 131 ajouts et 213 suppressions
  1. 0 3
      client/Cargo.toml
  2. 8 81
      client/src/actions.rs
  3. 26 23
      client/src/ui.rs
  4. 0 3
      client_cli/Cargo.toml
  5. 4 101
      client_cli/src/main.rs
  6. 3 0
      client_shared/Cargo.toml
  7. 90 2
      client_shared/src/utils.rs

+ 0 - 3
client/Cargo.toml

@@ -11,6 +11,3 @@ logging = { path = "../logging" }
 
 cursive = "0.21"
 cli-clipboard = "0.4.0"
-
-# TODO: Write an HTTP client.
-reqwest = { version = "0.12.15", features = [ "blocking" ] }

+ 8 - 81
client/src/actions.rs

@@ -1,8 +1,6 @@
-use std::time::Duration;
-
-use client_shared::{API_CONNECTION_TIMEOUT, message::Message, persistence::Appdata, utils::fix_url};
+use client_shared::{API_CONNECTION_TIMEOUT, message::Message, persistence::Appdata, utils::{ConnectionError, rx_messages, tx_message}};
 use cursive::{views::TextArea, Cursive};
-use utils::{binary::checksum, hash::Hashable as _, serialize::Serialize as _};
+use utils::hash::Hashable as _;
 
 use crate::{get_appdata, ui};
 
@@ -87,93 +85,22 @@ pub fn clear_input_field(siv: &mut Cursive) {
     .expect("Failed to clear input field.");
 }
 
-type StatusCode = u16;
-
-#[allow(dead_code)]
-pub enum NetworkError {
-    ReqwestError(reqwest::Error),
-    StatusCodeError(StatusCode),
-    EncryptionError(utils::aes::AesError),
-    UrlError(client_shared::utils::UrlError),
-}
-
-pub fn send_message(siv: &mut Cursive, mut message: Message) -> Result<(), NetworkError> {
+pub fn send_message(siv: &mut Cursive, mut message: Message) -> Result<(), ConnectionError> {
     message.sanitize();
 
     let appdata = get_appdata(siv);
-    let url = fix_url(&appdata.persistent_data.api_endpoint).map_err(|x| NetworkError::UrlError(x))?;
+    let url = appdata.persistent_data.api_endpoint;
     let password = appdata.persistent_data.api_password;
 
-    let mut bytes = message.serialize_checked();
-    utils::aes::encrypt_cbc(&mut bytes, &password);
-    bytes.push(checksum(&bytes));
-
-    let str = utils::binary::bin2hex(bytes);
-
-    let resp = reqwest::blocking::Client::new()
-        .post(format!("{}", url))
-        .body(str)
-        .timeout(Duration::from_secs(API_CONNECTION_TIMEOUT))
-        .send()
-        .map_err(|e| NetworkError::ReqwestError(e))?;
-
-    if resp.status().is_success() {
-        Ok(())
-    } else {
-        Err(NetworkError::StatusCodeError(resp.status().as_u16()))
-    }
+    tx_message(&url, &password, API_CONNECTION_TIMEOUT, message)
 }
 
-pub fn load_messages(siv: &mut Cursive) -> Result<(), NetworkError> {
+pub fn load_messages(siv: &mut Cursive) -> Result<(), ConnectionError> {
     let appdata = get_appdata(siv);
-    let url = fix_url(&appdata.persistent_data.api_endpoint).map_err(|x| NetworkError::UrlError(x))?;
+    let url = appdata.persistent_data.api_endpoint;
     let password = appdata.persistent_data.api_password;
 
-    let resp = reqwest::blocking::Client::new()
-        .get(url)
-        .timeout(Duration::from_secs(API_CONNECTION_TIMEOUT))
-        .send()
-        .map_err(|e| NetworkError::ReqwestError(e))?;
-
-    if resp.status() != reqwest::StatusCode::OK {
-        return Err(NetworkError::StatusCodeError(resp.status().as_u16()));
-    }
-
-    let bytes = resp.bytes().map_err(|e| NetworkError::ReqwestError(e))?;
-
-    let contents = String::from_utf8_lossy(&bytes);
-    let mut messages = vec![];
-
-    for message_ser_hex in contents.split(",") {
-        let Some(mut message_ser_bin) = utils::binary::hex2bin(message_ser_hex) else {
-            continue;
-        };
-
-        if message_ser_bin.len() < 2 {
-            continue;
-        }
-
-        // Checksum before decryption
-        if checksum(&message_ser_bin[..message_ser_bin.len()-1]) != message_ser_bin[message_ser_bin.len()-1] {
-            continue;
-        }
-
-        // Remove checksum
-        message_ser_bin.pop();
-
-        if utils::aes::decrypt_cbc(&mut message_ser_bin, &password).is_err() {
-            continue;
-        }
-
-        let Ok(mut message) = Message::deserialize_checked(message_ser_bin) else {
-            continue;
-        };
-
-        if message.is_valid() {
-            message.sanitize();
-            messages.push(message);
-        }
-    }
+    let messages = rx_messages(&url, &password, API_CONNECTION_TIMEOUT)?;
 
     siv.with_user_data(|appdata: &mut Appdata| {
         for message in messages {

+ 26 - 23
client/src/ui.rs

@@ -1,5 +1,6 @@
 use cli_clipboard::ClipboardProvider as _;
 use client_shared::message::{self, MessageSanitized};
+use client_shared::utils::ConnectionError;
 use client_shared::{DEFAULT_PASSWORD, MAX_MESSAGE_LENGTH, MAX_USERNAME_LENGTH};
 use client_shared::ui::Language;
 use cursive::view::{Nameable as _, Resizable as _};
@@ -10,7 +11,7 @@ use cursive::views::{
 use cursive::{event, Cursive};
 use utils::hash::Hashable as _;
 
-use crate::actions::{self, NetworkError};
+use crate::actions;
 use crate::{
     get_appdata, save_appdata, Appdata
 };
@@ -69,8 +70,8 @@ pub enum Labels {
     InvalidMessage,
     Success,
     SuccessfullySentMessage,
-    FailedToSendMessage(NetworkError),
-    FailedToLoadMessages(NetworkError),
+    FailedToSendMessage(ConnectionError),
+    FailedToLoadMessages(ConnectionError),
     RefreshButton,
     BlockedWords,
     ServerSettings,
@@ -117,14 +118,14 @@ impl Labels {
                 let reason_buf: [String; 3];
 
                 match e {
-                    NetworkError::ReqwestError(_) => {
+                    ConnectionError::ReqwestError(_) => {
                         reason_buf = [
                             "Connection error.".to_string(),
                             "Verbindingsfout.".to_string(),
                             "接続エラー。".to_string(),
                         ];
                     }
-                    NetworkError::StatusCodeError(code) => {
+                    ConnectionError::StatusCodeError(code) => {
                         // NOTE: Needs to match the server
                         if *code == 400 {
                             reason_buf = [
@@ -140,20 +141,21 @@ impl Labels {
                             ]
                         }
                     }
-                    NetworkError::UrlError(_) => {
+                    ConnectionError::UrlError(_) => {
                         reason_buf = [
                             "Invalid URL.".to_string(),
                             "Ongeldig URL.".to_string(),
                             "無効なURL。".to_string(),
                         ];
                     }
-                    NetworkError::EncryptionError(_) => {
-                        reason_buf = [
-                            "Encryption error.".to_string(),
-                            "Encryptiefout.".to_string(),
-                            "暗号化エラー。".to_string(),
-                        ];
-                    }
+                    // TODO: Check if it's safe to remove this.
+                    // ConnectionError::EncryptionError(_) => {
+                    //     reason_buf = [
+                    //         "Encryption error.".to_string(),
+                    //         "Encryptiefout.".to_string(),
+                    //         "暗号化エラー。".to_string(),
+                    //     ];
+                    // }
                 };
 
                 buf = [
@@ -168,34 +170,35 @@ impl Labels {
                 let reason_buf: [String; 3];
 
                 match error {
-                    NetworkError::ReqwestError(_) => {
+                    ConnectionError::ReqwestError(_) => {
                         reason_buf = [
                             "Connection error.".to_string(),
                             "Verbindingsfout.".to_string(),
                             "接続エラー。".to_string(),
                         ];
                     }
-                    NetworkError::StatusCodeError(code) => {
+                    ConnectionError::StatusCodeError(code) => {
                         reason_buf = [
                             format!("Status code: {code}"),
                             format!("Statuscode: {code}"),
                             format!("ステータスコード: {code}"),
                         ];
                     }
-                    NetworkError::UrlError(_) => {
+                    ConnectionError::UrlError(_) => {
                         reason_buf = [
                             "Invalid URL.".to_string(),
                             "Ongeldig URL.".to_string(),
                             "無効なURL。".to_string(),
                         ];
                     }
-                    NetworkError::EncryptionError(_) => {
-                        reason_buf = [
-                            "Decryption error.".to_string(),
-                            "Fout bij het ontcijferen.".to_string(),
-                            "復号エラー".to_string(),
-                        ];
-                    }
+                    // TODO: Check if it's safe to remove this.
+                    // ConnectionError::EncryptionError(_) => {
+                    //     reason_buf = [
+                    //         "Decryption error.".to_string(),
+                    //         "Fout bij het ontcijferen.".to_string(),
+                    //         "復号エラー".to_string(),
+                    //     ];
+                    // }
                 };
 
                 buf = [

+ 0 - 3
client_cli/Cargo.toml

@@ -9,7 +9,4 @@ utils = { path = "../utils" }
 logging = { path = "../logging" }
 
 clap = { version = "4.5.60", features = ["derive"] }
-
-# TODO: Write an HTTP client.
-reqwest = { version = "0.12.15", features = [ "blocking" ] }
 json = "0.12.4"

+ 4 - 101
client_cli/src/main.rs

@@ -1,8 +1,6 @@
-use std::{path::PathBuf, time::Duration};
-
 use clap::{Parser, Subcommand};
-use client_shared::{message::Message, utils::{UrlError, fix_url}};
-use utils::{binary::checksum, serialize::Serialize as _, time::time_millis};
+use client_shared::{message::Message, utils::{rx_messages, tx_message}};
+use utils::time::time_millis;
 
 #[derive(Parser, Debug)]
 #[command(version, about, long_about = None)]
@@ -21,14 +19,6 @@ struct Args {
     )]
     password: String,
 
-    #[arg(
-        short = 'B',
-        id = "BLOCKED_WORDS_FILE",
-        required = false,
-        help = "A file containing blocked words separated by newlines.\nExample: \n\tWord1\n\tWord2\n\tWord3\n\t...",
-    )]
-    blocked_words: Option<PathBuf>,
-
     #[arg(
         long = "timeout",
         id = "TIMEOUT",
@@ -77,13 +67,12 @@ enum Commands {
     }
 }
 
-
 fn main() {
     let args = Args::parse();
 
     match args.command {
         Commands::Get { json } => {
-            let mut messages = load_messages(&args)
+            let mut messages = rx_messages(&args.host, &args.password, args.timeout_sec)
                 .expect("Failed to load messages.");
 
             messages.sort_by(|a, b| {
@@ -118,94 +107,8 @@ fn main() {
 
             message.sanitize();
 
-            send_message(&args, message)
+            tx_message(&args.host, &args.password, args.timeout_sec, message)
                 .expect("Failed to send message.");
         },
     }
 }
-
-#[derive(Debug)]
-#[allow(unused)]
-enum ClientError {
-    UrlError(UrlError),
-    ReqwestError(reqwest::Error),
-    StatusCodeError(u16),
-}
-
-fn send_message(args: &Args, message: Message) -> Result<(), ClientError> {
-    let url = fix_url(&args.host)
-        .map_err(|x| ClientError::UrlError(x))?;
-
-    let mut bytes = message.serialize_checked();
-    utils::aes::encrypt_cbc(&mut bytes, &args.password);
-    bytes.push(checksum(&bytes));
-
-    let str = utils::binary::bin2hex(bytes);
-
-    let resp = reqwest::blocking::Client::new()
-        .post(format!("{}", url))
-        .body(str)
-        .timeout(Duration::from_secs(args.timeout_sec))
-        .send()
-        .map_err(|e| ClientError::ReqwestError(e))?;
-
-    if resp.status().is_success() {
-        Ok(())
-    } else {
-        Err(ClientError::StatusCodeError(resp.status().as_u16()))
-    }
-}
-
-fn load_messages(args: &Args) -> Result<Vec<Message>, ClientError> {
-    let url = fix_url(&args.host)
-        .map_err(|x| ClientError::UrlError(x))?;
-
-    let resp = reqwest::blocking::Client::new()
-        .get(url)
-        .timeout(Duration::from_secs(args.timeout_sec))
-        .send()
-        .map_err(|x| ClientError::ReqwestError(x))?;
-
-    if resp.status() != reqwest::StatusCode::OK {
-        return Err(ClientError::StatusCodeError(resp.status().as_u16()));
-    }
-
-    let bytes = resp.bytes()
-        .map_err(|e| ClientError::ReqwestError(e))?;
-
-    let contents = String::from_utf8_lossy(&bytes);
-    let mut messages = vec![];
-
-    for message_ser_hex in contents.split(",") {
-        let Some(mut message_ser_bin) = utils::binary::hex2bin(message_ser_hex) else {
-            continue;
-        };
-
-        if message_ser_bin.len() < 2 {
-            continue;
-        }
-
-        // Checksum before decryption
-        if checksum(&message_ser_bin[..message_ser_bin.len()-1]) != message_ser_bin[message_ser_bin.len()-1] {
-            continue;
-        }
-
-        // Remove checksum
-        message_ser_bin.pop();
-
-        if utils::aes::decrypt_cbc(&mut message_ser_bin, &args.password).is_err() {
-            continue;
-        }
-
-        let Ok(message) = Message::deserialize_checked(message_ser_bin) else {
-            continue;
-        };
-
-        if message.is_valid() {
-            messages.push(message);
-        }
-    }
-
-    Ok(messages)
-}
-

+ 3 - 0
client_shared/Cargo.toml

@@ -7,4 +7,7 @@ edition = "2024"
 logging = { path = "../logging" }
 utils = { path = "../utils" }
 
+# TODO: Write an HTTP client.
+reqwest = { version = "0.12.15", features = [ "blocking" ] }
+
 url = "2.5.8"

+ 90 - 2
client_shared/src/utils.rs

@@ -1,9 +1,10 @@
 
-use std::str::FromStr as _;
+use std::{str::FromStr as _, time::Duration};
 
 use url::Url;
+use utils::{binary::checksum, serialize::Serialize as _};
 
-use crate::API_DEFAULT_PORT;
+use crate::{API_DEFAULT_PORT, message::Message};
 
 #[derive(Debug)]
 pub enum UrlError {
@@ -32,3 +33,90 @@ pub fn fix_url(url: &str) -> Result<String, UrlError> {
 
     Ok(url)
 }
+
+#[derive(Debug)]
+pub enum ConnectionError {
+    UrlError(UrlError),
+    ReqwestError(reqwest::Error),
+    StatusCodeError(u16),
+}
+
+pub fn tx_message(host: &str, password: &str, timeout_sec: u64, mut message: Message) -> Result<(), ConnectionError> {
+    message.sanitize();
+
+    let url = fix_url(host)
+        .map_err(|x| ConnectionError::UrlError(x))?;
+
+    let mut bytes = message.serialize_checked();
+    utils::aes::encrypt_cbc(&mut bytes, &password);
+    bytes.push(checksum(&bytes));
+
+    let str = utils::binary::bin2hex(bytes);
+
+    let resp = reqwest::blocking::Client::new()
+        .post(url)
+        .body(str)
+        .timeout(Duration::from_secs(timeout_sec))
+        .send()
+        .map_err(|e| ConnectionError::ReqwestError(e))?;
+
+    if resp.status().is_success() {
+        Ok(())
+    } else {
+        Err(ConnectionError::StatusCodeError(resp.status().as_u16()))
+    }
+}
+
+pub fn rx_messages(host: &str, password: &str, timeout_sec: u64) -> Result<Vec<Message>, ConnectionError> {
+    let url = fix_url(host)
+        .map_err(|x| ConnectionError::UrlError(x))?;
+
+    let resp = reqwest::blocking::Client::new()
+        .get(url)
+        .timeout(Duration::from_secs(timeout_sec))
+        .send()
+        .map_err(|x| ConnectionError::ReqwestError(x))?;
+
+    if resp.status() != reqwest::StatusCode::OK {
+        return Err(ConnectionError::StatusCodeError(resp.status().as_u16()));
+    }
+
+    let bytes = resp.bytes()
+        .map_err(|e| ConnectionError::ReqwestError(e))?;
+
+    let contents = String::from_utf8_lossy(&bytes);
+    let mut messages = vec![];
+
+    for message_ser_hex in contents.split(",") {
+        let Some(mut message_ser_bin) = utils::binary::hex2bin(message_ser_hex) else {
+            continue;
+        };
+
+        if message_ser_bin.len() < 2 {
+            continue;
+        }
+
+        // Checksum before decryption
+        if checksum(&message_ser_bin[..message_ser_bin.len()-1]) != message_ser_bin[message_ser_bin.len()-1] {
+            continue;
+        }
+
+        // Remove checksum
+        message_ser_bin.pop();
+
+        if utils::aes::decrypt_cbc(&mut message_ser_bin, &password).is_err() {
+            continue;
+        }
+
+        let Ok(mut message) = Message::deserialize_checked(message_ser_bin) else {
+            continue;
+        };
+
+        if message.is_valid() {
+            message.sanitize();
+            messages.push(message);
+        }
+    }
+
+    Ok(messages)
+}