130 lines
2.5 KiB
Rust
130 lines
2.5 KiB
Rust
use base64::Engine;
|
|
use serde::{Deserialize, Serialize};
|
|
use sha2::{Digest, Sha256};
|
|
|
|
pub type Time = u64;
|
|
|
|
pub const BASE64: base64::engine::general_purpose::GeneralPurpose =
|
|
base64::engine::general_purpose::GeneralPurpose::new(
|
|
&base64::alphabet::URL_SAFE,
|
|
base64::engine::general_purpose::NO_PAD,
|
|
);
|
|
|
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
|
pub struct MutationToken(pub [u8; 16]);
|
|
|
|
impl Default for MutationToken {
|
|
fn default() -> Self {
|
|
Self([0; 16])
|
|
}
|
|
}
|
|
|
|
impl MutationToken {
|
|
pub fn new() -> Self {
|
|
Self(rand::random())
|
|
}
|
|
|
|
pub fn to_base64(&self) -> String {
|
|
BASE64.encode(self.0)
|
|
}
|
|
|
|
pub fn from_base64(s: &str) -> Result<Self, base64::DecodeError> {
|
|
std::panic::catch_unwind(|| {
|
|
let mut buf = [0; 16];
|
|
BASE64.decode_slice_unchecked(s.as_bytes(), &mut buf)?;
|
|
Ok(Self(buf))
|
|
})
|
|
.map_err(|_| base64::DecodeError::InvalidLength)?
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for MutationToken {
|
|
fn as_ref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
|
pub struct TopicHash(pub [u8; 32]);
|
|
|
|
impl Default for TopicHash {
|
|
fn default() -> Self {
|
|
Self([0; 32])
|
|
}
|
|
}
|
|
|
|
impl TopicHash {
|
|
pub fn from_topic(topic: &str) -> Self {
|
|
let mut hasher = Sha256::new();
|
|
hasher.update(topic.as_bytes());
|
|
Self(hasher.finalize().into())
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for TopicHash {
|
|
fn as_ref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
|
pub struct CommentId(pub [u8; 16]);
|
|
|
|
impl Default for CommentId {
|
|
fn default() -> Self {
|
|
Self([0; 16])
|
|
}
|
|
}
|
|
|
|
impl CommentId {
|
|
pub fn new() -> Self {
|
|
Self(rand::random())
|
|
}
|
|
|
|
pub fn zero() -> Self {
|
|
Self([0; 16])
|
|
}
|
|
|
|
pub fn max() -> Self {
|
|
Self([255; 16])
|
|
}
|
|
|
|
pub fn to_base64(&self) -> String {
|
|
BASE64.encode(self.0)
|
|
}
|
|
|
|
pub fn from_base64(s: &str) -> Result<Self, base64::DecodeError> {
|
|
std::panic::catch_unwind(|| {
|
|
let mut buf = [0; 16];
|
|
BASE64.decode_slice_unchecked(s.as_bytes(), &mut buf)?;
|
|
Ok(Self(buf))
|
|
})
|
|
.map_err(|_| base64::DecodeError::InvalidLength)?
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for CommentId {
|
|
fn as_ref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
#[repr(u8)]
|
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
|
pub enum CommentStatus {
|
|
Pending = 0,
|
|
Approved = 1,
|
|
ApprovedEdited(Comment) = 2,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
|
pub struct Comment {
|
|
pub author: String,
|
|
pub email: Option<String>,
|
|
pub last_edit_time: Option<u64>,
|
|
pub mutation_token: MutationToken,
|
|
pub post_time: u64,
|
|
pub text: String,
|
|
pub topic_hash: TopicHash,
|
|
}
|