diff options
Diffstat (limited to 'client-native-rift/src/main.rs')
-rw-r--r-- | client-native-rift/src/main.rs | 155 |
1 files changed, 14 insertions, 141 deletions
diff --git a/client-native-rift/src/main.rs b/client-native-rift/src/main.rs index f3db429..b839ee2 100644 --- a/client-native-rift/src/main.rs +++ b/client-native-rift/src/main.rs @@ -4,12 +4,13 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ #![allow(clippy::type_complexity)] +pub mod command; pub mod file; pub mod port; +pub mod repl; -use anyhow::bail; +use crate::command::dispatch_command; use clap::{ColorChoice, Parser}; -use file::{DownloadHandler, FileSender}; use libkeks::{ instance::Instance, peer::{Peer, TransportChannel}, @@ -18,13 +19,11 @@ use libkeks::{ Config, DynFut, EventHandler, }; use log::{error, info, trace, warn}; -use port::{ForwardHandler, PortExposer}; -use rustyline::{error::ReadlineError, DefaultEditor}; +use repl::repl; use std::{ - collections::HashMap, future::Future, os::unix::prelude::MetadataExt, path::PathBuf, pin::Pin, - process::exit, sync::Arc, + collections::HashMap, future::Future, path::PathBuf, pin::Pin, process::exit, sync::Arc, }; -use tokio::{fs, net::TcpListener, sync::RwLock}; +use tokio::sync::RwLock; use users::get_current_username; fn main() { @@ -64,6 +63,11 @@ pub struct Args { pub enum Command { /// List all peers and their services. List, + /// Stop providing a services by ID. + Stop { + // IDs of the services to stop. If ommited, all services are stopped. + ids: Vec<String>, + }, /// Provide a file for download to other peers Provide { path: PathBuf, id: Option<String> }, /// Download another peer's files. @@ -128,144 +132,13 @@ async fn run() -> anyhow::Result<()> { }; info!("done"); } - let mut rl = DefaultEditor::new()?; - loop { - match rl.readline("> ") { - Ok(line) => match shlex::split(&line) { - Some(tokens) => match Command::try_parse_from(tokens) { - Ok(command) => match dispatch_command(&inst, &state, command).await { - Ok(()) => (), - Err(err) => error!("{err}"), - }, - Err(err) => err.print().unwrap(), - }, - None => warn!("fix your quoting"), - }, - Err(ReadlineError::Eof) => { - info!("exit"); - break; - } - Err(ReadlineError::Interrupted) => { - info!("interrupted; exiting..."); - break; - } - Err(e) => Err(e)?, - } - } + tokio::task::spawn_blocking(move || repl(inst, state)) + .await? + .await?; Ok(()) } -async fn dispatch_command( - inst: &Arc<Instance>, - state: &Arc<RwLock<State>>, - command: Command, -) -> anyhow::Result<()> { - match command { - Command::List => { - let peers = inst.peers.read().await; - println!("{} clients available", peers.len()); - for p in peers.values() { - let username = p - .username - .read() - .await - .clone() - .unwrap_or("<unknown>".to_string()); - println!("{username}:"); - for (rid, r) in p.remote_provided.read().await.iter() { - println!( - "\t{rid:?}: {} {:?}", - r.kind, - r.label.clone().unwrap_or_default() - ) - } - } - } - Command::Provide { path, id } => { - inst.add_local_resource(Box::new(FileSender { - info: ProvideInfo { - id: id.unwrap_or("file".to_owned()), - kind: "file".to_string(), - track_kind: None, - label: Some(path.file_name().unwrap().to_str().unwrap().to_string()), - size: Some(fs::metadata(&path).await.unwrap().size() as usize), - }, - path: path.into(), - })) - .await; - } - Command::Download { id, path } => { - let (peer, _resource) = find_id(inst, id.clone(), "file").await?; - state - .write() - .await - .requested - .insert(id.clone(), Box::new(DownloadHandler { path })); - peer.request_resource(id).await; - } - Command::Expose { port, id } => { - inst.add_local_resource(Box::new(PortExposer { - port, - info: ProvideInfo { - kind: "port".to_string(), - id: id.unwrap_or(format!("p{port}")), - track_kind: None, - label: Some(format!("port {port}")), - size: None, - }, - })) - .await; - } - Command::Forward { id, port } => { - let (peer, _resource) = find_id(inst, id.clone(), "port").await?; - let state = state.clone(); - tokio::task::spawn(async move { - let Ok(listener) = TcpListener::bind(("127.0.0.1", port.unwrap_or(0))).await else { - error!("cannot bind tcp listener"); - return; - }; - info!("tcp listener bound to {}", listener.local_addr().unwrap()); - while let Ok((stream, addr)) = listener.accept().await { - info!("new connection from {addr:?}"); - state.write().await.requested.insert( - id.clone(), - Box::new(ForwardHandler { - stream: Arc::new(RwLock::new(Some(stream))), - }), - ); - peer.request_resource(id.clone()).await; - } - }); - } - Command::Chat { message } => { - inst.send_relay(None, RelayMessage::Chat(ChatMesssage::Text(message))) - .await; - } - } - Ok(()) -} - -async fn find_id( - inst: &Arc<Instance>, - id: String, - kind: &str, -) -> anyhow::Result<(Arc<Peer>, ProvideInfo)> { - let peers = inst.peers.read().await; - for peer in peers.values() { - for (rid, r) in peer.remote_provided.read().await.iter() { - if rid == &id { - if r.kind == kind { - return Ok((peer.to_owned(), r.to_owned())); - } else { - bail!("wrong type: expected {kind:?}, found {:?}", r.kind) - } - } - } - } - bail!("id not found") -} - impl EventHandler for Handler { fn peer_join(&self, _peer: Arc<Peer>) -> libkeks::DynFut<()> { Box::pin(async move {}) |