Compare commits
No commits in common. "99fd0a9433812b087174c4ac0b3ae0b3a5929509" and "f039b9a6e145ee4c1cdac9fe420f16cf598b2dce" have entirely different histories.
99fd0a9433
...
f039b9a6e1
17 changed files with 201 additions and 791 deletions
97
Cargo.lock
generated
97
Cargo.lock
generated
|
@ -11,18 +11,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.57"
|
||||
|
@ -46,29 +34,6 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.11.0"
|
||||
|
@ -87,12 +52,6 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -114,12 +73,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
|
@ -159,27 +112,6 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.3"
|
||||
|
@ -199,16 +131,6 @@ dependencies = [
|
|||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.7"
|
||||
|
@ -242,7 +164,6 @@ dependencies = [
|
|||
name = "harsh_server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"chrono",
|
||||
"harsh_common",
|
||||
"rand",
|
||||
|
@ -587,12 +508,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.99"
|
||||
|
@ -657,24 +572,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
|
|
18
README.md
18
README.md
|
@ -1,18 +0,0 @@
|
|||
# Harsh
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
An embedded Harmony server implementation written in rust.
|
||||
|
||||
> **Warning**
|
||||
> This project is in early design phase, it is non conforming and very few features are implemented.
|
||||
|
||||
## Usage
|
||||
|
||||
To launch the server, ensure your rustup toolchain is up to date and use the `start-server.sh` script
|
||||
|
||||
To launch the debug client, use the `start-client.sh` script
|
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 113 KiB |
|
@ -57,37 +57,13 @@ pub fn parse(input: &str) -> Option<Command> {
|
|||
let content = parts.next()?;
|
||||
ClientRequest::new_message_set_content(channel_id, id, content)
|
||||
}
|
||||
"usrls" => ClientRequest::new_user_list(),
|
||||
"usradd" => {
|
||||
let name = parts.next()?;
|
||||
let pass = parts.next()?;
|
||||
ClientRequest::new_user_create(name, pass)
|
||||
}
|
||||
"usrdel" => {
|
||||
let id = parts.next()?.parse().ok()?;
|
||||
ClientRequest::new_user_delete(id)
|
||||
}
|
||||
"usrgname" => {
|
||||
let id = parts.next()?.parse().ok()?;
|
||||
ClientRequest::new_user_get_name(id)
|
||||
}
|
||||
"usrsname" => {
|
||||
let id = parts.next()?.parse().ok()?;
|
||||
let name = parts.next()?;
|
||||
ClientRequest::new_user_set_name(id, name)
|
||||
}
|
||||
"usrspass" => {
|
||||
let id = parts.next()?.parse().ok()?;
|
||||
let pass = parts.next()?;
|
||||
ClientRequest::new_user_set_pass(id, pass)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(Command::Request(command))
|
||||
}
|
||||
|
||||
pub const CMDS: &[Description] = &[
|
||||
pub const CMDS: &'static [Description] = &[
|
||||
// all commands
|
||||
Description::new("help", &[], "returns a help message"),
|
||||
Description::new(
|
||||
|
@ -109,12 +85,6 @@ pub const CMDS: &[Description] = &[
|
|||
&["channel_id", "id", "content"],
|
||||
"set a message's content",
|
||||
),
|
||||
Description::new("usrls", &[], "list users"),
|
||||
Description::new("usradd", &["name", "pass"], "add a user"),
|
||||
Description::new("usrdel", &["id"], "delete a user"),
|
||||
Description::new("usrgname", &["id"], "get a user name"),
|
||||
Description::new("usrsname", &["id", "name"], "set a user name"),
|
||||
Description::new("usrspass", &["id", "pass"], "set a user pass"),
|
||||
];
|
||||
|
||||
pub fn smart_split(input: &str) -> Vec<String> {
|
||||
|
@ -133,8 +103,12 @@ pub fn smart_split(input: &str) -> Vec<String> {
|
|||
}
|
||||
|
||||
match char {
|
||||
'\\' => ignoring = true,
|
||||
'"' => capturing = !capturing,
|
||||
'\\' => {
|
||||
ignoring = true;
|
||||
}
|
||||
'"' => {
|
||||
capturing = !capturing;
|
||||
}
|
||||
' ' if !capturing => {
|
||||
result.push(current);
|
||||
current = String::new();
|
||||
|
|
|
@ -3,13 +3,13 @@ use std::{
|
|||
process::exit,
|
||||
};
|
||||
|
||||
use harsh_common::ServerEvent;
|
||||
use harsh_common::ServerRequest;
|
||||
use tokio::{
|
||||
io::{stdin, AsyncBufReadExt, AsyncWriteExt, BufReader},
|
||||
net::TcpStream,
|
||||
};
|
||||
|
||||
const ADDRESS: &str = "localhost:42000";
|
||||
const ADDRESS: &'static str = "localhost:42069";
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -21,10 +21,13 @@ async fn main() {
|
|||
let mut reader = BufReader::new(reader);
|
||||
loop {
|
||||
let mut line = String::new();
|
||||
if let Ok(0) = reader.read_line(&mut line).await {
|
||||
break;
|
||||
match reader.read_line(&mut line).await {
|
||||
Ok(0) => {
|
||||
break;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if let Some(parsed) = ServerEvent::try_parse(&line) {
|
||||
if let Some(parsed) = ServerRequest::try_parse(&line) {
|
||||
println!("[main/info] received '{parsed:?}'");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,6 @@ pub struct Ping {
|
|||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Authenticate {
|
||||
pub id: u64,
|
||||
pub pass: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChannelList {}
|
||||
|
||||
|
@ -98,8 +92,6 @@ pub struct UserSetPass {
|
|||
#[derive(Debug)]
|
||||
pub enum ClientRequest {
|
||||
Ping(Ping),
|
||||
Authenticate(Authenticate),
|
||||
|
||||
ChannelList(ChannelList),
|
||||
ChannelCreate(ChannelCreate),
|
||||
ChannelDelete(ChannelDelete),
|
||||
|
@ -125,10 +117,6 @@ impl ClientRequest {
|
|||
Self::Ping(Ping { content })
|
||||
}
|
||||
|
||||
pub fn new_authenticate(id: u64, pass: String) -> Self {
|
||||
Self::Authenticate(Authenticate { id, pass })
|
||||
}
|
||||
|
||||
pub fn new_channel_list() -> Self {
|
||||
Self::ChannelList(ChannelList {})
|
||||
}
|
||||
|
@ -174,54 +162,56 @@ impl ClientRequest {
|
|||
content,
|
||||
})
|
||||
}
|
||||
pub fn new_user_list() -> Self {
|
||||
Self::UserList(UserList {})
|
||||
}
|
||||
pub fn new_user_create(name: String, pass: String) -> Self {
|
||||
Self::UserCreate(UserCreate { name, pass })
|
||||
}
|
||||
pub fn new_user_delete(id: u64) -> Self {
|
||||
Self::UserDelete(UserDelete { id })
|
||||
}
|
||||
pub fn new_user_get_name(id: u64) -> Self {
|
||||
Self::UserGetName(UserGetName { id })
|
||||
}
|
||||
pub fn new_user_set_name(id: u64, name: String) -> Self {
|
||||
Self::UserSetName(UserSetName { id, name })
|
||||
}
|
||||
pub fn new_user_set_pass(id: u64, pass: String) -> Self {
|
||||
Self::UserSetPass(UserSetPass { id, pass })
|
||||
}
|
||||
|
||||
pub fn try_parse(line: &str) -> Option<Self> {
|
||||
use repr::Command::*;
|
||||
let command: repr::Command = serde_json::from_str(line).ok()?;
|
||||
let mapped = match command {
|
||||
ping { content } => Self::new_ping(content),
|
||||
authenticate { id, pass } => Self::new_authenticate(id, pass),
|
||||
channel_list {} => Self::new_channel_list(),
|
||||
channel_create { name } => Self::new_channel_create(name),
|
||||
channel_delete { id } => Self::new_channel_delete(id),
|
||||
channel_get_name { id } => Self::new_channel_get_name(id),
|
||||
channel_set_name { id, name } => Self::new_channel_set_name(id, name),
|
||||
message_list { channel_id } => Self::new_message_list(channel_id),
|
||||
ping { content } => Self::Ping(Ping { content }),
|
||||
channel_list {} => Self::ChannelList(ChannelList {}),
|
||||
channel_create { name } => Self::ChannelCreate(ChannelCreate { name }),
|
||||
channel_delete { id: channel_id } => {
|
||||
Self::ChannelDelete(ChannelDelete { id: channel_id })
|
||||
}
|
||||
channel_get_name { id: channel_id } => {
|
||||
Self::ChannelGetName(ChannelGetName { id: channel_id })
|
||||
}
|
||||
channel_set_name {
|
||||
id: channel_id,
|
||||
name,
|
||||
} => Self::ChannelSetName(ChannelSetName {
|
||||
id: channel_id,
|
||||
name,
|
||||
}),
|
||||
message_list { channel_id } => Self::MessageList(MessageList { channel_id }),
|
||||
message_create {
|
||||
channel_id,
|
||||
content,
|
||||
} => Self::new_message_create(channel_id, content),
|
||||
message_delete { id, channel_id } => Self::new_message_delete(channel_id, id),
|
||||
message_get_content { id, channel_id } => Self::new_message_get_content(channel_id, id),
|
||||
} => Self::MessageCreate(MessageCreate {
|
||||
channel_id,
|
||||
content,
|
||||
}),
|
||||
message_delete { id, channel_id } => {
|
||||
Self::MessageDelete(MessageDelete { id, channel_id })
|
||||
}
|
||||
message_get_content { id, channel_id } => {
|
||||
Self::MessageGetContent(MessageGetContent { id, channel_id })
|
||||
}
|
||||
message_set_content {
|
||||
id,
|
||||
channel_id,
|
||||
content,
|
||||
} => Self::new_message_set_content(channel_id, id, content),
|
||||
user_list {} => Self::new_user_list(),
|
||||
user_create { name, pass } => Self::new_user_create(name, pass),
|
||||
user_delete { id } => Self::new_user_delete(id),
|
||||
user_get_name { id } => Self::new_user_get_name(id),
|
||||
user_set_name { id, name } => Self::new_user_set_name(id, name),
|
||||
user_set_pass { id, pass } => Self::new_user_set_pass(id, pass),
|
||||
} => Self::MessageSetContent(MessageSetContent {
|
||||
content,
|
||||
id,
|
||||
channel_id,
|
||||
}),
|
||||
user_list {} => Self::UserList(UserList {}),
|
||||
user_create { name, pass } => Self::UserCreate(UserCreate { name, pass }),
|
||||
user_delete { id } => Self::UserDelete(UserDelete { id }),
|
||||
user_get_name { id } => Self::UserGetName(UserGetName { id }),
|
||||
user_set_name { id, name } => Self::UserSetName(UserSetName { id, name }),
|
||||
user_set_pass { id, pass } => Self::UserSetPass(UserSetPass { id, pass }),
|
||||
};
|
||||
Some(mapped)
|
||||
}
|
||||
|
@ -230,7 +220,6 @@ impl ClientRequest {
|
|||
use repr::Command::*;
|
||||
let mapped = match self {
|
||||
Self::Ping(Ping { content }) => ping { content },
|
||||
Self::Authenticate(Authenticate { id, pass }) => authenticate { id, pass },
|
||||
Self::ChannelList(ChannelList {}) => repr::Command::channel_list {},
|
||||
Self::ChannelCreate(ChannelCreate { name }) => channel_create { name },
|
||||
Self::ChannelDelete(ChannelDelete { id: channel_id }) => {
|
||||
|
@ -291,10 +280,6 @@ mod repr {
|
|||
ping {
|
||||
content: String,
|
||||
},
|
||||
authenticate {
|
||||
id: u64,
|
||||
pass: String,
|
||||
},
|
||||
channel_list {},
|
||||
channel_create {
|
||||
name: String,
|
||||
|
|
|
@ -10,5 +10,5 @@ mod tests {
|
|||
pub use client::ClientRequest;
|
||||
pub mod client;
|
||||
|
||||
pub use server::ServerEvent;
|
||||
pub use server::ServerRequest;
|
||||
pub mod server;
|
||||
|
|
|
@ -61,9 +61,7 @@ pub struct MessageSetContent {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UserList {
|
||||
pub users: Vec<u64>,
|
||||
}
|
||||
pub struct UserList {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UserCreate {
|
||||
|
@ -94,7 +92,7 @@ pub struct UserSetPass {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ServerEvent {
|
||||
pub enum ServerRequest {
|
||||
Pong(Pong),
|
||||
|
||||
ChannelCreate(ChannelCreate),
|
||||
|
@ -117,7 +115,7 @@ pub enum ServerEvent {
|
|||
UserSetPass(UserSetPass),
|
||||
}
|
||||
|
||||
impl ServerEvent {
|
||||
impl ServerRequest {
|
||||
pub fn new_pong(content: String) -> Self {
|
||||
Self::Pong(Pong { content })
|
||||
}
|
||||
|
@ -176,30 +174,6 @@ impl ServerEvent {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn new_user_list(users: Vec<u64>) -> Self {
|
||||
Self::UserList(UserList { users })
|
||||
}
|
||||
|
||||
pub fn new_user_create(id: u64, name: String) -> Self {
|
||||
Self::UserCreate(UserCreate { id, name })
|
||||
}
|
||||
|
||||
pub fn new_user_delete(id: u64) -> Self {
|
||||
Self::UserDelete(UserDelete { id })
|
||||
}
|
||||
|
||||
pub fn new_user_get_name(id: u64, name: Option<String>) -> Self {
|
||||
Self::UserGetName(UserGetName { id, name })
|
||||
}
|
||||
|
||||
pub fn new_user_set_name(id: u64, name: String) -> Self {
|
||||
Self::UserSetName(UserSetName { id, name })
|
||||
}
|
||||
|
||||
pub fn new_user_set_pass(id: u64) -> Self {
|
||||
Self::UserSetPass(UserSetPass { id })
|
||||
}
|
||||
|
||||
pub fn try_parse(line: &str) -> Option<Self> {
|
||||
use repr::Command::*;
|
||||
let command: repr::Command = serde_json::from_str(line).ok()?;
|
||||
|
@ -247,7 +221,7 @@ impl ServerEvent {
|
|||
content,
|
||||
id,
|
||||
}),
|
||||
user_list { users } => Self::UserList(UserList { users }),
|
||||
user_list {} => Self::UserList(UserList {}),
|
||||
user_create { id, name } => Self::UserCreate(UserCreate { id, name }),
|
||||
user_delete { id } => Self::UserDelete(UserDelete { id }),
|
||||
user_get_name { id, name } => Self::UserGetName(UserGetName { id, name }),
|
||||
|
@ -304,7 +278,7 @@ impl ServerEvent {
|
|||
id,
|
||||
content,
|
||||
},
|
||||
Self::UserList(UserList { users }) => user_list { users },
|
||||
Self::UserList(UserList {}) => user_list {},
|
||||
Self::UserCreate(UserCreate { id, name }) => user_create { id, name },
|
||||
Self::UserDelete(UserDelete { id }) => user_delete { id },
|
||||
Self::UserGetName(UserGetName { id, name }) => user_get_name { id, name },
|
||||
|
@ -368,9 +342,7 @@ mod repr {
|
|||
id: u64,
|
||||
content: String,
|
||||
},
|
||||
user_list {
|
||||
users: Vec<u64>,
|
||||
},
|
||||
user_list {},
|
||||
user_create {
|
||||
id: u64,
|
||||
name: String,
|
||||
|
|
|
@ -15,4 +15,3 @@ tokio = { version = "1.20", features = ["full"] }
|
|||
harsh_common = { path = "../harsh-common/" }
|
||||
chrono = "0.4"
|
||||
rand = "0.8.5"
|
||||
blake3 = "1.3.1"
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use harsh_common::{client, server, ClientRequest, ServerEvent};
|
||||
use harsh_common::{client, server, ClientRequest, ServerRequest};
|
||||
use telecomande::{Processor, Remote};
|
||||
|
||||
use crate::{
|
||||
sessions::SessionExt, storage::Perm, Addr, Id, SecurityCmd, SecurityProc, SessionCmd,
|
||||
SessionProc, StorageCmd, StorageProc,
|
||||
};
|
||||
use crate::{Addr, Id, SessionCmd, SessionProc, StorageCmd, StorageProc};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GatewayCmd {
|
||||
|
@ -15,246 +12,161 @@ pub enum GatewayCmd {
|
|||
pub struct GatewayProc {
|
||||
sessions: Remote<SessionProc>,
|
||||
storage: Remote<StorageProc>,
|
||||
security: Remote<SecurityProc>,
|
||||
}
|
||||
|
||||
use client::*;
|
||||
|
||||
impl GatewayProc {
|
||||
async fn handle_request(&mut self, addr: Addr, request: ClientRequest) -> Result<(), String> {
|
||||
use client::*;
|
||||
use ClientRequest as CR;
|
||||
|
||||
// auth-free API
|
||||
let request = match request {
|
||||
CR::Ping(ping) => return self.on_ping(ping, addr),
|
||||
CR::Authenticate(authenticate) => {
|
||||
return self.on_authenticate(authenticate, addr).await
|
||||
}
|
||||
_ => request,
|
||||
};
|
||||
|
||||
// let user = self.sessions.get_user(addr.clone()).await.ok_or("owno")?;
|
||||
|
||||
// auth API
|
||||
async fn handle_request(&mut self, address: Addr, request: ClientRequest) {
|
||||
use client as c;
|
||||
use ClientRequest::*;
|
||||
match request {
|
||||
CR::Ping(_) | CR::Authenticate(_) => unreachable!(),
|
||||
Ping(c::Ping { content }) => self.on_ping(content, address),
|
||||
|
||||
CR::ChannelCreate(req) => self.on_channel_create(req).await,
|
||||
CR::ChannelDelete(req) => todo!(), //self.on_channel_delete(req, user).await,
|
||||
CR::ChannelList(req) => self.on_channel_list(req, addr).await,
|
||||
CR::ChannelGetName(req) => self.on_channel_get_name(req, addr).await,
|
||||
CR::ChannelSetName(req) => self.on_channel_set_name(req),
|
||||
ChannelCreate(c::ChannelCreate { name }) => self.on_channel_create(name).await,
|
||||
ChannelDelete(c::ChannelDelete { id }) => self.on_channel_delete(id),
|
||||
ChannelList(c::ChannelList {}) => self.on_channel_list(address).await,
|
||||
ChannelGetName(c::ChannelGetName { id }) => self.on_channel_get_name(id, address).await,
|
||||
ChannelSetName(c::ChannelSetName { id, name }) => self.on_channel_set_name(id, name),
|
||||
|
||||
CR::MessageList(req) => self.on_message_list(req, addr).await,
|
||||
CR::MessageCreate(req) => self.on_message_create(req).await,
|
||||
CR::MessageDelete(req) => self.on_message_delete(req),
|
||||
CR::MessageGetContent(req) => self.on_message_get_content(req, addr).await,
|
||||
CR::MessageSetContent(req) => self.on_message_set_content(req),
|
||||
MessageList(c::MessageList { channel_id }) => {
|
||||
self.on_message_list(channel_id, address).await
|
||||
}
|
||||
MessageCreate(c::MessageCreate {
|
||||
channel_id,
|
||||
content,
|
||||
}) => self.on_message_create(channel_id, content).await,
|
||||
MessageDelete(c::MessageDelete { channel_id, id }) => {
|
||||
self.on_message_delete(channel_id, id)
|
||||
}
|
||||
MessageGetContent(c::MessageGetContent { channel_id, id }) => {
|
||||
self.on_message_get_content(channel_id, id, address).await
|
||||
}
|
||||
|
||||
CR::UserList(req) => self.on_user_list(req, addr).await,
|
||||
CR::UserCreate(req) => self.on_user_create(req).await,
|
||||
CR::UserDelete(req) => self.on_user_delete(req),
|
||||
CR::UserGetName(req) => self.on_user_get_name(req, addr).await,
|
||||
CR::UserSetName(req) => self.on_user_set_name(req),
|
||||
CR::UserSetPass(req) => self.on_user_set_pass(req, addr),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
MessageSetContent(c::MessageSetContent {
|
||||
channel_id,
|
||||
id,
|
||||
content,
|
||||
}) => {
|
||||
self.on_message_set_content(channel_id, id, content);
|
||||
}
|
||||
|
||||
async fn on_authenticate(
|
||||
&mut self,
|
||||
Authenticate { id, pass }: Authenticate,
|
||||
address: Addr,
|
||||
) -> Result<(), String> {
|
||||
let (cmd, rec) = SecurityCmd::new_authenticate(id.into(), pass);
|
||||
self.security.send(cmd).unwrap();
|
||||
if rec.await.unwrap() {
|
||||
let command = SessionCmd::new_set_user(address, Some(id.into()));
|
||||
self.sessions.send(command).unwrap();
|
||||
} else {
|
||||
Err("Invalid password")?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
sessions: Remote<SessionProc>,
|
||||
storage: Remote<StorageProc>,
|
||||
security: Remote<SecurityProc>,
|
||||
) -> Self {
|
||||
Self {
|
||||
sessions,
|
||||
storage,
|
||||
security,
|
||||
// TODO: user
|
||||
UserList(c::UserList {}) => {
|
||||
todo!()
|
||||
}
|
||||
UserCreate(c::UserCreate { name, pass }) => {
|
||||
todo!()
|
||||
}
|
||||
UserDelete(c::UserDelete { id }) => {
|
||||
todo!()
|
||||
}
|
||||
UserGetName(c::UserGetName { id }) => {
|
||||
todo!()
|
||||
}
|
||||
UserSetName(c::UserSetName { id, name }) => {
|
||||
todo!()
|
||||
}
|
||||
UserSetPass(c::UserSetPass { id, pass }) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_ping(&mut self, Ping { content }: Ping, address: Addr) -> Result<(), String> {
|
||||
println!("[gateway/PING] '{content:?}'");
|
||||
let request = ServerEvent::Pong(server::Pong { content });
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
Ok(())
|
||||
pub fn new(sessions: Remote<SessionProc>, storage: Remote<StorageProc>) -> Self {
|
||||
Self { sessions, storage }
|
||||
}
|
||||
|
||||
async fn on_channel_create(&mut self, ChannelCreate { name }: ChannelCreate) {
|
||||
fn on_ping(&mut self, content: String, address: Addr) {
|
||||
println!("[gateway/PING] '{content:?}'");
|
||||
let request = ServerRequest::Pong(server::Pong { content });
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_channel_create(&mut self, name: String) {
|
||||
let (cmd, rec) = StorageCmd::new_channel_create(name.clone());
|
||||
self.storage.send(cmd).unwrap();
|
||||
let id = rec.await.unwrap().to_u64();
|
||||
let request = ServerEvent::new_channel_create(id, name);
|
||||
let request = ServerRequest::new_channel_create(id, name);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_channel_delete(&mut self, ChannelDelete { id }: ChannelDelete, user: Id) {
|
||||
// TODO: verify is OP
|
||||
let (cmd, req) = SecurityCmd::new_verify(user, Perm::OpChannel(id.into()));
|
||||
self.security.send(cmd).unwrap();
|
||||
req.await.unwrap();
|
||||
fn on_channel_delete(&mut self, id: u64) {
|
||||
let command = StorageCmd::new_channel_delete(id.into());
|
||||
self.storage.send(command).unwrap();
|
||||
let request = ServerEvent::new_channel_delete(id);
|
||||
let request = ServerRequest::new_channel_delete(id);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_channel_list(&mut self, _: ChannelList, address: Addr) {
|
||||
async fn on_channel_list(&mut self, address: Addr) {
|
||||
let (cmd, rec) = StorageCmd::new_channel_list();
|
||||
self.storage.send(cmd).unwrap();
|
||||
let channels = rec.await.unwrap().iter().map(|id| id.to_u64()).collect();
|
||||
let request = ServerEvent::new_channel_list(channels);
|
||||
let request = ServerRequest::new_channel_list(channels);
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_channel_get_name(&mut self, ChannelGetName { id }: ChannelGetName, address: Addr) {
|
||||
async fn on_channel_get_name(&mut self, id: u64, address: Addr) {
|
||||
let (cmd, rec) = StorageCmd::new_channel_get_name(id.into());
|
||||
self.storage.send(cmd).unwrap();
|
||||
let name = rec.await.unwrap();
|
||||
let request = ServerEvent::new_channel_get_name(id, name);
|
||||
let request = ServerRequest::new_channel_get_name(id, name);
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
fn on_channel_set_name(&mut self, ChannelSetName { id, name }: ChannelSetName) {
|
||||
fn on_channel_set_name(&mut self, id: u64, name: String) {
|
||||
let command = StorageCmd::new_channel_set_name(id.into(), name.clone());
|
||||
self.storage.send(command).unwrap();
|
||||
let request = ServerEvent::new_channel_set_name(id, name);
|
||||
let request = ServerRequest::new_channel_set_name(id, name);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_message_list(&mut self, MessageList { channel_id }: MessageList, address: Addr) {
|
||||
async fn on_message_list(&mut self, channel_id: u64, address: Addr) {
|
||||
let (cmd, rec) = StorageCmd::new_message_list(channel_id.into());
|
||||
self.storage.send(cmd).unwrap();
|
||||
let messages = rec.await.unwrap().iter().map(Id::to_u64).collect();
|
||||
let request = ServerEvent::new_message_list(channel_id, messages);
|
||||
let request = ServerRequest::new_message_list(channel_id, messages);
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_message_create(
|
||||
&mut self,
|
||||
MessageCreate {
|
||||
channel_id,
|
||||
content,
|
||||
}: MessageCreate,
|
||||
) {
|
||||
async fn on_message_create(&mut self, channel_id: u64, content: String) {
|
||||
let (cmd, rec) = StorageCmd::new_message_create(channel_id.into(), content.clone());
|
||||
self.storage.send(cmd).unwrap();
|
||||
let id = rec.await.unwrap();
|
||||
let request = ServerEvent::new_message_create(channel_id, id.to_u64(), content);
|
||||
let request = ServerRequest::new_message_create(channel_id, id.to_u64(), content);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
fn on_message_delete(&mut self, MessageDelete { channel_id, id }: MessageDelete) {
|
||||
fn on_message_delete(&mut self, channel_id: u64, id: u64) {
|
||||
let command = StorageCmd::new_message_delete(channel_id.into(), id.into());
|
||||
self.storage.send(command).unwrap();
|
||||
let request = ServerEvent::new_message_delete(channel_id, id);
|
||||
let request = ServerRequest::new_message_delete(channel_id, id);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_message_get_content(
|
||||
&mut self,
|
||||
MessageGetContent { channel_id, id }: MessageGetContent,
|
||||
address: Addr,
|
||||
) {
|
||||
async fn on_message_get_content(&mut self, channel_id: u64, id: u64, address: Addr) {
|
||||
let (cmd, rec) = StorageCmd::new_message_get_content(channel_id.into(), id.into());
|
||||
self.storage.send(cmd).unwrap();
|
||||
let request = ServerEvent::new_message_get_content(channel_id, id, rec.await.unwrap());
|
||||
let request = ServerRequest::new_message_get_content(channel_id, id, rec.await.unwrap());
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
fn on_message_set_content(
|
||||
&mut self,
|
||||
MessageSetContent {
|
||||
channel_id,
|
||||
id,
|
||||
content,
|
||||
}: MessageSetContent,
|
||||
) {
|
||||
fn on_message_set_content(&mut self, channel_id: u64, id: u64, content: String) {
|
||||
let command =
|
||||
StorageCmd::new_message_set_content(channel_id.into(), id.into(), content.clone());
|
||||
self.storage.send(command).unwrap();
|
||||
let request = ServerEvent::new_message_set_content(channel_id, id, content);
|
||||
let request = ServerRequest::new_message_set_content(channel_id, id, content);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
fn on_user_set_pass(&mut self, UserSetPass { id, pass }: UserSetPass, address: Addr) {
|
||||
let command = StorageCmd::new_user_set_pass(id.into(), pass);
|
||||
self.storage.send(command).unwrap();
|
||||
let request = ServerEvent::new_user_set_pass(id);
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
fn on_user_set_name(&mut self, UserSetName { id, name }: UserSetName) {
|
||||
let command = StorageCmd::new_user_set_name(id.into(), name.clone());
|
||||
self.storage.send(command).unwrap();
|
||||
let request = ServerEvent::new_user_set_name(id, name);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_user_get_name(&mut self, UserGetName { id }: UserGetName, address: Addr) {
|
||||
let (cmd, rec) = StorageCmd::new_user_get_name(id.into());
|
||||
self.storage.send(cmd).unwrap();
|
||||
let name = rec.await.unwrap();
|
||||
let request = ServerEvent::new_user_get_name(id, name);
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
fn on_user_delete(&mut self, UserDelete { id }: UserDelete) {
|
||||
let command = StorageCmd::new_user_delete(id.into());
|
||||
self.storage.send(command).unwrap();
|
||||
let request = ServerEvent::new_user_delete(id);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_user_create(&mut self, UserCreate { name, pass }: UserCreate) {
|
||||
let (cmd, rec) = StorageCmd::new_user_create(name.clone(), pass);
|
||||
self.storage.send(cmd).unwrap();
|
||||
let id = rec.await.unwrap();
|
||||
let request = ServerEvent::new_user_create(id.into(), name);
|
||||
let command = SessionCmd::new_broadcast(request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
|
||||
async fn on_user_list(&mut self, _: UserList, address: Addr) {
|
||||
let (cmd, rec) = StorageCmd::new_user_list();
|
||||
self.storage.send(cmd).unwrap();
|
||||
let result = rec.await.unwrap().iter().map(Id::to_u64).collect();
|
||||
let request = ServerEvent::new_user_list(result);
|
||||
let command = SessionCmd::new_send(address, request);
|
||||
self.sessions.send(command).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[telecomande::async_trait]
|
||||
|
@ -266,11 +178,9 @@ impl Processor for GatewayProc {
|
|||
GatewayCmd::Request(address, request) => {
|
||||
if let Some(request) = ClientRequest::try_parse(&request) {
|
||||
println!("[session/info] received command '{request:?}'");
|
||||
if let Err(reason) = self.handle_request(address, request).await {
|
||||
eprintln!("[gateway/warn] exception '{reason}'");
|
||||
}
|
||||
self.handle_request(address, request).await;
|
||||
} else {
|
||||
println!("[session/info] failed to parse command");
|
||||
println!("[session/warn] failed to parse command");
|
||||
}
|
||||
}
|
||||
GatewayCmd::ClosedConnection(address) => self
|
||||
|
|
|
@ -1,31 +1,23 @@
|
|||
use telecomande::{Executor, SimpleExecutor};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
const ADDRESS: &str = "localhost:42000";
|
||||
const DB_PATH: &str = "./db.test";
|
||||
const ADDRESS: &'static str = "localhost:42069";
|
||||
const DB_PATH: &'static str = "./db.test";
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("[main/info] starting server ...");
|
||||
|
||||
let sessions = SimpleExecutor::new(SessionProc::default()).spawn();
|
||||
println!("[main/info] spawned sessions");
|
||||
|
||||
let storage = SimpleExecutor::new(StorageProc::new(DB_PATH)).spawn();
|
||||
println!("[main/info] spawned storage");
|
||||
|
||||
let security = SimpleExecutor::new(SecurityProc::new(storage.remote())).spawn();
|
||||
|
||||
let gateway = SimpleExecutor::new(GatewayProc::new(
|
||||
sessions.remote(),
|
||||
storage.remote(),
|
||||
security.remote(),
|
||||
))
|
||||
.spawn();
|
||||
let gateway =
|
||||
SimpleExecutor::new(GatewayProc::new(sessions.remote(), storage.remote())).spawn();
|
||||
println!("[main/info] spawned gateway");
|
||||
|
||||
let listener = TcpListener::bind(ADDRESS).await.unwrap();
|
||||
println!("[main/info] listening on '{ADDRESS}' ...");
|
||||
|
||||
let client_handler = sessions.remote();
|
||||
loop {
|
||||
let (stream, address) = listener.accept().await.unwrap();
|
||||
|
@ -50,6 +42,3 @@ pub use sessions::{SessionCmd, SessionProc};
|
|||
|
||||
mod storage;
|
||||
pub use storage::{StorageCmd, StorageProc};
|
||||
|
||||
mod security;
|
||||
pub use security::{SecurityCmd, SecurityProc};
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
use telecomande::{Processor, Remote};
|
||||
use tokio::sync::oneshot::{self, Receiver, Sender};
|
||||
|
||||
use crate::{storage::Perm, Id, StorageCmd, StorageProc};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SecurityCmd {
|
||||
Verify(Id, Perm, Sender<bool>),
|
||||
Authenticate(Id, String, Sender<bool>),
|
||||
StorePass(Id, String),
|
||||
}
|
||||
|
||||
impl SecurityCmd {
|
||||
pub fn new_verify(user_id: Id, permission: Perm) -> (Self, Receiver<bool>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let command = Self::Verify(user_id, permission, sender);
|
||||
(command, receiver)
|
||||
}
|
||||
|
||||
pub fn new_authenticate(user_id: Id, pass: String) -> (Self, Receiver<bool>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let command = Self::Authenticate(user_id, pass, sender);
|
||||
(command, receiver)
|
||||
}
|
||||
|
||||
pub fn new_store_pass(user_id: Id, pass: String) -> Self {
|
||||
Self::StorePass(user_id, pass)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SecurityProc {
|
||||
storage: Remote<StorageProc>,
|
||||
}
|
||||
|
||||
impl SecurityProc {
|
||||
pub fn new(storage: Remote<StorageProc>) -> Self {
|
||||
Self { storage }
|
||||
}
|
||||
|
||||
async fn handle_command(&mut self, command: SecurityCmd) {
|
||||
match command {
|
||||
SecurityCmd::Verify(user, perm, sender) => {
|
||||
let (cmd, req) = StorageCmd::new_perm_server_get_op();
|
||||
self.storage.send(cmd).unwrap();
|
||||
let serv_ops = req.await.unwrap();
|
||||
let is_serv_op = serv_ops.into_iter().any(|i| i == user);
|
||||
let result = match (is_serv_op, perm) {
|
||||
(true, _) => true,
|
||||
(false, Perm::OpChannel(chan_id)) => {
|
||||
let (cmd, req) = StorageCmd::new_perm_channel_get_op(chan_id);
|
||||
self.storage.send(cmd).unwrap();
|
||||
let channel_ops = req.await.unwrap();
|
||||
channel_ops.into_iter().any(|i| i == user)
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
sender.send(result).unwrap();
|
||||
}
|
||||
SecurityCmd::Authenticate(user, pass, sender) => {
|
||||
let (cmd, rec) = StorageCmd::new_user_get_pass(user);
|
||||
self.storage.send(cmd).unwrap();
|
||||
let stored = rec.await.unwrap();
|
||||
let result = stored.map(|stored| stored == hash(pass)).unwrap_or(false);
|
||||
sender.send(result).unwrap();
|
||||
}
|
||||
SecurityCmd::StorePass(user, pass) => {
|
||||
let pass = hash(pass);
|
||||
let command = StorageCmd::new_user_set_pass(user, pass);
|
||||
self.storage.send(command).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SALT: &str = ":)";
|
||||
|
||||
fn hash(input: String) -> String {
|
||||
let hash = blake3::hash((input + SALT).as_bytes());
|
||||
format!("{hash}")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
assert_eq!(
|
||||
&hash("arbre".into()),
|
||||
"c2d3a87dcb76c21a8a935b8e988745f31663c3650a0d3732430eaa323f12ee0f"
|
||||
);
|
||||
}
|
||||
|
||||
#[telecomande::async_trait]
|
||||
impl Processor for SecurityProc {
|
||||
type Command = SecurityCmd;
|
||||
type Error = ();
|
||||
|
||||
async fn handle(&mut self, command: Self::Command) -> Result<(), Self::Error> {
|
||||
self.handle_command(command).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::{collections::HashMap, net::SocketAddr};
|
||||
|
||||
use harsh_common::ServerEvent;
|
||||
use harsh_common::ServerRequest;
|
||||
use telecomande::{Processor, Remote};
|
||||
use tokio::{
|
||||
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
|
||||
|
@ -8,58 +8,33 @@ use tokio::{
|
|||
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
||||
TcpStream,
|
||||
},
|
||||
sync::oneshot::{self, Receiver, Sender},
|
||||
task::JoinHandle,
|
||||
};
|
||||
|
||||
use crate::{gateway, Addr, Id};
|
||||
use crate::{gateway, Addr};
|
||||
#[derive(Debug)]
|
||||
pub enum SessionCmd {
|
||||
AddSession(TcpStream, SocketAddr, Remote<gateway::GatewayProc>),
|
||||
RemoveSession(Addr),
|
||||
Send(Addr, String),
|
||||
Broadcast(String),
|
||||
GetUser(Addr, Sender<Option<Id>>),
|
||||
SetUser(Addr, Option<Id>),
|
||||
}
|
||||
|
||||
impl SessionCmd {
|
||||
pub fn new_add_session(
|
||||
stream: TcpStream,
|
||||
address: SocketAddr,
|
||||
gateway: Remote<gateway::GatewayProc>,
|
||||
) -> Self {
|
||||
Self::AddSession(stream, address, gateway)
|
||||
}
|
||||
|
||||
pub fn new_remove_session(address: Addr) -> Self {
|
||||
Self::RemoveSession(address)
|
||||
}
|
||||
|
||||
pub fn new_send(address: Addr, request: ServerEvent) -> Self {
|
||||
pub fn new_send(address: Addr, request: ServerRequest) -> Self {
|
||||
let content = request.serialize();
|
||||
Self::Send(address, content)
|
||||
}
|
||||
|
||||
pub fn new_broadcast(request: ServerEvent) -> Self {
|
||||
pub fn new_broadcast(request: ServerRequest) -> Self {
|
||||
let content = request.serialize();
|
||||
Self::Broadcast(content)
|
||||
}
|
||||
|
||||
pub fn new_get_user(address: Addr) -> (Self, Receiver<Option<Id>>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let command = Self::GetUser(address, sender);
|
||||
(command, receiver)
|
||||
}
|
||||
|
||||
pub fn new_set_user(address: Addr, user: Option<Id>) -> Self {
|
||||
Self::SetUser(address, user)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SessionProc {
|
||||
clients: HashMap<Addr, Client>,
|
||||
clients: HashMap<Addr, (OwnedWriteHalf, JoinHandle<()>)>,
|
||||
}
|
||||
|
||||
impl SessionProc {
|
||||
|
@ -71,7 +46,7 @@ impl SessionProc {
|
|||
) {
|
||||
let (reader, writer) = stream.into_split();
|
||||
let handle = tokio::spawn(session(address.clone(), reader, remote));
|
||||
self.clients.insert(address, Client::new(writer, handle));
|
||||
self.clients.insert(address, (writer, handle));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,29 +65,24 @@ impl Processor for SessionProc {
|
|||
}
|
||||
SessionCmd::RemoveSession(address) => {
|
||||
println!("[sessions/info] closed connection from '{address:?}'");
|
||||
if let Some(client) = self.clients.remove(&address) {
|
||||
client.unwrap().await.unwrap();
|
||||
if let Some((_writer, handle)) = self.clients.remove(&address) {
|
||||
handle.await.unwrap();
|
||||
}
|
||||
}
|
||||
SessionCmd::Send(address, content) => {
|
||||
if let Some(client) = self.clients.get_mut(&address) {
|
||||
if let Some((client, _)) = self.clients.get_mut(&address) {
|
||||
println!("[session/info] sending '{content}' to '{address:?}'");
|
||||
client.send(&content).await;
|
||||
client.write_all(content.as_bytes()).await.unwrap();
|
||||
client.write_all(b"\n").await.unwrap();
|
||||
} else {
|
||||
eprintln!("failed to find session with address '{address:?}'")
|
||||
}
|
||||
}
|
||||
SessionCmd::Broadcast(content) => {
|
||||
println!("[session/info] broadcasting '{content}'");
|
||||
for client in self.clients.values_mut() {
|
||||
client.send(&content).await;
|
||||
}
|
||||
}
|
||||
SessionCmd::GetUser(address, sender) => {
|
||||
let user = self.clients.get_mut(&address).and_then(|c| c.get_user());
|
||||
sender.send(user).unwrap();
|
||||
}
|
||||
SessionCmd::SetUser(address, user) => {
|
||||
if let Some(client) = self.clients.get_mut(&address) {
|
||||
client.set_user(user);
|
||||
for (client, _) in self.clients.values_mut() {
|
||||
println!("[session/info] broadcasting '{content}'");
|
||||
client.write_all(content.as_bytes()).await.unwrap();
|
||||
client.write_all(b"\n").await.unwrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -120,45 +90,6 @@ impl Processor for SessionProc {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Client {
|
||||
writer: OwnedWriteHalf,
|
||||
handle: JoinHandle<()>,
|
||||
user: Option<Id>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(writer: OwnedWriteHalf, handle: JoinHandle<()>) -> Self {
|
||||
let user = None;
|
||||
Self {
|
||||
handle,
|
||||
user,
|
||||
writer,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap(self) -> JoinHandle<()> {
|
||||
let Self {
|
||||
writer,
|
||||
handle,
|
||||
user,
|
||||
} = self;
|
||||
drop((writer, user));
|
||||
handle
|
||||
}
|
||||
|
||||
pub async fn send(&mut self, message: &str) {
|
||||
self.writer.write_all(message.as_bytes()).await.unwrap();
|
||||
self.writer.write_all(b"\n").await.unwrap();
|
||||
}
|
||||
pub fn set_user(&mut self, id: Option<Id>) {
|
||||
self.user = id;
|
||||
}
|
||||
pub fn get_user(&self) -> Option<Id> {
|
||||
self.user
|
||||
}
|
||||
}
|
||||
|
||||
async fn session(address: Addr, reader: OwnedReadHalf, remote: Remote<gateway::GatewayProc>) {
|
||||
let mut reader = BufReader::new(reader);
|
||||
loop {
|
||||
|
@ -176,24 +107,3 @@ async fn session(address: Addr, reader: OwnedReadHalf, remote: Remote<gateway::G
|
|||
.send(gateway::GatewayCmd::ClosedConnection(address))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[telecomande::async_trait]
|
||||
pub trait SessionExt {
|
||||
fn send(&self, cmd: SessionCmd);
|
||||
|
||||
async fn is_logged(&self, address: Addr) -> bool {
|
||||
self.get_user(address).await.is_some()
|
||||
}
|
||||
|
||||
async fn get_user(&self, address: Addr) -> Option<Id> {
|
||||
let (cmd, rec) = SessionCmd::new_get_user(address);
|
||||
self.send(cmd);
|
||||
rec.await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl SessionExt for Remote<SessionProc> {
|
||||
fn send(&self, cmd: SessionCmd) {
|
||||
self.send(cmd).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,6 @@ pub enum StorageCmd {
|
|||
UserSetName(Id, String),
|
||||
UserGetPass(Id, Sender<Option<String>>),
|
||||
UserSetPass(Id, String),
|
||||
PermServerAddOp(Id),
|
||||
PermServerRemoveOp(Id),
|
||||
PermServerGetOp(Sender<Vec<Id>>),
|
||||
PermChannelAddOp(Id, Id),
|
||||
PermChannelRemoveOp(Id, Id),
|
||||
PermChannelGetOp(Id, Sender<Vec<Id>>),
|
||||
}
|
||||
|
||||
impl StorageCmd {
|
||||
|
@ -80,70 +74,6 @@ impl StorageCmd {
|
|||
pub fn new_message_set_content(channel_id: Id, id: Id, content: String) -> Self {
|
||||
Self::MessageSetContent(channel_id, id, content)
|
||||
}
|
||||
|
||||
pub fn new_user_list() -> (Self, Receiver<Vec<Id>>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let cmd = Self::UserList(sender);
|
||||
(cmd, receiver)
|
||||
}
|
||||
|
||||
pub fn new_user_create(name: String, pass: String) -> (Self, Receiver<Id>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let cmd = Self::UserCreate(name, pass, sender);
|
||||
(cmd, receiver)
|
||||
}
|
||||
|
||||
pub fn new_user_delete(id: Id) -> Self {
|
||||
Self::UserDelete(id)
|
||||
}
|
||||
|
||||
pub fn new_user_get_name(id: Id) -> (Self, Receiver<Option<String>>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let cmd = Self::UserGetName(id, sender);
|
||||
(cmd, receiver)
|
||||
}
|
||||
|
||||
pub fn new_user_set_name(id: Id, name: String) -> Self {
|
||||
Self::UserSetName(id, name)
|
||||
}
|
||||
|
||||
pub fn new_user_get_pass(id: Id) -> (Self, Receiver<Option<String>>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let cmd = Self::UserGetPass(id, sender);
|
||||
(cmd, receiver)
|
||||
}
|
||||
|
||||
pub fn new_user_set_pass(id: Id, pass: String) -> Self {
|
||||
Self::UserSetPass(id, pass)
|
||||
}
|
||||
|
||||
pub fn new_perm_server_add_op(user_id: Id) -> Self {
|
||||
Self::PermServerAddOp(user_id)
|
||||
}
|
||||
|
||||
pub fn new_perm_server_remove_op(user_id: Id) -> Self {
|
||||
Self::PermServerRemoveOp(user_id)
|
||||
}
|
||||
|
||||
pub fn new_perm_server_get_op() -> (Self, Receiver<Vec<Id>>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let cmd = Self::PermServerGetOp(sender);
|
||||
(cmd, receiver)
|
||||
}
|
||||
|
||||
pub fn new_perm_channel_add_op(channel_id: Id, user_id: Id) -> Self {
|
||||
Self::PermChannelAddOp(channel_id, user_id)
|
||||
}
|
||||
|
||||
pub fn new_perm_channel_remove_op(channel_id: Id, user_id: Id) -> Self {
|
||||
Self::PermChannelRemoveOp(channel_id, user_id)
|
||||
}
|
||||
|
||||
pub fn new_perm_channel_get_op(channel_id: Id) -> (Self, Receiver<Vec<Id>>) {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let command = Self::PermChannelGetOp(channel_id, sender);
|
||||
(command, receiver)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StorageProc {
|
||||
|
@ -228,32 +158,47 @@ impl StorageProc {
|
|||
//
|
||||
// User
|
||||
//
|
||||
UserList(sender) => self.on_user_list(sender),
|
||||
UserCreate(name, pass, sender) => self.on_user_create(name, pass, sender),
|
||||
UserDelete(id) => self.on_user_delete(id),
|
||||
UserGetName(id, sender) => self.on_user_get_name(id, sender),
|
||||
UserSetName(id, name) => self.on_user_set_name(id, name),
|
||||
UserGetPass(id, sender) => self.on_user_get_pass(id, sender),
|
||||
UserSetPass(id, pass) => self.on_user_set_pass(id, pass),
|
||||
UserList(sender) => {
|
||||
let users = self.list("/users/");
|
||||
sender.send(users).unwrap();
|
||||
}
|
||||
|
||||
//
|
||||
// Perms
|
||||
//
|
||||
PermServerGetOp(sender) => {
|
||||
let result = self.list("/op/serv/".to_string());
|
||||
sender.send(result).unwrap();
|
||||
UserCreate(name, pass, sender) => {
|
||||
let user = User::new(name, pass);
|
||||
let id = user.get_id();
|
||||
sender.send(id).unwrap();
|
||||
}
|
||||
PermServerAddOp(user_id) => self.set(format!("/op/serv/{user_id}"), true),
|
||||
PermServerRemoveOp(user_id) => self.remove(format!("/op/serv/{user_id}")),
|
||||
PermChannelAddOp(channel_id, user_id) => {
|
||||
self.set(format!("/op/channels/{channel_id}/{user_id}"), true)
|
||||
|
||||
UserDelete(id) => {
|
||||
self.remove(format!("/users/{id}"));
|
||||
}
|
||||
PermChannelRemoveOp(channel_id, user_id) => {
|
||||
self.remove(format!("/op/channels/{channel_id}/{user_id}"))
|
||||
|
||||
UserGetName(id, sender) => {
|
||||
let user = self.get::<_, User>(format!("/users/{id}"));
|
||||
let name = user.map(|u| u.get_name().to_string());
|
||||
sender.send(name).unwrap();
|
||||
}
|
||||
PermChannelGetOp(channel_id, sender) => {
|
||||
let result = self.list(format!("/op/channels/{channel_id}/"));
|
||||
sender.send(result).unwrap();
|
||||
|
||||
UserSetName(id, name) => {
|
||||
let path = format!("/users/{id}");
|
||||
if let Some(mut user) = self.get::<_, User>(&path) {
|
||||
user.set_name(name);
|
||||
self.set(path, user);
|
||||
}
|
||||
}
|
||||
|
||||
UserGetPass(id, sender) => {
|
||||
let user = self.get::<_, User>(format!("/users/{id}"));
|
||||
let name = user.map(|u| u.get_pass().to_string());
|
||||
sender.send(name).unwrap();
|
||||
}
|
||||
|
||||
UserSetPass(id, pass) => {
|
||||
let path = format!("/users/{id}");
|
||||
if let Some(mut user) = self.get::<_, User>(&path) {
|
||||
user.set_pass(pass);
|
||||
self.set(path, user);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -274,9 +219,6 @@ impl StorageProc {
|
|||
}
|
||||
|
||||
fn on_channel_remove(&mut self, id: Id) {
|
||||
for message_id in self.list(format!("/messages/{id}/")) {
|
||||
self.remove(format!("/messages/{id}/{message_id}"))
|
||||
}
|
||||
self.remove(format!("/channels/{id}"))
|
||||
}
|
||||
|
||||
|
@ -326,54 +268,6 @@ impl StorageProc {
|
|||
self.set(path, message);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// User
|
||||
//
|
||||
|
||||
fn on_user_list(&mut self, sender: Sender<Vec<Id>>) {
|
||||
let users = self.list("/users/");
|
||||
sender.send(users).unwrap();
|
||||
}
|
||||
|
||||
fn on_user_create(&mut self, name: String, pass: String, sender: Sender<Id>) {
|
||||
let user = User::new(name, pass);
|
||||
let id = user.get_id();
|
||||
self.set(format!("/users/{id}"), user);
|
||||
sender.send(id).unwrap();
|
||||
}
|
||||
|
||||
fn on_user_delete(&mut self, id: Id) {
|
||||
self.remove(format!("/users/{id}"));
|
||||
}
|
||||
|
||||
fn on_user_get_name(&mut self, id: Id, sender: Sender<Option<String>>) {
|
||||
let user = self.get::<_, User>(format!("/users/{id}"));
|
||||
let name = user.map(|u| u.get_name().to_string());
|
||||
sender.send(name).unwrap();
|
||||
}
|
||||
|
||||
fn on_user_set_name(&mut self, id: Id, name: String) {
|
||||
let path = format!("/users/{id}");
|
||||
if let Some(mut user) = self.get::<_, User>(&path) {
|
||||
user.set_name(name);
|
||||
self.set(path, user);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_user_get_pass(&mut self, id: Id, sender: Sender<Option<String>>) {
|
||||
let user = self.get::<_, User>(format!("/users/{id}"));
|
||||
let name = user.map(|u| u.get_pass().to_string());
|
||||
sender.send(name).unwrap();
|
||||
}
|
||||
|
||||
fn on_user_set_pass(&mut self, id: Id, pass: String) {
|
||||
let path = format!("/users/{id}");
|
||||
if let Some(mut user) = self.get::<_, User>(&path) {
|
||||
user.set_pass(pass);
|
||||
self.set(path, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[telecomande::async_trait]
|
||||
|
@ -389,7 +283,7 @@ impl Processor for StorageProc {
|
|||
}
|
||||
|
||||
mod models;
|
||||
pub use models::{Channel, Message, Perm, SerDeser, User};
|
||||
pub use models::{Channel, Message, SerDeser, User};
|
||||
|
||||
fn list(db: &Db, path: String) -> Vec<Id> {
|
||||
let len = path.len();
|
||||
|
|
|
@ -114,9 +114,3 @@ where
|
|||
db.insert(path, bytes).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
pub enum Perm {
|
||||
OpServer,
|
||||
OpChannel(Id),
|
||||
}
|
||||
|
|
|
@ -43,12 +43,6 @@ impl From<u64> for Id {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Id> for u64 {
|
||||
fn from(input: Id) -> Self {
|
||||
input.to_u64()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_convertion() {
|
||||
let id = Id::from_now();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue