1pub mod commands;
2pub mod tui;
3
4use clap::{Args, Parser, Subcommand};
5use std::path::PathBuf;
6
7#[derive(Parser, Debug)]
8#[command(
9 name = "lanflare",
10 version,
11 about = "Fast, cross-platform local network file sharing (LocalSend v2.2 compatible)"
12)]
13pub struct Cli {
14 #[arg(long, global = true)]
16 pub alias: Option<String>,
17
18 #[arg(long, short, global = true)]
20 pub port: Option<u16>,
21
22 #[command(subcommand)]
23 pub command: Option<Commands>,
24}
25
26#[derive(Subcommand, Debug)]
27pub enum Commands {
28 Scan(ScanArgs),
30
31 Send(SendArgs),
33
34 Receive(ReceiveArgs),
36
37 Status,
39}
40
41#[derive(Args, Debug)]
42pub struct ScanArgs {
43 #[arg(long, short = 't', default_value = "3")]
45 pub duration: u64,
46
47 #[arg(long)]
49 pub no_multicast: bool,
50
51 #[arg(long)]
53 pub no_mdns: bool,
54
55 #[arg(long, short = 's')]
57 pub subnet: bool,
58
59 #[arg(long)]
61 pub no_subnet: bool,
62}
63
64#[derive(Args, Debug)]
65pub struct SendArgs {
66 #[arg(required = true)]
68 pub files: Vec<PathBuf>,
69
70 #[arg(long, short)]
72 pub to: Option<String>,
73
74 #[arg(long)]
76 pub pin: Option<String>,
77}
78
79#[derive(Args, Debug)]
80pub struct ReceiveArgs {
81 #[arg(long, short)]
83 pub dir: Option<PathBuf>,
84
85 #[arg(long, short)]
87 pub port: Option<u16>,
88
89 #[arg(long)]
91 pub auto_accept: bool,
92
93 #[arg(long)]
95 pub pin: Option<String>,
96}
97
98pub async fn run() -> anyhow::Result<()> {
100 let cli = Cli::parse();
101
102 let mut config = lanflare_core::config::AppConfig::default();
103 if let Some(alias) = cli.alias {
104 config.alias = alias;
105 }
106 if let Some(port) = cli.port {
107 config.port = port;
108 }
109
110 let identity = lanflare_core::crypto::cert::generate_self_signed()?;
112
113 match cli.command {
114 Some(Commands::Scan(args)) => {
115 let scan_opts = commands::ScanOptions {
116 duration_secs: args.duration,
117 multicast: !args.no_multicast,
118 mdns: !args.no_mdns,
119 subnet: args.subnet,
120 fallback_subnet: !args.no_subnet,
121 };
122 commands::scan(&config, &identity, &scan_opts).await?;
123 }
124 Some(Commands::Send(args)) => {
125 let send_opts = commands::SendOptions {
126 files: args.files,
127 to: args.to,
128 pin: args.pin,
129 };
130 commands::send(&config, &identity, &send_opts).await?;
131 }
132 Some(Commands::Receive(args)) => {
133 let receive_opts = commands::ReceiveOptions {
134 dir: args.dir,
135 port: args.port,
136 auto_accept: args.auto_accept,
137 pin: args.pin,
138 };
139 commands::receive(&config, &identity, &receive_opts).await?;
140 }
141 Some(Commands::Status) | None => {
142 commands::status(&config, &identity).await?;
143 }
144 }
145
146 Ok(())
147}