From b1f31a0de82e55a2df38825989f5c6dbd1464c1f Mon Sep 17 00:00:00 2001 From: Waylon Cude Date: Sat, 30 May 2026 22:06:59 -0700 Subject: [PATCH] Add media directory commands --- Cargo.lock | 2 +- Cargo.toml | 5 +++-- src/cli.rs | 45 +++++++++++++++++++++++++++++++++++---------- src/main.rs | 13 +++++++++++++ 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a669adf..c8b5d28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -397,7 +397,6 @@ dependencies = [ [[package]] name = "fedichat" version = "0.1.0" -source = "git+https://git.firechicken.net/fedichat/fedichat-lib#53398bf4ea611fb8bdff973e348d8bf9d37708ea" dependencies = [ "serde", "serde_bytes", @@ -424,6 +423,7 @@ dependencies = [ "toml", "tracing", "tracing-subscriber", + "uuid", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0d47db7..879bb3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] quinn = "0.11.9" -fedichat = {git = "https://git.firechicken.net/fedichat/fedichat-lib"} -#fedichat = {path = "../fedichat-lib"} +#fedichat = {git = "https://git.firechicken.net/fedichat/fedichat-lib"} +fedichat = {path = "../fedichat-lib"} tracing = "0.1.44" tracing-subscriber = "0.3.23" clap = { version = "4.6.1", features = ["derive"] } @@ -20,3 +20,4 @@ dotenv = "0.15.0" time = { version = "0.3.47", features = ["serde"] } hickory-resolver = "0.26.1" expanduser = "1.2.2" +uuid = { version = "1.23.2", features = ["v4"] } diff --git a/src/cli.rs b/src/cli.rs index 3d61b75..48bd66c 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,8 +2,12 @@ use clap::{Parser,Subcommand,ArgAction}; use fedichat::client::{ClientMessage,SignedClientMessage,AuthMethod}; use fedichat::ServerAddr; use fedichat::state::StatePath; +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; use time::OffsetDateTime; use thiserror::Error; +use uuid::Uuid; // Everything except server, user, and password lives in these @@ -61,6 +65,15 @@ pub enum Command { #[clap(short, long, value_parser=Room::from_str)] room: Room, }, + Upload { + file: PathBuf, + }, + Fetch { + #[clap(short, long)] + id: String, + #[clap(short, long)] + file: PathBuf + }, GetState { #[clap(short, long, value_parser=Room::from_str)] room: Room, @@ -90,9 +103,9 @@ pub enum Command { } impl Command { // Returns clientmessage and target server - fn into_client_message(self,username: String) -> (ClientMessage,Option) { + fn into_client_message(self,username: String) -> Result<(ClientMessage,Option),MessageError> { use Command::*; - match self { + Ok(match self { CreateUser { password, } => (ClientMessage::UserCreate {username, password},None), @@ -118,6 +131,14 @@ impl Command { Create { room, } => (ClientMessage::RoomCreate{room_id: room.get_coord()},room.get_server()), + Upload {file} => { + let mut buf = Vec::with_capacity(4096); + let mut file = File::open(file)?; + file.read_to_end(&mut buf)?; + (ClientMessage::MediaUpload{bytes: buf},None) + + }, + Fetch {file: _, id} => (ClientMessage::MediaFetch{id: Uuid::parse_str(&id)?},None), GetState { room, path, @@ -137,20 +158,19 @@ impl Command { body, user, } => (ClientMessage::MessagePost{body, user: user.clone()},Some(ServerAddr(user.server))), - - } + }) } - pub fn into_signed_message(self, username: String) -> SignedClientMessage { - let (message,target) = self.into_client_message(username); - SignedClientMessage { + pub fn into_signed_message(self, username: String) -> Result { + let (message,target) = self.into_client_message(username)?; + Ok(SignedClientMessage { message, target, timestamp: OffsetDateTime::now_utc(), // TODO: actually implement signatures signature: Box::new([0]) - } + }) } pub fn needs_auth(&self) -> bool { @@ -180,7 +200,7 @@ impl Command { signature: Box::new([0]) }) } - messages.push(self.into_signed_message(username)); + messages.push(self.into_signed_message(username)?); // If this message is authenticating us then we should be generating // a new token and saving it for future commands if !needs_auth { @@ -198,7 +218,12 @@ impl Command { #[derive(Error,Debug)] pub enum MessageError { #[error("Command needs a token. Login or create an account first.")] - NoToken + NoToken, + #[error("Error while parsing uuid: {0}")] + UuidError(#[from] uuid::Error), + #[error("Error during file IO: {0}")] + IoError(#[from] std::io::Error), + } diff --git a/src/main.rs b/src/main.rs index 40b8784..43a0887 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,8 @@ use clap::Parser; use fedichat::client::ServerMessage; use hickory_resolver::Resolver; use std::net::{IpAddr,SocketAddr}; +use std::fs::File; +use std::io::Write; use quinn::Endpoint; use rmp_serde::encode::Serializer; use serde::Serialize; @@ -76,11 +78,18 @@ async fn main() -> Result<(), Box> { SocketAddr::new(response,PORT), &target_server)?.await?; + // Dumb pattern + let mut file_to_write = None; + if let Command::Fetch{file, ..} = &cli.command { + file_to_write = Some(file.clone()); + } + // send messages, each time waiting for a response let messages = cli.command.generate_messages(cli.username.clone(),token)?; debug!("Sending commands"); + for message in messages { let mut buf = Vec::new(); @@ -101,6 +110,10 @@ async fn main() -> Result<(), Box> { ServerMessage::Token(ref token) => { config.insert_token(&target_server,cli.username.clone(),token.clone())?; }, + ServerMessage::Media(ref bytes) => { + let mut file = File::create(file_to_write.clone().expect("File path not specified"))?; + file.write_all(bytes)?; + }, _ => {} }