1#![warn(clippy::all, clippy::pedantic, rust_2018_idioms)]
5#![warn(missing_debug_implementations, clippy::unwrap_used)]
6#![allow(
7 clippy::module_name_repetitions,
8 clippy::missing_errors_doc,
9 clippy::missing_panics_doc
10)]
11
12use anyhow::Result;
15use clap::Parser;
16use crossbeam_channel::bounded;
17use std::sync::Arc;
18use tokio::sync::Mutex;
19use zello_client::{
20 PCM_CHANNEL_CAPACITY, connect_to_zello, create_decoder, initialize_logging, load_credentials,
21 setup_audio_output, utilities::load_dotenv_from_file,
22};
23
24#[derive(Parser, Debug)]
25#[command(name = "zello-client")]
26#[command(about = "This is a simple Zello client application that allows you\n\
27to listen to audio messages from and to send text messages to other\n\
28users on the Zello platform.")]
29#[command(
30 long_about = "This is a simple Zello client application that allows you\n\
31 to listen to audio messages from and to send text messages to other\n\
32 users on the Zello platform.
33
34Information must be provided to this command in the form of\n\
35a '.env' file with the following variables:
36
37 ZELLO_USERNAME='your_username'
38 ZELLO_PASSWORD='your_password'
39 ZELLO_TOKEN='your Zello authentication token'
40 ZELLO_CHANNEL='name of a Zello channel'
41
42The authentication token is required because this application\n\
43is using a development API which requires this token.\n\
44\n\
45This requirement may change in the future when the API is made public."
46)]
47#[command(version = env!("CARGO_PKG_VERSION"))]
48struct Args {
49 #[arg(short = 'm', long)]
51 message: Option<String>,
52
53 #[arg(short = 'c', long, requires = "message")]
55 callsign: Option<String>,
56}
57
58#[tokio::main]
59async fn main() -> Result<()> {
60 let args = Args::parse();
61
62 load_dotenv_from_file("examples/.env.example")?;
63 initialize_logging()?;
64
65 let credentials = load_credentials()?;
66 let decoder = create_decoder()?;
67
68 let (pcm_tx, pcm_rx) = bounded::<Vec<i16>>(PCM_CHANNEL_CAPACITY);
69 let pcm_rx = Arc::new(Mutex::new(pcm_rx));
70 let _stream = setup_audio_output(pcm_rx)?;
71
72 let mut client = connect_to_zello(&credentials).await?;
73
74 match (args.message, args.callsign) {
75 (Some(msg), Some(callsign)) => {
76 client
77 .send_text_message_to_callsign(&msg, &callsign)
78 .await?;
79 }
80 (Some(msg), None) => {
81 client.send_text_message(&msg).await?;
82 }
83 (None, _) => {
84 client.run_message_loop(decoder, &pcm_tx).await?;
85 }
86 }
87
88 client.close().await?;
89
90 Ok(())
91}