diff --git a/Cargo.lock b/Cargo.lock index ddbe4f280..a83447acf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "arrayvec" version = "0.4.10" @@ -16,6 +18,11 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byteorder" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.6" @@ -109,6 +116,15 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hashbrown" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.3" @@ -133,20 +149,12 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "log" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "medea" version = "0.1.0" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -457,6 +465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" @@ -467,11 +476,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" diff --git a/Cargo.toml b/Cargo.toml index 1f2a22047..7281bb4ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,8 @@ repository = "https://github.com/instrumentisto/medea" [dependencies] chrono = "0.4" -log = "0.4" -slog = { version = "2.4", features = ["max_level_info", "release_max_level_warn"] } +hashbrown = "0.1" +slog = { version = "2.4", features = ["max_level_debug", "release_max_level_warn"] } slog-async = "2.3" slog-json = "2.3" slog-scope = "4.1" diff --git a/src/api/control/member.rs b/src/api/control/member.rs new file mode 100644 index 000000000..162ab45b3 --- /dev/null +++ b/src/api/control/member.rs @@ -0,0 +1,86 @@ +//! Member definitions and implementations. + +use hashbrown::HashMap; + +use crate::log::prelude::*; + +/// ID of [`Member`]. +pub type Id = u64; + +/// Media server user with its ID and credentials. +#[derive(Clone, Debug)] +pub struct Member { + /// ID of [`Member`]. + pub id: Id, + /// Credentials to authorize [`Member`] with. + pub credentials: String, +} + +/// Repository that stores [`Member`]s. +#[derive(Default)] +pub struct MemberRepository { + members: HashMap, +} + +impl MemberRepository { + /// Creates new [`Member`]s repository with passed-in [`Member`]s. + pub fn new(members: HashMap) -> Self { + MemberRepository { members } + } + + /// Returns [`Member`] by its ID. + pub fn get(&self, id: Id) -> Option { + debug!("retrieve member by id: {}", id); + self.members.get(&id).map(|member| member.clone()) + } + + /// Returns [`Member`] by its credentials. + pub fn get_by_credentials(&self, credentials: &str) -> Option { + debug!("retrieve member by credentials: {}", credentials); + self.members + .values() + .find(|member| member.credentials.eq(credentials)) + .map(|member| member.clone()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn test_members() -> HashMap { + hashmap! { + 1 => Member{id: 1, credentials: "caller_credentials".to_owned()}, + 2 => Member{id: 2, credentials: "responder_credentials".to_owned()}, + } + } + + #[test] + fn returns_member_by_id() { + let repo = MemberRepository::new(test_members()); + + let res = repo.get(1); + assert!(res.is_some()); + let member = res.unwrap(); + assert_eq!(member.id, 1); + } + + #[test] + fn returns_member_by_credentials() { + let repo = MemberRepository::new(test_members()); + + let res = repo.get_by_credentials("responder_credentials"); + assert!(res.is_some()); + let member = res.unwrap(); + assert_eq!(member.id, 2); + assert_eq!(member.credentials, "responder_credentials"); + } + + #[test] + fn returns_error_not_found() { + let repo = MemberRepository::new(test_members()); + + let res = repo.get(999); + assert!(res.is_none()); + } +} diff --git a/src/api/control/mod.rs b/src/api/control/mod.rs new file mode 100644 index 000000000..edcb52719 --- /dev/null +++ b/src/api/control/mod.rs @@ -0,0 +1,5 @@ +//! Implementation of Control API. + +pub mod member; + +pub use self::member::{Id, Member, MemberRepository}; diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 000000000..3c2414f0c --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1,3 @@ +//! API implementations provided by application. + +pub mod control; diff --git a/src/main.rs b/src/main.rs index 5acb346eb..2a30589d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,27 @@ -use crate::log::prelude::*; +//! Medea media server application. +use crate::{ + api::control::{Member, MemberRepository}, + log::prelude::*, +}; + +#[macro_use] +mod utils; + +mod api; mod log; fn main() { let logger = log::new_dual_logger(std::io::stdout(), std::io::stderr()); let _scope_guard = slog_scope::set_global_logger(logger); - info!("Hooray!"); - warn!("It works"); + let repo = MemberRepository::new(hashmap! { + 1 => Member{id: 1, credentials: "caller_credentials".to_owned()}, + 2 => Member{id: 2, credentials: "responder_credentials".to_owned()}, + }); + if let Some(member) = repo.get(1) { + info!("{:?}", member); + info!("Hooray!"); + warn!("It works"); + } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 000000000..cfc1b0155 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,32 @@ +//! Helper utils used in project. + +/// Creates new [`::hashbrown::HashMap`] from a list of key-value pairs. +/// +/// ## Example +/// +/// ```rust +/// let map = hashmap! { +/// "a" => 1, +/// "b" => 2, +/// }; +/// assert_eq!(map["a"], 1); +/// assert_eq!(map["b"], 2); +/// assert_eq!(map.get("c"), None); +/// ``` +#[macro_export] +macro_rules! hashmap { + (@single $($x:tt)*) => (()); + (@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*])); + + ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) }; + ($($key:expr => $value:expr),*) => { + { + let _cap = hashmap!(@count $($key),*); + let mut _map = ::hashbrown::HashMap::with_capacity(_cap); + $( + let _ = _map.insert($key, $value); + )* + _map + } + }; +}