version API

new-idea
Avril 3 years ago
parent eeea6a13b1
commit 1212bfdb12
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -1,4 +1,5 @@
use crate::mnemonic::MnemonicSaltKind;
use crate::{version, version::Version};
/// Default anonymous name
pub const ANON_NAME: &'static str = "名無し";
@ -55,7 +56,7 @@ static_assert!(STATE_STREAM_BUFFER_SIZE > 0);
/// The current version of the file formats for saving state
///
/// TODO: Create `Version` type that takes from `env!(version)` at compile time.
pub const VERSION: u32 = 0;
pub const VERSION: Version = version!(0);
/// Max size of a HTTP request body to process.
pub const MAX_CONTENT_LENGTH: u64 = (1024 * 1024) * 15; //15MB

@ -33,6 +33,7 @@ static GLOBAL: Jemalloc = Jemalloc;
#[macro_use] mod ext; use ext::*;
mod version;
mod service;
mod bytes;
mod delta; //unused now, but tests still use it, so...

@ -0,0 +1,65 @@
use super::*;
use std::collections::HashMap;
use tokio::time::{
DelayQueue,
delay_queue,
};
#[derive(Debug)]
pub struct Cache
{
//TODO: HashMap and DelayQueue of mapping public keys to user IDs, etc.
pkey_maps: HashMap<String, (UserID, delay_queue::Key)>,
pkey_rems: DelayQueue<String>,
}
impl Cache
{
/// Create a new empty cache
pub fn new() -> Self
{
Self {
pkey_maps: HashMap::new(),
pkey_rems: DelayQueue::new(),
}
}
//how tf do we get this to run concurrently with insertions??? it holds `&mut self` forever!
//redesign required. maybe using Arc and RwLock or Mutex and interrupting the purge task when something needs to be inserted. i.e: give this task a stream that it can `select!` along with calling `next()`, if the other future completes first, we return? but wouldn't that lose us an item in `next()`? is there a `select with priority` in `futures`? i think there is. eh...
/// Run a purge on this cache.
pub async fn purge(&mut self) -> eyre::Result<()>
{
let mut errors = Vec::default();
while let Some(entry) = self.pkey_rems.next().await
{
match entry {
Ok(entry) => {
self.pkey_maps.remove(entry.get_ref());
},
Err(err) => {
errors.push(err);
}
}
}
if errors.len() > 0 {
let mut err = Err(eyre!("One or more removals failed"))
.with_note(|| errors.len().to_string().header("Number of failed removals"));
for e in errors.into_iter()
{
err = err.with_error(move || e);
}
return err;
} else {
Ok(())
}
}
/// Purge all values available to be purged now.
pub fn purge_now(&mut self) -> eyre::Result<()>
{
match self.purge().now_or_never() {
Some(x) => x,
None => Ok(())
}
}
}

@ -40,7 +40,7 @@ impl FreezeMetadata
{
Self {
chk: *FREEZE_CHK,
version: defaults::VERSION,
version: defaults::VERSION.to_u32(),
body_size: from.len().try_into().unwrap(), //this should never fail, right?
compressed: false,
body_hash: sha256::compute_slice(from),
@ -307,7 +307,8 @@ impl Freeze
posts_map,
users_map,
posts_user_map
})
}),
cache: Cache::new(),
}))
}
@ -336,6 +337,8 @@ impl Freeze
}
State(Arc::new(Inner {
cache: Cache::new(),
oneesan: RwLock::new(Oneesan {
users,
posts,

@ -13,6 +13,9 @@ use futures::prelude::*;
use user::{User, UserID};
use post::{Post, PostID};
mod cache;
pub use cache::*;
mod freeze;
pub use freeze::*;
@ -44,6 +47,9 @@ struct Inner
{
/// The posts and user state.
oneesan: RwLock<Oneesan>,
/// A non-persistant cache
cache: Cache,
}
/// Contains all posts and users
@ -65,7 +71,8 @@ impl State
posts_map: HashMap::new(),
posts_user_map: HashMap::new(),
})
}),
cache: Cache::new(),
}
))
}

@ -14,7 +14,7 @@ mod view
pub fn head() -> Markup
{
html! {
//TODO
//TODO
}
}
@ -44,5 +44,6 @@ mod view
/// Post view page
pub fn view(state: &state::State) -> Markup
{
//TODO: Create one-time-use token system for rendering page. Insert into state's one-time-use tokens
page(view::head(), view::body(state))
}

@ -0,0 +1,207 @@
use std::fmt;
use std::cmp::Ordering;
/// Represents a semver version number of the order `major.minor.bugfix`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] //TODO: Make these impls instead of derives, because safe packed borrows.
#[repr(C, packed)]
pub struct Version(u8,u8,u16);
impl fmt::Display for Version
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}.{}.{}", self.major(), self.minor(), self.bugfix())
}
}
impl From<u32> for Version
{
#[inline] fn from(from: u32) -> Self
{
Self::from_u32(from)
}
}
impl From<Version> for u32
{
fn from(from: Version) -> Self
{
from.to_u32()
}
}
impl PartialEq<Version> for u32
{
#[inline] fn eq(&self, other: &Version) -> bool
{
*self == other.to_u32()
}
}
impl PartialEq<u32> for Version
{
#[inline] fn eq(&self, other: &u32) -> bool
{
self.to_u32() == *other
}
}
impl PartialOrd<u32> for Version
{
#[inline] fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
self.to_u32().partial_cmp(other)
}
}
impl PartialOrd<Version> for u32
{
#[inline] fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
self.partial_cmp(&other.to_u32())
}
}
impl From<()> for Version
{
#[inline] fn from(from: ()) -> Self
{
Self(0,0,0)
}
}
impl From<(usize,)> for Version
{
#[inline] fn from(from: (usize,)) -> Self
{
Self::new(from.0,0,0)
}
}
impl From<(usize, usize)> for Version
{
#[inline] fn from((ma, mi): (usize, usize)) -> Self
{
Self::new(ma, mi, 0)
}
}
impl From<(usize, usize, usize)> for Version
{
#[inline] fn from((ma,mi,bu): (usize, usize, usize)) -> Self
{
Self::new(ma,mi,bu)
}
}
impl From<(u8, u8, u16)> for Version
{
#[inline] fn from((ma, mi, bu): (u8, u8, u16)) -> Self
{
Self(ma,mi,bu)
}
}
impl From<Version> for (u8, u8, u16)
{
#[inline] fn from(from: Version) -> Self
{
(from.0, from.1, from.2)
}
}
impl From<Version> for (usize, usize, usize)
{
#[inline] fn from(from: Version) -> Self
{
(from.major(), from.minor(), from.bugfix())
}
}
impl Version
{
/// The major component of this `Version`.
#[inline] pub const fn major(self) -> usize
{
self.0 as usize
}
/// The minor component of this `Version`.
#[inline] pub const fn minor(self) -> usize
{
self.1 as usize
}
/// The bugfix component of this `Version`.
#[inline] pub const fn bugfix(self) -> usize
{
self.2 as usize
}
/// Convert to a 32 bit integer representation
#[inline] pub const fn to_u32(self) -> u32
{
let mb = self.2.to_be_bytes();
u32::from_be_bytes([
self.0,
self.1,
mb[0],
mb[1],
])
}
/// Convert to a 32 bit integer representation
#[inline] pub const fn from_u32(from: u32) -> Self
{
let bytes = from.to_be_bytes();
Self(
bytes[0],
bytes[1],
u16::from_be_bytes([bytes[2], bytes[3]]),
)
}
/// Create a new version object
#[inline] pub const fn new_exact(major: u8, minor: u8, bugfix: u16) -> Self
{
Self(major,minor,bugfix)
}
/// Create a new version object
///
/// # Panics
/// If any of the components do not fit within their bounds.
#[inline] pub fn new(major: usize, minor: usize, bugfix: usize) -> Self
{
use std::convert::TryInto;
Self::new_exact(major.try_into().expect("Major exceeded limit of u8"),
minor.try_into().expect("Minor exceeded limit of u8"),
bugfix.try_into().expect("Bugfix exceeded limit of u16"),
)
}
}
#[macro_export] macro_rules! version {
($maj:expr, $min:expr, $bfx:expr) => ($crate::version::Version::new_exact($maj as u8, $min as u8, $bfx as u16));
($maj:expr, $min:expr) => ($crate::version::Version::new_exact($maj as u8, $min as u8, 0));
($maj:expr) => ($crate::version::Version::new_exact($maj as u8, 0, 0));
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn ordinal()
{
assert!( version!(1) > version!(0, 9, 1));
assert!( version!(2) > version!(1, 9, 300));
assert!( (version!(1)..version!(1, 9)).contains(&version!(1, 8)));
assert!( !(version!(1)..version!(2)).contains(&version!(2, 10, 432)));
println!("{}: {}", version!(1), version!(1).to_u32());
println!("{}: {}", version!(0,9,1), version!(0,9,1).to_u32());
assert!( version!(1).to_u32() > version!(0, 9, 1).to_u32());
assert!( version!(2).to_u32() > version!(1, 9, 300).to_u32());
assert!( (version!(1).to_u32()..version!(1, 9).to_u32()).contains(&version!(1, 8).to_u32()));
assert!( !(version!(1).to_u32()..version!(2).to_u32()).contains(&version!(2, 10, 432).to_u32()));
}
}

@ -50,6 +50,14 @@ pub fn setup(state: State) -> impl warp::Filter //TODO: What output should this
get_post_by_id
.or(get_posts_by_user_id)
});
root.and(post_api.
or(get_api))
let render_api = warp::get()
.and(state.clone())
.and_then(|state: State| {
async move {
Ok::<_, std::convert::Infallible>(template::view(&state).into_string())
}
});
root.and(post_api
.or(get_api)
.or(render_api))
}

Loading…
Cancel
Save