/voices: the voices the configured account can use, names and ids only.
The list is kept for a day: it changes when someone adds a voice to the account, and asking costs a call out. A failure to refresh serves the voices already known and says they are stale; with none known the route says plainly that the list cannot be read, so the app keeps the voice it has.
7use std::sync::{Mutex, PoisonError};
How long a list is served before the account is asked again.
17pub const VOICES_KEPT_MS: u64 = 24 * 60 * 60 * 1000;
POST /voices. Needs the voice and the clock.
The household's base voice, which a character with none of its own speaks in.
31 default: Option<&'a whiskers_ports::VoiceId>,
36impl<C: HasVoice + HasClock> Route<C> for Voices { 37 const PATHS: &'static [&'static str] = &["/voices"]; 38 async fn answer(&self, adapter: &C, _: &str, _: &str) -> Response { 39 let now = adapter.clock().now(); 40 let default = adapter.voice().base_voice().await; 41 let known = self.known.lock().unwrap_or_else(PoisonError::into_inner).clone(); 42 if let Some((at, list)) = &known 43 && now.get().saturating_sub(at.get()) < VOICES_KEPT_MS 44 { 45 debug!("/voices: {} voices from the list kept", list.len()); 46 return Response::of(&Reply { voices: list, default: default.as_ref(), stale: false }); 47 } 48 match adapter.voice().voices().await { 49 Ok(list) => { 50 info!("/voices: the account lists {} voices", list.len()); 51 *self.known.lock().unwrap_or_else(PoisonError::into_inner) = Some((now, list.clone())); 52 Response::of(&Reply { voices: &list, default: default.as_ref(), stale: false }) 53 } 54 Err(VoicesError::NotConfigured) => { 55 warn!("/voices refused: the voice is not configured"); 56 Response::text(503, VoicesError::NotConfigured.to_string()) 57 } 58 Err(e) => match known { 59 Some((_, list)) => { 60 warn!("/voices: the account could not be asked ({e}); serving {} voices already known", list.len()); 61 Response::of(&Reply { voices: &list, default: default.as_ref(), stale: true }) 62 } 63 None => { 64 warn!("/voices: the account could not be asked and none is known: {e}"); 65 Response::text(502, format!("the voice list cannot be read: {e}")) 66 } 67 }, 68 } 69 } 70}