فهرست منبع

generate the dart side code from the rust side event

appflowy 3 سال پیش
والد
کامیت
debc8960e0

+ 36 - 23
app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart

@@ -1,33 +1,46 @@
 /// Auto gen code from rust ast, do not edit
 part of 'dispatch.dart';
 
+class UserEventAuthCheck {
+  UserSignInParams params;
+  UserEventAuthCheck(this.params);
+
+  Future<Either<UserSignInResult, FlowyError>> send() {
+    return paramsToBytes(params).fold(
+      (bytes) {
+        final request = FFIRequest.create()
+          ..event = UserEvent.AuthCheck.toString()
+          ..payload = bytes;
+
+        return Dispatch.asyncRequest(request)
+            .then((bytesResult) => bytesResult.fold(
+                  (bytes) => left(UserSignInResult.fromBuffer(bytes)),
+                  (error) => right(error),
+                ));
+      },
+      (err) => Future(() => right(err)),
+    );
+  }
+}
+
 class UserEventSignIn {
-  UserSignInParams payload;
+  UserSignInParams params;
+  UserEventSignIn(this.params);
 
-  UserEventSignIn(this.payload);
   Future<Either<UserSignInResult, FlowyError>> send() {
-    var request = FFIRequest.create()..event = UserEvent.SignIn.toString();
-    return protobufToBytes(payload).fold(
-      (payload) {
-        request.payload = payload;
-        return Dispatch.asyncRequest(request).then((response) {
-          try {
-            if (response.code != FFIStatusCode.Ok) {
-              return right(FlowyError.from(response));
-            } else {
-              final pb = UserSignInResult.fromBuffer(response.payload);
-              return left(pb);
-            }
-          } catch (e, s) {
-            final error =
-                FlowyError.fromError('${e.runtimeType}. Stack trace: $s');
-            return right(error);
-          }
-        });
+    return paramsToBytes(params).fold(
+      (bytes) {
+        final request = FFIRequest.create()
+          ..event = UserEvent.SignIn.toString()
+          ..payload = bytes;
+
+        return Dispatch.asyncRequest(request)
+            .then((bytesResult) => bytesResult.fold(
+                  (bytes) => left(UserSignInResult.fromBuffer(bytes)),
+                  (error) => right(error),
+                ));
       },
-      (err) => Future(() {
-        return right(FlowyError.fromError(err));
-      }),
+      (err) => Future(() => right(err)),
     );
   }
 }

+ 65 - 27
app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart

@@ -26,29 +26,48 @@ class DispatchException implements Exception {
 }
 
 class Dispatch {
-  static Future<FFIResponse> asyncRequest(FFIRequest request) {
+  static Future<Either<Uint8List, FlowyError>> asyncRequest(
+      FFIRequest request) {
+    // FFIRequest => Rust SDK
+    final bytesFuture = _sendToRust(request);
+
+    // Rust SDK => FFIResponse
+    final responseFuture = _extractResponse(bytesFuture);
+
+    // FFIResponse's payload is the bytes of the Response object
+    final payloadFuture = _extractPayload(responseFuture);
+
+    return payloadFuture;
+  }
+}
+
+Future<Either<Uint8List, FlowyError>> _extractPayload(
+    Future<Either<FFIResponse, FlowyError>> responseFuture) {
+  return responseFuture.then((response) {
+    return response.fold(
+      (l) => left(Uint8List.fromList(l.payload)),
+      (r) => right(r),
+    );
+  });
+}
+
+Future<Either<FFIResponse, FlowyError>> _extractResponse(
+    Completer<Uint8List> bytesFuture) {
+  return bytesFuture.future.then((bytes) {
     try {
-      return _asyncRequest(request).future.then((value) {
-        try {
-          final response = FFIResponse.fromBuffer(value);
-          return Future.microtask(() => response);
-        } catch (e, s) {
-          Log.error('FlowyFFI asyncRequest error: ${e.runtimeType}\n');
-          Log.error('Stack trace \n $s');
-          final response = error_response(request, "${e.runtimeType}");
-          return Future.microtask(() => response);
-        }
-      });
+      final response = FFIResponse.fromBuffer(bytes);
+      if (response.code != FFIStatusCode.Ok) {
+        return right(FlowyError.from(response));
+      }
+
+      return left(response);
     } catch (e, s) {
-      Log.error('FlowyFFI asyncRequest error: ${e.runtimeType}\n');
-      Log.error('Stack trace \n $s');
-      final response = error_response(request, "${e.runtimeType}");
-      return Future.microtask(() => response);
+      return right(StackTraceError(e, s).toFlowyError());
     }
-  }
+  });
 }
 
-Completer<Uint8List> _asyncRequest(FFIRequest request) {
+Completer<Uint8List> _sendToRust(FFIRequest request) {
   Uint8List bytes = request.writeToBuffer();
   assert(bytes.isEmpty == false);
   if (bytes.isEmpty) {
@@ -67,14 +86,7 @@ Completer<Uint8List> _asyncRequest(FFIRequest request) {
   return completer;
 }
 
-FFIResponse error_response(FFIRequest request, String message) {
-  var response = FFIResponse();
-  response.code = FFIStatusCode.Err;
-  response.error = "${request.event}: ${message}";
-  return response;
-}
-
-Either<Uint8List, String> protobufToBytes<T extends GeneratedMessage>(
+Either<Uint8List, FlowyError> paramsToBytes<T extends GeneratedMessage>(
     T? message) {
   try {
     if (message != null) {
@@ -83,6 +95,32 @@ Either<Uint8List, String> protobufToBytes<T extends GeneratedMessage>(
       return left(Uint8List.fromList([]));
     }
   } catch (e, s) {
-    return right('FlowyFFI error: ${e.runtimeType}. Stack trace: $s');
+    return right(FlowyError.fromError('${e.runtimeType}. Stack trace: $s'));
   }
 }
+
+class StackTraceError {
+  Object error;
+  StackTrace trace;
+  StackTraceError(
+    this.error,
+    this.trace,
+  );
+
+  FlowyError toFlowyError() {
+    Log.error('${error.runtimeType}\n');
+    Log.error('Stack trace \n $trace');
+    return FlowyError.fromError('${error.runtimeType}. Stack trace: $trace');
+  }
+
+  String toString() {
+    return '${error.runtimeType}. Stack trace: $trace';
+  }
+}
+
+FFIResponse error_response(FFIRequest request, StackTraceError error) {
+  var response = FFIResponse();
+  response.code = FFIStatusCode.Err;
+  response.error = error.toString();
+  return response;
+}

+ 0 - 61
app_flowy/packages/flowy_sdk/lib/ffi/adaptor.dart

@@ -1,61 +0,0 @@
-import 'dart:convert';
-import 'dart:ffi';
-// ignore: import_of_legacy_library_into_null_safe
-import 'package:isolates/isolates.dart';
-// ignore: import_of_legacy_library_into_null_safe
-import 'package:isolates/ports.dart';
-import 'package:ffi/ffi.dart';
-// ignore: unused_import
-import 'package:flutter/services.dart';
-import 'dart:async';
-import 'dart:typed_data';
-import 'package:flowy_sdk/ffi/ffi.dart' as ffi;
-
-enum FFIExceptionType {
-  RequestPacketIsEmpty,
-  InvalidResponseLength,
-  ResponsePacketIsInvalid,
-}
-
-class FFIAdaptorException implements Exception {
-  FFIExceptionType type;
-  FFIAdaptorException(this.type);
-}
-
-class FFICommand {
-  final String event;
-  final Uint8List payload;
-  FFICommand(this.event, this.payload);
-
-  Map<String, dynamic> toJson() => {
-        'event': event,
-        'payload': payload,
-      };
-}
-
-class FFIAdaptor {
-  static Completer<Uint8List> 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) {
-      throw FFIAdaptorException(FFIExceptionType.RequestPacketIsEmpty);
-    }
-
-    final Pointer<Uint8> input = calloc.allocate<Uint8>(bytes.length);
-    final list = input.asTypedList(bytes.length);
-    list.setAll(0, bytes);
-
-    final completer = Completer<Uint8List>();
-    final port = singleCompletePort(completer);
-    ffi.async_command(port.nativePort, input, bytes.length);
-    calloc.free(input);
-
-    return completer;
-  }
-}

+ 10 - 6
rust-lib/dart-ffi/src/lib.rs

@@ -10,7 +10,7 @@ use crate::{
 use flowy_sdk::*;
 use flowy_sys::prelude::*;
 use lazy_static::lazy_static;
-use std::{ffi::CStr, future::Future, os::raw::c_char};
+use std::{ffi::CStr, os::raw::c_char};
 
 lazy_static! {
     pub static ref FFI_RUNTIME: tokio::runtime::Runtime =
@@ -31,11 +31,11 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 {
 
 #[no_mangle]
 pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
-    let request: DispatchRequest = FFIRequest::from_u8_pointer(input, len).into();
+    let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into();
     log::trace!(
         "[FFI]: {} Async Event: {:?} with {} port",
-        &request.id,
-        &request.event,
+        &request.id(),
+        &request.event(),
         port
     );
 
@@ -47,8 +47,12 @@ pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
 
 #[no_mangle]
 pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 {
-    let request: DispatchRequest = FFIRequest::from_u8_pointer(input, len).into();
-    log::trace!("[FFI]: {} Sync Event: {:?}", &request.id, &request.event,);
+    let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into();
+    log::trace!(
+        "[FFI]: {} Sync Event: {:?}",
+        &request.id(),
+        &request.event(),
+    );
     let _response = EventDispatch::sync_send(request);
 
     // FFIResponse {  }

+ 3 - 3
rust-lib/dart-ffi/src/model/ffi_request.rs

@@ -1,5 +1,5 @@
 use flowy_derive::ProtoBuf;
-use flowy_sys::prelude::DispatchRequest;
+use flowy_sys::prelude::ModuleRequest;
 use std::convert::TryFrom;
 
 #[derive(Default, ProtoBuf)]
@@ -19,6 +19,6 @@ impl FFIRequest {
     }
 }
 
-impl std::convert::Into<DispatchRequest> for FFIRequest {
-    fn into(self) -> DispatchRequest { DispatchRequest::new(self.event).payload(self.payload) }
+impl std::convert::Into<ModuleRequest> for FFIRequest {
+    fn into(self) -> ModuleRequest { ModuleRequest::new(self.event).payload(self.payload) }
 }

+ 3 - 2
rust-lib/flowy-ast/src/attr.rs

@@ -353,7 +353,7 @@ impl ASTEnumAttrVariant {
 }
 
 pub fn get_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result<Vec<syn::NestedMeta>, ()> {
-    if attr.path != PB_ATTRS {
+    if attr.path != PB_ATTRS && attr.path != EVENT {
         return Ok(Vec::new());
     }
 
@@ -361,10 +361,11 @@ pub fn get_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result<Vec<syn::Neste
     match attr.parse_meta() {
         Ok(List(meta)) => Ok(meta.nested.into_iter().collect()),
         Ok(other) => {
-            cx.error_spanned_by(other, "expected #[pb(...)]");
+            cx.error_spanned_by(other, "expected #[pb(...)] or or #[event(...)]");
             Err(())
         },
         Err(err) => {
+            cx.error_spanned_by(attr, "attribute must be str, e.g. #[pb(xx = \"xxx\")]");
             cx.syn_error(err);
             Err(())
         },

+ 4 - 0
rust-lib/flowy-derive/src/dart_event/mod.rs

@@ -0,0 +1,4 @@
+use proc_macro2::TokenStream;
+pub fn expand_enum_derive(_input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
+    Ok(TokenStream::default())
+}

+ 9 - 0
rust-lib/flowy-derive/src/lib.rs

@@ -8,6 +8,7 @@ use syn::{parse_macro_input, DeriveInput};
 #[macro_use]
 extern crate quote;
 
+mod dart_event;
 mod derive_cache;
 mod proto_buf;
 
@@ -28,6 +29,14 @@ pub fn derive_proto_buf_enum(input: TokenStream) -> TokenStream {
         .into()
 }
 
+#[proc_macro_derive(Flowy_Event, attributes(event))]
+pub fn derive_dart_event(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    dart_event::expand_enum_derive(&input)
+        .unwrap_or_else(to_compile_errors)
+        .into()
+}
+
 fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
     let compile_errors = errors.iter().map(syn::Error::to_compile_error);
     quote!(#(#compile_errors)*)

+ 0 - 2
rust-lib/flowy-sdk/src/lib.rs

@@ -14,5 +14,3 @@ impl FlowySDK {
         EventDispatch::construct(|| build_modules());
     }
 }
-
-pub fn sync_send(request: DispatchRequest) -> EventResponse { EventDispatch::sync_send(request) }

+ 25 - 62
rust-lib/flowy-sys/src/dispatch.rs

@@ -1,7 +1,6 @@
 use crate::{
     error::{Error, InternalError, SystemError},
-    module::{as_module_map, Event, Module, ModuleMap, ModuleRequest},
-    request::Payload,
+    module::{as_module_map, Module, ModuleMap, ModuleRequest},
     response::EventResponse,
     service::{Service, ServiceFactory},
     util::tokio_default_runtime,
@@ -11,13 +10,7 @@ use futures_core::future::BoxFuture;
 use futures_util::task::Context;
 use lazy_static::lazy_static;
 use pin_project::pin_project;
-use std::{
-    convert::TryInto,
-    fmt::{Debug, Display},
-    future::Future,
-    hash::Hash,
-    sync::RwLock,
-};
+use std::{future::Future, sync::RwLock};
 use tokio::macros::support::{Pin, Poll};
 
 lazy_static! {
@@ -48,21 +41,27 @@ impl EventDispatch {
 
     pub fn async_send<Req, Callback>(request: Req, callback: Callback) -> DispatchFuture
     where
-        Req: std::convert::Into<DispatchRequest>,
+        Req: std::convert::Into<ModuleRequest>,
         Callback: FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync,
     {
-        let mut request = request.into();
-        request.callback = Some(Box::new(callback));
-
+        let request: ModuleRequest = request.into();
         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 });
-                log::trace!("{}: dispatch {:?} to runtime", &request.id, &request.event);
+                log::trace!(
+                    "{}: dispatch {:?} to runtime",
+                    &request.id(),
+                    &request.event()
+                );
+                let service_ctx = DispatchContext {
+                    request,
+                    callback: Some(Box::new(callback)),
+                };
                 let join_handle = dispatch.runtime.spawn(async move {
                     service
-                        .call(request)
+                        .call(service_ctx)
                         .await
                         .unwrap_or_else(|e| InternalError::new(format!("{:?}", e)).as_response())
                 });
@@ -87,7 +86,7 @@ impl EventDispatch {
         }
     }
 
-    pub fn sync_send(request: DispatchRequest) -> EventResponse {
+    pub fn sync_send(request: ModuleRequest) -> EventResponse {
         futures::executor::block_on(async {
             EventDispatch::async_send(request, |response| {
                 dbg!(&response);
@@ -120,49 +119,16 @@ pub type BoxFutureCallback =
 
 #[derive(Derivative)]
 #[derivative(Debug)]
-pub struct DispatchRequest {
-    pub id: String,
-    pub event: Event,
-    pub payload: Payload,
+pub struct DispatchContext {
+    pub request: ModuleRequest,
     #[derivative(Debug = "ignore")]
     pub callback: Option<BoxFutureCallback>,
 }
 
-impl DispatchRequest {
-    pub fn new<E>(event: E) -> Self
-    where
-        E: Eq + Hash + Debug + Clone + Display,
-    {
-        Self {
-            payload: Payload::None,
-            event: event.into(),
-            id: uuid::Uuid::new_v4().to_string(),
-            callback: None,
-        }
-    }
-
-    pub fn payload<P>(mut self, payload: P) -> Self
-    where
-        P: Into<Payload>,
-    {
-        self.payload = payload.into();
-        self
-    }
-
-    pub fn callback(mut self, callback: BoxFutureCallback) -> Self {
-        self.callback = Some(callback);
-        self
-    }
-
+impl DispatchContext {
     pub(crate) fn into_parts(self) -> (ModuleRequest, Option<BoxFutureCallback>) {
-        let DispatchRequest {
-            event,
-            payload,
-            id,
-            callback,
-        } = self;
-
-        (ModuleRequest::new(event.clone(), id, payload), callback)
+        let DispatchContext { request, callback } = self;
+        (request, callback)
     }
 }
 
@@ -170,22 +136,19 @@ pub(crate) struct DispatchService {
     pub(crate) module_map: ModuleMap,
 }
 
-impl Service<DispatchRequest> for DispatchService {
+impl Service<DispatchContext> for DispatchService {
     type Response = EventResponse;
     type Error = SystemError;
     type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
 
     #[cfg_attr(
         feature = "use_tracing",
-        tracing::instrument(
-            name = "DispatchService",
-            level = "debug",
-            skip(self, dispatch_request)
-        )
+        tracing::instrument(name = "DispatchService", level = "debug", skip(self, ctx))
     )]
-    fn call(&self, dispatch_request: DispatchRequest) -> Self::Future {
+    fn call(&self, ctx: DispatchContext) -> Self::Future {
         let module_map = self.module_map.clone();
-        let (request, callback) = dispatch_request.into_parts();
+        let (request, callback) = ctx.into_parts();
+
         Box::pin(async move {
             let result = {
                 match module_map.get(&request.event()) {

+ 13 - 5
rust-lib/flowy-sys/src/module/module.rs

@@ -113,19 +113,27 @@ pub struct ModuleRequest {
 }
 
 impl ModuleRequest {
-    pub fn new<E>(event: E, id: String, payload: Payload) -> Self
+    pub fn new<E>(event: E) -> Self
     where
         E: Into<Event>,
     {
         Self {
-            inner: EventRequest::new(event, id),
-            payload,
+            inner: EventRequest::new(event, uuid::Uuid::new_v4().to_string()),
+            payload: Payload::None,
         }
     }
 
-    pub(crate) fn id(&self) -> &str { &self.inner.id }
+    pub fn payload<P>(mut self, payload: P) -> Self
+    where
+        P: Into<Payload>,
+    {
+        self.payload = payload.into();
+        self
+    }
+
+    pub fn id(&self) -> &str { &self.inner.id }
 
-    pub(crate) fn event(&self) -> &Event { &self.inner.event }
+    pub fn event(&self) -> &Event { &self.inner.event }
 }
 
 impl std::fmt::Display for ModuleRequest {

+ 6 - 9
rust-lib/flowy-sys/tests/api/module.rs

@@ -9,14 +9,11 @@ async fn test_init() {
     let event = "1";
     init_dispatch(|| vec![Module::new().event(event, hello)]);
 
-    let request = DispatchRequest::new(event);
-    let _ = EventDispatch::async_send(
-        request,
-        Some(|resp| {
-            Box::pin(async move {
-                dbg!(&resp);
-            })
-        }),
-    )
+    let request = ModuleRequest::new(event);
+    let _ = EventDispatch::async_send(request, |resp| {
+        Box::pin(async move {
+            dbg!(&resp);
+        })
+    })
     .await;
 }

+ 4 - 11
rust-lib/flowy-test/src/lib.rs

@@ -42,7 +42,7 @@ fn root_dir() -> String {
 }
 
 pub struct EventTester {
-    request: Option<DispatchRequest>,
+    request: Option<ModuleRequest>,
     assert_status_code: Option<StatusCode>,
     response: Option<EventResponse>,
 }
@@ -53,7 +53,7 @@ impl EventTester {
         E: Eq + Hash + Debug + Clone + Display,
     {
         init_sdk();
-        let request = DispatchRequest::new(event);
+        let request = ModuleRequest::new(event);
         Self {
             request: Some(request),
             assert_status_code: None,
@@ -91,7 +91,8 @@ impl EventTester {
     }
 
     pub fn sync_send(mut self) -> Self {
-        let resp = sync_send(self.request.take().unwrap());
+        let resp = EventDispatch::sync_send(self.request.take().unwrap());
+
         if let Some(ref status_code) = self.assert_status_code {
             assert_eq!(&resp.status_code, status_code)
         }
@@ -108,11 +109,3 @@ impl EventTester {
         <Data<R>>::try_from(response.payload).unwrap().into_inner()
     }
 }
-
-fn data_from_response<R>(response: &EventResponse) -> R
-where
-    R: FromBytes,
-{
-    let result = <Data<R>>::try_from(&response.payload).unwrap().into_inner();
-    result
-}

+ 1 - 1
rust-lib/flowy-user/Flowy.toml

@@ -1,3 +1,3 @@
 
 proto_crates = ["src/domain"]
-event_files = ["src/module.rs"]
+event_files = ["src/domain/event.rs"]

+ 4 - 15
rust-lib/flowy-user/src/domain/event.rs

@@ -1,10 +1,12 @@
 use derive_more::Display;
-use flowy_derive::ProtoBuf_Enum;
+use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
 pub enum UserEvent {
     #[display(fmt = "AuthCheck")]
+    #[event(input = "UserSignInParams", output = "UserSignInResult")]
     AuthCheck = 0,
+    #[event(input = "UserSignInParams", output = "UserSignInResult")]
     #[display(fmt = "SignIn")]
     SignIn    = 1,
     #[display(fmt = "SignUp")]
@@ -12,16 +14,3 @@ pub enum UserEvent {
     #[display(fmt = "SignOut")]
     SignOut   = 3,
 }
-
-// impl std::convert::TryFrom<&crate::protobuf::UserEvent> for UserEvent {
-//     type Error = String;
-//     fn try_from(pb: &crate::protobuf::UserEvent) -> Result<Self, Self::Error>
-// {         let a = UserEvent::SignIn;
-//         match pb {
-//             crate::protobuf::UserEvent::AuthCheck => { UserEvent::SignIn }
-//             UserEvent::SignIn => { UserEvent::SignIn }
-//             UserEvent::SignUp => {UserEvent::SignIn }
-//             UserEvent::SignOut => {UserEvent::SignIn}
-//         }
-//     }
-// }

+ 1 - 0
scripts/flowy-tool/src/dart_event/dart_event.rs

@@ -100,6 +100,7 @@ pub fn parse_event_crate(event_crate: &DartEventCrate) -> Vec<EventASTContext> {
 
 pub fn ast_to_event_render_ctx(ast: &Vec<EventASTContext>) -> Vec<EventRenderContext> {
     ast.iter()
+        .filter(|event_ast| event_ast.event_input.is_some() && event_ast.event_output.is_some())
         .map(|event_ast| EventRenderContext {
             input_deserializer: event_ast
                 .event_input

+ 27 - 65
scripts/flowy-tool/src/dart_event/event_template.rs

@@ -1,3 +1,4 @@
+use crate::util::get_tera;
 use tera::Context;
 
 pub struct EventTemplate {
@@ -6,7 +7,7 @@ pub struct EventTemplate {
 
 pub const DART_IMPORTED: &'static str = r#"
 /// Auto gen code from rust ast, do not edit
-part of 'cqrs.dart';
+part of 'dispatch.dart';
 "#;
 
 pub struct EventRenderContext {
@@ -24,69 +25,30 @@ impl EventTemplate {
         };
     }
 
-    pub fn render(&mut self, _render_context: EventRenderContext, _index: usize) -> Option<String> {
-        None
-        // if index == 0 {
-        //     self.tera_context
-        //         .insert("imported_dart_files", DART_IMPORTED)
-        // }
-        // self.tera_context.insert("index", &index);
-        //
-        //
-        //
-        // self.tera_context.insert(
-        //     "command_request_struct_ident",
-        //     &render_context.command_request_struct_ident,
-        // );
-        //
-        // self.tera_context
-        //     .insert("request_deserializer", &render_context.request_deserializer);
-        //
-        // if render_context.request_deserializer.is_empty() {
-        //     self.tera_context.insert("has_request_deserializer", &false);
-        // } else {
-        //     self.tera_context.insert("has_request_deserializer", &true);
-        // }
-        // self.tera_context
-        //     .insert("command_ident", &render_context.event);
-        //
-        // if render_context.response_deserializer.is_empty() {
-        //     self.tera_context
-        //         .insert("has_response_deserializer", &false);
-        //     self.tera_context
-        //         .insert("response_deserializer", "ResponsePacket");
-        // } else {
-        //     self.tera_context.insert("has_response_deserializer", &true);
-        //     self.tera_context.insert(
-        //         "response_deserializer",
-        //         &render_context.response_deserializer,
-        //     );
-        // }
-        //
-        // self.tera_context
-        //     .insert("async_cqrs_type", &render_context.async_cqrs_type);
-        // let repo_absolute_path =
-        //     std::fs::canonicalize("./flowy-scripts/rust-tool/src/flutter/cqrs")
-        //         .unwrap()
-        //         .as_path()
-        //         .display()
-        //         .to_string();
-        //
-        // let template_path = format!("{}/**/*.tera", repo_absolute_path);
-        // let tera = match Tera::new(&template_path) {
-        //     Ok(t) => t,
-        //     Err(e) => {
-        //         log::error!("Parsing error(s): {}", e);
-        //         ::std::process::exit(1);
-        //     }
-        // };
-        //
-        // match tera.render("command_request_template.tera", &self.tera_context) {
-        //     Ok(r) => Some(r),
-        //     Err(e) => {
-        //         log::error!("{:?}", e);
-        //         None
-        //     }
-        // }
+    pub fn render(&mut self, ctx: EventRenderContext, index: usize) -> Option<String> {
+        if index == 0 {
+            self.tera_context
+                .insert("imported_dart_files", DART_IMPORTED)
+        }
+        self.tera_context.insert("index", &index);
+
+        let dart_class_name = format!("{}{}", ctx.event_ty, ctx.event);
+        let event = format!("{}.{}", ctx.event_ty, ctx.event);
+
+        self.tera_context.insert("event_class", &dart_class_name);
+        self.tera_context.insert("event", &event);
+        self.tera_context
+            .insert("input_deserializer", &ctx.input_deserializer);
+        self.tera_context
+            .insert("output_deserializer", &ctx.output_deserializer);
+
+        let tera = get_tera("dart_event");
+        match tera.render("event_template.tera", &self.tera_context) {
+            Ok(r) => Some(r),
+            Err(e) => {
+                log::error!("{:?}", e);
+                None
+            }
+        }
     }
 }

+ 17 - 63
scripts/flowy-tool/src/dart_event/event_template.tera

@@ -2,71 +2,25 @@
 {{ imported_dart_files }}
 {%- endif -%}
 
-class {{ command_request_struct_ident }} {
-{%- if has_request_deserializer %}
-    {{ request_deserializer }} body;
-{%- else %}
-    Uint8List? body;
-{%- endif %}
+class {{ event_class }} {
+    {{ input_deserializer }} params;
+    {{ event_class }}(this.params);
 
-{%- if has_request_deserializer %}
-    {{ command_request_struct_ident }}(this.body);
-{%- else %}
-    {{ command_request_struct_ident }}();
-{%- endif %}
-    Future<Either<{{ response_deserializer }}, FlowyError>> send() {
-      final command = Command.{{ command_ident }};
-      var request = RequestPacket.create()
-      ..command = command
-      ..id = uuid();
+    Future<Either<{{ output_deserializer }}, FlowyError>> send() {
+    return paramsToBytes(params).fold(
+        (bytes) {
+          final request = FFIRequest.create()
+            ..event = {{ event }}.toString()
+            ..payload = bytes;
 
-{%- if has_request_deserializer  %}
-      return protobufToBytes(body).fold(
-        (req_bytes) {
-          request.body = req_bytes;
-          return {{ async_cqrs_type }}(request).then((response) {
-            {%- if has_response_deserializer  %}
-            try {
-              if (response.hasErr()) {
-                return right(FlowyError.from(response));
-              } else {
-                final pb = {{ response_deserializer }}.fromBuffer(response.body);
-                return left(pb);
-              }
-
-            } catch (e, s) {
-              final error = FlowyError.fromError('error: ${e.runtimeType}. Stack trace: $s', StatusCode.ProtobufDeserializeError);
-              return right(error);
-            }
-            {%- else %}
-            return left(response);
-            {%- endif %}
-          });
+          return Dispatch.asyncRequest(request)
+              .then((bytesResult) => bytesResult.fold(
+                    (bytes) => left({{ output_deserializer }}.fromBuffer(bytes)),
+                    (error) => right(error),
+                  ));
         },
-        (err) => Future(() {
-            final error = FlowyError.fromError(err, StatusCode.ProtobufSerializeError);
-            return right(error);
-        }),
-      );
-{%- else %}
-      return {{ async_cqrs_type }}(request).then((response) {
-        {%- if has_response_deserializer  %}
-        try {
-          if (response.hasErr()) {
-            return right(FlowyError.from(response));
-          } else {
-            final pb = {{ response_deserializer }}.fromBuffer(response.body);
-            return left(pb);
-          }
-        } catch (e, s) {
-          final error = FlowyError.fromError('error: ${e.runtimeType}. Stack trace: $s', StatusCode.ProtobufDeserializeError);
-          return right(error);
-        }
-        {%- else %}
-        return left(response);
-        {%- endif %}
-
-      });
-{%- endif %}
+        (err) => Future(() => right(err)),
+        );
     }
 }
+

+ 1 - 1
scripts/flowy-tool/src/proto/template/derive_meta/derive_meta.rs

@@ -24,7 +24,7 @@ impl ProtobufDeriveMeta {
         self.context.insert("names", &self.structs);
         self.context.insert("enums", &self.enums);
 
-        let tera = get_tera("derive_meta");
+        let tera = get_tera("proto/template/derive_meta");
         match tera.render("derive_meta.tera", &self.context) {
             Ok(r) => Some(r),
             Err(e) => {

+ 1 - 1
scripts/flowy-tool/src/proto/template/proto_file/enum_template.rs

@@ -26,7 +26,7 @@ impl EnumTemplate {
 
     pub fn render(&mut self) -> Option<String> {
         self.context.insert("items", &self.items);
-        let tera = get_tera("proto_file");
+        let tera = get_tera("proto/template/proto_file");
         match tera.render("enum.tera", &self.context) {
             Ok(r) => Some(r),
             Err(e) => {

+ 1 - 1
scripts/flowy-tool/src/proto/template/proto_file/struct_template.rs

@@ -84,7 +84,7 @@ impl StructTemplate {
 
     pub fn render(&mut self) -> Option<String> {
         self.context.insert("fields", &self.fields);
-        let tera = get_tera("proto_file");
+        let tera = get_tera("proto/template/proto_file");
         match tera.render("struct.tera", &self.context) {
             Ok(r) => Some(r),
             Err(e) => {

+ 1 - 1
scripts/flowy-tool/src/util/file.rs

@@ -89,7 +89,7 @@ pub fn print_diff(old_content: String, new_content: String) {
 }
 
 pub fn get_tera(directory: &str) -> Tera {
-    let mut root = "./scripts/flowy-tool/src/proto/template/".to_owned();
+    let mut root = "./scripts/flowy-tool/src/".to_owned();
     root.push_str(directory);
 
     let root_absolute_path = std::fs::canonicalize(root)

+ 20 - 2
scripts/makefile/protobuf.toml

@@ -5,7 +5,7 @@ dependencies = ["gen_pb_file"]
 [tasks.gen_pb_file]
 script = [
     """
-    pb_gen_bin=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/scripts/flowy-tool/Cargo.toml
+    flowy_tool=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/scripts/flowy-tool/Cargo.toml
     rust_source=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/
     rust_lib=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib
     flutter_lib=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/packages
@@ -14,10 +14,28 @@ script = [
     flutter_package_lib=${flutter_lib}/flowy_sdk/lib
 
     cargo run \
-     --manifest-path ${pb_gen_bin} pb-gen \
+     --manifest-path ${flowy_tool} pb-gen \
      --rust_source=${rust_source} \
      --derive_meta=${derive_meta} \
      --flutter_package_lib=${flutter_package_lib}
     """,
 ]
 script_runner = "@shell"
+
+
+[tasks.gen_dart_event]
+script = [
+    """
+    flowy_tool=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/scripts/flowy-tool/Cargo.toml
+    flutter_lib=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/packages
+
+    rust_source=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/
+    output=${flutter_lib}/flowy_sdk/lib/dispatch/code_gen.dart
+
+    cargo run \
+     --manifest-path ${flowy_tool} dart-event \
+     --rust_source=${rust_source} \
+     --output=${output}
+    """,
+]
+script_runner = "@shell"