adaptor.dart 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import 'dart:ffi';
  2. // ignore: import_of_legacy_library_into_null_safe
  3. import 'package:isolates/isolates.dart';
  4. // ignore: import_of_legacy_library_into_null_safe
  5. import 'package:isolates/ports.dart';
  6. import 'package:ffi/ffi.dart';
  7. import 'package:flowy_protobuf/model/grpc.pb.dart';
  8. import 'package:flutter/services.dart';
  9. import 'dart:async';
  10. import 'dart:typed_data';
  11. import 'package:flowy_sdk/ffi/ffi.dart' as ffi;
  12. enum FFIExceptionType {
  13. RequestPacketIsEmpty,
  14. InvalidResponseLength,
  15. ResponsePacketIsInvalid,
  16. }
  17. class FFIAdaptorException implements Exception {
  18. FFIExceptionType type;
  19. FFIAdaptorException(this.type);
  20. }
  21. class FFIAdaptor {
  22. static Completer<Uint8List> asyncRequest(RequestPacket request) {
  23. Uint8List bytes = request.writeToBuffer();
  24. assert(bytes.isEmpty == false);
  25. if (bytes.isEmpty) {
  26. throw FFIAdaptorException(FFIExceptionType.RequestPacketIsEmpty);
  27. }
  28. final Pointer<Uint8> input = calloc.allocate<Uint8>(bytes.length);
  29. final list = input.asTypedList(bytes.length);
  30. list.setAll(0, bytes);
  31. final completer = Completer<Uint8List>();
  32. final port = singleCompletePort(completer);
  33. ffi.async_command(port.nativePort, input, bytes.length);
  34. calloc.free(input);
  35. return completer;
  36. }
  37. static Completer<Uint8List> asyncQuery(RequestPacket request) {
  38. Uint8List bytes = request.writeToBuffer();
  39. assert(bytes.isEmpty == false);
  40. if (bytes.isEmpty) {
  41. throw FFIAdaptorException(FFIExceptionType.RequestPacketIsEmpty);
  42. }
  43. final Pointer<Uint8> input = calloc.allocate<Uint8>(bytes.length);
  44. final list = input.asTypedList(bytes.length);
  45. list.setAll(0, bytes);
  46. final completer = Completer<Uint8List>();
  47. final port = singleCompletePort(completer);
  48. ffi.async_query(port.nativePort, input, bytes.length);
  49. calloc.free(input);
  50. return completer;
  51. }
  52. //https://suragch.medium.com/working-with-bytes-in-dart-6ece83455721
  53. static FFISafeUint8Wrapper syncRequest(RequestPacket request) {
  54. Uint8List bytes;
  55. try {
  56. bytes = request.writeToBuffer();
  57. } catch (e, s) {
  58. //TODO nathan: upload the log
  59. print('Sync RequestPacket writeToBuffer error: ${e.runtimeType}');
  60. print('Stack trace \n $s');
  61. rethrow;
  62. }
  63. assert(bytes.isEmpty == false);
  64. if (bytes.isEmpty) {
  65. throw FFIAdaptorException(FFIExceptionType.RequestPacketIsEmpty);
  66. }
  67. final Pointer<Uint8> dartPtr = _pointerFromBytes(bytes);
  68. Pointer<Uint8> rustPtr = ffi.sync_command(dartPtr, bytes.length);
  69. calloc.free(dartPtr);
  70. FFISafeUint8Wrapper safeWrapper;
  71. try {
  72. safeWrapper = FFISafeUint8Wrapper(rustPtr);
  73. } catch (_) {
  74. rethrow;
  75. }
  76. return safeWrapper;
  77. }
  78. // inline?
  79. static Pointer<Uint8> _pointerFromBytes(Uint8List bytes) {
  80. final Pointer<Uint8> ptr = calloc.allocate<Uint8>(bytes.length);
  81. final list = ptr.asTypedList(bytes.length);
  82. list.setAll(0, bytes);
  83. return ptr;
  84. }
  85. }
  86. class FFISafeUint8Wrapper {
  87. Pointer<Uint8> _ptr;
  88. int _responseBytesLen = 0;
  89. int _markerBytesLen = 4;
  90. FFISafeUint8Wrapper(this._ptr) {
  91. try {
  92. this._responseBytesLen =
  93. ByteData.sublistView(_ptr.asTypedList(_markerBytesLen))
  94. .getUint32(0, Endian.big);
  95. } catch (_) {
  96. throw FFIAdaptorException(FFIExceptionType.RequestPacketIsEmpty);
  97. }
  98. if (this._responseBytesLen < _markerBytesLen) {
  99. throw FFIAdaptorException(FFIExceptionType.ResponsePacketIsInvalid);
  100. }
  101. }
  102. void destroy() {
  103. ffi.free_rust(_ptr, _responseBytesLen + _markerBytesLen);
  104. }
  105. Uint8List buffer() {
  106. Pointer<Uint8> respPtr = _ptr.elementAt(_markerBytesLen);
  107. return respPtr.asTypedList(_responseBytesLen);
  108. }
  109. }