| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- use std::{str::FromStr as _, time::Duration};
- use url::Url;
- use utils::{binary::checksum, serialize::Serialize as _};
- use crate::{API_DEFAULT_PORT, message::Message};
- #[derive(Debug)]
- pub enum UrlError {
- ParseError(url::ParseError),
- DomainBasePortError,
- }
- pub fn fix_url(url: &str) -> Result<String, UrlError> {
- let mut url: String = url.to_string();
- if !url.starts_with("http://") && !url.starts_with("https://") {
- url = format!("http://{}", url);
- }
- let mut url = Url::from_str(&url).map_err(|x| UrlError::ParseError(x))?;
- if url.port().is_none() {
- url.set_port(Some(API_DEFAULT_PORT)).map_err(|_| UrlError::DomainBasePortError)?;
- }
- let mut url = url.to_string();
- if !url.ends_with('/') {
- url.push('/');
- }
- 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)
- }
- #[test]
- fn test_tx_rx() {
- let host = "http://localhost:13337/";
- let password = "null";
- let message = Message::new("Alice", "Hello", "root");
- tx_message(host, password, 5, message.clone()).expect("Failed to send message");
- let messages = rx_messages(host, password, 5).expect("Failed to receive messages");
- assert_eq!(messages.len(), 1);
- assert_eq!(messages[0].sender, message.sender);
- assert_eq!(messages[0].content, message.content);
- }
|