mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
add flowy-sys crate
This commit is contained in:
parent
126ac20ccc
commit
4d91ed147d
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,4 +9,5 @@ Cargo.lock
|
|||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
/rust-lib
|
/rust-lib/flowy-ast
|
||||||
|
/rust-lib/flowy-derive
|
3
.idea/appflowy_client.iml
generated
3
.idea/appflowy_client.iml
generated
@ -3,6 +3,9 @@
|
|||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-ast/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-ast/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/tests" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sys/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />
|
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
* [**Roadmap**](doc/roadmap.md)
|
* [**Roadmap**](doc/roadmap.md)
|
||||||
* [**Deep Dive AppFlowy**](doc/architecture.md)
|
* [**Deep Dive AppFlowy**](doc/architecture.md)
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Read the [Contributing Doc](doc/contribute.md) before you want to contribute.
|
Read the [Contributing Doc](doc/contribute.md) before you want to contribute.
|
||||||
|
|
||||||
|
@ -12,8 +12,32 @@
|
|||||||
## 📚 Component Design
|
## 📚 Component Design
|
||||||
|
|
||||||
### 📕 Component 1
|
### 📕 Component 1
|
||||||
|
|
||||||
|
|
||||||
### 📗 Component 2
|
### 📗 Component 2
|
||||||
### 📘 Component 3
|
|
||||||
### 📙 Component 3
|
|
||||||
|
|
||||||
|
|
||||||
|
### 📘 Flutter Event Flow
|
||||||
|
|
||||||
|
|
||||||
|
### 📙 Rust Event Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────┐
|
||||||
|
┌─▶│Service A│
|
||||||
|
│ └─────────┘
|
||||||
|
┌─────────┐ ┌───────────┐ ┌─────────────┐ │ ┌─────────┐
|
||||||
|
┌─▶│Module A │─▶│ Services │─▶│Deps Resolved│─┼─▶│Service B│
|
||||||
|
│ └─────────┘ └───────────┘ └─────────────┘ │ └─────────┘
|
||||||
|
│ │ ┌─────────┐
|
||||||
|
┌───────┐ ┌────────┐ │ ┌─────────┐ └─▶│Service C│
|
||||||
|
│ Event │──▶│Runtime │──┼─▶│Module B │ └─────────┘
|
||||||
|
└───────┘ └────────┘ │ └─────────┘
|
||||||
|
│
|
||||||
|
│ ┌─────────┐
|
||||||
|
└─▶│Module C │
|
||||||
|
└─────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
* sync will cause typing lag
|
||||||
|
|
||||||
|
10
rust-lib/.gitignore
vendored
Normal file
10
rust-lib/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
7
rust-lib/Cargo.toml
Normal file
7
rust-lib/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"flowy-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
split-debuginfo = "unpacked"
|
15
rust-lib/flowy-sys/Cargo.toml
Normal file
15
rust-lib/flowy-sys/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "flowy-sys"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pin-project = "1.0.0"
|
||||||
|
futures-core = { version = "0.3", default-features = false }
|
||||||
|
paste = "1"
|
||||||
|
futures-channel = "0.3.15"
|
||||||
|
futures = "0.3.15"
|
||||||
|
futures-util = "0.3.15"
|
||||||
|
bytes = "0.5"
|
150
rust-lib/flowy-sys/src/error.rs
Normal file
150
rust-lib/flowy-sys/src/error.rs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
use crate::response::{FlowyResponse, StatusCode};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub struct Error {
|
||||||
|
inner: Box<dyn HandlerError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn as_handler_error(&self) -> &dyn HandlerError {
|
||||||
|
self.inner.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.inner, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{:?}", &self.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for FlowyResponse {
|
||||||
|
fn from(err: Error) -> Self {
|
||||||
|
FlowyResponse::from_error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FlowyResponse> for Error {
|
||||||
|
fn from(res: FlowyResponse) -> Error {
|
||||||
|
InternalError::from_response("", res).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Error` for any error that implements `ResponseError`
|
||||||
|
impl<T: HandlerError + 'static> From<T> for Error {
|
||||||
|
fn from(err: T) -> Error {
|
||||||
|
Error {
|
||||||
|
inner: Box::new(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HandlerError: fmt::Debug + fmt::Display {
|
||||||
|
fn status_code(&self) -> StatusCode;
|
||||||
|
|
||||||
|
fn as_response(&self) -> FlowyResponse {
|
||||||
|
let resp = FlowyResponse::new(self.status_code());
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InternalError<T> {
|
||||||
|
inner: T,
|
||||||
|
status: InternalErrorType,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum InternalErrorType {
|
||||||
|
Status(StatusCode),
|
||||||
|
Response(RefCell<Option<FlowyResponse>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> InternalError<T> {
|
||||||
|
pub fn new(inner: T, status: StatusCode) -> Self {
|
||||||
|
InternalError {
|
||||||
|
inner,
|
||||||
|
status: InternalErrorType::Status(status),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_response(inner: T, response: FlowyResponse) -> Self {
|
||||||
|
InternalError {
|
||||||
|
inner,
|
||||||
|
status: InternalErrorType::Response(RefCell::new(Some(response))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Debug for InternalError<T>
|
||||||
|
where
|
||||||
|
T: fmt::Debug + 'static,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Debug::fmt(&self.inner, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Display for InternalError<T>
|
||||||
|
where
|
||||||
|
T: fmt::Display + 'static,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.inner, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> HandlerError for InternalError<T>
|
||||||
|
where
|
||||||
|
T: fmt::Debug + fmt::Display + 'static,
|
||||||
|
{
|
||||||
|
fn status_code(&self) -> StatusCode {
|
||||||
|
match self.status {
|
||||||
|
InternalErrorType::Status(st) => st,
|
||||||
|
InternalErrorType::Response(ref resp) => {
|
||||||
|
if let Some(resp) = resp.borrow().as_ref() {
|
||||||
|
resp.status.clone()
|
||||||
|
} else {
|
||||||
|
StatusCode::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_response(&self) -> FlowyResponse {
|
||||||
|
panic!()
|
||||||
|
// match self.status {
|
||||||
|
// InternalErrorType::Status(st) => {
|
||||||
|
// let mut res = Response::new(st);
|
||||||
|
// let mut buf = BytesMut::new();
|
||||||
|
// let _ = write!(Writer(&mut buf), "{}", self);
|
||||||
|
// res.headers_mut().insert(
|
||||||
|
// header::CONTENT_TYPE,
|
||||||
|
// header::HeaderValue::from_static("text/plain; charset=utf-8"),
|
||||||
|
// );
|
||||||
|
// res.set_body(Body::from(buf))
|
||||||
|
// }
|
||||||
|
// InternalErrorType::Response(ref resp) => {
|
||||||
|
// if let Some(resp) = resp.borrow_mut().take() {
|
||||||
|
// resp
|
||||||
|
// } else {
|
||||||
|
// Response::new(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
138
rust-lib/flowy-sys/src/handler/boxed.rs
Normal file
138
rust-lib/flowy-sys/src/handler/boxed.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
use crate::error::Error;
|
||||||
|
use crate::payload::Payload;
|
||||||
|
use crate::request::FlowyRequest;
|
||||||
|
use crate::response::{FlowyResponse, Responder};
|
||||||
|
use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
|
||||||
|
use crate::util::ready::*;
|
||||||
|
use futures_core::ready;
|
||||||
|
use paste::paste;
|
||||||
|
use pin_project::pin_project;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
pub struct BoxServiceFactory<Cfg, Req, Res, Err, InitErr>(Inner<Cfg, Req, Res, Err, InitErr>);
|
||||||
|
impl<C, Req, Res, Err, InitErr> ServiceFactory<Req> for BoxServiceFactory<C, Req, Res, Err, InitErr>
|
||||||
|
where
|
||||||
|
Req: 'static,
|
||||||
|
Res: 'static,
|
||||||
|
Err: 'static,
|
||||||
|
InitErr: 'static,
|
||||||
|
{
|
||||||
|
type Response = Res;
|
||||||
|
type Error = Err;
|
||||||
|
type Service = BoxService<Req, Res, Err>;
|
||||||
|
type InitError = InitErr;
|
||||||
|
type Config = C;
|
||||||
|
|
||||||
|
type Future = BoxFuture<Result<Self::Service, InitErr>>;
|
||||||
|
|
||||||
|
fn new_service(&self, cfg: C) -> Self::Future {
|
||||||
|
self.0.new_service(cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
|
||||||
|
pub type BoxService<Req, Res, Err> =
|
||||||
|
Box<dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<Result<Res, Err>>>>;
|
||||||
|
|
||||||
|
pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
|
||||||
|
where
|
||||||
|
S: Service<Req> + 'static,
|
||||||
|
Req: 'static,
|
||||||
|
S::Future: 'static,
|
||||||
|
{
|
||||||
|
Box::new(ServiceWrapper::new(service))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, Req> Service<Req> for Box<S>
|
||||||
|
where
|
||||||
|
S: Service<Req> + ?Sized,
|
||||||
|
{
|
||||||
|
type Response = S::Response;
|
||||||
|
type Error = S::Error;
|
||||||
|
type Future = S::Future;
|
||||||
|
|
||||||
|
fn call(&self, request: Req) -> S::Future {
|
||||||
|
(**self).call(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ServiceWrapper<S> {
|
||||||
|
inner: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> ServiceWrapper<S> {
|
||||||
|
fn new(inner: S) -> Self {
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
|
||||||
|
where
|
||||||
|
S: Service<Req, Response = Res, Error = Err>,
|
||||||
|
S::Future: 'static,
|
||||||
|
{
|
||||||
|
type Response = Res;
|
||||||
|
type Error = Err;
|
||||||
|
type Future = BoxFuture<Result<Res, Err>>;
|
||||||
|
|
||||||
|
fn call(&self, req: Req) -> Self::Future {
|
||||||
|
Box::pin(self.inner.call(req))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FactoryWrapper<SF>(SF);
|
||||||
|
|
||||||
|
impl<SF, Req, Cfg, Res, Err, InitErr> ServiceFactory<Req> for FactoryWrapper<SF>
|
||||||
|
where
|
||||||
|
Req: 'static,
|
||||||
|
Res: 'static,
|
||||||
|
Err: 'static,
|
||||||
|
InitErr: 'static,
|
||||||
|
SF: ServiceFactory<Req, Config = Cfg, Response = Res, Error = Err, InitError = InitErr>,
|
||||||
|
SF::Future: 'static,
|
||||||
|
SF::Service: 'static,
|
||||||
|
<SF::Service as Service<Req>>::Future: 'static,
|
||||||
|
{
|
||||||
|
type Response = Res;
|
||||||
|
type Error = Err;
|
||||||
|
// type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
|
||||||
|
type Service = BoxService<Req, Res, Err>;
|
||||||
|
type InitError = InitErr;
|
||||||
|
type Config = Cfg;
|
||||||
|
type Future = BoxFuture<Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
|
fn new_service(&self, cfg: Cfg) -> Self::Future {
|
||||||
|
let f = self.0.new_service(cfg);
|
||||||
|
Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn factory<SF, Req>(
|
||||||
|
factory: SF,
|
||||||
|
) -> BoxServiceFactory<SF::Config, Req, SF::Response, SF::Error, SF::InitError>
|
||||||
|
where
|
||||||
|
SF: ServiceFactory<Req> + 'static,
|
||||||
|
Req: 'static,
|
||||||
|
SF::Response: 'static,
|
||||||
|
SF::Service: 'static,
|
||||||
|
SF::Future: 'static,
|
||||||
|
SF::Error: 'static,
|
||||||
|
SF::InitError: 'static,
|
||||||
|
{
|
||||||
|
BoxServiceFactory(Box::new(FactoryWrapper(factory)))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Inner<C, Req, Res, Err, InitErr> = Box<
|
||||||
|
dyn ServiceFactory<
|
||||||
|
Req,
|
||||||
|
Config = C,
|
||||||
|
Response = Res,
|
||||||
|
Error = Err,
|
||||||
|
InitError = InitErr,
|
||||||
|
Service = BoxService<Req, Res, Err>,
|
||||||
|
Future = BoxFuture<Result<BoxService<Req, Res, Err>, InitErr>>,
|
||||||
|
>,
|
||||||
|
>;
|
36
rust-lib/flowy-sys/src/handler/dispatch.rs
Normal file
36
rust-lib/flowy-sys/src/handler/dispatch.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::error::Error;
|
||||||
|
use crate::handler::{boxed, BoxServiceFactory, FromRequest, Handler, HandlerService};
|
||||||
|
use crate::response::Responder;
|
||||||
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
pub struct HandlerDispatch {
|
||||||
|
service: BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HandlerDispatch {
|
||||||
|
pub fn new<H, T, R>(handler: H) -> Self
|
||||||
|
where
|
||||||
|
H: Handler<T, R>,
|
||||||
|
T: FromRequest + 'static,
|
||||||
|
R: Future + 'static,
|
||||||
|
R::Output: Responder + 'static,
|
||||||
|
{
|
||||||
|
HandlerDispatch {
|
||||||
|
service: boxed::factory(HandlerService::new(handler)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn not_found() -> String {
|
||||||
|
"hello".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn extract_string() {
|
||||||
|
let dispatch = HandlerDispatch::new(not_found);
|
||||||
|
}
|
||||||
|
}
|
249
rust-lib/flowy-sys/src/handler/handler.rs
Normal file
249
rust-lib/flowy-sys/src/handler/handler.rs
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
use crate::error::Error;
|
||||||
|
use crate::payload::Payload;
|
||||||
|
use crate::request::FlowyRequest;
|
||||||
|
use crate::response::{FlowyResponse, Responder};
|
||||||
|
use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
|
||||||
|
use crate::util::ready::*;
|
||||||
|
use futures_core::ready;
|
||||||
|
use paste::paste;
|
||||||
|
use pin_project::pin_project;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
pub trait Handler<T, R>: Clone + 'static
|
||||||
|
where
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
fn call(&self, param: T) -> R;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromRequest: Sized {
|
||||||
|
type Error: Into<Error>;
|
||||||
|
type Future: Future<Output = Result<Self, Self::Error>>;
|
||||||
|
|
||||||
|
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HandlerService<H, T, R>
|
||||||
|
where
|
||||||
|
H: Handler<T, R>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
handler: H,
|
||||||
|
_phantom: PhantomData<(T, R)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, T, R> HandlerService<H, T, R>
|
||||||
|
where
|
||||||
|
H: Handler<T, R>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
pub fn new(handler: H) -> Self {
|
||||||
|
Self {
|
||||||
|
handler,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H, T, R> Clone for HandlerService<H, T, R>
|
||||||
|
where
|
||||||
|
H: Handler<T, R>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
handler: self.handler.clone(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T, R> ServiceFactory<ServiceRequest> for HandlerService<F, T, R>
|
||||||
|
where
|
||||||
|
F: Handler<T, R>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
type Response = ServiceResponse;
|
||||||
|
type Error = Error;
|
||||||
|
type Service = Self;
|
||||||
|
type InitError = ();
|
||||||
|
type Config = ();
|
||||||
|
type Future = Ready<Result<Self::Service, ()>>;
|
||||||
|
|
||||||
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
|
ready(Ok(self.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HandlerService is both it's ServiceFactory and Service Type.
|
||||||
|
impl<H, T, R> Service<ServiceRequest> for HandlerService<H, T, R>
|
||||||
|
where
|
||||||
|
H: Handler<T, R>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
type Response = ServiceResponse;
|
||||||
|
type Error = Error;
|
||||||
|
type Future = HandlerServiceFuture<H, T, R>;
|
||||||
|
|
||||||
|
fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||||
|
let (req, mut payload) = req.into_parts();
|
||||||
|
let fut = T::from_request(&req, &mut payload);
|
||||||
|
HandlerServiceFuture::Extract(fut, Some(req), self.handler.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pin_project(project = HandlerServiceProj)]
|
||||||
|
pub enum HandlerServiceFuture<H, T, R>
|
||||||
|
where
|
||||||
|
H: Handler<T, R>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
Extract(#[pin] T::Future, Option<FlowyRequest>, H),
|
||||||
|
Handle(#[pin] R, Option<FlowyRequest>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T, R> Future for HandlerServiceFuture<F, T, R>
|
||||||
|
where
|
||||||
|
F: Handler<T, R>,
|
||||||
|
T: FromRequest,
|
||||||
|
R: Future,
|
||||||
|
R::Output: Responder,
|
||||||
|
{
|
||||||
|
// Error type in this future is a placeholder type.
|
||||||
|
// all instances of error must be converted to ServiceResponse and return in Ok.
|
||||||
|
type Output = Result<ServiceResponse, Error>;
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
loop {
|
||||||
|
match self.as_mut().project() {
|
||||||
|
HandlerServiceProj::Extract(fut, req, handle) => {
|
||||||
|
match ready!(fut.poll(cx)) {
|
||||||
|
Ok(item) => {
|
||||||
|
let fut = handle.call(item);
|
||||||
|
let state = HandlerServiceFuture::Handle(fut, req.take());
|
||||||
|
self.as_mut().set(state);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let req = req.take().unwrap();
|
||||||
|
let res = FlowyResponse::from_error(err.into());
|
||||||
|
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
HandlerServiceProj::Handle(fut, req) => {
|
||||||
|
let res = ready!(fut.poll(cx));
|
||||||
|
let req = req.take().unwrap();
|
||||||
|
let res = res.respond_to(&req);
|
||||||
|
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! factory_tuple ({ $($param:ident)* } => {
|
||||||
|
impl<Func, $($param,)* Res> Handler<($($param,)*), Res> for Func
|
||||||
|
where Func: Fn($($param),*) -> Res + Clone + 'static,
|
||||||
|
Res: Future,
|
||||||
|
Res::Output: Responder,
|
||||||
|
{
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn call(&self, ($($param,)*): ($($param,)*)) -> Res {
|
||||||
|
(self)($($param,)*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
macro_rules! tuple_from_req ({$tuple_type:ident, $(($n:tt, $T:ident)),+} => {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
mod $tuple_type {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[pin_project::pin_project]
|
||||||
|
struct FromRequestFutures<$($T: FromRequest),+>($(#[pin] $T::Future),+);
|
||||||
|
|
||||||
|
/// FromRequest implementation for tuple
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
type Future = $tuple_type<$($T),+>;
|
||||||
|
|
||||||
|
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future {
|
||||||
|
$tuple_type {
|
||||||
|
items: <($(Option<$T>,)+)>::default(),
|
||||||
|
futs: FromRequestFutures($($T::from_request(req, payload),)+),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[pin_project::pin_project]
|
||||||
|
pub struct $tuple_type<$($T: FromRequest),+> {
|
||||||
|
items: ($(Option<$T>,)+),
|
||||||
|
#[pin]
|
||||||
|
futs: FromRequestFutures<$($T,)+>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<$($T: FromRequest),+> Future for $tuple_type<$($T),+>
|
||||||
|
{
|
||||||
|
type Output = Result<($($T,)+), Error>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let mut this = self.project();
|
||||||
|
let mut ready = true;
|
||||||
|
$(
|
||||||
|
if this.items.$n.is_none() {
|
||||||
|
match this.futs.as_mut().project().$n.poll(cx) {
|
||||||
|
Poll::Ready(Ok(item)) => this.items.$n = Some(item),
|
||||||
|
Poll::Pending => ready = false,
|
||||||
|
Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
|
||||||
|
if ready {
|
||||||
|
Poll::Ready(Ok(
|
||||||
|
($(this.items.$n.take().unwrap(),)+)
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
factory_tuple! {}
|
||||||
|
factory_tuple! { A }
|
||||||
|
factory_tuple! { A B }
|
||||||
|
factory_tuple! { A B C }
|
||||||
|
factory_tuple! { A B C D }
|
||||||
|
factory_tuple! { A B C D E }
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
mod m {
|
||||||
|
use super::*;
|
||||||
|
tuple_from_req!(TupleFromRequest1, (0, A));
|
||||||
|
tuple_from_req!(TupleFromRequest2, (0, A), (1, B));
|
||||||
|
tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C));
|
||||||
|
tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D));
|
||||||
|
tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E));
|
||||||
|
}
|
7
rust-lib/flowy-sys/src/handler/mod.rs
Normal file
7
rust-lib/flowy-sys/src/handler/mod.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
mod boxed;
|
||||||
|
mod dispatch;
|
||||||
|
mod handler;
|
||||||
|
|
||||||
|
pub use boxed::*;
|
||||||
|
pub use dispatch::*;
|
||||||
|
pub use handler::*;
|
7
rust-lib/flowy-sys/src/lib.rs
Normal file
7
rust-lib/flowy-sys/src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
mod error;
|
||||||
|
mod handler;
|
||||||
|
mod payload;
|
||||||
|
mod request;
|
||||||
|
mod response;
|
||||||
|
mod service;
|
||||||
|
mod util;
|
12
rust-lib/flowy-sys/src/payload.rs
Normal file
12
rust-lib/flowy-sys/src/payload.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use bytes::Bytes;
|
||||||
|
use futures::Stream;
|
||||||
|
|
||||||
|
pub enum PayloadError {}
|
||||||
|
|
||||||
|
pub type PayloadStream = Pin<Box<dyn Stream<Item = Result<Bytes, PayloadError>>>>;
|
||||||
|
pub enum Payload<S = PayloadStream> {
|
||||||
|
None,
|
||||||
|
Stream(S),
|
||||||
|
}
|
3
rust-lib/flowy-sys/src/request/mod.rs
Normal file
3
rust-lib/flowy-sys/src/request/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod request;
|
||||||
|
|
||||||
|
pub use request::*;
|
1
rust-lib/flowy-sys/src/request/request.rs
Normal file
1
rust-lib/flowy-sys/src/request/request.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub struct FlowyRequest {}
|
47
rust-lib/flowy-sys/src/response/builder.rs
Normal file
47
rust-lib/flowy-sys/src/response/builder.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use crate::error::Error;
|
||||||
|
use crate::response::{FlowyResponse, ResponseData, StatusCode};
|
||||||
|
|
||||||
|
macro_rules! static_response {
|
||||||
|
($name:ident, $status:expr) => {
|
||||||
|
#[allow(non_snake_case, missing_docs)]
|
||||||
|
pub fn $name() -> FlowyResponseBuilder {
|
||||||
|
FlowyResponseBuilder::new($status)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FlowyResponseBuilder<T = ResponseData> {
|
||||||
|
pub data: T,
|
||||||
|
pub status: StatusCode,
|
||||||
|
pub error: Option<Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowyResponseBuilder {
|
||||||
|
pub fn new(status: StatusCode) -> Self {
|
||||||
|
FlowyResponseBuilder {
|
||||||
|
data: ResponseData::None,
|
||||||
|
status,
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data<D: std::convert::Into<ResponseData>>(mut self, data: D) -> Self {
|
||||||
|
self.data = data.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(mut self, error: Option<Error>) -> Self {
|
||||||
|
self.error = error;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> FlowyResponse {
|
||||||
|
FlowyResponse {
|
||||||
|
data: self.data,
|
||||||
|
status: self.status,
|
||||||
|
error: self.error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_response!(Ok, StatusCode::Success);
|
||||||
|
}
|
7
rust-lib/flowy-sys/src/response/mod.rs
Normal file
7
rust-lib/flowy-sys/src/response/mod.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
mod builder;
|
||||||
|
mod responder;
|
||||||
|
mod response;
|
||||||
|
|
||||||
|
pub use builder::*;
|
||||||
|
pub use responder::*;
|
||||||
|
pub use response::*;
|
20
rust-lib/flowy-sys/src/response/responder.rs
Normal file
20
rust-lib/flowy-sys/src/response/responder.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use crate::request::FlowyRequest;
|
||||||
|
use crate::response::FlowyResponse;
|
||||||
|
use crate::response::FlowyResponseBuilder;
|
||||||
|
|
||||||
|
pub trait Responder {
|
||||||
|
fn respond_to(self, req: &FlowyRequest) -> FlowyResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_responder {
|
||||||
|
($res: ty) => {
|
||||||
|
impl Responder for $res {
|
||||||
|
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse {
|
||||||
|
FlowyResponseBuilder::Ok().data(self).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_responder!(&'static str);
|
||||||
|
impl_responder!(String);
|
66
rust-lib/flowy-sys/src/response/response.rs
Normal file
66
rust-lib/flowy-sys/src/response/response.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use crate::error::Error;
|
||||||
|
use crate::request::FlowyRequest;
|
||||||
|
use crate::response::FlowyResponseBuilder;
|
||||||
|
use crate::response::Responder;
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum StatusCode {
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ResponseData {
|
||||||
|
Bytes(Vec<u8>),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FlowyResponse<T = ResponseData> {
|
||||||
|
pub data: T,
|
||||||
|
pub status: StatusCode,
|
||||||
|
pub error: Option<Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowyResponse {
|
||||||
|
pub fn new(status: StatusCode) -> Self {
|
||||||
|
FlowyResponse {
|
||||||
|
data: ResponseData::None,
|
||||||
|
status,
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn success() -> Self {
|
||||||
|
FlowyResponse {
|
||||||
|
data: ResponseData::None,
|
||||||
|
status: StatusCode::Success,
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_error(error: Error) -> FlowyResponse {
|
||||||
|
let mut resp = error.as_handler_error().as_response();
|
||||||
|
resp.error = Some(error);
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Responder for FlowyResponse {
|
||||||
|
#[inline]
|
||||||
|
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::Into<ResponseData> for String {
|
||||||
|
fn into(self) -> ResponseData {
|
||||||
|
ResponseData::Bytes(self.into_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::Into<ResponseData> for &str {
|
||||||
|
fn into(self) -> ResponseData {
|
||||||
|
self.to_string().into()
|
||||||
|
}
|
||||||
|
}
|
46
rust-lib/flowy-sys/src/service.rs
Normal file
46
rust-lib/flowy-sys/src/service.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use crate::payload::Payload;
|
||||||
|
use crate::request::FlowyRequest;
|
||||||
|
use crate::response::{FlowyResponse, Responder, ResponseData};
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
pub trait Service<Request> {
|
||||||
|
type Response;
|
||||||
|
type Error;
|
||||||
|
type Future: Future<Output = Result<Self::Response, Self::Error>>;
|
||||||
|
|
||||||
|
fn call(&self, req: Request) -> Self::Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ServiceFactory<Req> {
|
||||||
|
type Response;
|
||||||
|
type Error;
|
||||||
|
type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
|
||||||
|
type InitError;
|
||||||
|
type Config;
|
||||||
|
type Future: Future<Output = Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
|
fn new_service(&self, cfg: Self::Config) -> Self::Future;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ServiceRequest {
|
||||||
|
req: FlowyRequest,
|
||||||
|
payload: Payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServiceRequest {
|
||||||
|
#[inline]
|
||||||
|
pub fn into_parts(self) -> (FlowyRequest, Payload) {
|
||||||
|
(self.req, self.payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ServiceResponse<T = ResponseData> {
|
||||||
|
request: FlowyRequest,
|
||||||
|
response: FlowyResponse<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ServiceResponse<T> {
|
||||||
|
pub fn new(request: FlowyRequest, response: FlowyResponse<T>) -> Self {
|
||||||
|
ServiceResponse { request, response }
|
||||||
|
}
|
||||||
|
}
|
1
rust-lib/flowy-sys/src/util/mod.rs
Normal file
1
rust-lib/flowy-sys/src/util/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod ready;
|
30
rust-lib/flowy-sys/src/util/ready.rs
Normal file
30
rust-lib/flowy-sys/src/util/ready.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
pub struct Ready<T> {
|
||||||
|
val: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Ready<T> {
|
||||||
|
#[inline]
|
||||||
|
pub fn into_inner(mut self) -> T {
|
||||||
|
self.val.take().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Unpin for Ready<T> {}
|
||||||
|
|
||||||
|
impl<T> Future for Ready<T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
|
||||||
|
let val = self.val.take().expect("Ready polled after completion");
|
||||||
|
Poll::Ready(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ready<T>(val: T) -> Ready<T> {
|
||||||
|
Ready { val: Some(val) }
|
||||||
|
}
|
3
rust-lib/rust-toolchain
Normal file
3
rust-lib/rust-toolchain
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly-2021-04-24"
|
||||||
|
targets = [ "aarch64-apple-darwin", "x86_64-apple-darwin", "aarch64-apple-ios", "x86_64-apple-ios" ]
|
17
rust-lib/rustfmt.toml
Normal file
17
rust-lib/rustfmt.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# https://rust-lang.github.io/rustfmt/?version=master&search=
|
||||||
|
max_width = 120
|
||||||
|
tab_spaces = 4
|
||||||
|
fn_single_line = true
|
||||||
|
match_block_trailing_comma = true
|
||||||
|
normalize_comments = true
|
||||||
|
wrap_comments = true
|
||||||
|
merge_imports = true
|
||||||
|
reorder_impl_items = true
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
use_try_shorthand = true
|
||||||
|
normalize_doc_attributes = true
|
||||||
|
report_todo = "Always"
|
||||||
|
report_fixme = "Always"
|
||||||
|
imports_layout = "HorizontalVertical"
|
||||||
|
enum_discrim_align_threshold = 20
|
||||||
|
edition = "2018"
|
Loading…
x
Reference in New Issue
Block a user