Implement the skeleton for the Server Session handling
This commit is contained in:
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -220,10 +220,13 @@ dependencies = [
|
|||||||
"actix-tls",
|
"actix-tls",
|
||||||
"futures",
|
"futures",
|
||||||
"libbonknet",
|
"libbonknet",
|
||||||
|
"rand",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
"rustls",
|
"rustls",
|
||||||
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@@ -702,6 +705,12 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.76"
|
version = "1.0.76"
|
||||||
@@ -720,6 +729,36 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rcgen"
|
name = "rcgen"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
|||||||
@@ -13,14 +13,17 @@ actix-rt = "2.9.0"
|
|||||||
actix-server = "2.3.0"
|
actix-server = "2.3.0"
|
||||||
actix-service = "2.0.2"
|
actix-service = "2.0.2"
|
||||||
actix-tls = { version = "3.3.0", features = ["rustls-0_22"] }
|
actix-tls = { version = "3.3.0", features = ["rustls-0_22"] }
|
||||||
|
tokio = { version = "1", features = ["io-util", "sync", "time"] }
|
||||||
rustls = "0.22.2"
|
rustls = "0.22.2"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
tokio-util = { version = "0.7.10", features = ["codec"] }
|
tokio-util = { version = "0.7.10", features = ["codec"] }
|
||||||
|
serde = "1"
|
||||||
rmp-serde = "1.1.2"
|
rmp-serde = "1.1.2"
|
||||||
rcgen = { version = "0.12.1", features = ["x509-parser"] }
|
rcgen = { version = "0.12.1", features = ["x509-parser"] }
|
||||||
|
rand = "0.8.5"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "init_certs"
|
name = "init_certs"
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
mod servercertdb;
|
||||||
|
|
||||||
|
use servercertdb::*;
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc};
|
||||||
|
use std::time::{Instant, Duration};
|
||||||
|
use actix::fut::wrap_future;
|
||||||
use libbonknet::*;
|
use libbonknet::*;
|
||||||
use rustls::{RootCertStore, ServerConfig};
|
use rustls::{RootCertStore, ServerConfig};
|
||||||
use rustls::server::WebPkiClientVerifier;
|
use rustls::server::WebPkiClientVerifier;
|
||||||
@@ -9,12 +14,18 @@ use actix_server::Server;
|
|||||||
use actix_rt::net::TcpStream;
|
use actix_rt::net::TcpStream;
|
||||||
use actix_service::{ServiceFactoryExt as _};
|
use actix_service::{ServiceFactoryExt as _};
|
||||||
use futures::{StreamExt, SinkExt};
|
use futures::{StreamExt, SinkExt};
|
||||||
use thiserror::Error;
|
use rand::random;
|
||||||
use tokio_util::codec::{Framed, LengthDelimitedCodec};
|
use tokio_util::codec::{Framed, FramedRead, FramedWrite, LengthDelimitedCodec};
|
||||||
use tracing::{info, error};
|
use tracing::{info, error};
|
||||||
use rcgen::{Certificate, CertificateParams, DnType, KeyPair};
|
use rcgen::{Certificate, CertificateParams, DnType, KeyPair};
|
||||||
|
use tokio::io::{ReadHalf, WriteHalf};
|
||||||
|
use tokio_util::bytes::{Bytes, BytesMut};
|
||||||
|
use tokio::io::Error;
|
||||||
|
use tokio::sync::{oneshot, Mutex};
|
||||||
|
|
||||||
type TransportStream = Framed<TlsStream<TcpStream>, LengthDelimitedCodec>;
|
type TransportStream = Framed<TlsStream<TcpStream>, LengthDelimitedCodec>;
|
||||||
|
type TransportStreamTx = FramedWrite<WriteHalf<TlsStream<TcpStream>>, LengthDelimitedCodec>;
|
||||||
|
type TransportStreamRx = FramedRead<ReadHalf<TlsStream<TcpStream>>, LengthDelimitedCodec>;
|
||||||
|
|
||||||
struct ServerCert {
|
struct ServerCert {
|
||||||
cert: Vec<u8>,
|
cert: Vec<u8>,
|
||||||
@@ -35,71 +46,128 @@ fn generate_server_cert(root_cert: &Certificate, name: &str) -> ServerCert {
|
|||||||
ServerCert { cert, prkey }
|
ServerCert { cert, prkey }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
enum DBError {
|
#[derive(MessageResponse)]
|
||||||
#[error("Certificate is already registered with name {0}")]
|
enum SendMsgResult {
|
||||||
CertAlreadyRegistered(String),
|
Accepted,
|
||||||
// #[error("Generic Failure")]
|
Rejected,
|
||||||
// GenericFailure,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
#[rtype(result = "bool")]
|
#[rtype(result = "SendMsgResult")]
|
||||||
struct IsNameRegistered {
|
struct SendMsg {
|
||||||
name: String,
|
msg: ToServerMessageBody,
|
||||||
|
reply_channel: oneshot::Sender<FromServerReplyBody>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
#[rtype(result = "Result<(), DBError>")]
|
#[rtype(result = "()")]
|
||||||
struct RegisterServer {
|
struct SendPing;
|
||||||
cert: Vec<u8>,
|
|
||||||
name: String,
|
struct ServerTransporter {
|
||||||
|
rx: Option<TransportStreamRx>,
|
||||||
|
tx: Arc<Mutex<TransportStreamTx>>,
|
||||||
|
last_transmission: Instant,
|
||||||
|
reply_channels: HashMap<u64, oneshot::Sender<FromServerReplyBody>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Message)]
|
impl ServerTransporter {
|
||||||
#[rtype(result = "Option<String>")]
|
fn new(transport: TransportStream) -> Self {
|
||||||
struct FetchName {
|
let internal = transport.into_inner();
|
||||||
cert: Vec<u8>,
|
let (srx, stx) = tokio::io::split(internal);
|
||||||
}
|
let codec = LengthDelimitedCodec::new();
|
||||||
|
let rx = FramedRead::new(srx, codec.clone());
|
||||||
// TODO: Move into Sqlite DB with unique check on col1 and col2!!!! Right now name is not unique
|
let tx = FramedWrite::new(stx, codec.clone());
|
||||||
struct ServerCertDB {
|
ServerTransporter {
|
||||||
db: HashMap<Vec<u8>, String>, // Cert to Name
|
rx: Some(rx),
|
||||||
}
|
tx: Arc::new(Mutex::new(tx)),
|
||||||
|
last_transmission: Instant::now(),
|
||||||
impl Actor for ServerCertDB {
|
reply_channels: HashMap::new(),
|
||||||
type Context = Context<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Handler<RegisterServer> for ServerCertDB {
|
|
||||||
type Result = Result<(), DBError>;
|
|
||||||
|
|
||||||
fn handle(&mut self, msg: RegisterServer, _ctx: &mut Self::Context) -> Self::Result {
|
|
||||||
match self.db.get(&msg.cert) {
|
|
||||||
None => {
|
|
||||||
self.db.insert(msg.cert, msg.name);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Some(name) => {
|
|
||||||
Err(DBError::CertAlreadyRegistered(name.clone()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler<IsNameRegistered> for ServerCertDB {
|
impl Actor for ServerTransporter {
|
||||||
type Result = bool;
|
type Context = Context<Self>;
|
||||||
|
|
||||||
fn handle(&mut self, msg: IsNameRegistered, _ctx: &mut Self::Context) -> Self::Result {
|
fn started(&mut self, ctx: &mut Self::Context) {
|
||||||
self.db.values().any(|x| *x == msg.name)
|
let rx = self.rx.take().expect("Rx Stream not found");
|
||||||
|
ctx.add_stream(rx);
|
||||||
|
ctx.run_interval(Duration::from_secs(60), |_s, c| {
|
||||||
|
c.notify(SendPing);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler<FetchName> for ServerCertDB {
|
impl Handler<SendPing> for ServerTransporter {
|
||||||
type Result = Option<String>;
|
type Result = ();
|
||||||
|
|
||||||
fn handle(&mut self, msg: FetchName, _ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, _msg: SendPing, ctx: &mut Self::Context) -> Self::Result {
|
||||||
self.db.get(&msg.cert).map(|s| s.to_owned())
|
let msg = ToServerMessage::Ping;
|
||||||
|
let payload: Bytes = rmp_serde::to_vec(&msg).unwrap().into();
|
||||||
|
let arc_tx = self.tx.clone();
|
||||||
|
ctx.spawn(wrap_future::<_, Self>(async move {
|
||||||
|
arc_tx.lock().await.send(payload).await
|
||||||
|
}).map(|res, _a, _ctx| {
|
||||||
|
info!("Ping sent result: {:?}", res);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<SendMsg> for ServerTransporter {
|
||||||
|
type Result = SendMsgResult;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: SendMsg, ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
let mut reply_id: u64;
|
||||||
|
if self.reply_channels.len() == u64::MAX as usize {
|
||||||
|
return SendMsgResult::Rejected;
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
reply_id = random();
|
||||||
|
if !self.reply_channels.contains_key(&reply_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.reply_channels.insert(reply_id, msg.reply_channel);
|
||||||
|
let msg = ToServerMessage::Msg {
|
||||||
|
reply_id,
|
||||||
|
body: msg.msg,
|
||||||
|
};
|
||||||
|
let payload: Bytes = rmp_serde::to_vec(&msg).unwrap().into();
|
||||||
|
let arc_tx = self.tx.clone();
|
||||||
|
ctx.spawn(async move {
|
||||||
|
arc_tx.lock().await.send(payload).await
|
||||||
|
}.into_actor(self).map(|res, _a, _ctx| {
|
||||||
|
info!("ToServerMsg sent result: {:?}", res);
|
||||||
|
}));
|
||||||
|
SendMsgResult::Accepted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StreamHandler<Result<BytesMut, Error>> for ServerTransporter {
|
||||||
|
fn handle(&mut self, item: Result<BytesMut, Error>, _ctx: &mut Self::Context) {
|
||||||
|
match item {
|
||||||
|
Ok(buf) => {
|
||||||
|
use FromServerReply::*;
|
||||||
|
let msg: FromServerReply = rmp_serde::from_slice(&buf).unwrap();
|
||||||
|
match msg {
|
||||||
|
Pong => {
|
||||||
|
self.last_transmission = Instant::now();
|
||||||
|
}
|
||||||
|
Msg { reply_id, body } => match self.reply_channels.remove(&reply_id) {
|
||||||
|
None => {}
|
||||||
|
Some(reply_tx) => {
|
||||||
|
if let Err(_e) = reply_tx.send(body) {
|
||||||
|
error!("Oneshot channel {} got invalidated! No reply sent.", reply_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("ERROR {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +257,12 @@ async fn main() {
|
|||||||
server_command_handler(transport, peer_cert_bytes, &server_db_addr).await;
|
server_command_handler(transport, peer_cert_bytes, &server_db_addr).await;
|
||||||
}
|
}
|
||||||
Subscribe => {
|
Subscribe => {
|
||||||
info!("Subscribe Stream")
|
info!("Subscribe Stream");
|
||||||
|
let reply = ToServerConnTypeReply::OkSubscribe;
|
||||||
|
transport.send(rmp_serde::to_vec(&reply).unwrap().into()).await.unwrap();
|
||||||
|
// TODO: If I pass transport away and the service returns, what happen to the connection?
|
||||||
|
// in theory it will remain open but better check
|
||||||
|
server_subscribe_handler(transport).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,6 +293,21 @@ async fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn server_subscribe_handler(transport: TransportStream) {
|
||||||
|
let h = ServerTransporter::new(transport).start();
|
||||||
|
info!("Actor spawned");
|
||||||
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||||
|
info!("5 seconds elapsed, sending msg");
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
h.send(SendMsg {
|
||||||
|
msg: ToServerMessageBody::Required { id: "session_id".to_string() },
|
||||||
|
reply_channel: tx,
|
||||||
|
}).await.unwrap();
|
||||||
|
if let Ok(item) = rx.await {
|
||||||
|
info!("Response: {:?}", item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn server_command_handler(mut transport: TransportStream, peer_cert_bytes: Vec<u8>, server_db_addr: &Addr<ServerCertDB>) {
|
async fn server_command_handler(mut transport: TransportStream, peer_cert_bytes: Vec<u8>, server_db_addr: &Addr<ServerCertDB>) {
|
||||||
loop {
|
loop {
|
||||||
match transport.next().await {
|
match transport.next().await {
|
||||||
|
|||||||
73
bonknet_broker/src/servercertdb.rs
Normal file
73
bonknet_broker/src/servercertdb.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use actix::{Actor, Context, Handler, Message};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
// TODO: Probably it's better to remove the pub from inside the structs and impl a new() funct
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum DBError {
|
||||||
|
#[error("Certificate is already registered with name {0}")]
|
||||||
|
CertAlreadyRegistered(String),
|
||||||
|
// #[error("Generic Failure")]
|
||||||
|
// GenericFailure,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "bool")]
|
||||||
|
pub struct IsNameRegistered {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "Result<(), DBError>")]
|
||||||
|
pub struct RegisterServer {
|
||||||
|
pub cert: Vec<u8>,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "Option<String>")]
|
||||||
|
pub struct FetchName {
|
||||||
|
pub cert: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Move into Sqlite DB with unique check on col1 and col2!!!! Right now name is not unique
|
||||||
|
pub struct ServerCertDB {
|
||||||
|
pub db: HashMap<Vec<u8>, String>, // Cert to Name
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Actor for ServerCertDB {
|
||||||
|
type Context = Context<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<RegisterServer> for ServerCertDB {
|
||||||
|
type Result = Result<(), DBError>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: RegisterServer, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
match self.db.get(&msg.cert) {
|
||||||
|
None => {
|
||||||
|
self.db.insert(msg.cert, msg.name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Some(name) => {
|
||||||
|
Err(DBError::CertAlreadyRegistered(name.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<IsNameRegistered> for ServerCertDB {
|
||||||
|
type Result = bool;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: IsNameRegistered, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
self.db.values().any(|x| *x == msg.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<FetchName> for ServerCertDB {
|
||||||
|
type Result = Option<String>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: FetchName, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
self.db.get(&msg.cert).map(|s| s.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -175,22 +175,46 @@ async fn main() -> std::io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Subscribe consume
|
// Subscribe consume
|
||||||
transport.for_each(|item| async move {
|
loop {
|
||||||
match item {
|
match transport.next().await {
|
||||||
Ok(buf) => {
|
None => {
|
||||||
use ToServerMessage::*;
|
info!("Empty Buffer");
|
||||||
let msg: ToServerMessage = rmp_serde::from_slice(&buf).unwrap();
|
}
|
||||||
match msg {
|
Some(item) => {
|
||||||
Required { id } => {
|
let mut out: Option<FromServerReply> = None;
|
||||||
info!("I'm required with Connection ID {}", id);
|
match item {
|
||||||
|
Ok(buf) => {
|
||||||
|
use ToServerMessage::*;
|
||||||
|
let msg: ToServerMessage = rmp_serde::from_slice(&buf).unwrap();
|
||||||
|
match msg {
|
||||||
|
Msg { reply_id, body } => {
|
||||||
|
use ToServerMessageBody::*;
|
||||||
|
match body {
|
||||||
|
Required { id } => {
|
||||||
|
info!("I'm required with Connection ID {}", id);
|
||||||
|
out = Some(FromServerReply::Msg {
|
||||||
|
reply_id,
|
||||||
|
body: FromServerReplyBody::RequiredAccepted,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ping => {
|
||||||
|
info!("Ping!");
|
||||||
|
out = Some(FromServerReply::Pong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if let Some(msg) = out {
|
||||||
Err(e) => {
|
transport.send(rmp_serde::to_vec(&msg).unwrap().into()).await.unwrap();
|
||||||
error!("Error: {:?}", e);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).await;
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,6 @@ pub fn load_prkey(filename: &str) -> std::io::Result<PrivatePkcs8KeyDer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub enum RequiredReplyValues {
|
|
||||||
Ok,
|
|
||||||
GenericFailure { status_code: u32, msg: Option<String> },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum FromServerConnTypeMessage {
|
pub enum FromServerConnTypeMessage {
|
||||||
SendCommand,
|
SendCommand,
|
||||||
@@ -65,10 +59,35 @@ pub enum YouAreValues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum ToServerMessage {
|
pub enum ToServerMessageBody {
|
||||||
Required { id: String },
|
Required { id: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum ToServerMessage {
|
||||||
|
Ping,
|
||||||
|
Msg {
|
||||||
|
reply_id: u64,
|
||||||
|
body: ToServerMessageBody,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum FromServerReplyBody {
|
||||||
|
RequiredAccepted,
|
||||||
|
RequiredFailed,
|
||||||
|
Pong,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum FromServerReply {
|
||||||
|
Pong,
|
||||||
|
Msg {
|
||||||
|
reply_id: u64,
|
||||||
|
body: FromServerReplyBody
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum FromGuestServerMessage {
|
pub enum FromGuestServerMessage {
|
||||||
Announce { name: String }
|
Announce { name: String }
|
||||||
|
|||||||
Reference in New Issue
Block a user