Add essential packets

This commit is contained in:
Joscha 2022-02-11 20:32:27 +01:00
parent 286ace55b4
commit 7458eac931
6 changed files with 190 additions and 55 deletions

View file

@ -4,13 +4,15 @@ use hex::ToHex;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::macros::id_alias;
// TODO Use base64 representation instead
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct Id(#[serde(with = "hex")] [u8; 32]);
struct Id(#[serde(with = "hex")] [u8; 32]);
impl Id {
pub fn of(str: &str) -> Self {
fn of(str: &str) -> Self {
let mut hasher = Sha256::new();
hasher.update(str);
Self(hasher.finalize().into())
@ -22,3 +24,8 @@ impl fmt::Display for Id {
write!(f, "{}", self.0.encode_hex::<String>())
}
}
// Prevent misuse of one id as another by only making the aliases public.
id_alias!(MessageId);
id_alias!(SessionId);
id_alias!(Identity);

View file

@ -1,44 +1,9 @@
mod id;
mod macros;
mod message;
use serde::{Deserialize, Serialize};
pub mod packets;
mod user;
pub use self::id::*;
use self::macros::packets;
pub use self::message::*;
#[derive(Debug, Deserialize, Serialize)]
pub struct HelloCmd {
pub id: Id,
pub name: String,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum HelloRpl {
Success { id: Id },
InvalidName { reason: String },
NameAlreadyUsed,
}
// Create a Cmd enum for all commands and a Rpl enum for all replies, as well as
// TryFrom impls for the individual command and reply structs.
packets! {
Hello(HelloCmd, HelloRpl),
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum Packet {
Cmd {
id: u64,
#[serde(flatten)]
cmd: Cmd,
},
Rpl {
id: u64,
#[serde(flatten)]
rpl: Rpl,
},
}
pub use self::user::*;

View file

@ -1,9 +1,36 @@
// Use `pub(crate) use <macro_name>` to make a macro importable from elsewhere.
// See https://stackoverflow.com/a/31749071
macro_rules! id_alias {
($name:ident) => {
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct $name(Id);
impl $name {
pub fn of(str: &str) -> Self {
Self(Id::of(str))
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
};
}
pub(crate) use id_alias;
macro_rules! packets {
( $( $name:ident($cmd:ident, $rpl:ident), )* ) => {
(
$( cmd $cmdName:ident($cmd:ident, $rpl:ident), )* // Commands with reply
$( ntf $ntfName:ident($ntf:ident), )* // Notifications
) => {
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "name", content = "data")]
pub enum Cmd {
$( $name($cmd), )*
$( $cmdName($cmd), )*
}
$(
@ -11,7 +38,7 @@ macro_rules! packets {
type Error = ();
fn try_from(cmd: Cmd) -> Result<Self, Self::Error> {
match cmd {
Cmd::$name(val) => Ok(val),
Cmd::$cmdName(val) => Ok(val),
_ => Err(()),
}
}
@ -21,7 +48,7 @@ macro_rules! packets {
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "name", content = "data")]
pub enum Rpl {
$( $name($rpl), )*
$( $cmdName($rpl), )*
}
$(
@ -29,7 +56,25 @@ macro_rules! packets {
type Error = ();
fn try_from(rpl: Rpl) -> Result<Self, Self::Error> {
match rpl {
Rpl::$name(val) => Ok(val),
Rpl::$cmdName(val) => Ok(val),
_ => Err(()),
}
}
}
)*
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "name", content = "data")]
pub enum Ntf {
$( $ntfName($ntf), )*
}
$(
impl std::convert::TryFrom<Ntf> for $ntf {
type Error = ();
fn try_from(ntf: Ntf) -> Result<Self, Self::Error> {
match ntf {
Ntf::$ntfName(val) => Ok(val),
_ => Err(()),
}
}
@ -38,6 +83,4 @@ macro_rules! packets {
};
}
// Make macro importable from elsewhere
// See https://stackoverflow.com/a/31749071
pub(crate) use packets;

View file

@ -1,18 +1,18 @@
use serde::{Deserialize, Serialize};
use crate::Id;
use crate::{ Identity, MessageId};
#[derive(Debug, Deserialize, Serialize)]
pub struct Message {
pub pred: Option<Id>,
pub parent: Option<Id>,
pub identity: Id,
pub pred: Option<MessageId>,
pub parent: Option<MessageId>,
pub identity: Identity,
pub nick: String,
pub content: String,
}
impl Message {
pub fn id(&self) -> Id {
pub fn id(&self) -> MessageId {
let pred = match self.pred {
Some(id) => format!("{id}"),
None => "none".to_string(),
@ -22,9 +22,9 @@ impl Message {
None => "none".to_string(),
};
let identity = self.identity;
let nick = Id::of(&self.nick);
let content = Id::of(&self.content);
let nick = MessageId::of(&self.nick);
let content = MessageId::of(&self.content);
let str = format!("message {pred} {parent} {identity} {nick} {content}");
Id::of(&str)
MessageId::of(&str)
}
}

110
cove-core/src/packets.rs Normal file
View file

@ -0,0 +1,110 @@
use serde::{Deserialize, Serialize};
use crate::macros::packets;
use crate::{Message, MessageId, User};
#[derive(Debug, Deserialize, Serialize)]
pub struct HelloCmd {
pub nick: String,
pub identity: String,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum HelloRpl {
Success {
you: User,
others: Vec<User>,
last_message: MessageId,
},
NickTooLong,
IdentityTooLong,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct NickCmd {
pub nick: String,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum NickRpl {
Success { you: User },
NickTooLong,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct SendCmd {
pub parent: Option<MessageId>,
pub nick: Option<String>,
pub content: String,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum SendRpl {
Success { message: Message },
NickTooLong,
ContentTooLong,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct WhoCmd;
#[derive(Debug, Deserialize, Serialize)]
pub struct WhoRpl {
you: User,
others: Vec<User>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct JoinNtf {
user: User,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct NickNtf {
user: User,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct PartNtf {
user: User,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct SendNtf {
message: Message,
}
// Create a Cmd enum for all commands, a Rpl enum for all replies and a Ntf enum
// for all notifications, as well as TryFrom impls for the individual structs.
packets! {
cmd Hello(HelloCmd, HelloRpl),
cmd Nick(NickCmd, NickRpl),
cmd Send(SendCmd, SendRpl),
cmd Who(WhoCmd, WhoRpl),
ntf Join(JoinNtf),
ntf Nick(NickNtf),
ntf Part(PartNtf),
ntf Send(SendNtf),
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum Packet {
Cmd {
id: u64,
#[serde(flatten)]
cmd: Cmd,
},
Rpl {
id: u64,
#[serde(flatten)]
rpl: Rpl,
},
Ntf {
#[serde(flatten)]
ntf: Ntf,
},
}

10
cove-core/src/user.rs Normal file
View file

@ -0,0 +1,10 @@
use serde::{Deserialize, Serialize};
use crate::{Identity, SessionId};
#[derive(Debug, Deserialize, Serialize)]
pub struct User {
nick: String,
identity: Identity,
sid: SessionId,
}