| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 | import 'dart:ffi';import 'package:dartz/dartz.dart';import 'package:flowy_sdk/log.dart';// ignore: unnecessary_importimport 'package:flowy_sdk/protobuf/dart-ffi/ffi_response.pb.dart';import 'package:flowy_sdk/protobuf/flowy-collaboration/document_info.pb.dart';import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';import 'package:flowy_sdk/protobuf/flowy-net/event.pb.dart';import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart';import 'package:flowy_sdk/protobuf/flowy-user/event_map.pb.dart';import 'package:flowy_sdk/protobuf/flowy-folder/event_map.pb.dart';import 'package:isolates/isolates.dart';import 'package:isolates/ports.dart';import 'package:ffi/ffi.dart';// ignore: unused_importimport 'package:flutter/services.dart';import 'dart:async';import 'dart:typed_data';import 'package:flowy_sdk/ffi.dart' as ffi;import 'package:flowy_sdk/protobuf/flowy-user-data-model/protobuf.dart';import 'package:flowy_sdk/protobuf/dart-ffi/protobuf.dart';import 'package:flowy_sdk/protobuf/flowy-folder-data-model/protobuf.dart';import 'package:flowy_sdk/protobuf/flowy-collaboration/protobuf.dart';// ignore: unused_importimport 'package:protobuf/protobuf.dart';import 'dart:convert' show utf8;import 'error.dart';part 'dart_event/flowy-folder/dart_event.dart';part 'dart_event/flowy-net/dart_event.dart';part 'dart_event/flowy-user/dart_event.dart';enum FFIException {  RequestIsEmpty,}class DispatchException implements Exception {  FFIException type;  DispatchException(this.type);}class Dispatch {  static Future<Either<Uint8List, Uint8List>> 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, Uint8List>> _extractPayload(Future<Either<FFIResponse, FlowyInternalError>> responseFuture) {  return responseFuture.then((result) {    return result.fold(      (response) {        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());        }      },      (error) {        Log.error("Response should not be empty $error");        return right(emptyBytes());      },    );  });}Future<Either<FFIResponse, FlowyInternalError>> _extractResponse(Completer<Uint8List> bytesFuture) {  return bytesFuture.future.then((bytes) {    try {      final response = FFIResponse.fromBuffer(bytes);      return left(response);    } catch (e, s) {      final error = StackTraceError(e, s);      Log.error('Deserialize response failed. ${error.toString()}');      return right(error.asFlowyError());    }  });}Completer<Uint8List> _sendToRust(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_event(port.nativePort, input, bytes.length);  calloc.free(input);  return completer;}Uint8List requestToBytes<T extends GeneratedMessage>(T? message) {  try {    if (message != null) {      return message.writeToBuffer();    } else {      return emptyBytes();    }  } catch (e, s) {    final error = StackTraceError(e, s);    Log.error('Serial request failed. ${error.toString()}');    return emptyBytes();  }}Uint8List emptyBytes() {  return Uint8List.fromList([]);}
 |