This commit is contained in:
Aleksandr 2025-12-14 03:25:23 +03:00
parent 7583f7e557
commit 8d3c25b59d
34 changed files with 373 additions and 196 deletions

View file

@ -56,27 +56,25 @@ pub mod search {
pub badges: Logic<game::Badge, 16>, pub badges: Logic<game::Badge, 16>,
} }
type SortKey<K> = (K, game::Id);
#[data(copy, display(name))] #[data(copy, display(name))]
pub enum SortBy { pub enum SortBy {
/// By game id. Simplest possible ordering.
Id { after: Option<game::Id> },
/// By game release date. /// By game release date.
ReleaseDate { ReleaseDate { after: Option<SortKey<time::Date>> },
after: Option<(time::Date, game::Id)>,
},
/// Sort by game creation date.
CreatedAt { after: Option<game::Id> },
/// By publish on site date. /// By publish on site date.
PublishedAt { PublishedAt { after: Option<SortKey<time::Date>> },
after: Option<(time::Date, game::Id)>,
},
/// By game rating. /// By game rating.
Rating { Rating {
after: Option<(game::RatingValue, game::Id)>, after: Option<SortKey<game::RatingValue>>,
}, },
} }
impl Default for SortBy { impl Default for SortBy {
fn default() -> Self { fn default() -> Self {
Self::CreatedAt { after: None } Self::Id { after: None }
} }
} }

View file

@ -0,0 +1,81 @@
use crate::{
errors,
types::{Patch, True, author, entity, file, game},
};
use eva::{array, data, str};
#[data]
pub struct TextEntry<I> {
pub id: I,
pub text: str::CompactString,
}
pub mod add {
use super::*;
#[data]
pub enum Args {
Tag(str::CompactString),
Badge(str::CompactString),
}
#[data]
pub struct Ok {
pub id: entity::Id,
}
#[data(error, display("_"))]
pub enum Err {}
}
pub mod list_genres {
use super::*;
pub const MAX: usize = 256;
#[data]
pub struct Args {}
#[data]
pub struct Ok {
pub genres: array::ImmutableHeap<game::Genre, MAX>,
}
#[data(error, display("_"))]
pub enum Err {}
}
pub mod list_badges {
use super::*;
#[data]
pub struct Args {
pub query: str::CompactString,
}
#[data]
pub struct Ok {
pub badges: Vec<TextEntry<game::Badge>>,
}
#[data(error, display("_"))]
pub enum Err {}
}
pub mod list_tags {
use super::*;
#[data]
pub struct Args {
pub query: str::CompactString,
}
#[data]
pub struct Ok {
pub tags: Vec<TextEntry<game::Tag>>,
}
#[data(error, display("_"))]
pub enum Err {}
}

View file

@ -2,6 +2,8 @@ use crate::errors::Generic;
pub type Response<O, E> = Result<O, Generic<E>>; pub type Response<O, E> = Result<O, Generic<E>>;
pub mod marks;
pub mod boards; pub mod boards;
pub mod messages; pub mod messages;
pub mod threads; pub mod threads;

View file

@ -1,3 +1,5 @@
use std::num::NonZeroU64;
use eva::{data, str}; use eva::{data, str};
use crate::{ use crate::{
@ -14,6 +16,7 @@ pub mod start {
//! - Concurrent uploads limit - also by bytes //! - Concurrent uploads limit - also by bytes
//! //!
//! Quotas are applied per-class. //! Quotas are applied per-class.
use super::*; use super::*;
#[data] #[data]
@ -27,11 +30,11 @@ pub mod start {
pub hash: file::Hash, pub hash: file::Hash,
/// Class of the file. /// Class of the file.
pub class: file::Class, pub class: file::ClassKind,
/// Size of the file to upload. Must be known /// Size of the file to upload. Must be known
/// prior to upload, streaming is not supported. /// prior to upload, streaming is not supported.
pub size: u64, pub size: NonZeroU64,
} }
#[data] #[data]
@ -51,10 +54,10 @@ pub mod start {
pub mod finish { pub mod finish {
use super::*; use super::*;
#[data] #[data(not(Debug, serde, schemars, Clone, PartialEq))]
pub struct Args<S: UploadStream> { pub struct Args {
pub id: upload::Id, pub id: upload::Id,
pub stream: S, pub stream: UploadStream<'static>,
} }
#[data] #[data]

View file

@ -0,0 +1,32 @@
use crate::service::IsSession;
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct Session<S>(S);
impl<S: IsSession> Session<S> {
pub const fn new(session: S) -> Self {
Self(session)
}
}
macro_rules! project {
($(fn $method:ident() -> $($path:ident)::+;)*) => {$(
pub const fn $method(&mut self) -> impl $crate::service::$($path)::* {
&mut self.0
}
)*};
}
#[rustfmt::skip]
impl<S: IsSession> Session<S> {project!{
fn users() -> users::Users;
fn authors() -> authors::Authors;
fn games() -> games::Games;
fn boards() -> boards::Boards;
fn threads() -> threads::Threads;
fn messages() -> messages::Messages;
fn authz() -> authz::Authentication;
}}

View file

@ -6,12 +6,9 @@ use crate::{
use eva::auto_impl; use eva::auto_impl;
#[auto_impl(&mut, Box)] #[auto_impl(&mut, Box)]
pub trait AuthorsRef: Send + Sync { pub trait Authors: Send + Sync {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>; fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>;
}
#[auto_impl(&mut, Box)]
pub trait AuthorsMut: AuthorsRef {
fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>; fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>;
fn update(&mut self) -> impl CallStep<update::Args, Ok = update::Ok, Err = update::Err>; fn update(&mut self) -> impl CallStep<update::Args, Ok = update::Ok, Err = update::Err>;
} }

View file

@ -3,7 +3,7 @@ use eva::auto_impl;
use crate::{service::AuxFut, types::session}; use crate::{service::AuxFut, types::session};
#[auto_impl(&mut)] #[auto_impl(&mut)]
pub trait AuthenticationMut: Send + Sync { pub trait Authentication: Send + Sync {
fn authenticate(&mut self, session: session::Token) -> impl AuxFut<()>; fn authenticate(&mut self, session: session::Token) -> impl AuxFut<()>;
fn clear(&mut self); fn clear(&mut self);

View file

@ -6,12 +6,9 @@ use crate::{
}; };
#[auto_impl(&mut, Box)] #[auto_impl(&mut, Box)]
pub trait BoardsRef: Send + Sync { pub trait Boards: Send + Sync {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>; fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>;
}
#[auto_impl(&mut, Box)]
pub trait BoardsMut: BoardsRef {
fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>; fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>;
fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err>; fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err>;
fn edit(&mut self) -> impl CallStep<edit::Args, Ok = edit::Ok, Err = edit::Err>; fn edit(&mut self) -> impl CallStep<edit::Args, Ok = edit::Ok, Err = edit::Err>;

View file

@ -0,0 +1,9 @@
use eva::auto_impl;
use crate::{requests::files::get_info, service::CallStep};
#[auto_impl(&mut, Box)]
pub trait Files {
fn get_info(&mut self)
-> impl CallStep<get_info::Args, Ok = get_info::Ok, Err = get_info::Err>;
}

View file

@ -6,13 +6,10 @@ use crate::{
}; };
#[auto_impl(&mut, Box)] #[auto_impl(&mut, Box)]
pub trait GamesRef: Send + Sync { pub trait Games: Send + Sync {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>; fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>;
fn search(&mut self) -> impl CallStep<search::Args, Ok = search::Ok, Err = search::Err>; fn search(&mut self) -> impl CallStep<search::Args, Ok = search::Ok, Err = search::Err>;
}
#[auto_impl(&mut, Box)]
pub trait GamesMut: GamesRef {
fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>; fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>;
fn update(&mut self) -> impl CallStep<update::Args, Ok = update::Ok, Err = update::Err>; fn update(&mut self) -> impl CallStep<update::Args, Ok = update::Ok, Err = update::Err>;
} }

View file

@ -6,12 +6,9 @@ use crate::{
}; };
#[auto_impl(&mut, Box)] #[auto_impl(&mut, Box)]
pub trait MessagesRef: Send + Sync { pub trait Messages: Send + Sync {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>; fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>;
}
#[auto_impl(&mut, Box)]
pub trait MessagesMut: Send + Sync {
fn post(&mut self) -> impl CallStep<post::Args, Ok = post::Ok, Err = post::Err>; fn post(&mut self) -> impl CallStep<post::Args, Ok = post::Ok, Err = post::Err>;
fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err>; fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err>;
fn edit(&mut self) -> impl CallStep<edit::Args, Ok = edit::Ok, Err = edit::Err>; fn edit(&mut self) -> impl CallStep<edit::Args, Ok = edit::Ok, Err = edit::Err>;

View file

@ -2,6 +2,10 @@ use eva::{auto_impl, handling, trait_set};
use crate::{errors::Aux, requests::Response}; use crate::{errors::Aux, requests::Response};
pub use self::api_looks::Session;
mod api_looks;
pub mod boards; pub mod boards;
pub mod messages; pub mod messages;
pub mod threads; pub mod threads;
@ -10,6 +14,9 @@ pub mod authors;
pub mod games; pub mod games;
pub mod users; pub mod users;
pub mod files;
pub mod uploads;
pub mod authz; pub mod authz;
pub type SessionOf<T> = <T as SessionMaker>::Session; pub type SessionOf<T> = <T as SessionMaker>::Session;
@ -17,6 +24,23 @@ pub type SessionOf<T> = <T as SessionMaker>::Session;
trait_set! { trait_set! {
pub trait RespFut<O, E> = Future<Output = Response<O, E>> + Send; pub trait RespFut<O, E> = Future<Output = Response<O, E>> + Send;
pub trait AuxFut<O> = Future<Output = Result<O, Aux>> + Send; pub trait AuxFut<O> = Future<Output = Result<O, Aux>> + Send;
pub trait IsService = SessionMaker;
pub trait IsSession = boards::Boards
+ messages::Messages
+ threads::Threads
+ authors::Authors
+ games::Games
+ users::Users
+ authz::Authentication
;
}
#[auto_impl(&, &mut, Arc)]
pub trait SessionMaker: Send + Sync {
type Session: IsSession;
fn make_session(&self) -> impl AuxFut<Session<Self::Session>>;
} }
pub trait CallStep<I>: Send + Sync { pub trait CallStep<I>: Send + Sync {
@ -44,32 +68,3 @@ where
type Ok = O; type Ok = O;
type Err = E; type Err = E;
} }
#[auto_impl(&, &mut, Arc)]
pub trait SessionMaker: Send + Sync {
type Session: Session;
fn make_session(&self) -> impl AuxFut<Self::Session>;
}
trait_set! {
pub trait Service = SessionMaker;
}
#[auto_impl(&mut)]
pub trait Session: Send + Sync {
fn users(&mut self) -> impl users::UsersRef;
fn users_mut(&mut self) -> impl users::UsersMut;
fn authors(&mut self) -> impl authors::AuthorsRef;
fn authors_mut(&mut self) -> impl authors::AuthorsMut;
fn games(&mut self) -> impl games::GamesRef;
fn games_mut(&mut self) -> impl games::GamesMut;
fn authentication_mut(&mut self) -> impl authz::AuthenticationMut;
fn boards(&mut self) -> impl boards::BoardsMut;
fn threads(&mut self) -> impl threads::ThreadsMut;
fn messages(&mut self) -> impl messages::MessagesMut;
}

View file

@ -6,13 +6,10 @@ use crate::{
}; };
#[auto_impl(&mut, Box)] #[auto_impl(&mut, Box)]
pub trait ThreadsRef: Send + Sync { pub trait Threads: Send + Sync {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>; fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>;
fn search(&mut self) -> impl CallStep<search::Args, Ok = search::Ok, Err = search::Err>; fn search(&mut self) -> impl CallStep<search::Args, Ok = search::Ok, Err = search::Err>;
}
#[auto_impl(&mut, Box)]
pub trait ThreadsMut: ThreadsRef {
fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err>; fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err>;
fn edit(&mut self) -> impl CallStep<edit::Args, Ok = edit::Ok, Err = edit::Err>; fn edit(&mut self) -> impl CallStep<edit::Args, Ok = edit::Ok, Err = edit::Err>;
fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>; fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err>;

View file

@ -0,0 +1,17 @@
use eva::auto_impl;
use crate::{
requests::uploads::{abort, finish, list_pending, start},
service::CallStep,
};
#[auto_impl(&mut, Box)]
pub trait Uploads: Send + Sync {
fn list_pending(
&mut self,
) -> impl CallStep<list_pending::Args, Ok = list_pending::Ok, Err = list_pending::Err>;
fn start(&mut self) -> impl CallStep<start::Args, Ok = start::Ok, Err = start::Err>;
fn abort(&mut self) -> impl CallStep<abort::Args, Ok = abort::Ok, Err = abort::Err>;
fn finish(&mut self) -> impl CallStep<finish::Args, Ok = finish::Ok, Err = finish::Err>;
}

View file

@ -8,15 +8,12 @@ use crate::{
}; };
#[auto_impl(&mut)] #[auto_impl(&mut)]
pub trait UsersRef: Send + Sync { pub trait Users: Send + Sync {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>; fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err>;
fn check_auth( fn check_auth(
&mut self, &mut self,
) -> impl CallStep<check_auth::Args, Ok = check_auth::Ok, Err = check_auth::Err>; ) -> impl CallStep<check_auth::Args, Ok = check_auth::Ok, Err = check_auth::Err>;
}
#[auto_impl(&mut)]
pub trait UsersMut: UsersRef {
fn begin_auth( fn begin_auth(
&mut self, &mut self,
) -> impl CallStep<begin_auth::Args, Ok = begin_auth::Ok, Err = begin_auth::Err>; ) -> impl CallStep<begin_auth::Args, Ok = begin_auth::Ok, Err = begin_auth::Err>;

View file

@ -17,37 +17,28 @@ use eva::{data, hash::blake3, int, rand::Rng, str, str::ToCompactString, time::C
pub type Hash = blake3::Hash; pub type Hash = blake3::Hash;
pub mod game_file;
pub mod image;
#[data] #[data]
pub struct FileInfo { pub struct FileInfo {
pub id: Id, pub id: Id,
pub format: FileFormat,
pub class: Class, pub class: Class,
pub size: NonZeroU64, pub size: NonZeroU64,
} }
#[data(copy)]
pub enum FileFormat {
#[display("image:{_0}")]
Image(ImageFormat),
#[display("opaque")]
Opaque,
}
#[data(copy, ord, display(name))] #[data(copy, ord, display(name))]
pub enum ImageFormat { pub enum ClassKind {
Png,
Jpeg,
Bmp,
Gif,
Webp,
}
#[data(copy, ord, display(name))]
pub enum Class {
Image, Image,
GameFile, GameFile,
} }
#[data]
pub enum Class {
Image(image::ImageInfo),
GameFile(game_file::GameFileInfo),
}
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref BASE_NAME_CHAR_PAT: String = { static ref BASE_NAME_CHAR_PAT: String = {
let mut out = String::from("^"); let mut out = String::from("^");

View file

@ -0,0 +1,11 @@
use eva::data;
#[data(copy, ord)]
pub enum GameFileFormat {
BinaryData,
}
#[data]
pub struct GameFileInfo {
pub format: GameFileFormat,
}

View file

@ -0,0 +1,19 @@
use std::num::NonZeroU16;
use eva::data;
#[data]
pub struct ImageInfo {
pub format: ImageFormat,
pub width: NonZeroU16,
pub height: NonZeroU16,
}
#[data(copy, ord, display(name))]
pub enum ImageFormat {
Png,
Jpeg,
Bmp,
Gif,
Webp,
}

View file

@ -1,6 +1,6 @@
use eva::{bytes::Bytes, data, trait_set}; use eva::{bytes::Bytes, data};
use futures::stream::Stream; use futures::stream::BoxStream;
#[data] #[data]
pub enum Action { pub enum Action {
@ -8,6 +8,4 @@ pub enum Action {
Abort, Abort,
} }
trait_set! { pub type UploadStream<'a> = BoxStream<'a, Action>;
pub trait UploadStream = Stream<Item = Action> + Unpin + Send;
}

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[features] [features]
default = [] default = ["server", "client"]
client = ["dep:reqwest"] client = ["dep:reqwest"]
server = [ server = [
"dep:axum", "dep:axum",

View file

@ -2,14 +2,14 @@ use viendesu_core::errors::AuxResult;
use super::*; use super::*;
impl AuthenticationMut for Hidden<'_> { impl Authentication for HttpClient {
async fn authenticate(&mut self, session: session::Token) -> AuxResult<()> { async fn authenticate(&mut self, session: session::Token) -> AuxResult<()> {
self.0.session = Some(session); self.session = Some(session);
Ok(()) Ok(())
} }
fn clear(&mut self) { fn clear(&mut self) {
self.0.session = None; self.session = None;
} }
} }

View file

@ -4,15 +4,13 @@ use viendesu_core::requests::authors::{create, get, update};
use crate::requests::authors as requests; use crate::requests::authors as requests;
impl AuthorsRef for Hidden<'_> { impl Authors for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> { fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, |get::Args { author }| { self.do_call(Method::GET, |get::Args { author }| {
(format_compact!("/authors/{author}"), requests::Get {}) (format_compact!("/authors/{author}"), requests::Get {})
}) })
} }
}
impl AuthorsMut for Hidden<'_> {
fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err> { fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err> {
self.do_call( self.do_call(
Method::POST, Method::POST,

View file

@ -4,13 +4,11 @@ use viendesu_core::requests::boards::{create, delete, edit, get};
use crate::requests::boards as requests; use crate::requests::boards as requests;
impl BoardsRef for Hidden<'_> { impl Boards for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> { fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, todo::<_, requests::Get>()) self.do_call(Method::GET, todo::<_, requests::Get>())
} }
}
impl BoardsMut for Hidden<'_> {
fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err> { fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err> {
self.do_call(Method::POST, todo::<_, requests::Create>()) self.do_call(Method::POST, todo::<_, requests::Create>())
} }

View file

@ -7,7 +7,7 @@ use viendesu_core::{
use crate::requests::games as requests; use crate::requests::games as requests;
impl GamesRef for Hidden<'_> { impl Games for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> { fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, |get::Args { game }| match game { self.do_call(Method::GET, |get::Args { game }| match game {
Selector::Id(id) => (format_compact!("/games/{}", id.to_str()), requests::Get {}), Selector::Id(id) => (format_compact!("/games/{}", id.to_str()), requests::Get {}),
@ -45,9 +45,7 @@ impl GamesRef for Hidden<'_> {
}, },
) )
} }
}
impl GamesMut for Hidden<'_> {
fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err> { fn create(&mut self) -> impl CallStep<create::Args, Ok = create::Ok, Err = create::Err> {
self.do_call( self.do_call(
Method::POST, Method::POST,

View file

@ -4,13 +4,11 @@ use viendesu_core::requests::messages::{delete, edit, get, post};
use crate::requests::messages as requests; use crate::requests::messages as requests;
impl MessagesRef for Hidden<'_> { impl Messages for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> { fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, todo::<_, requests::Get>()) self.do_call(Method::GET, todo::<_, requests::Get>())
} }
}
impl MessagesMut for Hidden<'_> {
fn post(&mut self) -> impl CallStep<post::Args, Ok = post::Ok, Err = post::Err> { fn post(&mut self) -> impl CallStep<post::Args, Ok = post::Ok, Err = post::Err> {
self.do_call(Method::POST, todo::<_, requests::Post>()) self.do_call(Method::POST, todo::<_, requests::Post>())
} }

View file

@ -10,14 +10,8 @@ use viendesu_core::{
errors::{self, Aux}, errors::{self, Aux},
requests::Response, requests::Response,
service::{ service::{
CallStep, Session, SessionMaker, CallStep, Session, SessionMaker, authors::Authors, authz::Authentication, boards::Boards,
authors::{AuthorsMut, AuthorsRef}, games::Games, messages::Messages, threads::Threads, users::Users,
authz::AuthenticationMut,
boards::{BoardsMut, BoardsRef},
games::{GamesMut, GamesRef},
messages::{MessagesMut, MessagesRef},
threads::{ThreadsMut, ThreadsRef},
users::{UsersMut, UsersRef},
}, },
types::session, types::session,
}; };
@ -57,30 +51,10 @@ where
} }
} }
struct Hidden<'a>(&'a mut HttpClient);
fn todo<C, O>() -> impl Send + Sync + FnMut(C) -> (CompactString, O) { fn todo<C, O>() -> impl Send + Sync + FnMut(C) -> (CompactString, O) {
|_| todo!() |_| todo!()
} }
impl<'t> Hidden<'t> {
fn do_call<'this, P>(&'this mut self, method: Method, map_payload: P) -> DoRequest<'this, P> {
DoRequest {
client: self.0,
method,
map_payload,
}
}
}
macro_rules! fwd {
($($method:ident -> $Ret:ident;)*) => {$(
fn $method(&mut self) -> impl $Ret {
Hidden(self)
}
)*};
}
pub struct HttpClient { pub struct HttpClient {
options: Arc<ClientOptions>, options: Arc<ClientOptions>,
client: reqwest::Client, client: reqwest::Client,
@ -88,6 +62,14 @@ pub struct HttpClient {
} }
impl HttpClient { impl HttpClient {
fn do_call<'this, P>(&'this mut self, method: Method, map_payload: P) -> DoRequest<'this, P> {
DoRequest {
client: self,
method,
map_payload,
}
}
async fn do_request<R>( async fn do_request<R>(
&self, &self,
method: Method, method: Method,
@ -150,21 +132,6 @@ impl HttpClient {
} }
} }
impl Session for HttpClient {
fwd! {
users -> UsersRef;
users_mut -> UsersMut;
authors -> AuthorsRef;
authors_mut -> AuthorsMut;
games -> GamesRef;
games_mut -> GamesMut;
boards -> BoardsMut;
threads -> ThreadsMut;
messages -> MessagesMut;
authentication_mut -> AuthenticationMut;
}
}
pub struct ClientOptions { pub struct ClientOptions {
pub format: Format, pub format: Format,
pub endpoint: String, pub endpoint: String,
@ -179,12 +146,12 @@ pub struct HttpService {
impl SessionMaker for HttpService { impl SessionMaker for HttpService {
type Session = HttpClient; type Session = HttpClient;
async fn make_session(&self) -> errors::AuxResult<Self::Session> { async fn make_session(&self) -> errors::AuxResult<Session<Self::Session>> {
Ok(HttpClient { Ok(Session::new(HttpClient {
options: Arc::clone(&self.options), options: Arc::clone(&self.options),
client: self.inner.clone(), client: self.inner.clone(),
session: None, session: None,
}) }))
} }
} }

View file

@ -4,7 +4,7 @@ use viendesu_core::requests::threads::{create, delete, edit, get, search};
use crate::requests::threads as requests; use crate::requests::threads as requests;
impl ThreadsRef for Hidden<'_> { impl Threads for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> { fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, todo::<_, requests::Get>()) self.do_call(Method::GET, todo::<_, requests::Get>())
} }
@ -12,9 +12,7 @@ impl ThreadsRef for Hidden<'_> {
fn search(&mut self) -> impl CallStep<search::Args, Ok = search::Ok, Err = search::Err> { fn search(&mut self) -> impl CallStep<search::Args, Ok = search::Ok, Err = search::Err> {
self.do_call(Method::POST, todo::<_, requests::Search>()) self.do_call(Method::POST, todo::<_, requests::Search>())
} }
}
impl ThreadsMut for Hidden<'_> {
fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err> { fn delete(&mut self) -> impl CallStep<delete::Args, Ok = delete::Ok, Err = delete::Err> {
self.do_call(Method::DELETE, todo::<_, requests::Delete>()) self.do_call(Method::DELETE, todo::<_, requests::Delete>())
} }

View file

@ -8,7 +8,7 @@ use viendesu_core::requests::users::{
use crate::requests::users as requests; use crate::requests::users as requests;
impl UsersRef for Hidden<'_> { impl Users for HttpClient {
fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> { fn get(&mut self) -> impl CallStep<get::Args, Ok = get::Ok, Err = get::Err> {
self.do_call(Method::GET, |get::Args { user }| match user { self.do_call(Method::GET, |get::Args { user }| match user {
Some(u) => (format_compact!("/users/{u}"), requests::Get {}), Some(u) => (format_compact!("/users/{u}"), requests::Get {}),
@ -23,9 +23,7 @@ impl UsersRef for Hidden<'_> {
("/users/check_auth".into(), requests::CheckAuth {}) ("/users/check_auth".into(), requests::CheckAuth {})
}) })
} }
}
impl UsersMut for Hidden<'_> {
fn begin_auth( fn begin_auth(
&mut self, &mut self,
) -> impl CallStep<begin_auth::Args, Ok = begin_auth::Ok, Err = begin_auth::Err> { ) -> impl CallStep<begin_auth::Args, Ok = begin_auth::Ok, Err = begin_auth::Err> {

View file

@ -0,0 +1,19 @@
use eva::data;
use crate::requests::status_code;
use viendesu_core::{errors, requests::files as reqs};
#[data]
pub struct GetInfo {}
impl_req!(GetInfo => [reqs::get_info::Ok; reqs::get_info::Err]);
status_code::direct!(reqs::get_info::Ok => OK);
status_code::map!(reqs::get_info::Err => [NotFound]);
const _: () = {
use errors::files::*;
use status_code::direct;
direct!(NotFound => NOT_FOUND);
};

View file

@ -32,3 +32,6 @@ pub mod games;
pub mod boards; pub mod boards;
pub mod messages; pub mod messages;
pub mod threads; pub mod threads;
pub mod files;
pub mod uploads;

View file

@ -0,0 +1,57 @@
use std::num::NonZeroU64;
use eva::data;
use crate::requests::status_code;
use viendesu_core::{errors, requests::uploads as reqs, types::file};
#[data]
pub struct ListPending {}
impl_req!(ListPending => [reqs::list_pending::Ok; reqs::list_pending::Err]);
status_code::direct!(reqs::list_pending::Ok => OK);
status_code::map!(reqs::list_pending::Err => []);
#[data]
pub struct Start {
pub file_name: Option<file::BaseName>,
pub hash: file::Hash,
pub class: file::ClassKind,
pub size: NonZeroU64,
}
impl_req!(Start => [reqs::start::Ok; reqs::start::Err]);
status_code::direct!(reqs::start::Ok => CREATED);
status_code::map!(reqs::start::Err => [QuotaExceeded, SimUpQuotaExceeded]);
#[data]
pub struct Finish {}
impl_req!(Finish => [reqs::finish::Ok; reqs::finish::Err]);
status_code::direct!(reqs::finish::Ok => OK);
status_code::map!(reqs::finish::Err => [
HashMismatch,
NotFound,
Overuploading,
ConcurrentUploadInProgress,
]);
#[data]
pub struct Abort {}
impl_req!(Abort => [reqs::abort::Ok; reqs::abort::Err]);
status_code::direct!(reqs::abort::Ok => OK);
status_code::map!(reqs::abort::Err => [NotFound]);
const _: () = {
use errors::uploads::*;
use status_code::direct;
direct!(ConcurrentUploadInProgress => BAD_REQUEST);
direct!(NotFound => NOT_FOUND);
direct!(QuotaExceeded => TOO_MANY_REQUESTS);
direct!(SimUpQuotaExceeded => TOO_MANY_REQUESTS);
direct!(Overuploading => BAD_REQUEST);
direct!(HashMismatch => BAD_REQUEST);
};

View file

@ -11,17 +11,14 @@ use axum::{
use viendesu_core::{ use viendesu_core::{
errors as core_errors, errors as core_errors,
service::{Session, SessionOf, authz::AuthenticationMut}, service::{Session, SessionOf, authz::Authentication as _},
}; };
use crate::{ use crate::server::{
format::Format,
server::{
State, Types, State, Types,
context::{Context, load_args}, context::{Context, load_args},
request::{ServerRequest, extract}, request::{ServerRequest, extract},
response, response,
},
}; };
struct Inner<R: ServerRequest, Cx> { struct Inner<R: ServerRequest, Cx> {
@ -130,7 +127,7 @@ impl<R: ServerRequest, M, T: Types, Cx: MakeContext<R>> FinishedHandler<R, M, T,
.map_err(|e| response::err(resp_format, e))? .map_err(|e| response::err(resp_format, e))?
{ {
session session
.authentication_mut() .authz()
.authenticate(token) .authenticate(token)
.await .await
.map_err(|e| response::err(resp_format, e))?; .map_err(|e| response::err(resp_format, e))?;
@ -246,7 +243,7 @@ where
} }
pub trait MakeRequest<T: Types, R: ServerRequest>: pub trait MakeRequest<T: Types, R: ServerRequest>:
Send + Sync + 'static + Fn(SessionOf<T::Service>, Context<R>) -> Self::HFut Send + Sync + 'static + Fn(Session<SessionOf<T::Service>>, Context<R>) -> Self::HFut
{ {
type HFut: Fut<Output = core_errors::Result<R::Response, R::Error>> type HFut: Fut<Output = core_errors::Result<R::Response, R::Error>>
+ Captures<SessionOf<T::Service>>; + Captures<SessionOf<T::Service>>;
@ -254,7 +251,7 @@ pub trait MakeRequest<T: Types, R: ServerRequest>:
impl<T, R, F, H> MakeRequest<T, R> for H impl<T, R, F, H> MakeRequest<T, R> for H
where where
H: Send + Sync + 'static + Fn(SessionOf<T::Service>, Context<R>) -> F, H: Send + Sync + 'static + Fn(Session<SessionOf<T::Service>>, Context<R>) -> F,
F: Fut<Output = core_errors::Result<R::Response, R::Error>> + Captures<SessionOf<T::Service>>, F: Fut<Output = core_errors::Result<R::Response, R::Error>> + Captures<SessionOf<T::Service>>,
T: Types, T: Types,
R: ServerRequest, R: ServerRequest,

View file

@ -5,7 +5,7 @@ use eva::{
use eyre::Context; use eyre::Context;
use viendesu_core::{ use viendesu_core::{
errors::AuxResult, errors::AuxResult,
service::{Service, SessionMaker, SessionOf}, service::{IsService, Session, SessionMaker, SessionOf},
}; };
use tokio::net; use tokio::net;
@ -22,7 +22,7 @@ mod response;
mod routes; mod routes;
pub trait Types: Send + Sync + 'static { pub trait Types: Send + Sync + 'static {
type Service: Service + Clone; type Service: IsService + Clone;
} }
pub async fn serve( pub async fn serve(
@ -73,7 +73,7 @@ struct State<T: Types> {
} }
impl<T: Types> State<T> { impl<T: Types> State<T> {
async fn make_session(&self) -> AuxResult<SessionOf<T::Service>> { async fn make_session(&self) -> AuxResult<Session<SessionOf<T::Service>>> {
self.service.make_session().await Ok(self.service.make_session().await?)
} }
} }

View file

@ -5,14 +5,11 @@ use crate::server::{
}; };
use viendesu_core::{ use viendesu_core::{
service::{ service::{CallStep, Session, SessionOf as SessionOfService},
CallStep, Session, SessionOf as SessionOfService,
users::{UsersMut, UsersRef},
},
types::user, types::user,
}; };
type SessionOf<T> = SessionOfService<<T as Types>::Service>; type SessionOf<T> = Session<SessionOfService<<T as Types>::Service>>;
pub fn make<T: Types>(router: RouterScope<T>) -> RouterScope<T> { pub fn make<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
router router
@ -30,8 +27,11 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
use crate::requests::users::{ use crate::requests::users::{
BeginAuth, CheckAuth, ConfirmSignUp, FinishAuth, Get, SignIn, SignUp, Update, BeginAuth, CheckAuth, ConfirmSignUp, FinishAuth, Get, SignIn, SignUp, Update,
}; };
use viendesu_core::requests::users::{ use viendesu_core::{
requests::users::{
begin_auth, check_auth, confirm_sign_up, finish_auth, get, sign_in, sign_up, update, begin_auth, check_auth, confirm_sign_up, finish_auth, get, sign_in, sign_up, update,
},
service::users::Users,
}; };
fn convert_update(u: Update) -> update::Update { fn convert_update(u: Update) -> update::Update {
@ -64,7 +64,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
"/begin-auth", "/begin-auth",
post(async |mut session: SessionOf<T>, ctx: Ctx<BeginAuth>| { post(async |mut session: SessionOf<T>, ctx: Ctx<BeginAuth>| {
session session
.users_mut() .users()
.begin_auth() .begin_auth()
.call(begin_auth::Args { .call(begin_auth::Args {
method: ctx.request.method, method: ctx.request.method,
@ -78,7 +78,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
async |mut session: SessionOf<T>, mut ctx: Ctx<FinishAuth>| { async |mut session: SessionOf<T>, mut ctx: Ctx<FinishAuth>| {
let auth_session: user::AuthSessionId = ctx.path().await?; let auth_session: user::AuthSessionId = ctx.path().await?;
session session
.users_mut() .users()
.finish_auth() .finish_auth()
.call(finish_auth::Args { auth_session }) .call(finish_auth::Args { auth_session })
.await .await
@ -101,7 +101,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
"/sign_in", "/sign_in",
post(async |mut session: SessionOf<T>, ctx: Ctx<SignIn>| { post(async |mut session: SessionOf<T>, ctx: Ctx<SignIn>| {
session session
.users_mut() .users()
.sign_in() .sign_in()
.call(sign_in::Args { .call(sign_in::Args {
nickname: ctx.request.nickname, nickname: ctx.request.nickname,
@ -120,7 +120,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
display_name, display_name,
} = ctx.request; } = ctx.request;
session session
.users_mut() .users()
.sign_up() .sign_up()
.call(sign_up::Args { .call(sign_up::Args {
nickname, nickname,
@ -136,7 +136,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
patch(async |mut session: SessionOf<T>, mut ctx: Ctx<Update>| { patch(async |mut session: SessionOf<T>, mut ctx: Ctx<Update>| {
let user: user::Selector = ctx.path().await?; let user: user::Selector = ctx.path().await?;
session session
.users_mut() .users()
.update() .update()
.call(update::Args { .call(update::Args {
user: Some(user), user: Some(user),
@ -149,7 +149,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
"/me", "/me",
patch(async |mut session: SessionOf<T>, ctx: Ctx<Update>| { patch(async |mut session: SessionOf<T>, ctx: Ctx<Update>| {
session session
.users_mut() .users()
.update() .update()
.call(update::Args { .call(update::Args {
user: None, user: None,
@ -164,7 +164,7 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
async |mut session: SessionOf<T>, mut ctx: Ctx<ConfirmSignUp>| { async |mut session: SessionOf<T>, mut ctx: Ctx<ConfirmSignUp>| {
let (user, token) = ctx.path().await?; let (user, token) = ctx.path().await?;
session session
.users_mut() .users()
.confirm_sign_up() .confirm_sign_up()
.call(confirm_sign_up::Args { user, token }) .call(confirm_sign_up::Args { user, token })
.await .await
@ -173,12 +173,20 @@ fn users<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
) )
} }
fn uploads<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
use crate::requests::uploads::{Abort, Finish, ListPending, Start};
use viendesu_core::requests::uploads::{abort, finish, list_pending, start};
router
}
fn authors<T: Types>(router: RouterScope<T>) -> RouterScope<T> { fn authors<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
use crate::requests::authors::{Create, Get, Update}; use crate::requests::authors::{Create, Get, Update};
use viendesu_core::{ use viendesu_core::{
requests::authors::{create, get, update}, requests::authors::{create, get, update},
service::authors::{AuthorsMut as _, AuthorsRef as _}, service::authors::Authors,
types::author, types::author,
}; };
@ -193,7 +201,7 @@ fn authors<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
owner, owner,
} = ctx.request; } = ctx.request;
session session
.authors_mut() .authors()
.create() .create()
.call(create::Args { .call(create::Args {
title, title,
@ -226,7 +234,7 @@ fn authors<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
} = ctx.request; } = ctx.request;
session session
.authors_mut() .authors()
.update() .update()
.call(update::Args { .call(update::Args {
author, author,
@ -248,7 +256,7 @@ fn games<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
use viendesu_core::{ use viendesu_core::{
requests::games::{create, get, search, update}, requests::games::{create, get, search, update},
service::games::{GamesMut as _, GamesRef as _}, service::games::Games,
types::{author, game}, types::{author, game},
}; };
@ -266,7 +274,7 @@ fn games<T: Types>(router: RouterScope<T>) -> RouterScope<T> {
release_date, release_date,
} = ctx.request; } = ctx.request;
session session
.games_mut() .games()
.create() .create()
.call(create::Args { .call(create::Args {
title, title,