diff --git a/.gitignore b/.gitignore index 884eddcb82..088ba6ba7d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,3 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk - - -/rust-lib/flowy-derive \ No newline at end of file diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 1e952e4d5f..88a96cd453 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -524,14 +524,6 @@ - - - - - - @@ -841,8 +833,6 @@ - - diff --git a/app_flowy/.vscode/launch.json b/app_flowy/.vscode/launch.json index 5e7d5eef3c..836c8b2753 100644 --- a/app_flowy/.vscode/launch.json +++ b/app_flowy/.vscode/launch.json @@ -9,6 +9,7 @@ "request": "launch", "program": "${workspaceRoot}/lib/main.dart", "type": "dart", + // "preLaunchTask": "build rust sdk" }, { "name": "app_flowy (profile mode)", diff --git a/app_flowy/lib/startup/startup.dart b/app_flowy/lib/startup/startup.dart index f990c67fff..31a75755a9 100644 --- a/app_flowy/lib/startup/startup.dart +++ b/app_flowy/lib/startup/startup.dart @@ -25,7 +25,7 @@ class App { resolveDependencies(env); // add task - // getIt().addTask(RustSDKInitTask()); + getIt().addTask(RustSDKInitTask()); getIt().addTask(AppWidgetTask()); // execute the tasks diff --git a/app_flowy/packages/flowy_sdk/example/pubspec.lock b/app_flowy/packages/flowy_sdk/example/pubspec.lock index 8043273325..66181a88e0 100644 --- a/app_flowy/packages/flowy_sdk/example/pubspec.lock +++ b/app_flowy/packages/flowy_sdk/example/pubspec.lock @@ -92,13 +92,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.1" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.11" flowy_logger: dependency: transitive description: @@ -106,13 +99,6 @@ packages: relative: true source: path version: "0.0.1" - flowy_protobuf: - dependency: transitive - description: - path: "../../flowy_protobuf" - relative: true - source: path - version: "0.0.1" flowy_sdk: dependency: "direct main" description: @@ -215,13 +201,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.1" - protobuf: - dependency: transitive - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" sky_engine: dependency: transitive description: flutter diff --git a/app_flowy/packages/flowy_sdk/lib/ffi/adaptor.dart b/app_flowy/packages/flowy_sdk/lib/ffi/adaptor.dart index 26face2e2d..3ee9fdac20 100644 --- a/app_flowy/packages/flowy_sdk/lib/ffi/adaptor.dart +++ b/app_flowy/packages/flowy_sdk/lib/ffi/adaptor.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:ffi'; // ignore: import_of_legacy_library_into_null_safe import 'package:isolates/isolates.dart'; @@ -5,7 +6,7 @@ import 'package:isolates/isolates.dart'; import 'package:isolates/ports.dart'; import 'package:ffi/ffi.dart'; -import 'package:flowy_protobuf/model/grpc.pb.dart'; +// ignore: unused_import import 'package:flutter/services.dart'; import 'dart:async'; import 'dart:typed_data'; @@ -22,9 +23,25 @@ class FFIAdaptorException implements Exception { FFIAdaptorException(this.type); } +class FFICommand { + final String event; + final Uint8List payload; + FFICommand(this.event, this.payload); + + Map toJson() => { + 'event': event, + 'payload': payload, + }; +} + class FFIAdaptor { - static Completer asyncRequest(RequestPacket request) { - Uint8List bytes = request.writeToBuffer(); + static Completer asyncRequest() { + // final command = FFICommand( + // "AuthCheck", Uint8List.fromList(utf8.encode("this is payload"))); + + final command = FFICommand("AuthCheck", Uint8List(0)); + + Uint8List bytes = Uint8List.fromList(utf8.encode(jsonEncode(command))); assert(bytes.isEmpty == false); if (bytes.isEmpty) { @@ -43,4 +60,3 @@ class FFIAdaptor { return completer; } } - diff --git a/app_flowy/packages/flowy_sdk/lib/ffi/ffi.dart b/app_flowy/packages/flowy_sdk/lib/ffi/ffi.dart index 7dc5fa8e2f..df3ff0de61 100644 --- a/app_flowy/packages/flowy_sdk/lib/ffi/ffi.dart +++ b/app_flowy/packages/flowy_sdk/lib/ffi/ffi.dart @@ -45,25 +45,24 @@ typedef _invoke_async_Dart = void Function( int len, ); - /// C function `command_sync`. Pointer sync_command( - Pointer input, - int len, - ) { + Pointer input, + int len, +) { return _invoke_sync(input, len); } final _invoke_sync_Dart _invoke_sync = -_dl.lookupFunction<_invoke_sync_C, _invoke_sync_Dart>('sync_command'); + _dl.lookupFunction<_invoke_sync_C, _invoke_sync_Dart>('sync_command'); typedef _invoke_sync_C = Pointer Function( - Pointer input, - Uint64 len, - ); + Pointer input, + Uint64 len, +); typedef _invoke_sync_Dart = Pointer Function( - Pointer input, - int len, - ); + Pointer input, + int len, +); /// C function `init_sdk`. int init_sdk( @@ -111,11 +110,12 @@ typedef _store_dart_post_cobject_Dart = void Function( bool is_tester() { if (Foundation.kDebugMode) { // ignore: unnecessary_null_comparison - if (Platform.executable == null) { - return false; - } else { - return Platform.executable.contains("tester"); - } + // if (Platform.executable.isEmpty) { + // return false; + // } else { + // return Platform.executable.contains("tester"); + // } + return false; } else { return false; } diff --git a/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart b/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart index 5abe02caea..6b2ee9265b 100644 --- a/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart +++ b/app_flowy/packages/flowy_sdk/lib/flowy_sdk.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'dart:async'; import 'package:flutter/services.dart'; import 'dart:ffi'; +import 'ffi/adaptor.dart'; import 'ffi/ffi.dart' as ffi; import 'package:ffi/ffi.dart'; @@ -16,12 +17,13 @@ class FlowySDK { const FlowySDK(); - void dispose() { - - } + void dispose() {} Future init(Directory sdkDir) async { ffi.store_dart_post_cobject(NativeApi.postCObject); + ffi.init_sdk(sdkDir.path.toNativeUtf8()); + final resp = await FFIAdaptor.asyncRequest(); + print(resp); } } diff --git a/app_flowy/packages/flowy_sdk/macos/Classes/binding.h b/app_flowy/packages/flowy_sdk/macos/Classes/binding.h index ac6bcf50e4..0455d23a96 100644 --- a/app_flowy/packages/flowy_sdk/macos/Classes/binding.h +++ b/app_flowy/packages/flowy_sdk/macos/Classes/binding.h @@ -8,4 +8,6 @@ int64_t init_sdk(char *path); void async_command(int64_t port, const uint8_t *input, uintptr_t len); +const uint8_t *sync_command(const uint8_t *input, uintptr_t len); + void link_me_please(void); \ No newline at end of file diff --git a/app_flowy/packages/flowy_sdk/pubspec.lock b/app_flowy/packages/flowy_sdk/pubspec.lock index 29eacfab55..226a179f9b 100644 --- a/app_flowy/packages/flowy_sdk/pubspec.lock +++ b/app_flowy/packages/flowy_sdk/pubspec.lock @@ -204,13 +204,6 @@ packages: relative: true source: path version: "0.0.1" - flowy_protobuf: - dependency: "direct main" - description: - path: "../flowy_protobuf" - relative: true - source: path - version: "0.0.1" flutter: dependency: "direct main" description: flutter @@ -354,13 +347,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.5.0" - protobuf: - dependency: transitive - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" pub_semver: dependency: transitive description: diff --git a/app_flowy/packages/flowy_sdk/pubspec.yaml b/app_flowy/packages/flowy_sdk/pubspec.yaml index e90d63afb0..0f75d84953 100644 --- a/app_flowy/packages/flowy_sdk/pubspec.yaml +++ b/app_flowy/packages/flowy_sdk/pubspec.yaml @@ -16,8 +16,6 @@ dependencies: isolates: ^3.0.3+8 flowy_logger: path: ../flowy_logger - flowy_protobuf: - path: ../flowy_protobuf infra: path: ../infra dartz: '0.10.0-nullsafety.2' diff --git a/app_flowy/pubspec.lock b/app_flowy/pubspec.lock index 4caf2001f8..c3225910e2 100644 --- a/app_flowy/pubspec.lock +++ b/app_flowy/pubspec.lock @@ -232,13 +232,6 @@ packages: relative: true source: path version: "0.0.1" - flowy_protobuf: - dependency: "direct main" - description: - path: "packages/flowy_protobuf" - relative: true - source: path - version: "0.0.1" flowy_sdk: dependency: "direct main" description: @@ -501,13 +494,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.1" - protobuf: - dependency: transitive - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" provider: dependency: transitive description: diff --git a/app_flowy/pubspec.yaml b/app_flowy/pubspec.yaml index 72d88d79bd..9d276bda02 100644 --- a/app_flowy/pubspec.yaml +++ b/app_flowy/pubspec.yaml @@ -31,8 +31,6 @@ dependencies: sdk: flutter flowy_sdk: path: packages/flowy_sdk - flowy_protobuf: - path: packages/flowy_protobuf flowy_style: path: packages/flowy_style diff --git a/rust-lib/dart-ffi/Cargo.toml b/rust-lib/dart-ffi/Cargo.toml index 5d7006663a..42b0f6ce86 100644 --- a/rust-lib/dart-ffi/Cargo.toml +++ b/rust-lib/dart-ffi/Cargo.toml @@ -20,7 +20,7 @@ byteorder = {version = "1.3.4"} ffi-support = {version = "0.4.2"} protobuf = {version = "2.20.0"} lazy_static = {version = "1.4.0"} -tokio = { version = "1", features = ["sync"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread"] } log = "0.4.14" serde = { version = "1.0", features = ["derive"] } serde_json = {version = "1.0"} diff --git a/rust-lib/dart-ffi/src/lib.rs b/rust-lib/dart-ffi/src/lib.rs index a8e90739f4..95ce9aa534 100644 --- a/rust-lib/dart-ffi/src/lib.rs +++ b/rust-lib/dart-ffi/src/lib.rs @@ -3,50 +3,50 @@ mod c; use crate::c::forget_rust; use flowy_sdk::*; use flowy_sys::prelude::*; +use lazy_static::lazy_static; use std::{cell::RefCell, ffi::CStr, future::Future, os::raw::c_char}; +lazy_static! { + pub static ref FFI_RUNTIME: tokio::runtime::Runtime = + tokio::runtime::Builder::new_current_thread() + .thread_name("flowy-dart-ffi") + .build() + .unwrap(); +} + #[no_mangle] pub extern "C" fn init_sdk(path: *mut c_char) -> i64 { let c_str: &CStr = unsafe { CStr::from_ptr(path) }; let path: &str = c_str.to_str().unwrap(); - FlowySDK::init_log(); + FlowySDK::init_log(path); FlowySDK::init(path); return 1; } -#[derive(serde::Deserialize)] -pub struct FFICommand { - event: String, - payload: Vec, -} - -impl FFICommand { - pub fn from_bytes(bytes: Vec) -> Self { - let command: FFICommand = serde_json::from_slice(&bytes).unwrap(); - command - } - - pub fn from_u8_pointer(pointer: *const u8, len: usize) -> Self { - let bytes = unsafe { std::slice::from_raw_parts(pointer, len) }.to_vec(); - FFICommand::from_bytes(bytes) - } -} - #[no_mangle] pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) { let FFICommand { event, payload } = FFICommand::from_u8_pointer(input, len); - log::info!("Event: {:?}", event); - - let mut request = DispatchRequest::new(port, event).callback(|_, resp| { - log::info!("async resp: {:?}", resp); - }); - + let mut request = DispatchRequest::new(event); + log::trace!( + "[FFI]: {} Async Event: {:?} with {} port", + &request.id, + &request.event, + port + ); if !payload.is_empty() { request = request.payload(Payload::Bytes(payload)); } - async_send(request); - spawn_future(async { vec![] }, 123); + request = request.callback(Box::new(move |resp: EventResponse| { + let bytes = match resp.data { + ResponseData::Bytes(bytes) => bytes, + ResponseData::None => vec![], + }; + log::trace!("[FFI]: Post data to dart through {} port", port); + Box::pin(spawn_future(async { bytes }, port)) + })); + + let _ = EventDispatch::async_send(request); } #[no_mangle] @@ -56,19 +56,36 @@ pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 { unim #[no_mangle] pub extern "C" fn link_me_please() {} +#[derive(serde::Deserialize)] +pub struct FFICommand { + event: String, + payload: Vec, +} + +impl FFICommand { + pub fn from_u8_pointer(pointer: *const u8, len: usize) -> Self { + let bytes = unsafe { std::slice::from_raw_parts(pointer, len) }.to_vec(); + let command: FFICommand = serde_json::from_slice(&bytes).unwrap(); + command + } +} + #[inline(always)] -fn spawn_future(future: F, port: i64) +async fn spawn_future(future: F, port: i64) where F: Future> + Send + 'static, { let isolate = allo_isolate::Isolate::new(port); - isolate.catch_unwind(future); - - // if let Err(e) = isolate.catch_unwind(future) { - // if let Some(msg) = e.downcast_ref::<&str>() { - // log::error!("🔥 {:?}", msg); - // } else { - // log::error!("no info provided for that panic 😡"); - // } - // } + match isolate.catch_unwind(future).await { + Ok(success) => { + log::trace!("[FFI]: Post data to dart success"); + }, + Err(e) => { + if let Some(msg) = e.downcast_ref::<&str>() { + log::error!("[FFI]: ❌ {:?}", msg); + } else { + log::error!("[FFI]: allo_isolate post panic"); + } + }, + } } diff --git a/rust-lib/flowy-ast/src/attr.rs b/rust-lib/flowy-ast/src/attr.rs index c83a3eaf92..7695686f22 100644 --- a/rust-lib/flowy-ast/src/attr.rs +++ b/rust-lib/flowy-ast/src/attr.rs @@ -262,7 +262,7 @@ pub struct ASTEnumAttrVariant { } impl ASTEnumAttrVariant { - pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { + pub fn from_ast(_cx: &Ctxt, variant: &syn::Variant) -> Self { let name = variant.ident.to_string(); let mut value = String::new(); if variant.discriminant.is_some() { diff --git a/rust-lib/flowy-ast/src/ty_ext.rs b/rust-lib/flowy-ast/src/ty_ext.rs index 401f99bfe7..f78c203d48 100644 --- a/rust-lib/flowy-ast/src/ty_ext.rs +++ b/rust-lib/flowy-ast/src/ty_ext.rs @@ -1,5 +1,5 @@ -use crate::Ctxt; -use quote::format_ident; + + use syn::{self, AngleBracketedGenericArguments, PathSegment}; #[derive(Eq, PartialEq, Debug)] diff --git a/rust-lib/flowy-log/Cargo.toml b/rust-lib/flowy-log/Cargo.toml index 3a54ab023f..fed23fba70 100644 --- a/rust-lib/flowy-log/Cargo.toml +++ b/rust-lib/flowy-log/Cargo.toml @@ -6,8 +6,9 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tracing = { version = "0.1" } -tracing-log = { version = "0.1.1", features = ["env_logger"]} +#tracing = { version = "0.1" } +tracing = { version = "0.1", features = ["max_level_debug", "release_max_level_warn"] } +tracing-log = { version = "0.1.1"} tracing-futures = "0.2.4" tracing-subscriber = { version = "0.2.12", features = ["registry", "env-filter"] } tracing-bunyan-formatter = "0.2.2" diff --git a/rust-lib/flowy-log/src/lib.rs b/rust-lib/flowy-log/src/lib.rs index 5d90144f76..04e54cf9ba 100644 --- a/rust-lib/flowy-log/src/lib.rs +++ b/rust-lib/flowy-log/src/lib.rs @@ -1,37 +1,96 @@ -use tracing::subscriber::set_global_default; +use log::LevelFilter; +use std::path::Path; +use tracing::{subscriber::set_global_default, Level}; +use tracing_appender::rolling::RollingFileAppender; use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_log::LogTracer; -use tracing_subscriber::{layer::SubscriberExt, EnvFilter}; +use tracing_subscriber::{ + layer::{Layered, SubscriberExt}, + EnvFilter, +}; -pub fn init_log(name: &str, env_filter: &str) -> std::result::Result<(), String> { - let env_filter = - EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter.to_owned())); - let formatting_layer = BunyanFormattingLayer::new(name.to_owned(), std::io::stdout); +pub struct FlowyLogBuilder { + name: String, + env_filter: String, + directory: String, + file_appender: RollingFileAppender, +} - let subscriber = tracing_subscriber::fmt() - .with_target(false) - .with_writer(std::io::stdout) - .with_thread_ids(false) - .with_target(false) - .compact() - .finish() - .with(env_filter) - .with(JsonStorageLayer) - .with(formatting_layer); +impl FlowyLogBuilder { + pub fn new(name: &str, directory: impl AsRef) -> Self { + let directory = directory.as_ref().to_str().unwrap().to_owned(); + let local_file_name = format!("{}.log", name); + let file_appender = tracing_appender::rolling::hourly(directory.clone(), local_file_name); + FlowyLogBuilder { + name: name.to_owned(), + env_filter: "Info".to_owned(), + directory, + file_appender, + } + } - let _ = LogTracer::init().map_err(|e| format!("{:?}", e))?; - let _ = set_global_default(subscriber).map_err(|e| format!("{:?}", e))?; - Ok(()) + pub fn env_filter(mut self, env_filter: &str) -> Self { + self.env_filter = env_filter.to_owned(); + self + } + + pub fn build(self) -> std::result::Result<(), String> { + let env_filter = EnvFilter::new(self.env_filter); + + let (non_blocking, _guard) = tracing_appender::non_blocking(self.file_appender); + + let formatting_layer = BunyanFormattingLayer::new(self.name, std::io::stdout); + + let mut subscriber = tracing_subscriber::fmt() + .with_target(false) + .with_max_level(tracing::Level::TRACE) + .with_writer(std::io::stdout) + .with_thread_ids(false) + .with_target(false) + // .with_writer(non_blocking) + .compact() + .finish() + .with(env_filter) + .with(JsonStorageLayer) + .with(formatting_layer); + + let _ = LogTracer::builder() + .with_max_level(LevelFilter::Trace) + .init() + .map_err(|e| format!("{:?}", e)) + .unwrap(); + let _ = set_global_default(subscriber).map_err(|e| format!("{:?}", e))?; + Ok(()) + } +} + +pub fn init_log(name: &str, directory: &str, env_filter: &str) -> std::result::Result<(), String> { + FlowyLogBuilder::new(name, directory) + .env_filter(env_filter) + .build() } #[cfg(test)] mod tests { use super::*; + #[derive(Debug)] + struct Position { + x: f32, + y: f32, + } + #[test] fn test_log() { - init_log("flowy-log", "info").unwrap(); + init_log("flowy", ".", "Debug").unwrap(); tracing::info!("😁 Tracing info log"); - log::info!("😁 bridge 'log' to 'tracing'"); + + let pos = Position { + x: 3.234, + y: -1.223, + }; + + tracing::debug!(?pos.x, ?pos.y); + log::debug!("😁 bridge 'log' to 'tracing'"); } } diff --git a/rust-lib/flowy-sdk/.gitignore b/rust-lib/flowy-sdk/.gitignore new file mode 100644 index 0000000000..e7b93bf3a1 --- /dev/null +++ b/rust-lib/flowy-sdk/.gitignore @@ -0,0 +1,12 @@ +# 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 + +**/temp/ \ No newline at end of file diff --git a/rust-lib/flowy-sdk/Cargo.toml b/rust-lib/flowy-sdk/Cargo.toml index 23fe08189d..aebaa1df66 100644 --- a/rust-lib/flowy-sdk/Cargo.toml +++ b/rust-lib/flowy-sdk/Cargo.toml @@ -6,10 +6,10 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -flowy-sys = { path = "../flowy-sys" } +flowy-sys = { path = "../flowy-sys", features = ["use_tracing"]} flowy-log = { path = "../flowy-log" } flowy-user = { path = "../flowy-user" } - +tracing = { version = "0.1" } log = "0.4.14" [dev-dependencies] diff --git a/rust-lib/flowy-sdk/src/lib.rs b/rust-lib/flowy-sdk/src/lib.rs index 1fc35378e7..c3ea644534 100644 --- a/rust-lib/flowy-sdk/src/lib.rs +++ b/rust-lib/flowy-sdk/src/lib.rs @@ -6,19 +6,17 @@ use module::build_modules; pub struct FlowySDK {} impl FlowySDK { - pub fn init_log() { flowy_log::init_log("flowy", "Debug").unwrap(); } + pub fn init_log(directory: &str) { flowy_log::init_log("flowy", directory, "Debug").unwrap(); } pub fn init(path: &str) { - log::info!("🔥 System start running"); - log::debug!("🔥 Root path: {}", path); + log::info!("🔥 Start running"); + tracing::info!("🔥 Root path: {}", path); EventDispatch::construct(|| build_modules()); } } -pub async fn async_send(data: DispatchRequest) -> Result { - EventDispatch::async_send(data).await +pub async fn async_send(request: DispatchRequest) -> EventResponse { + EventDispatch::async_send(request).await } -pub fn sync_send(data: DispatchRequest) -> Result { - EventDispatch::sync_send(data) -} +pub fn sync_send(request: DispatchRequest) -> EventResponse { EventDispatch::sync_send(request) } diff --git a/rust-lib/flowy-sdk/tests/sdk/helper.rs b/rust-lib/flowy-sdk/tests/sdk/helper.rs index 2f70aa6b56..85e258f16d 100644 --- a/rust-lib/flowy-sdk/tests/sdk/helper.rs +++ b/rust-lib/flowy-sdk/tests/sdk/helper.rs @@ -3,32 +3,42 @@ pub use flowy_sdk::*; use flowy_sys::prelude::*; use std::{ fmt::{Debug, Display}, + fs, hash::Hash, sync::Once, }; static INIT: Once = Once::new(); -#[allow(dead_code)] +pub fn init_sdk() { + let root_dir = root_dir(); -pub fn init_system() { INIT.call_once(|| { - FlowySDK::init_log(); + FlowySDK::init_log(&root_dir); }); - - FlowySDK::init("123"); + FlowySDK::init(&root_dir); } -pub struct FlowySDKTester { - request: DispatchRequest, +fn root_dir() -> String { + let mut path = fs::canonicalize(".").unwrap(); + path.push("tests/temp/flowy/"); + let path_str = path.to_str().unwrap().to_string(); + if !std::path::Path::new(&path).exists() { + std::fs::create_dir_all(path).unwrap(); + } + path_str } -impl FlowySDKTester { +pub struct EventTester { + request: DispatchRequest, +} + +impl EventTester { pub fn new(event: E) -> Self where E: Eq + Hash + Debug + Clone + Display, { Self { - request: DispatchRequest::new(1, event), + request: DispatchRequest::new(event), } } @@ -52,16 +62,18 @@ impl FlowySDKTester { self } + #[allow(dead_code)] pub async fn async_send(self) -> EventResponse { - init_system(); - let resp = async_send(self.request).await.unwrap(); + init_sdk(); + let resp = async_send(self.request).await; dbg!(&resp); resp } + #[allow(dead_code)] pub fn sync_send(self) -> EventResponse { - init_system(); - let resp = sync_send(self.request).unwrap(); + init_sdk(); + let resp = sync_send(self.request); dbg!(&resp); resp } diff --git a/rust-lib/flowy-sdk/tests/sdk/user_check.rs b/rust-lib/flowy-sdk/tests/sdk/user_check.rs index 0b2a379e8d..75777eb92c 100644 --- a/rust-lib/flowy-sdk/tests/sdk/user_check.rs +++ b/rust-lib/flowy-sdk/tests/sdk/user_check.rs @@ -4,19 +4,17 @@ use flowy_user::prelude::*; use tokio::time::{sleep, Duration}; #[test] +#[should_panic] fn auth_check_no_payload() { - let callback = |_, resp: EventResponse| { - assert_eq!(resp.status, StatusCode::Err); - }; - - let resp = FlowySDKTester::new(AuthCheck).sync_send(); + let resp = EventTester::new(AuthCheck).sync_send(); + assert_eq!(resp.status, StatusCode::Ok); } #[tokio::test] async fn auth_check_with_user_name_email_payload() { let user_data = UserData::new("jack".to_owned(), "helloworld@gmail.com".to_owned()); - FlowySDKTester::new(AuthCheck) + EventTester::new(AuthCheck) .bytes_payload(user_data) .sync_send(); } diff --git a/rust-lib/flowy-sys/Cargo.toml b/rust-lib/flowy-sys/Cargo.toml index 77635ae1f2..75c8c0213e 100644 --- a/rust-lib/flowy-sys/Cargo.toml +++ b/rust-lib/flowy-sys/Cargo.toml @@ -28,6 +28,7 @@ serde = { version = "1.0", features = ["derive"] } #optional crate bincode = { version = "1.3", optional = true} protobuf = {version = "2.24.1", optional = true} +tracing = { version = "0.1", optional = true} [dev-dependencies] tokio = { version = "1", features = ["full"] } @@ -36,3 +37,4 @@ futures-util = "0.3.15" [features] use_serde = ["bincode"] use_protobuf= ["protobuf"] +use_tracing= ["tracing"] diff --git a/rust-lib/flowy-sys/src/dispatch.rs b/rust-lib/flowy-sys/src/dispatch.rs index bc47b939c9..3cbc043f25 100644 --- a/rust-lib/flowy-sys/src/dispatch.rs +++ b/rust-lib/flowy-sys/src/dispatch.rs @@ -8,11 +8,19 @@ use crate::{ }; use derivative::*; use futures_core::future::BoxFuture; +use futures_util::task::Context; use lazy_static::lazy_static; +use pin_project::pin_project; use std::{ fmt::{Debug, Display}, + future::Future, hash::Hash, sync::RwLock, + thread::JoinHandle, +}; +use tokio::{ + macros::support::{Pin, Poll}, + task::JoinError, }; lazy_static! { @@ -30,9 +38,9 @@ impl EventDispatch { F: FnOnce() -> Vec, { let modules = module_factory(); + log::debug!("{}", module_info(&modules)); let module_map = as_module_map(modules); let runtime = tokio_default_runtime().unwrap(); - let dispatch = EventDispatch { module_map, runtime, @@ -41,115 +49,133 @@ impl EventDispatch { *(EVENT_DISPATCH.write().unwrap()) = Some(dispatch); } - pub async fn async_send(request: DispatchRequest) -> Result - where - T: 'static + Debug + Send + Sync, - { + pub fn async_send(request: DispatchRequest) -> DispatchFuture { match EVENT_DISPATCH.read() { Ok(dispatch) => { let dispatch = dispatch.as_ref().unwrap(); let module_map = dispatch.module_map.clone(); let service = Box::new(DispatchService { module_map }); - dispatch - .runtime - .spawn(async move { service.call(request).await }) - .await - .unwrap_or_else(|e| { - let msg = format!("{:?}", e); - Ok(InternalError::new(msg).as_response()) - }) + log::trace!("{}: dispatch {:?} to runtime", &request.id, &request.event); + let join_handle = dispatch.runtime.spawn(async move { + service + .call(request) + .await + .unwrap_or_else(|e| InternalError::new(format!("{:?}", e)).as_response()) + }); + + DispatchFuture { + fut: Box::pin(async move { + join_handle.await.unwrap_or_else(|e| { + InternalError::new(format!("Dispatch join error: {:?}", e)) + .as_response() + }) + }), + } }, Err(e) => { - let msg = format!("{:?}", e); - Err(InternalError::new(msg).into()) + let msg = format!("Dispatch runtime error: {:?}", e); + log::trace!("{}", msg); + DispatchFuture { + fut: Box::pin(async { InternalError::new(msg).as_response() }), + } }, } } - pub fn sync_send(request: DispatchRequest) -> Result - where - T: 'static + Debug + Send + Sync, - { + pub fn sync_send(request: DispatchRequest) -> EventResponse { futures::executor::block_on(async { EventDispatch::async_send(request).await }) } } -pub type BoxStreamCallback = Box; +#[pin_project] +pub struct DispatchFuture { + #[pin] + fut: BoxFuture<'static, EventResponse>, +} + +impl Future for DispatchFuture { + type Output = EventResponse; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = self.as_mut().project(); + loop { + return Poll::Ready(futures_core::ready!(this.fut.poll(cx))); + } + } +} + +pub type BoxFutureCallback = + Box BoxFuture<'static, ()> + 'static + Send + Sync>; #[derive(Derivative)] #[derivative(Debug)] -pub struct DispatchRequest -where - T: 'static + Debug, -{ - pub config: T, +pub struct DispatchRequest { + pub id: String, pub event: Event, - pub payload: Option, + pub payload: Payload, #[derivative(Debug = "ignore")] - pub callback: Option>, + pub callback: Option, } -impl DispatchRequest -where - T: 'static + Debug, -{ - pub fn new(config: T, event: E) -> Self +impl DispatchRequest { + pub fn new(event: E) -> Self where E: Eq + Hash + Debug + Clone + Display, { Self { - config, - payload: None, + payload: Payload::None, event: event.into(), + id: uuid::Uuid::new_v4().to_string(), callback: None, } } pub fn payload(mut self, payload: Payload) -> Self { - self.payload = Some(payload); + self.payload = payload; self } - pub fn callback(mut self, callback: F) -> Self - where - F: FnOnce(T, EventResponse) + 'static + Send + Sync, - { - self.callback = Some(Box::new(callback)); + pub fn callback(mut self, callback: BoxFutureCallback) -> Self { + self.callback = Some(callback); self } + + pub(crate) fn into_parts(self) -> (ModuleRequest, Option) { + let DispatchRequest { + event, + payload, + id, + callback, + } = self; + + (ModuleRequest::new(event.clone(), id, payload), callback) + } } pub(crate) struct DispatchService { pub(crate) module_map: ModuleMap, } -impl Service> for DispatchService -where - T: 'static + Debug + Send + Sync, -{ +impl Service for DispatchService { type Response = EventResponse; type Error = SystemError; type Future = BoxFuture<'static, Result>; - fn call(&self, dispatch_request: DispatchRequest) -> Self::Future { + fn call(&self, dispatch_request: DispatchRequest) -> Self::Future { let module_map = self.module_map.clone(); - let DispatchRequest { - config, - event, - payload, - callback, - } = dispatch_request; - - let mut request = ModuleRequest::new(event.clone()); - if let Some(payload) = payload { - request = request.payload(payload); - }; + let (request, callback) = dispatch_request.into_parts(); Box::pin(async move { let result = { - match module_map.get(&event) { + match module_map.get(&request.event()) { Some(module) => { let fut = module.new_service(()); + log::trace!( + "{}: handle event: {:?} by {}", + request.id(), + request.event(), + module.name + ); let service_fut = fut.await?.call(request); service_fut.await }, @@ -158,17 +184,27 @@ where "Can not find the module to handle the request:{:?}", request ); + log::trace!("{}", msg); Err(InternalError::new(msg).into()) }, } }; let response = result.unwrap_or_else(|e| e.into()); + log::trace!("Dispatch result: {:?}", response); if let Some(callback) = callback { - callback(config, response.clone()); + callback(response.clone()).await; } Ok(response) }) } } + +fn module_info(modules: &Vec) -> String { + let mut info = format!("{} modules loaded\n", modules.len()); + for module in modules { + info.push_str(&format!("-> {} loaded \n", module.name)); + } + info +} diff --git a/rust-lib/flowy-sys/src/module/module.rs b/rust-lib/flowy-sys/src/module/module.rs index 68b7edb951..3b7e017e49 100644 --- a/rust-lib/flowy-sys/src/module/module.rs +++ b/rust-lib/flowy-sys/src/module/module.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + fmt, fmt::{Debug, Display}, future::Future, hash::Hash, @@ -53,7 +54,7 @@ impl std::convert::From for Event { pub type EventServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, SystemError>; pub struct Module { - name: String, + pub name: String, data: DataContainer, service_map: Arc>, } @@ -112,26 +113,27 @@ pub struct ModuleRequest { } impl ModuleRequest { - pub fn new(event: E) -> Self + pub fn new(event: E, id: String, payload: Payload) -> Self where E: Into, { Self { - inner: EventRequest::new(event), - payload: Payload::None, + inner: EventRequest::new(event, id), + payload, } } - pub fn payload(mut self, payload: Payload) -> Self { - self.payload = payload; - self - } - pub(crate) fn id(&self) -> &str { &self.inner.id } pub(crate) fn event(&self) -> &Event { &self.inner.event } } +impl std::fmt::Display for ModuleRequest { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{:?}", self.inner.id, self.inner.event) + } +} + impl std::convert::Into for ModuleRequest { fn into(self) -> ServiceRequest { ServiceRequest::new(self.inner, self.payload) } } @@ -162,8 +164,9 @@ impl Service for ModuleService { type Error = SystemError; type Future = BoxFuture<'static, Result>; + // #[cfg_attr(feature = "use_tracing", xxx)] + #[tracing::instrument(name = "Module Service", level = "debug", skip(self))] fn call(&self, request: ModuleRequest) -> Self::Future { - log::trace!("Call module service for request {}", &request.id()); match self.service_map.get(&request.event()) { Some(factory) => { let service_fut = factory.new_service(()); diff --git a/rust-lib/flowy-sys/src/request/request.rs b/rust-lib/flowy-sys/src/request/request.rs index ae3d16a20d..7ac5d6465e 100644 --- a/rust-lib/flowy-sys/src/request/request.rs +++ b/rust-lib/flowy-sys/src/request/request.rs @@ -7,7 +7,6 @@ use crate::{ util::ready::{ready, Ready}, }; - use futures_core::ready; use std::{ fmt::Debug, @@ -23,12 +22,12 @@ pub struct EventRequest { } impl EventRequest { - pub fn new(event: E) -> EventRequest + pub fn new(event: E, id: String) -> EventRequest where E: Into, { Self { - id: uuid::Uuid::new_v4().to_string(), + id, event: event.into(), } } @@ -63,11 +62,8 @@ impl FromRequest for String { } fn unexpected_none_payload(request: &EventRequest) -> SystemError { - log::warn!( - "Event: {:?} expected payload but payload is empty", - &request.event - ); - InternalError::new("Expected payload but payload is empty").into() + log::warn!("{:?} expected payload", &request.event); + InternalError::new("Expected payload").into() } #[doc(hidden)] diff --git a/rust-lib/flowy-sys/src/response/mod.rs b/rust-lib/flowy-sys/src/response/mod.rs index b3f464fbb4..86a66482fc 100644 --- a/rust-lib/flowy-sys/src/response/mod.rs +++ b/rust-lib/flowy-sys/src/response/mod.rs @@ -1,8 +1,9 @@ pub use builder::*; +pub use data::*; pub use responder::*; pub use response::*; mod builder; -pub mod data; +mod data; mod responder; mod response; diff --git a/rust-lib/flowy-sys/src/util/mod.rs b/rust-lib/flowy-sys/src/util/mod.rs index a7960f90c9..eae33c97d3 100644 --- a/rust-lib/flowy-sys/src/util/mod.rs +++ b/rust-lib/flowy-sys/src/util/mod.rs @@ -6,7 +6,7 @@ pub mod ready; pub(crate) fn tokio_default_runtime() -> io::Result { runtime::Builder::new_multi_thread() - .thread_name("flowy-sys") + .thread_name("flowy-rt") .enable_io() .enable_time() .on_thread_start(move || { diff --git a/rust-lib/flowy-sys/tests/api/helper.rs b/rust-lib/flowy-sys/tests/api/helper.rs index 723f16793e..45ee393232 100644 --- a/rust-lib/flowy-sys/tests/api/helper.rs +++ b/rust-lib/flowy-sys/tests/api/helper.rs @@ -10,14 +10,13 @@ pub fn setup_env() { }); } -pub async fn async_send(data: DispatchRequest) -> Result { - EventDispatch::async_send(data).await +pub async fn async_send(request: DispatchRequest) -> EventResponse { + EventDispatch::async_send(request).await } -pub fn init_system(module_factory: F) +pub fn init_dispatch(module_factory: F) where F: FnOnce() -> Vec, { - let system = EventDispatch::new(module_factory); - EventDispatch::set_current(system); + EventDispatch::construct(module_factory); } diff --git a/rust-lib/flowy-sys/tests/api/module.rs b/rust-lib/flowy-sys/tests/api/module.rs index 6003133bb0..b5d7ecf066 100644 --- a/rust-lib/flowy-sys/tests/api/module.rs +++ b/rust-lib/flowy-sys/tests/api/module.rs @@ -7,9 +7,9 @@ pub async fn hello() -> String { "say hello".to_string() } async fn test_init() { setup_env(); let event = "1"; - init_system(|| vec![Module::new().event(event, hello)]); + init_dispatch(|| vec![Module::new().event(event, hello)]); - let request = DispatchRequest::new(1, event); - let resp = async_send(request).await.unwrap(); - log::info!("sync resp: {:?}", resp); + let request = DispatchRequest::new(event); + let resp = async_send(request).await; + dbg!(&resp); } diff --git a/rust-lib/flowy-user/src/module.rs b/rust-lib/flowy-user/src/module.rs index 22f6d05e2f..88bde35186 100644 --- a/rust-lib/flowy-user/src/module.rs +++ b/rust-lib/flowy-user/src/module.rs @@ -3,6 +3,7 @@ use flowy_sys::prelude::*; pub fn create() -> Module { Module::new() + .name("Flowy-User") .event(AuthCheck, user_check) .event(SignIn, user_check) .event(SignUp, user_check) diff --git a/scripts/build_sdk.sh b/scripts/build_sdk.sh new file mode 100755 index 0000000000..8dc74c6d27 --- /dev/null +++ b/scripts/build_sdk.sh @@ -0,0 +1,6 @@ +#!/bin/sh +#!/usr/bin/env fish +echo 'Start building rust sdk' +rustup show + +cargo make desktop \ No newline at end of file