| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  | import 'dart:ffi'; | 
					
						
							|  |  |  | import 'package:dartz/dartz.dart'; | 
					
						
							| 
									
										
										
										
											2021-09-12 23:04:34 +08:00
										 |  |  | import 'package:flowy_log/flowy_log.dart'; | 
					
						
							| 
									
										
										
										
											2021-12-10 22:48:30 +08:00
										 |  |  | // ignore: unnecessary_import
 | 
					
						
							| 
									
										
										
										
											2021-07-13 14:28:01 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/dart-ffi/ffi_response.pb.dart'; | 
					
						
							| 
									
										
										
										
											2021-12-14 15:31:44 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; | 
					
						
							|  |  |  | import 'package:flowy_sdk/protobuf/flowy-net/event.pb.dart'; | 
					
						
							| 
									
										
										
										
											2021-12-12 21:48:52 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart'; | 
					
						
							| 
									
										
										
										
											2021-12-05 14:04:25 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/flowy-user/event.pb.dart'; | 
					
						
							| 
									
										
										
										
											2021-12-06 14:41:09 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/flowy-core/event.pb.dart'; | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  | 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'; | 
					
						
							| 
									
										
										
										
											2021-07-13 10:59:51 +08:00
										 |  |  | import 'package:flowy_sdk/ffi.dart' as ffi; | 
					
						
							| 
									
										
										
										
											2021-12-19 21:29:33 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/flowy-user-data-model/protobuf.dart'; | 
					
						
							| 
									
										
										
										
											2021-07-13 14:28:01 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/dart-ffi/protobuf.dart'; | 
					
						
							| 
									
										
										
										
											2021-12-19 21:29:33 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/flowy-core-data-model/protobuf.dart'; | 
					
						
							| 
									
										
										
										
											2021-12-11 13:47:16 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/flowy-collaboration/protobuf.dart'; | 
					
						
							| 
									
										
										
										
											2021-11-13 11:53:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-13 14:28:01 +08:00
										 |  |  | // ignore: unused_import
 | 
					
						
							| 
									
										
										
										
											2021-12-06 14:41:09 +08:00
										 |  |  | import 'package:flowy_sdk/protobuf/lib-infra/protobuf.dart'; | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  | import 'package:protobuf/protobuf.dart'; | 
					
						
							| 
									
										
										
										
											2021-08-31 11:32:51 +08:00
										 |  |  | import 'dart:convert' show utf8; | 
					
						
							| 
									
										
										
										
											2021-07-08 21:23:44 +08:00
										 |  |  | import 'error.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  | part 'code_gen.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum FFIException { | 
					
						
							|  |  |  |   RequestIsEmpty, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DispatchException implements Exception { | 
					
						
							|  |  |  |   FFIException type; | 
					
						
							|  |  |  |   DispatchException(this.type); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Dispatch { | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  |   static Future<Either<Uint8List, Uint8List>> asyncRequest(FFIRequest request) { | 
					
						
							| 
									
										
										
										
											2021-07-08 13:47:11 +08:00
										 |  |  |     // 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; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-14 15:31:44 +08:00
										 |  |  | Future<Either<Uint8List, Uint8List>> _extractPayload(Future<Either<FFIResponse, FlowyInternalError>> responseFuture) { | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  |   return responseFuture.then((result) { | 
					
						
							|  |  |  |     return result.fold( | 
					
						
							|  |  |  |       (response) { | 
					
						
							| 
									
										
										
										
											2021-08-31 11:32:51 +08:00
										 |  |  |         switch (response.code) { | 
					
						
							|  |  |  |           case FFIStatusCode.Ok: | 
					
						
							|  |  |  |             return left(Uint8List.fromList(response.payload)); | 
					
						
							|  |  |  |           case FFIStatusCode.Err: | 
					
						
							|  |  |  |             return right(Uint8List.fromList(response.payload)); | 
					
						
							|  |  |  |           case FFIStatusCode.Internal: | 
					
						
							|  |  |  |             final error = utf8.decode(response.payload); | 
					
						
							|  |  |  |             Log.error("Dispatch internal error: $error"); | 
					
						
							|  |  |  |             return right(emptyBytes()); | 
					
						
							|  |  |  |           default: | 
					
						
							|  |  |  |             Log.error("Impossible to here"); | 
					
						
							|  |  |  |             return right(emptyBytes()); | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2021-08-30 16:18:58 +08:00
										 |  |  |       (error) { | 
					
						
							|  |  |  |         Log.error("Response should not be empty $error"); | 
					
						
							|  |  |  |         return right(emptyBytes()); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2021-07-08 13:47:11 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-14 15:31:44 +08:00
										 |  |  | Future<Either<FFIResponse, FlowyInternalError>> _extractResponse(Completer<Uint8List> bytesFuture) { | 
					
						
							| 
									
										
										
										
											2021-07-08 13:47:11 +08:00
										 |  |  |   return bytesFuture.future.then((bytes) { | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2021-07-08 13:47:11 +08:00
										 |  |  |       final response = FFIResponse.fromBuffer(bytes); | 
					
						
							|  |  |  |       return left(response); | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |     } catch (e, s) { | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  |       final error = StackTraceError(e, s); | 
					
						
							|  |  |  |       Log.error('Deserialize response failed. ${error.toString()}'); | 
					
						
							|  |  |  |       return right(error.asFlowyError()); | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-08 13:47:11 +08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-08 13:47:11 +08:00
										 |  |  | Completer<Uint8List> _sendToRust(FFIRequest request) { | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2021-12-04 10:27:08 +08:00
										 |  |  |   ffi.async_event(port.nativePort, input, bytes.length); | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |   calloc.free(input); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return completer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  | Uint8List requestToBytes<T extends GeneratedMessage>(T? message) { | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |   try { | 
					
						
							|  |  |  |     if (message != null) { | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  |       return message.writeToBuffer(); | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  |       return emptyBytes(); | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } catch (e, s) { | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  |     final error = StackTraceError(e, s); | 
					
						
							|  |  |  |     Log.error('Serial request failed. ${error.toString()}'); | 
					
						
							|  |  |  |     return emptyBytes(); | 
					
						
							| 
									
										
										
										
											2021-07-07 22:24:26 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-12 13:53:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Uint8List emptyBytes() { | 
					
						
							|  |  |  |   return Uint8List.fromList([]); | 
					
						
							|  |  |  | } |