use std::collections::HashMap; use std::sync::Arc; use log::warn; use parking_lot::Mutex; use solstice_proto::server::{ ServerRequest, ServerResponse, UserStatusRequest, UserStatusResponse, }; use crate::{ClientHandlerFactory, RequestHandler}; /// A map of user names to user status responses to serve. #[derive(Debug, Default)] pub struct UserStatusMap { map: HashMap, } // IDEA: impl FromIterator for UserStatusMap. impl UserStatusMap { /// Inserts the given `response` in this map. /// Overwrites the previous entry for the same user name, if any. pub fn insert(&mut self, response: UserStatusResponse) { self.map.insert(response.user_name.clone(), response); } /// Returns a clone of the response for the given user name. pub fn get(&self, user_name: &str) -> Option { self.map.get(user_name).map(|response| response.clone()) } } /// A handler that can serve responses to user status requests. /// Responses are sent only for users who appear in `user_status_map`. /// All other requests are ignored. #[derive(Clone, Default)] pub struct UserStatusHandler { user_status_map: Arc>, } impl RequestHandler for UserStatusHandler { fn handle( &mut self, request: &ServerRequest, ) -> anyhow::Result> { let user_name = match request { ServerRequest::UserStatusRequest(UserStatusRequest { ref user_name }) => { user_name } _ => { warn!("Unhandled request: {:?}", request); return Ok(None); } }; let entry = self.user_status_map.lock().get(user_name); if let Some(response) = entry { Ok(Some(ServerResponse::UserStatusResponse(response))) } else { warn!("Received UserStatusRequest for unknown user {}", user_name); Ok(None) } } } /// A factory for `UserStatusHandler`. All handlers share `user_status_map`. #[derive(Default)] pub struct UserStatusHandlerFactory { /// The status map from which responses are served. /// /// Testing code may wish to retain a copy of this in order to mutate the map /// concurrently with requests being handled. pub user_status_map: Arc>, } impl ClientHandlerFactory for UserStatusHandlerFactory { type Handler = UserStatusHandler; fn make(&self) -> Self::Handler { Self::Handler { user_status_map: self.user_status_map.clone(), } } } impl UserStatusHandlerFactory { /// Convenience function to create a new factory wrapping the given `map`. pub fn new(map: UserStatusMap) -> Self { Self { user_status_map: Arc::new(Mutex::new(map)), } } }