-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adding rid message channel (#27)
* rid-build: adding message channel - this message channel supports sending message from rust to dart and is built into the rid framework along with the following macros leveragint it - `rid:log_info`, `rid:log_debug`, `rid::log_warn` to send messages to be logged in Dart - `rid::error`, `rid::severe` to report errors to dart * tests: adding message channel integration tests * test: field_access no longer checking in Cargo.lock * rid: upgrading allo_isolate dep * rid-build: removing unused preamble property from yaml config * rid-build: including init isolate wrappers with expanded code * rid-build: re-exporting message channel types
- Loading branch information
Showing
26 changed files
with
561 additions
and
651 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import 'dart:async'; | ||
import 'dart:ffi'; | ||
import 'dart:isolate'; | ||
|
||
import '_isolate_binding.dart' show initIsolate; | ||
|
||
const String _MSG_SEPARATOR = '^'; | ||
|
||
enum RidMsgType { Severe, Error, LogWarn, LogInfo, LogDebug } | ||
|
||
RidMsgType _ridMsgTypeFromString(String s) { | ||
switch (s.toLowerCase()) { | ||
case "err_severe": | ||
return RidMsgType.Severe; | ||
case "err_error": | ||
return RidMsgType.Error; | ||
case "log_warn": | ||
return RidMsgType.LogWarn; | ||
case "log_info": | ||
return RidMsgType.LogInfo; | ||
case "log_debug": | ||
return RidMsgType.LogDebug; | ||
default: | ||
throw ArgumentError.value(s); | ||
} | ||
} | ||
|
||
final _REMOVE_QUOTE_RX = RegExp(r'(^"|"$)'); | ||
|
||
class RidMsg { | ||
final RidMsgType type; | ||
late final String message; | ||
late final String? details; | ||
|
||
RidMsg._(this.type, String message, String? details) { | ||
this.message = message.replaceAll(_REMOVE_QUOTE_RX, ''); | ||
this.details = details?.replaceAll(_REMOVE_QUOTE_RX, ''); | ||
} | ||
|
||
@override | ||
String toString() { | ||
final detailsString = details == null ? '' : ', details: "$details"'; | ||
return 'RidMsg{ type: $type, message: "$message"$detailsString }'; | ||
} | ||
|
||
@override | ||
bool operator ==(Object other) => | ||
identical(this, other) || | ||
other is RidMsg && | ||
runtimeType == other.runtimeType && | ||
type == other.type && | ||
message == other.message && | ||
details == other.details; | ||
|
||
@override | ||
int get hashCode => type.hashCode ^ message.hashCode ^ details.hashCode; | ||
} | ||
|
||
class RidMsgChannel { | ||
final _zone = Zone.current; | ||
final StreamController<RidMsg> _sink; | ||
final DynamicLibrary _dl; | ||
late final RawReceivePort _receivePort; | ||
late final _zonedAdd; | ||
|
||
RidMsgChannel._(this._dl, bool isDebugMode) | ||
: _sink = StreamController.broadcast() { | ||
_receivePort = | ||
RawReceivePort(_onReceivedMsg, 'rid::messaging_channel::port'); | ||
initIsolate(this._dl, 'rid_init_msg_isolate', | ||
_receivePort.sendPort.nativePort, isDebugMode); | ||
_zonedAdd = _zone.registerUnaryCallback(_add); | ||
} | ||
|
||
void _onReceivedMsg(String reply) { | ||
_zone.runUnary(_zonedAdd, reply); | ||
} | ||
|
||
void _add(String reply) { | ||
if (!_sink.isClosed) { | ||
_sink.add(_decode(reply)); | ||
} | ||
} | ||
|
||
RidMsg _decode(String data) { | ||
int sepIdx = data.indexOf(_MSG_SEPARATOR); | ||
final type = data.substring(0, sepIdx); | ||
final msgType = _ridMsgTypeFromString(type); | ||
|
||
final msg = data.substring(sepIdx + 1); | ||
sepIdx = msg.indexOf(_MSG_SEPARATOR); | ||
if (sepIdx < 0) { | ||
// No details | ||
return RidMsg._(msgType, msg, null); | ||
} else { | ||
final message = msg.substring(0, sepIdx); | ||
final details = msg.substring(sepIdx + 1); | ||
return RidMsg._(msgType, message, details); | ||
} | ||
} | ||
|
||
Stream<RidMsg> get stream => _sink.stream; | ||
|
||
int get nativePort { | ||
return _receivePort.sendPort.nativePort; | ||
} | ||
|
||
Future<void> dispose() { | ||
_receivePort.close(); | ||
return _sink.close(); | ||
} | ||
|
||
static bool _initialized = false; | ||
static RidMsgChannel instance( | ||
DynamicLibrary dl, | ||
bool isDebugMode, | ||
) { | ||
if (_initialized && !isDebugMode) { | ||
throw Exception( | ||
"The message channel can only be initialized once unless running in debug mode"); | ||
} | ||
_initialized = true; | ||
return RidMsgChannel._(dl, isDebugMode); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// Exporting Native Library to call Rust functions directly | ||
// | ||
final dart_ffi.DynamicLibrary _dl = _open(); | ||
|
||
// | ||
// Expose a rid instance which initializes and provides access to various features facilitating Dart/Rust interaction | ||
// | ||
class Rid { | ||
final RidMsgChannel _messageChannel; | ||
Rid._(dart_ffi.DynamicLibrary dl, bool isDebugMode) | ||
: _messageChannel = RidMsgChannel.instance(dl, isDebugMode); | ||
|
||
RidMsgChannel get messageChannel => _messageChannel; | ||
} | ||
|
||
final rid = Rid._(_dl, _isDebugMode); | ||
|
||
// Dart evaluates code lazily and won't initialize some parts in time for Rust to | ||
// properly use it. Therefore when rid_ffi is accessed we enforce initialization of everything | ||
// it might need like the message channel by forcing evaluation of the Rid constructor. | ||
ffigen_bind.NativeLibrary _initRidFFI() { | ||
// ignore: unnecessary_null_comparison | ||
if (rid == null) {} | ||
return ffigen_bind.NativeLibrary(_dl); | ||
} | ||
|
||
final rid_ffi = _initRidFFI(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.