From 04f35d36d66336627984bdf339af91484202f7ee Mon Sep 17 00:00:00 2001 From: Avril Date: Wed, 9 Sep 2020 04:41:21 +0100 Subject: [PATCH] now using serde CBOR --- Cargo.lock | 46 +++++++++++++++++++++++-- Cargo.toml | 8 +++-- src/bytes.rs | 84 ++++++++++++++++++++++---------------------- src/config.rs | 7 ++-- src/identity.rs | 25 ++------------ src/main.rs | 8 ++--- src/post/mod.rs | 86 ++++++---------------------------------------- src/state/local.rs | 2 +- src/suspend.rs | 79 ++++++++++++++++-------------------------- src/tripcode.rs | 5 +-- 10 files changed, 145 insertions(+), 205 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 146fa11..e4cd791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,7 @@ checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" dependencies = [ "num-integer", "num-traits", + "serde", "time", ] @@ -75,11 +76,13 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" [[package]] name = "cryptohelpers" -version = "0.1.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8689d930e1c3d1cbd99014c9f7bf1a1197db8e0665ff134517b86c78233ef4fb" +checksum = "3aea2aded66cedf86364894060626fd5837b10b81d8a9592bc0bcde7a5a3af3d" dependencies = [ "libc", + "serde", + "serde_derive", "sha2", "tokio", ] @@ -142,6 +145,12 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "half" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" + [[package]] name = "hermit-abi" version = "0.1.15" @@ -414,6 +423,36 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "serde" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.9.1" @@ -531,6 +570,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" dependencies = [ "rand", + "serde", ] [[package]] @@ -606,6 +646,8 @@ dependencies = [ "libc", "once_cell", "rustc_version", + "serde", + "serde_cbor", "tokio", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml index a180a78..94537c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,14 @@ edition = "2018" [dependencies] tokio = {version = "0.2", features=["full"]} async-trait = "0.1.40" -chrono = "0.4.15" -uuid = {version = "0.8", features=["v4"]} +chrono = {version = "0.4.15", features=["serde"]} +uuid = {version = "0.8", features=["v4", "serde"]} once_cell = "1.4.1" -crypto = {package= "cryptohelpers", version = "0.1", features= ["async", "sha256"]} +crypto = {version = "1.1.1", package= "cryptohelpers", features= ["serialise", "async", "sha256"]} libc = "0.2.76" byteorder = "1.3.4" +serde_cbor = "0.11.1" +serde = {version = "1.0.115", features= ["derive"]} [build-dependencies] rustc_version = "0.2" diff --git a/src/bytes.rs b/src/bytes.rs index d3de2ae..5291229 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -5,13 +5,13 @@ use std::{ use libc::c_void; pub unsafe fn refer<'a, T>(src: &'a T) -> &'a [u8] - where T: ?Sized +where T: ?Sized { std::slice::from_raw_parts(src as *const T as *const u8, std::mem::size_of_val(src)) } pub unsafe fn refer_mut<'a, T>(src: &'a mut T) -> &'a mut [u8] - where T: ?Sized +where T: ?Sized { std::slice::from_raw_parts_mut(src as *mut T as *mut u8, std::mem::size_of_val(src)) } @@ -27,58 +27,60 @@ pub unsafe fn derefer_mut<'a, T>(src: &'a mut [u8]) -> &'a mut T assert!(src.len() >= std::mem::size_of::()); &mut *(&mut src[0] as *mut u8 as *mut T) } +mod old { + use super::*; + /// Represents a type that can be converted from bytes to itself + pub trait FromBytes: Sized + { + type Error; + fn from_bytes>(bytes: T) -> Result; + } -/// Represents a type that can be converted from bytes to itself -pub trait FromBytes: Sized -{ - type Error; - fn from_bytes>(bytes: T) -> Result; -} - -/// Represents a type that can be converted into bytes -pub trait IntoBytes:Sized -{ - fn into_bytes(self) -> Box<[u8]>; -} + /// Represents a type that can be converted into bytes + pub trait IntoBytes:Sized + { + fn into_bytes(self) -> Box<[u8]>; + } -impl>> IntoBytes for T -{ - #[inline] fn into_bytes(self) -> Box<[u8]> + impl>> IntoBytes for T { - self.into() + #[inline] fn into_bytes(self) -> Box<[u8]> + { + self.into() + } } -} -impl FromBytes for Vec -{ - type Error = !; - #[inline] fn from_bytes>(bytes: T) -> Result + impl FromBytes for Vec { - Ok(Vec::from(bytes.as_ref())) + type Error = !; + #[inline] fn from_bytes>(bytes: T) -> Result + { + Ok(Vec::from(bytes.as_ref())) + } } -} -impl FromBytes for Box<[u8]> -{ - type Error = !; - #[inline] fn from_bytes>(bytes: T) -> Result + impl FromBytes for Box<[u8]> { - Ok(Vec::from(bytes.as_ref()).into_boxed_slice()) + type Error = !; + #[inline] fn from_bytes>(bytes: T) -> Result + { + Ok(Vec::from(bytes.as_ref()).into_boxed_slice()) + } } -} -/// The error used when a `FromBytes` conversion fails because the buffer was not the correct size -#[derive(Debug)] -pub struct SizeError; -impl error::Error for SizeError{} -impl fmt::Display for SizeError -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + + /// The error used when a `FromBytes` conversion fails because the buffer was not the correct size + #[derive(Debug)] + pub struct SizeError; + impl error::Error for SizeError{} + impl fmt::Display for SizeError { - write!(f,"buffer was not the correct size") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f,"buffer was not the correct size") + } } -} - +} /// Copy slice of bytes only /// /// # Notes diff --git a/src/config.rs b/src/config.rs index 87061d8..358d697 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,7 @@ use super::*; +use std::{ + borrow::Cow, +}; //TODO: Use tokio Watcher instead, to allow hotreloading? use once_cell::sync::OnceCell; @@ -24,7 +27,7 @@ pub fn get() -> &'static Config pub struct Config { /// Name for nanashi - pub anon_name: String, + pub anon_name: Cow<'static, str>, } impl Default for Config @@ -33,7 +36,7 @@ impl Default for Config fn default() -> Self { Self { - anon_name: "Nanashi", + anon_name: Cow::Borrowed("Nanashi"), } } } diff --git a/src/identity.rs b/src/identity.rs index 9f05cc7..2b6d3f5 100644 --- a/src/identity.rs +++ b/src/identity.rs @@ -7,31 +7,9 @@ use uuid::Uuid; /// A globally unique post identifier. #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +#[derive(Serialize, Deserialize)] pub struct PostID(Uuid); -impl bytes::IntoBytes for PostID -{ - fn into_bytes(self) -> Box<[u8]> - { - Box::from(*self.0.as_bytes()) - } -} - -impl bytes::FromBytes for PostID -{ - type Error = bytes::SizeError; - fn from_bytes>(bytes: T) -> Result { - let bytes = bytes.as_ref(); - if bytes.len() < 16 { - Err(bytes::SizeError) - } else { - let by = [0u8; 16]; - assert_eq!(bytes::copy_slice(&mut by[..], bytes), 16); - Ok(Self(Uuid::from_bytes(by))) - } - } -} - impl PostID { /// Generate a new `PostID`. @@ -51,6 +29,7 @@ impl fmt::Display for PostID /// A user's data, if set. #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[derive(Serialize, Deserialize)] pub struct User { pub name: Option, diff --git a/src/main.rs b/src/main.rs index cb8aad6..370119a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,12 +4,8 @@ #![allow(dead_code)] use async_trait::async_trait; - -use self::{ - bytes::{ - FromBytes as _, - IntoBytes as _, - }, +use serde::{ + Serialize, Deserialize, }; mod bytes; diff --git a/src/post/mod.rs b/src/post/mod.rs index dddcf99..1914acd 100644 --- a/src/post/mod.rs +++ b/src/post/mod.rs @@ -12,63 +12,15 @@ use chrono::prelude::*; /// /// Usually in UTC, pls keep it in Utc... #[derive(Debug, Clone, PartialEq, Eq)] -pub struct PostTimestamp -where T: TimeZone, +#[derive(Serialize, Deserialize)] +pub struct PostTimestamp { - pub opened: DateTime, - pub closed: Option>, - pub last_edit: DateTime, + pub opened: DateTime, + pub closed: Option>, + pub last_edit: DateTime, } -impl bytes::IntoBytes for PostTimestamp -where T: TimeZone, -{ - fn into_bytes(self) -> Box<[u8]> { - const ESIZE: usize = std::mem::size_of::(); - let mut output =[0u8; ESIZE * 3]; - use byteorder::{ - LittleEndian, - WriteBytesExt, - }; - //FUCK this. why is ther eno from_timestamp_nanos()!??? wtf is the point of the nanos versions then?????? fuck - output[..ESIZE] .as_mut().write_i64::(self.opened.timestamp()).unwrap(); - output[ESIZE..ESIZE*2] .as_mut().write_i64::(self.closed.map(|x| x.timestamp()).unwrap_or(i64::MIN)).unwrap(); - output[ESIZE*2..ESIZE*3].as_mut().write_i64::(self.last_edit.timestamp()).unwrap(); - output.into() - } -} - -impl bytes::FromBytes for PostTimestamp -{ - type Error = bytes::SizeError; - fn from_bytes>(bytes: U) -> Result { - const ESIZE: usize = std::mem::size_of::(); - let bytes=bytes.as_ref(); - if bytes.len() < ESIZE * 3 { - return Err(bytes::SizeError); - } - - use byteorder::{ - LittleEndian, - ReadBytesExt, - }; - - let opened = bytes.read_i64::().unwrap(); - let closed = match bytes[ESIZE..].as_ref().read_i64::().unwrap() { - i64::MIN => None, - x => Some(x), - }; - let last_edit = bytes[ESIZE*2..].as_ref().read_i64::().unwrap(); - - Ok(Self{ - opened: DateTime::from_utc(NaiveDateTime::from_timestamp(opened, 0), Utc), - closed: closed.map(|closed| DateTime::from_utc(NaiveDateTime::from_timestamp(closed, 0), Utc)), - last_edit: DateTime::from_utc(NaiveDateTime::from_timestamp(last_edit, 0), Utc), - }) - } -} - -impl Hash for PostTimestamp { +impl Hash for PostTimestamp { fn hash(&self, state: &mut H) { self.opened.hash(state); self.closed.hash(state); @@ -76,9 +28,7 @@ impl Hash for PostTimestamp { } } -impl fmt::Display for PostTimestamp -where T: TimeZone, - T::Offset: fmt::Display +impl fmt::Display for PostTimestamp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -94,7 +44,7 @@ where T: TimeZone, } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// A closed and finished post. The inverse of `Imouto`. pub struct Static { @@ -122,26 +72,12 @@ impl Suspendable for Static async fn suspend(self, into: &mut S) -> Result<(), suspend::Error> { let mut output = suspend::Object::new(); - output.insert_value("id", self.id); - - output.insert_bool("Some(user-name)", self.user.name.is_some()); - output.insert_string("user-name", self.user.name.unwrap_or_default()); - output.insert_bool("Some(user-email)", self.user.email.is_some()); - output.insert_string("user-email", self.user.email.unwrap_or_default()); - //TODO: Tripcode - output.insert_bool("Some(title)", self.title.is_some()); - output.insert_string("title", self.title.unwrap_or_default()); - - output.insert_string("body", self.karada); - output.insert_value("timestamp", self.timestamp); - - output.insert_bytes("hash", self.hash); - + output.insert("post-static", self); into.set_object(output).await } async fn load(from: &mut S) -> Result { - fuck - todo!() //ehhhh... this is so dumb... + let mut input = from.get_object().await?.ok_or(suspend::Error::BadObject)?; + input.try_get("post-static").ok_or(suspend::Error::BadObject) } } diff --git a/src/state/local.rs b/src/state/local.rs index 2ddd7bc..418fd8e 100644 --- a/src/state/local.rs +++ b/src/state/local.rs @@ -74,7 +74,7 @@ pub struct Karada /// Handles working on `Karada` instances. pub struct Kokoro { - ...//TODO +// ...//TODO } /// An open, as yet unfinied post diff --git a/src/suspend.rs b/src/suspend.rs index ed8c5ac..0cf548b 100644 --- a/src/suspend.rs +++ b/src/suspend.rs @@ -24,10 +24,6 @@ use tokio::{ AsyncWrite, }, }; -use bytes::{ - IntoBytes, - FromBytes, -}; /// Represents an opaque bytes stream of serialised data to insert into `SuspendStream`. #[derive(Debug, Clone, PartialEq, Eq)] @@ -56,6 +52,7 @@ where I: IntoIterator, impl Object { + /// Create a new empty `Object`. #[inline] pub fn new() -> Self { @@ -73,46 +70,47 @@ impl Object } true } - - /// Insert a boolean - pub fn insert_bool(&mut self, name: impl Into>, value: bool) - { - self.insert_bytes(name, if value {&[1]} else {&[0]}) - } - /// Get a boolean - pub fn get_bool(&self, name: impl Borrow) -> Option - { - self.get_bytes(name).map(|x| if x[0]==0 {false} else {true}) - } - - /// Insert a UTF-8 string - pub fn insert_string(&mut self, name: impl Into>, stri: impl AsRef) - { - self.insert_bytes(name, stri.as_ref().as_bytes()) - } - - /// Try to get a UTF-8 string, returning `None` if either the name was not present, or the string was not formatted correctly - pub fn try_get_string(&self, name: impl Borrow) -> Option<&str> + + /// Try to get a value of type `T` from `name`. + pub fn get<'a, T>(&'a mut self, name: impl Borrow) -> Option + where T: Deserialize<'a> { if let Some(bytes) = self.get_bytes(name) { - std::str::from_utf8(bytes).ok() + serde_cbor::from_slice(&bytes[..]).expect("Failed to deserialize CBOR value") } else { None } } - /// Try to get a UTF-8 string, returning `None` if the name was not present - /// - /// # Panics - /// If the present string was not valid UTF-8 - pub fn get_string(&self, name: impl Borrow) -> Option<&str> + + /// Try to get a value of type `T` from `name`. + pub fn try_get<'a, T>(&'a mut self, name: impl Borrow) -> Option + where T: Deserialize<'a> { if let Some(bytes) = self.get_bytes(name) { - Some(std::str::from_utf8(bytes).expect("String contained invalid UTF-8")) + serde_cbor::from_slice(&bytes[..]).ok() } else { None } } + + /// Serialize and insert `value` into the stream with `name`. + pub fn insert(&mut self, name: impl Into>, value: T) + where T: Serialize + { + let len = self.data.len(); + match serde_cbor::to_writer(&mut self.data, &value) { + Ok(()) => { + let nlen = self.data.len(); + self.data_instances.insert(name.into(), len..nlen).unwrap_none(); + }, + Err(err) => { + self.data.resize(len, 0); //Roll back result + panic!("Failed inserting CBOR object: {}", err) //TODO: Return Err instead of panic + }, + } + } + /// Insert bytes directly with this name pub fn insert_bytes(&mut self, name: impl Into>, bytes: impl AsRef<[u8]>) { @@ -132,25 +130,6 @@ impl Object self.insert_bytes(name, bytes::refer(value)) } - /// Convert a value to bytes and insert it into this object - pub fn insert_value(&mut self, name: U, value: T) - where U: Into> - { - self.insert_bytes(name, value.into_bytes()) - } - - - /// Try to get a value from the bytes specified by name - pub fn get_value(&self, name: impl Borrow) -> Result, T::Error> - where T: FromBytes - { - if let Some(range) = self.data_instances.get(name.borrow()) { - Ok(Some(T::from_bytes(&self.data[range.clone()])?)) - } else { - Ok(None) - } - } - /// Try to get the bytes specified by name pub fn get_bytes(&self, name: impl Borrow) -> Option<&[u8]> { diff --git a/src/tripcode.rs b/src/tripcode.rs index 5ecf928..2f9536a 100644 --- a/src/tripcode.rs +++ b/src/tripcode.rs @@ -4,9 +4,10 @@ use super::*; ///TODO: A kana-hash tripcode #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum Tripcode +#[derive(Serialize, Deserialize)] +pub struct Tripcode;/* { Secure(i32), Normal(i32), Special(&'static str), -} +}*/