test event from dart to rust using protobuf as bytes adaptor

This commit is contained in:
appflowy 2021-07-07 22:24:26 +08:00
parent 21b95233fc
commit 2cb26d9e90
44 changed files with 882 additions and 186 deletions

View file

@ -13,8 +13,9 @@ class WelcomeScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => create: (context) {
getIt<WelcomeBloc>()..add(const WelcomeEvent.check()), return getIt<WelcomeBloc>()..add(const WelcomeEvent.check());
},
child: Scaffold( child: Scaffold(
body: BlocListener<WelcomeBloc, WelcomeState>( body: BlocListener<WelcomeBloc, WelcomeState>(
listener: (context, state) { listener: (context, state) {

View file

@ -55,11 +55,25 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logger: logger:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -123,6 +123,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -166,6 +173,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.1" version: "4.0.1"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logger: logger:
dependency: transitive dependency: transitive
description: description:

View file

@ -0,0 +1,33 @@
/// Auto gen code from rust ast, do not edit
part of 'dispatch.dart';
class UserEventSignIn {
UserSignInParams payload;
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);
}
});
},
(err) => Future(() {
return right(FlowyError.fromError(err));
}),
);
}
}

View file

@ -0,0 +1,88 @@
import 'dart:ffi';
import 'package:dartz/dartz.dart';
import 'package:flowy_logger/flowy_logger.dart';
import 'package:flowy_sdk/dispatch/flowy_error.dart';
import 'package:flowy_sdk/protobuf/ffi_response.pb.dart';
import 'package:isolates/isolates.dart';
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;
import 'package:flowy_sdk/protobuf.dart';
import 'package:protobuf/protobuf.dart';
part 'code_gen.dart';
enum FFIException {
RequestIsEmpty,
}
class DispatchException implements Exception {
FFIException type;
DispatchException(this.type);
}
class Dispatch {
static Future<FFIResponse> asyncRequest(FFIRequest request) {
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);
}
});
} 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);
}
}
}
Completer<Uint8List> _asyncRequest(FFIRequest request) {
Uint8List bytes = request.writeToBuffer();
assert(bytes.isEmpty == false);
if (bytes.isEmpty) {
throw DispatchException(FFIException.RequestIsEmpty);
}
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;
}
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>(
T? message) {
try {
if (message != null) {
return left(message.writeToBuffer());
} else {
return left(Uint8List.fromList([]));
}
} catch (e, s) {
return right('FlowyFFI error: ${e.runtimeType}. Stack trace: $s');
}
}

View file

@ -0,0 +1,35 @@
import '../protobuf/ffi_response.pb.dart';
class FlowyError {
late FFIStatusCode _statusCode;
late String _error;
FFIStatusCode get statusCode {
return _statusCode;
}
String get error {
return _error;
}
bool get has_error {
return _statusCode != FFIStatusCode.Ok;
}
String toString() {
return "$_statusCode: $_error";
}
FlowyError({required FFIStatusCode statusCode, required String error}) {
_statusCode = statusCode;
_error = error;
}
factory FlowyError.from(FFIResponse resp) {
return FlowyError(statusCode: resp.code, error: resp.error);
}
factory FlowyError.fromError(String error) {
return FlowyError(statusCode: FFIStatusCode.Err, error: error);
}
}

View file

@ -5,7 +5,6 @@ import 'package:isolates/isolates.dart';
// ignore: import_of_legacy_library_into_null_safe // ignore: import_of_legacy_library_into_null_safe
import 'package:isolates/ports.dart'; import 'package:isolates/ports.dart';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
// ignore: unused_import // ignore: unused_import
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'dart:async'; import 'dart:async';

View file

@ -2,12 +2,16 @@ export 'package:async/async.dart';
import 'dart:io'; import 'dart:io';
import 'dart:async'; import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/flowy_error.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'dart:ffi'; import 'dart:ffi';
import 'ffi/adaptor.dart';
import 'ffi/ffi.dart' as ffi; import 'ffi/ffi.dart' as ffi;
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'package:flowy_sdk/protobuf.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
class FlowySDK { class FlowySDK {
static const MethodChannel _channel = MethodChannel('flowy_sdk'); static const MethodChannel _channel = MethodChannel('flowy_sdk');
static Future<String> get platformVersion async { static Future<String> get platformVersion async {
@ -23,7 +27,20 @@ class FlowySDK {
ffi.store_dart_post_cobject(NativeApi.postCObject); ffi.store_dart_post_cobject(NativeApi.postCObject);
ffi.init_sdk(sdkDir.path.toNativeUtf8()); ffi.init_sdk(sdkDir.path.toNativeUtf8());
final resp = await FFIAdaptor.asyncRequest();
print(resp); final params = UserSignInParams.create();
params.email = "nathan.fu@gmail.com";
params.password = "Helloworld!2";
Either<UserSignInResult, FlowyError> resp =
await UserEventSignIn(params).send();
resp.fold(
(result) {
print(result);
},
(error) {
print(error);
},
);
} }
} }

View file

@ -3,4 +3,5 @@ export 'protobuf/ffi_response.pb.dart';
export 'protobuf/ffi_request.pb.dart'; export 'protobuf/ffi_request.pb.dart';
export 'protobuf/sign_up.pb.dart'; export 'protobuf/sign_up.pb.dart';
export 'protobuf/sign_in.pb.dart'; export 'protobuf/sign_in.pb.dart';
export 'protobuf/event.pb.dart';
export 'protobuf/user.pb.dart'; export 'protobuf/user.pb.dart';

View file

@ -0,0 +1,11 @@
///
// Generated code. Do not modify.
// source: event.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
import 'dart:core' as $core;
export 'event.pbenum.dart';

View file

@ -0,0 +1,30 @@
///
// Generated code. Do not modify.
// source: event.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
// ignore_for_file: UNDEFINED_SHOWN_NAME
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class UserEvent extends $pb.ProtobufEnum {
static const UserEvent AuthCheck = UserEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AuthCheck');
static const UserEvent SignIn = UserEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SignIn');
static const UserEvent SignUp = UserEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SignUp');
static const UserEvent SignOut = UserEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SignOut');
static const $core.List<UserEvent> values = <UserEvent> [
AuthCheck,
SignIn,
SignUp,
SignOut,
];
static final $core.Map<$core.int, UserEvent> _byValue = $pb.ProtobufEnum.initByValue(values);
static UserEvent? valueOf($core.int value) => _byValue[value];
const UserEvent._($core.int v, $core.String n) : super(v, n);
}

View file

@ -0,0 +1,18 @@
///
// Generated code. Do not modify.
// source: event.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
import 'dart:core' as $core;
const UserEvent$json = const {
'1': 'UserEvent',
'2': const [
const {'1': 'AuthCheck', '2': 0},
const {'1': 'SignIn', '2': 1},
const {'1': 'SignUp', '2': 2},
const {'1': 'SignOut', '2': 3},
],
};

View file

@ -0,0 +1,9 @@
///
// Generated code. Do not modify.
// source: event.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
export 'event.pb.dart';

View file

@ -9,30 +9,34 @@ import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb; import 'package:protobuf/protobuf.dart' as $pb;
import 'ffi_response.pbenum.dart';
export 'ffi_response.pbenum.dart';
class FFIResponse extends $pb.GeneratedMessage { class FFIResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FFIResponse', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FFIResponse', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'event') ..a<$core.List<$core.int>>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'payload', $pb.PbFieldType.OY)
..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'payload', $pb.PbFieldType.OY) ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'error')
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'error') ..e<FFIStatusCode>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code', $pb.PbFieldType.OE, defaultOrMaker: FFIStatusCode.Unknown, valueOf: FFIStatusCode.valueOf, enumValues: FFIStatusCode.values)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
FFIResponse._() : super(); FFIResponse._() : super();
factory FFIResponse({ factory FFIResponse({
$core.String? event,
$core.List<$core.int>? payload, $core.List<$core.int>? payload,
$core.String? error, $core.String? error,
FFIStatusCode? code,
}) { }) {
final _result = create(); final _result = create();
if (event != null) {
_result.event = event;
}
if (payload != null) { if (payload != null) {
_result.payload = payload; _result.payload = payload;
} }
if (error != null) { if (error != null) {
_result.error = error; _result.error = error;
} }
if (code != null) {
_result.code = code;
}
return _result; return _result;
} }
factory FFIResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory FFIResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@ -57,30 +61,30 @@ class FFIResponse extends $pb.GeneratedMessage {
static FFIResponse? _defaultInstance; static FFIResponse? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.String get event => $_getSZ(0); $core.List<$core.int> get payload => $_getN(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
set event($core.String v) { $_setString(0, v); } set payload($core.List<$core.int> v) { $_setBytes(0, v); }
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.bool hasEvent() => $_has(0); $core.bool hasPayload() => $_has(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
void clearEvent() => clearField(1); void clearPayload() => clearField(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.List<$core.int> get payload => $_getN(1); $core.String get error => $_getSZ(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
set payload($core.List<$core.int> v) { $_setBytes(1, v); } set error($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.bool hasPayload() => $_has(1); $core.bool hasError() => $_has(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
void clearPayload() => clearField(2); void clearError() => clearField(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
$core.String get error => $_getSZ(2); FFIStatusCode get code => $_getN(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
set error($core.String v) { $_setString(2, v); } set code(FFIStatusCode v) { setField(3, v); }
@$pb.TagNumber(3) @$pb.TagNumber(3)
$core.bool hasError() => $_has(2); $core.bool hasCode() => $_has(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
void clearError() => clearField(3); void clearCode() => clearField(3);
} }

View file

@ -5,3 +5,24 @@
// @dart = 2.12 // @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
// ignore_for_file: UNDEFINED_SHOWN_NAME
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class FFIStatusCode extends $pb.ProtobufEnum {
static const FFIStatusCode Unknown = FFIStatusCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
static const FFIStatusCode Ok = FFIStatusCode._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Ok');
static const FFIStatusCode Err = FFIStatusCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Err');
static const $core.List<FFIStatusCode> values = <FFIStatusCode> [
Unknown,
Ok,
Err,
];
static final $core.Map<$core.int, FFIStatusCode> _byValue = $pb.ProtobufEnum.initByValue(values);
static FFIStatusCode? valueOf($core.int value) => _byValue[value];
const FFIStatusCode._($core.int v, $core.String n) : super(v, n);
}

View file

@ -6,12 +6,21 @@
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
import 'dart:core' as $core; import 'dart:core' as $core;
const FFIResponse$json = const { const FFIStatusCode$json = const {
'1': 'FFIResponse', '1': 'FFIStatusCode',
'2': const [ '2': const [
const {'1': 'event', '3': 1, '4': 1, '5': 9, '10': 'event'}, const {'1': 'Unknown', '2': 0},
const {'1': 'payload', '3': 2, '4': 1, '5': 12, '10': 'payload'}, const {'1': 'Ok', '2': 1},
const {'1': 'error', '3': 3, '4': 1, '5': 9, '10': 'error'}, const {'1': 'Err', '2': 2},
],
};
const FFIResponse$json = const {
'1': 'FFIResponse',
'2': const [
const {'1': 'payload', '3': 1, '4': 1, '5': 12, '10': 'payload'},
const {'1': 'error', '3': 2, '4': 1, '5': 9, '10': 'error'},
const {'1': 'code', '3': 3, '4': 1, '5': 14, '6': '.FFIStatusCode', '10': 'code'},
], ],
}; };

View file

@ -209,6 +209,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -284,6 +291,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.1" version: "4.0.1"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logger: logger:
dependency: transitive dependency: transitive
description: description:

View file

@ -259,7 +259,7 @@ packages:
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
flutter_lints: flutter_lints:
dependency: "direct main" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"

View file

@ -1,10 +1,11 @@
mod c; mod c;
mod model; mod model;
mod protobuf; mod protobuf;
mod util;
use crate::{ use crate::{
c::{extend_front_four_bytes_into_bytes, forget_rust}, c::{extend_front_four_bytes_into_bytes, forget_rust},
protobuf::FFIRequest, model::{FFIRequest, FFIResponse},
}; };
use flowy_sdk::*; use flowy_sdk::*;
use flowy_sys::prelude::*; use flowy_sys::prelude::*;
@ -30,7 +31,7 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 {
#[no_mangle] #[no_mangle]
pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) { pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
let mut request: DispatchRequest = FFIRequest::from_u8_pointer(input, len).into(); let request: DispatchRequest = FFIRequest::from_u8_pointer(input, len).into();
log::trace!( log::trace!(
"[FFI]: {} Async Event: {:?} with {} port", "[FFI]: {} Async Event: {:?} with {} port",
&request.id, &request.id,
@ -38,16 +39,10 @@ pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
port port
); );
request = request.callback(Box::new(move |resp: EventResponse| { let _ = EventDispatch::async_send(request, move |resp: EventResponse| {
let bytes = match resp.payload {
Payload::Bytes(bytes) => bytes,
Payload::None => vec![],
};
log::trace!("[FFI]: Post data to dart through {} port", port); log::trace!("[FFI]: Post data to dart through {} port", port);
Box::pin(spawn_future(async { bytes }, port)) Box::pin(post_to_flutter(resp, port))
})); });
let _ = EventDispatch::async_send(request);
} }
#[no_mangle] #[no_mangle]
@ -66,13 +61,17 @@ pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 {
#[no_mangle] #[no_mangle]
pub extern "C" fn link_me_please() {} pub extern "C" fn link_me_please() {}
use flowy_sys::prelude::ToBytes;
#[inline(always)] #[inline(always)]
async fn spawn_future<F>(future: F, port: i64) async fn post_to_flutter(response: EventResponse, port: i64) {
where
F: Future<Output = Vec<u8>> + Send + 'static,
{
let isolate = allo_isolate::Isolate::new(port); let isolate = allo_isolate::Isolate::new(port);
match isolate.catch_unwind(future).await { match isolate
.catch_unwind(async {
let ffi_resp = FFIResponse::from(response);
ffi_resp.into_bytes().unwrap()
})
.await
{
Ok(_success) => { Ok(_success) => {
log::trace!("[FFI]: Post data to dart success"); log::trace!("[FFI]: Post data to dart success");
}, },
@ -85,15 +84,3 @@ where
}, },
} }
} }
impl std::convert::From<FFIRequest> for DispatchRequest {
fn from(ffi_request: FFIRequest) -> Self {
let payload = if !ffi_request.payload.is_empty() {
Payload::Bytes(ffi_request.payload)
} else {
Payload::None
};
let request = DispatchRequest::new(ffi_request.event).payload(payload);
request
}
}

View file

@ -1,13 +1,14 @@
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use flowy_sys::prelude::DispatchRequest;
use std::convert::TryFrom; use std::convert::TryFrom;
#[derive(Default, ProtoBuf)] #[derive(Default, ProtoBuf)]
pub struct FFIRequest { pub struct FFIRequest {
#[pb(index = 1)] #[pb(index = 1)]
event: String, pub(crate) event: String,
#[pb(index = 2)] #[pb(index = 2)]
payload: Vec<u8>, pub(crate) payload: Vec<u8>,
} }
impl FFIRequest { impl FFIRequest {
@ -17,3 +18,7 @@ impl FFIRequest {
request request
} }
} }
impl std::convert::Into<DispatchRequest> for FFIRequest {
fn into(self) -> DispatchRequest { DispatchRequest::new(self.event).payload(self.payload) }
}

View file

@ -1,13 +1,50 @@
use flowy_derive::ProtoBuf; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_sys::prelude::{EventResponse, Payload, StatusCode};
#[derive(ProtoBuf_Enum, Clone, Copy)]
pub enum FFIStatusCode {
Unknown = 0,
Ok = 1,
Err = 2,
}
impl std::default::Default for FFIStatusCode {
fn default() -> FFIStatusCode { FFIStatusCode::Unknown }
}
#[derive(ProtoBuf, Default)] #[derive(ProtoBuf, Default)]
pub struct FFIResponse { pub struct FFIResponse {
#[pb(index = 1)] #[pb(index = 1)]
event: String,
#[pb(index = 2)]
payload: Vec<u8>, payload: Vec<u8>,
#[pb(index = 3)] #[pb(index = 2)]
error: String, error: String,
#[pb(index = 3)]
code: FFIStatusCode,
}
impl std::convert::From<EventResponse> for FFIResponse {
fn from(resp: EventResponse) -> Self {
let payload = match resp.payload {
Payload::Bytes(bytes) => bytes,
Payload::None => vec![],
};
let error = match resp.error {
Some(e) => format!("{}", e),
None => "".to_owned(),
};
let code = match resp.status_code {
StatusCode::Ok => FFIStatusCode::Ok,
StatusCode::Err => FFIStatusCode::Err,
};
FFIResponse {
payload,
error,
code,
}
}
} }

View file

@ -26,9 +26,9 @@
#[derive(PartialEq,Clone,Default)] #[derive(PartialEq,Clone,Default)]
pub struct FFIResponse { pub struct FFIResponse {
// message fields // message fields
pub event: ::std::string::String,
pub payload: ::std::vec::Vec<u8>, pub payload: ::std::vec::Vec<u8>,
pub error: ::std::string::String, pub error: ::std::string::String,
pub code: FFIStatusCode,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -45,33 +45,7 @@ impl FFIResponse {
::std::default::Default::default() ::std::default::Default::default()
} }
// string event = 1; // bytes payload = 1;
pub fn get_event(&self) -> &str {
&self.event
}
pub fn clear_event(&mut self) {
self.event.clear();
}
// Param is passed by value, moved
pub fn set_event(&mut self, v: ::std::string::String) {
self.event = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_event(&mut self) -> &mut ::std::string::String {
&mut self.event
}
// Take field
pub fn take_event(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.event, ::std::string::String::new())
}
// bytes payload = 2;
pub fn get_payload(&self) -> &[u8] { pub fn get_payload(&self) -> &[u8] {
@ -97,7 +71,7 @@ impl FFIResponse {
::std::mem::replace(&mut self.payload, ::std::vec::Vec::new()) ::std::mem::replace(&mut self.payload, ::std::vec::Vec::new())
} }
// string error = 3; // string error = 2;
pub fn get_error(&self) -> &str { pub fn get_error(&self) -> &str {
@ -122,6 +96,21 @@ impl FFIResponse {
pub fn take_error(&mut self) -> ::std::string::String { pub fn take_error(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.error, ::std::string::String::new()) ::std::mem::replace(&mut self.error, ::std::string::String::new())
} }
// .FFIStatusCode code = 3;
pub fn get_code(&self) -> FFIStatusCode {
self.code
}
pub fn clear_code(&mut self) {
self.code = FFIStatusCode::Unknown;
}
// Param is passed by value, moved
pub fn set_code(&mut self, v: FFIStatusCode) {
self.code = v;
}
} }
impl ::protobuf::Message for FFIResponse { impl ::protobuf::Message for FFIResponse {
@ -134,14 +123,14 @@ impl ::protobuf::Message for FFIResponse {
let (field_number, wire_type) = is.read_tag_unpack()?; let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number { match field_number {
1 => { 1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.event)?;
},
2 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.payload)?; ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.payload)?;
}, },
3 => { 2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.error)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.error)?;
}, },
3 => {
::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.code, 3, &mut self.unknown_fields)?
},
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
}, },
@ -154,14 +143,14 @@ impl ::protobuf::Message for FFIResponse {
#[allow(unused_variables)] #[allow(unused_variables)]
fn compute_size(&self) -> u32 { fn compute_size(&self) -> u32 {
let mut my_size = 0; let mut my_size = 0;
if !self.event.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.event);
}
if !self.payload.is_empty() { if !self.payload.is_empty() {
my_size += ::protobuf::rt::bytes_size(2, &self.payload); my_size += ::protobuf::rt::bytes_size(1, &self.payload);
} }
if !self.error.is_empty() { if !self.error.is_empty() {
my_size += ::protobuf::rt::string_size(3, &self.error); my_size += ::protobuf::rt::string_size(2, &self.error);
}
if self.code != FFIStatusCode::Unknown {
my_size += ::protobuf::rt::enum_size(3, self.code);
} }
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size); self.cached_size.set(my_size);
@ -169,14 +158,14 @@ impl ::protobuf::Message for FFIResponse {
} }
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.event.is_empty() {
os.write_string(1, &self.event)?;
}
if !self.payload.is_empty() { if !self.payload.is_empty() {
os.write_bytes(2, &self.payload)?; os.write_bytes(1, &self.payload)?;
} }
if !self.error.is_empty() { if !self.error.is_empty() {
os.write_string(3, &self.error)?; os.write_string(2, &self.error)?;
}
if self.code != FFIStatusCode::Unknown {
os.write_enum(3, ::protobuf::ProtobufEnum::value(&self.code))?;
} }
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
@ -216,11 +205,6 @@ impl ::protobuf::Message for FFIResponse {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| { descriptor.get(|| {
let mut fields = ::std::vec::Vec::new(); let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"event",
|m: &FFIResponse| { &m.event },
|m: &mut FFIResponse| { &mut m.event },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
"payload", "payload",
|m: &FFIResponse| { &m.payload }, |m: &FFIResponse| { &m.payload },
@ -231,6 +215,11 @@ impl ::protobuf::Message for FFIResponse {
|m: &FFIResponse| { &m.error }, |m: &FFIResponse| { &m.error },
|m: &mut FFIResponse| { &mut m.error }, |m: &mut FFIResponse| { &mut m.error },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<FFIStatusCode>>(
"code",
|m: &FFIResponse| { &m.code },
|m: &mut FFIResponse| { &mut m.code },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<FFIResponse>( ::protobuf::reflect::MessageDescriptor::new_pb_name::<FFIResponse>(
"FFIResponse", "FFIResponse",
fields, fields,
@ -247,9 +236,9 @@ impl ::protobuf::Message for FFIResponse {
impl ::protobuf::Clear for FFIResponse { impl ::protobuf::Clear for FFIResponse {
fn clear(&mut self) { fn clear(&mut self) {
self.event.clear();
self.payload.clear(); self.payload.clear();
self.error.clear(); self.error.clear();
self.code = FFIStatusCode::Unknown;
self.unknown_fields.clear(); self.unknown_fields.clear();
} }
} }
@ -266,20 +255,82 @@ impl ::protobuf::reflect::ProtobufValue for FFIResponse {
} }
} }
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub enum FFIStatusCode {
Unknown = 0,
Ok = 1,
Err = 2,
}
impl ::protobuf::ProtobufEnum for FFIStatusCode {
fn value(&self) -> i32 {
*self as i32
}
fn from_i32(value: i32) -> ::std::option::Option<FFIStatusCode> {
match value {
0 => ::std::option::Option::Some(FFIStatusCode::Unknown),
1 => ::std::option::Option::Some(FFIStatusCode::Ok),
2 => ::std::option::Option::Some(FFIStatusCode::Err),
_ => ::std::option::Option::None
}
}
fn values() -> &'static [Self] {
static values: &'static [FFIStatusCode] = &[
FFIStatusCode::Unknown,
FFIStatusCode::Ok,
FFIStatusCode::Err,
];
values
}
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
::protobuf::reflect::EnumDescriptor::new_pb_name::<FFIStatusCode>("FFIStatusCode", file_descriptor_proto())
})
}
}
impl ::std::marker::Copy for FFIStatusCode {
}
impl ::std::default::Default for FFIStatusCode {
fn default() -> Self {
FFIStatusCode::Unknown
}
}
impl ::protobuf::reflect::ProtobufValue for FFIStatusCode {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
}
}
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x12ffi_response.proto\"S\n\x0bFFIResponse\x12\x14\n\x05event\x18\x01\ \n\x12ffi_response.proto\"a\n\x0bFFIResponse\x12\x18\n\x07payload\x18\
\x20\x01(\tR\x05event\x12\x18\n\x07payload\x18\x02\x20\x01(\x0cR\x07payl\ \x01\x20\x01(\x0cR\x07payload\x12\x14\n\x05error\x18\x02\x20\x01(\tR\x05\
oad\x12\x14\n\x05error\x18\x03\x20\x01(\tR\x05errorJ\xcf\x01\n\x06\x12\ error\x12\"\n\x04code\x18\x03\x20\x01(\x0e2\x0e.FFIStatusCodeR\x04code*-\
\x04\0\0\x06\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\ \n\rFFIStatusCode\x12\x0b\n\x07Unknown\x10\0\x12\x06\n\x02Ok\x10\x01\x12\
\x02\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x13\n\x0b\n\x04\x04\0\ \x07\n\x03Err\x10\x02J\xe2\x02\n\x06\x12\x04\0\0\x0b\x01\n\x08\n\x01\x0c\
\x02\0\x12\x03\x03\x04\x15\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\ \x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x06\x01\n\n\n\x03\x04\0\
\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x10\n\x0c\n\x05\x04\0\x02\0\ \x01\x12\x03\x02\x08\x13\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x16\n\
\x03\x12\x03\x03\x13\x14\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x16\n\ \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\
\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\t\n\x0c\n\x05\x04\0\x02\x01\ \x12\x03\x03\n\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\x0b\
\x01\x12\x03\x04\n\x11\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x14\x15\ \n\x04\x04\0\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x05\
\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x15\n\x0c\n\x05\x04\0\x02\x02\ \x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x10\n\
\x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\x10\ \x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x13\x14\n\x0b\n\x04\x04\0\x02\
\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x13\x14b\x06proto3\ \x02\x12\x03\x05\x04\x1b\n\x0c\n\x05\x04\0\x02\x02\x06\x12\x03\x05\x04\
\x11\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x12\x16\n\x0c\n\x05\x04\0\
\x02\x02\x03\x12\x03\x05\x19\x1a\n\n\n\x02\x05\0\x12\x04\x07\0\x0b\x01\n\
\n\n\x03\x05\0\x01\x12\x03\x07\x05\x12\n\x0b\n\x04\x05\0\x02\0\x12\x03\
\x08\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x08\x04\x0b\n\x0c\n\x05\
\x05\0\x02\0\x02\x12\x03\x08\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\t\
\x04\x0b\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\t\x04\x06\n\x0c\n\x05\x05\
\0\x02\x01\x02\x12\x03\t\t\n\n\x0b\n\x04\x05\0\x02\x02\x12\x03\n\x04\x0c\
\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\n\x04\x07\n\x0c\n\x05\x05\0\x02\
\x02\x02\x12\x03\n\n\x0bb\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View file

@ -1,7 +1,12 @@
syntax = "proto3"; syntax = "proto3";
message FFIResponse { message FFIResponse {
string event = 1; bytes payload = 1;
bytes payload = 2; string error = 2;
string error = 3; FFIStatusCode code = 3;
}
enum FFIStatusCode {
Unknown = 0;
Ok = 1;
Err = 2;
} }

View file

@ -0,0 +1 @@

View file

@ -25,6 +25,9 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
| "UserSignInRequest" | "UserSignInRequest"
| "UserSignInResult" | "UserSignInResult"
=> TypeCategory::Protobuf, => TypeCategory::Protobuf,
"FFIStatusCode"
| "UserEvent"
=> TypeCategory::Enum,
"Option" => TypeCategory::Opt, "Option" => TypeCategory::Opt,
_ => TypeCategory::Primitive, _ => TypeCategory::Primitive,

View file

@ -60,7 +60,7 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option<TokenStream>
let ty = ty_info.ty; let ty = ty_info.ty;
Some(quote! { Some(quote! {
if pb.#has_func() { if pb.#has_func() {
let enum_de_from_pb = #ty::try_from(&mut pb.#get_func()).unwrap(); let enum_de_from_pb = #ty::try_from(&pb.#get_func()).unwrap();
o.#member = Some(enum_de_from_pb); o.#member = Some(enum_de_from_pb);
} }
}) })
@ -122,7 +122,7 @@ fn token_stream_for_field(
TypeCategory::Enum => { TypeCategory::Enum => {
let ty = ty_info.ty; let ty = ty_info.ty;
Some(quote! { Some(quote! {
let enum_de_from_pb = #ty::try_from(&mut pb.#member).unwrap(); let enum_de_from_pb = #ty::try_from(&pb.#member).unwrap();
o.#member = enum_de_from_pb; o.#member = enum_de_from_pb;
}) })

View file

@ -5,27 +5,36 @@ use proc_macro2::TokenStream;
pub fn make_enum_token_stream(_ctxt: &Ctxt, cont: &ASTContainer) -> Option<TokenStream> { pub fn make_enum_token_stream(_ctxt: &Ctxt, cont: &ASTContainer) -> Option<TokenStream> {
let enum_ident = &cont.ident; let enum_ident = &cont.ident;
let pb_enum = cont.attrs.pb_enum_type()?; let pb_enum = cont.attrs.pb_enum_type()?;
let _build_to_pb_enum = cont.data.all_idents().map(|i| { let build_to_pb_enum = cont.data.all_idents().map(|i| {
let token_stream: TokenStream = quote! { let token_stream: TokenStream = quote! {
#enum_ident::#i => #pb_enum::#i, #enum_ident::#i => crate::protobuf::#pb_enum::#i,
}; };
token_stream token_stream
}); });
let build_from_pb_enum = cont.data.all_idents().map(|i| { let build_from_pb_enum = cont.data.all_idents().map(|i| {
let token_stream: TokenStream = quote! { let token_stream: TokenStream = quote! {
#pb_enum::#i => #enum_ident::#i, crate::protobuf::#pb_enum::#i => #enum_ident::#i,
}; };
token_stream token_stream
}); });
Some(quote! { Some(quote! {
impl std::convert::TryFrom<#pb_enum> for #enum_ident { impl std::convert::TryFrom<&crate::protobuf::#pb_enum> for #enum_ident {
type Error = String; type Error = String;
fn try_from(pb: #pb_enum) -> Result<Self, Self::Error> { fn try_from(pb:&crate::protobuf::#pb_enum) -> Result<Self, Self::Error> {
match field_type { Ok(match pb {
#(#build_from_pb_enum)* #(#build_from_pb_enum)*
} })
}
}
impl std::convert::TryInto<crate::protobuf::#pb_enum> for #enum_ident {
type Error = String;
fn try_into(self) -> Result<crate::protobuf::#pb_enum, Self::Error> {
Ok(match self {
#(#build_to_pb_enum)*
})
} }
} }
}) })

View file

@ -58,7 +58,7 @@ fn se_token_stream_for_field(ctxt: &Ctxt, field: &ASTField, _take: bool) -> Opti
let set_func = format_ident!("set_{}", ident.to_string()); let set_func = format_ident!("set_{}", ident.to_string());
Some(quote! { Some(quote! {
match self.#member { match self.#member {
Some(ref s) => { pb.#set_func(s.to_protobuf()) } Some(ref s) => { pb.#set_func(s.try_into().unwrap()) }
None => {} None => {}
} }
}) })
@ -98,7 +98,7 @@ fn gen_token_stream(
} }
}, },
TypeCategory::Protobuf => Some( TypeCategory::Protobuf => Some(
quote! { pb.#member = ::protobuf::SingularPtrField::some(self.#member.to_protobuf()); }, quote! { pb.#member = ::protobuf::SingularPtrField::some(self.#member.try_into().unwrap()); },
), ),
TypeCategory::Opt => { TypeCategory::Opt => {
gen_token_stream(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true) gen_token_stream(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true)
@ -109,7 +109,7 @@ fn gen_token_stream(
// flowy_protobuf::#pb_enum_ident::from_i32(self.#member.value()).unwrap(); // flowy_protobuf::#pb_enum_ident::from_i32(self.#member.value()).unwrap();
// }) // })
Some(quote! { Some(quote! {
pb.#member = self.#member.to_protobuf(); pb.#member = self.#member.try_into().unwrap();
}) })
}, },
_ => Some(quote! { pb.#member = self.#member; }), _ => Some(quote! { pb.#member = self.#member; }),
@ -124,7 +124,7 @@ fn token_stream_for_vec(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op
pb.#member = ::protobuf::RepeatedField::from_vec( pb.#member = ::protobuf::RepeatedField::from_vec(
self.#member self.#member
.iter() .iter()
.map(|m| m.to_protobuf()) .map(|m| m.try_into().unwrap())
.collect()); .collect());
}), }),
TypeCategory::Bytes => Some(quote! { pb.#member = self.#member.clone(); }), TypeCategory::Bytes => Some(quote! { pb.#member = self.#member.clone(); }),
@ -146,7 +146,7 @@ fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op
Some(quote! { Some(quote! {
let mut m: std::collections::HashMap<String, #flowy_protobuf::#value_type> = std::collections::HashMap::new(); let mut m: std::collections::HashMap<String, #flowy_protobuf::#value_type> = std::collections::HashMap::new();
self.#member.iter().for_each(|(k,v)| { self.#member.iter().for_each(|(k,v)| {
m.insert(k.clone(), v.to_protobuf()); m.insert(k.clone(), v.try_into().unwrap());
}); });
pb.#member = m; pb.#member = m;
}) })

View file

@ -15,8 +15,4 @@ impl FlowySDK {
} }
} }
pub async fn async_send(request: DispatchRequest) -> EventResponse {
EventDispatch::async_send(request).await
}
pub fn sync_send(request: DispatchRequest) -> EventResponse { EventDispatch::sync_send(request) } pub fn sync_send(request: DispatchRequest) -> EventResponse { EventDispatch::sync_send(request) }

View file

@ -46,7 +46,14 @@ impl EventDispatch {
*(EVENT_DISPATCH.write().unwrap()) = Some(dispatch); *(EVENT_DISPATCH.write().unwrap()) = Some(dispatch);
} }
pub fn async_send(request: DispatchRequest) -> DispatchFuture { pub fn async_send<Req, Callback>(request: Req, callback: Callback) -> DispatchFuture
where
Req: std::convert::Into<DispatchRequest>,
Callback: FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync,
{
let mut request = request.into();
request.callback = Some(Box::new(callback));
match EVENT_DISPATCH.read() { match EVENT_DISPATCH.read() {
Ok(dispatch) => { Ok(dispatch) => {
let dispatch = dispatch.as_ref().unwrap(); let dispatch = dispatch.as_ref().unwrap();
@ -81,7 +88,13 @@ impl EventDispatch {
} }
pub fn sync_send(request: DispatchRequest) -> EventResponse { pub fn sync_send(request: DispatchRequest) -> EventResponse {
futures::executor::block_on(async { EventDispatch::async_send(request).await }) futures::executor::block_on(async {
EventDispatch::async_send(request, |response| {
dbg!(&response);
Box::pin(async {})
})
.await
})
} }
} }
@ -130,16 +143,9 @@ impl DispatchRequest {
pub fn payload<P>(mut self, payload: P) -> Self pub fn payload<P>(mut self, payload: P) -> Self
where where
P: TryInto<Payload, Error = String>, P: Into<Payload>,
{ {
let payload = match payload.try_into() { self.payload = payload.into();
Ok(payload) => payload,
Err(e) => {
log::error!("{}", e);
Payload::None
},
};
self.payload = payload;
self self
} }

View file

@ -10,10 +10,6 @@ pub fn setup_env() {
}); });
} }
pub async fn async_send(request: DispatchRequest) -> EventResponse {
EventDispatch::async_send(request).await
}
pub fn init_dispatch<F>(module_factory: F) pub fn init_dispatch<F>(module_factory: F)
where where
F: FnOnce() -> Vec<Module>, F: FnOnce() -> Vec<Module>,

View file

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

View file

@ -66,7 +66,8 @@ impl EventTester {
P: ToBytes, P: ToBytes,
{ {
let mut request = self.request.take().unwrap(); let mut request = self.request.take().unwrap();
request = request.payload(Data(payload)); let bytes = payload.into_bytes().unwrap();
request = request.payload(bytes);
self.request = Some(request); self.request = Some(request);
self self
} }
@ -78,7 +79,9 @@ impl EventTester {
#[allow(dead_code)] #[allow(dead_code)]
pub async fn async_send(mut self) -> Self { pub async fn async_send(mut self) -> Self {
let resp = async_send(self.request.take().unwrap()).await; let resp =
EventDispatch::async_send(self.request.take().unwrap(), |_| Box::pin(async {})).await;
if let Some(ref status_code) = self.assert_status_code { if let Some(ref status_code) = self.assert_status_code {
assert_eq!(&resp.status_code, status_code) assert_eq!(&resp.status_code, status_code)
} }

View file

@ -0,0 +1,27 @@
use derive_more::Display;
use flowy_derive::ProtoBuf_Enum;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum)]
pub enum UserEvent {
#[display(fmt = "AuthCheck")]
AuthCheck = 0,
#[display(fmt = "SignIn")]
SignIn = 1,
#[display(fmt = "SignUp")]
SignUp = 2,
#[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}
// }
// }
// }

View file

@ -1,3 +1,4 @@
pub mod event;
pub mod user; pub mod user;
pub use user::*; pub use user::*;

View file

@ -5,5 +5,5 @@ pub mod module;
mod protobuf; mod protobuf;
pub mod prelude { pub mod prelude {
pub use crate::{domain::*, handlers::auth::*, module::UserEvent::*}; pub use crate::{domain::*, handlers::auth::*};
} }

View file

@ -1,20 +1,6 @@
use crate::handlers::*; use crate::{domain::event::UserEvent, handlers::*};
use flowy_sys::prelude::*; use flowy_sys::prelude::*;
use derive_more::Display;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash)]
pub enum UserEvent {
#[display(fmt = "AuthCheck")]
AuthCheck = 0,
#[display(fmt = "SignIn")]
SignIn = 1,
#[display(fmt = "SignUp")]
SignUp = 2,
#[display(fmt = "SignOut")]
SignOut = 3,
}
pub fn create() -> Module { pub fn create() -> Module {
Module::new() Module::new()
.name("Flowy-User") .name("Flowy-User")

View file

@ -0,0 +1,108 @@
// This file is generated by rust-protobuf 2.22.1. Do not edit
// @generated
// https://github.com/rust-lang/rust-clippy/issues/702
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![allow(unused_attributes)]
#![cfg_attr(rustfmt, rustfmt::skip)]
#![allow(box_pointers)]
#![allow(dead_code)]
#![allow(missing_docs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(trivial_casts)]
#![allow(unused_imports)]
#![allow(unused_results)]
//! Generated file from `event.proto`
/// Generated files are compatible only with the same version
/// of protobuf runtime.
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_22_1;
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub enum UserEvent {
AuthCheck = 0,
SignIn = 1,
SignUp = 2,
SignOut = 3,
}
impl ::protobuf::ProtobufEnum for UserEvent {
fn value(&self) -> i32 {
*self as i32
}
fn from_i32(value: i32) -> ::std::option::Option<UserEvent> {
match value {
0 => ::std::option::Option::Some(UserEvent::AuthCheck),
1 => ::std::option::Option::Some(UserEvent::SignIn),
2 => ::std::option::Option::Some(UserEvent::SignUp),
3 => ::std::option::Option::Some(UserEvent::SignOut),
_ => ::std::option::Option::None
}
}
fn values() -> &'static [Self] {
static values: &'static [UserEvent] = &[
UserEvent::AuthCheck,
UserEvent::SignIn,
UserEvent::SignUp,
UserEvent::SignOut,
];
values
}
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
::protobuf::reflect::EnumDescriptor::new_pb_name::<UserEvent>("UserEvent", file_descriptor_proto())
})
}
}
impl ::std::marker::Copy for UserEvent {
}
impl ::std::default::Default for UserEvent {
fn default() -> Self {
UserEvent::AuthCheck
}
}
impl ::protobuf::reflect::ProtobufValue for UserEvent {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
}
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0bevent.proto*?\n\tUserEvent\x12\r\n\tAuthCheck\x10\0\x12\n\n\x06Sig\
nIn\x10\x01\x12\n\n\x06SignUp\x10\x02\x12\x0b\n\x07SignOut\x10\x03J\xce\
\x01\n\x06\x12\x04\0\0\x07\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
\x05\0\x12\x04\x02\0\x07\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x0e\n\
\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\x05\x05\0\x02\0\x01\
\x12\x03\x03\x04\r\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x10\x11\n\x0b\
\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x0f\n\x0c\n\x05\x05\0\x02\x01\x01\
\x12\x03\x04\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\r\x0e\n\x0b\
\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x0f\n\x0c\n\x05\x05\0\x02\x02\x01\
\x12\x03\x05\x04\n\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\r\x0e\n\x0b\
\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x10\n\x0c\n\x05\x05\0\x02\x03\x01\
\x12\x03\x06\x04\x0b\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x0e\x0fb\
\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto {
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
}
pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
file_descriptor_proto_lazy.get(|| {
parse_descriptor_proto()
})
}

View file

@ -6,5 +6,8 @@ pub use sign_up::*;
mod sign_in; mod sign_in;
pub use sign_in::*; pub use sign_in::*;
mod event;
pub use event::*;
mod user; mod user;
pub use user::*; pub use user::*;

View file

@ -0,0 +1,8 @@
syntax = "proto3";
enum UserEvent {
AuthCheck = 0;
SignIn = 1;
SignUp = 2;
SignOut = 3;
}

View file

@ -1,5 +1,5 @@
use flowy_test::prelude::*; use flowy_test::prelude::*;
use flowy_user::prelude::*; use flowy_user::prelude::{event::UserEvent::*, *};
#[test] #[test]
fn sign_in_with_invalid_email() { fn sign_in_with_invalid_email() {

View file

@ -4,6 +4,11 @@ pub struct EventTemplate {
tera_context: Context, tera_context: Context,
} }
pub const DART_IMPORTED: &'static str = r#"
/// Auto gen code from rust ast, do not edit
part of 'cqrs.dart';
"#;
pub struct EventRenderContext { pub struct EventRenderContext {
pub input_deserializer: String, pub input_deserializer: String,
pub output_deserializer: String, pub output_deserializer: String,
@ -21,5 +26,67 @@ impl EventTemplate {
pub fn render(&mut self, _render_context: EventRenderContext, _index: usize) -> Option<String> { pub fn render(&mut self, _render_context: EventRenderContext, _index: usize) -> Option<String> {
None 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
// }
// }
} }
} }

View file

@ -0,0 +1,72 @@
{%- if index == 0 %}
{{ imported_dart_files }}
{%- endif -%}
class {{ command_request_struct_ident }} {
{%- if has_request_deserializer %}
{{ request_deserializer }} body;
{%- else %}
Uint8List? body;
{%- endif %}
{%- 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();
{%- 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 %}
});
},
(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 %}
}
}

View file

@ -24,7 +24,7 @@ pub fn parse_crate_config_from(entry: &walkdir::DirEntry) -> Option<CrateConfig>
let folder_name = path.file_stem().unwrap().to_str().unwrap().to_string(); let folder_name = path.file_stem().unwrap().to_str().unwrap().to_string();
let config_path = format!("{}/Flowy.toml", crate_path); let config_path = format!("{}/Flowy.toml", crate_path);
if std::path::Path::new(&config_path).exists() { if !std::path::Path::new(&config_path).exists() {
return None; return None;
} }