use std::path::PathBuf;
use anyhow::Result;
use crate::api::ApiClient;
use crate::audio::AudioPlayer;
use crate::buttons::Button;
use crate::config::{ApiConfig, PartyConfig};
use crate::events::{Event, EventReceiver};
use crate::model::{UserId, UserMode};
use crate::random::Random;
struct Client {
audio_player: AudioPlayer,
random: Random,
api_client: ApiClient,
party_config: PartyConfig,
event_receiver: EventReceiver,
}
impl Client {
fn new(
sounds_path: PathBuf,
api_config: &ApiConfig,
party_config: PartyConfig,
event_receiver: EventReceiver,
) -> Result<Self> {
Ok(Self {
audio_player: AudioPlayer::new(sounds_path)?,
random: Random::new(),
api_client: ApiClient::new(api_config, party_config.party_id.clone()),
party_config,
event_receiver,
})
}
fn sign_on(&self) -> Result<()> {
log::info!("Signing on ...");
match self.api_client.sign_on() {
Ok(()) => {
log::info!("Signed on.");
self.play_sound("signon_successful");
}
Err(e) => {
log::warn!("Signing on failed.\n{e}");
self.play_sound("signon_failed");
}
}
Ok(())
}
fn sign_off(&self) -> Result<()> {
log::info!("Signing off ...");
match self.api_client.sign_off() {
Ok(()) => {
log::info!("Signed off.");
self.play_sound("signoff_successful");
}
Err(e) => {
log::warn!("Signing off failed.\n{e}");
self.play_sound("signoff_failed");
}
}
Ok(())
}
fn handle_tag_read(&self, tag: &str) -> Result<Option<UserId>> {
log::debug!("Requesting details for tag {} ...", tag);
match self.api_client.get_tag_details(tag) {
Ok(details) => match details {
Some(details) => {
log::debug!(
"User for tag {}: {} (ID: {})",
details.identifier,
details.user.screen_name.unwrap_or("<nameless>".to_string()),
details.user.id
);
let user_id = details.user.id;
if let Some(name) = details.sound_name {
self.play_sound(&name);
}
log::debug!("Awaiting whereabouts for user {user_id} ...");
Ok(Some(user_id))
}
None => {
log::info!("Unknown user tag: {tag}");
self.play_sound("unknown_user_tag");
Ok(None)
}
},
Err(e) => {
log::warn!("Requesting tag details failed.\n{e}");
self.play_sound("communication_failed");
Ok(None)
}
}
}
fn handle_button_press_with_identified_user(
&self,
user_id: &UserId,
button: Button,
) -> Result<()> {
if let Some(whereabouts_name) = &self.party_config.buttons_to_whereabouts.get(&button) {
log::debug!("Submitting whereabouts for user {user_id} -> {whereabouts_name} ...");
let response = self.update_status(user_id, whereabouts_name);
match response {
Ok(_) => {
log::debug!("Status successfully updated.");
let sound_name =
match &self.party_config.whereabouts_sounds.get(*whereabouts_name) {
Some(sound_names) => &self.random.choose_random_element(sound_names),
None => "status_changed",
};
self.play_sound(sound_name);
}
Err(e) => {
log::warn!("Status update failed.\n{e}");
self.play_sound("communication_failed");
}
}
}
Ok(())
}
fn shutdown(&self) -> Result<()> {
log::info!("Shutdown requested.");
self.sign_off()?;
log::info!("Shutting down ...");
Ok(())
}
fn update_status(&self, user_id: &UserId, whereabouts_name: &str) -> Result<()> {
self.api_client.update_status(user_id, whereabouts_name)
}
fn play_sound(&self, name: &str) {
if let Err(e) = self.audio_player.play(name) {
log::warn!("Could not play sound: {e}");
}
}
}
struct SingleUserClient {
client: Client,
user_id: UserId,
}
impl SingleUserClient {
fn new(client: Client, user_id: UserId) -> Result<Self> {
Ok(Self { client, user_id })
}
fn run(&self) -> Result<()> {
self.client.sign_on()?;
self.handle_events(&self.user_id)?;
Ok(())
}
fn handle_events(&self, user_id: &UserId) -> Result<()> {
for msg in self.client.event_receiver.iter() {
match msg {
Event::TagRead { .. } => {
log::error!("Unexpected tag read event received.");
}
Event::ButtonPressed { button } => {
log::debug!("Button pressed: {:?}", button);
self.client
.handle_button_press_with_identified_user(user_id, button)?;
}
Event::ShutdownRequested => {
self.client.shutdown()?;
break;
}
}
}
Ok(())
}
}
struct MultiUserClient {
client: Client,
}
impl MultiUserClient {
fn new(client: Client) -> Result<Self> {
Ok(Self { client })
}
fn run(&self) -> Result<()> {
self.client.sign_on()?;
self.handle_events()?;
Ok(())
}
fn handle_events(&self) -> Result<()> {
let mut current_user_id: Option<UserId> = None;
for msg in self.client.event_receiver.iter() {
match msg {
Event::TagRead { tag } => {
log::debug!("Tag read: {tag}");
current_user_id = self.client.handle_tag_read(&tag)?;
}
Event::ButtonPressed { button } => {
log::debug!("Button pressed: {:?}", button);
if let Some(user_id) = current_user_id {
self.client
.handle_button_press_with_identified_user(&user_id, button)?;
current_user_id = None; }
}
Event::ShutdownRequested => {
self.client.shutdown()?;
break;
}
}
}
Ok(())
}
}
pub fn run_client(
sounds_path: PathBuf,
api_config: &ApiConfig,
party_config: PartyConfig,
event_receiver: EventReceiver,
user_mode: &UserMode,
) -> Result<()> {
let client = Client::new(sounds_path, api_config, party_config, event_receiver)?;
match user_mode {
UserMode::SingleUser(user_id) => SingleUserClient::new(client, user_id.clone())?.run(),
UserMode::MultiUser => MultiUserClient::new(client)?.run(),
}
}