Skip to content

Commit

Permalink
Merge pull request #2062 from fzyzcjy/feat/12203
Browse files Browse the repository at this point in the history
Refactor web-related logic
  • Loading branch information
fzyzcjy authored Jun 10, 2024
2 parents c4d277b + f9331ab commit 918a23c
Show file tree
Hide file tree
Showing 22 changed files with 333 additions and 319 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,4 @@ external RustLibWasmModule get wasmModule;

@JS()
@anonymous
class RustLibWasmModule implements WasmModule {
@override
external Object /* Promise */ call([String? moduleName]);

@override
external RustLibWasmModule bind(dynamic thisArg, String moduleName);
}
class RustLibWasmModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,7 @@ fn generate_wasm_module_class(
format!(
"@JS('wasm_bindgen') external {wasm_module_name} get wasmModule;
@JS() @anonymous class {wasm_module_name} implements WasmModule {{
@override
external Object /* Promise */ call([String? moduleName]);
@override
external {wasm_module_name} bind(dynamic thisArg, String moduleName);
@JS() @anonymous class {wasm_module_name} {{
{body}
}}
"
Expand Down
204 changes: 90 additions & 114 deletions frb_dart/lib/src/generalized_isolate/_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,174 +12,153 @@ import 'package:flutter_rust_bridge/src/platform_utils/_web.dart';
String serializeNativePort(NativePortType port) => port.name;

/// {@macro flutter_rust_bridge.only_for_generated_code}
typedef MessagePort = PortLike;

/// An alias to [MessagePort] on web platforms.
typedef SendPort = PortLike;
typedef MessagePort = _PortLike;

/// {@macro flutter_rust_bridge.only_for_generated_code}
abstract class Channel {
/// {@macro flutter_rust_bridge.only_for_generated_code}
SendPort get sendPort;

/// {@macro flutter_rust_bridge.only_for_generated_code}
SendPort get receivePort;

/// {@macro flutter_rust_bridge.only_for_generated_code}
const Channel();
typedef SendPort = _PortLike;

/// {@macro flutter_rust_bridge.only_for_generated_code}
factory Channel.messageChannel() = _MessageChannelWrapper;

/// {@macro flutter_rust_bridge.only_for_generated_code}
factory Channel.broadcastChannel(String channelName) =
_BroadcastChannelWrapper;
}
/// Web implementation of the `dart:isolate`'s ReceivePort.
class ReceivePort extends Stream<dynamic> {
/// The receive port.
final RawReceivePort _rawReceivePort;

class _MessageChannelWrapper implements Channel {
final channel = MessageChannel();
/// Create a new receive port from an optional [RawReceivePort].
factory ReceivePort() => ReceivePort._raw();

@override
SendPort get sendPort => PortLike.messagePort(channel.port2);
ReceivePort._raw([RawReceivePort? rawReceivePort])
: _rawReceivePort = rawReceivePort ?? RawReceivePort();

@override
SendPort get receivePort => PortLike.messagePort(channel.port1);
}

class _BroadcastChannelWrapper implements Channel {
final BroadcastChannel _sendChannel;
final BroadcastChannel _receiveChannel;
StreamSubscription listen(
void Function(dynamic event)? onData, {
Function? onError,
void Function()? onDone,
bool? cancelOnError,
}) {
return _rawReceivePort._receivePort.onMessage.map(_extractData).listen(
onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
}

_BroadcastChannelWrapper(String channelName)
// Note: It is *wrong* to reuse the same HTML BroadcastChannel object,
// because HTML BroadcastChannel spec says that, the event will not be fired
// at the object which sends it. Therefore, we need two different objects.
: _sendChannel = BroadcastChannel(channelName),
_receiveChannel = BroadcastChannel(channelName);
static dynamic _extractData(MessageEvent event) => event.data;

@override
SendPort get sendPort => PortLike.broadcastChannel(_sendChannel);
/// The send port.
SendPort get sendPort => _rawReceivePort.sendPort;

@override
SendPort get receivePort => PortLike.broadcastChannel(_receiveChannel);
/// Close the receive port, ignoring any further messages.
void close() => _rawReceivePort.close();
}

/// Wrapper around a [MessageChannel].
class RawReceivePort {
/// The underlying message channel.
final Channel channel;
final _Channel _channel;

/// {@macro flutter_rust_bridge.only_for_generated_code}
RawReceivePort([Channel? channel])
: channel = channel ?? Channel.messageChannel();
factory RawReceivePort() => RawReceivePort._raw();

RawReceivePort._raw([_Channel? channel])
: _channel = channel ?? _Channel.messageChannel();

set handler(Function(dynamic) handler) {
receivePort.onMessage.listen((event) => handler(event.data));
_receivePort.onMessage.listen((event) => handler(event.data));
}

/// Close the receive port.
void close() => channel.receivePort.close();
void close() => _channel.receivePort.close();

/// The port to be used by other workers.
SendPort get sendPort => channel.sendPort;
SendPort get sendPort => _channel.sendPort;

/// The port used to receive messages from other workers.
SendPort get receivePort => channel.receivePort;
SendPort get _receivePort => _channel.receivePort;
}

/// Web implementation of the `dart:isolate`'s ReceivePort.
class ReceivePort extends Stream<dynamic> {
/// The receive port.
final RawReceivePort port;
/// {@macro flutter_rust_bridge.internal}
ReceivePort broadcastPort(String channelName) => ReceivePort._raw(
RawReceivePort._raw(_Channel.broadcastChannel(channelName)));

static dynamic _extractData(MessageEvent event) => event.data;
abstract class _Channel {
SendPort get sendPort;

/// Create a new receive port from an optional [RawReceivePort].
ReceivePort([RawReceivePort? port]) : port = port ?? RawReceivePort();
SendPort get receivePort;

@override
StreamSubscription listen(
void Function(dynamic event)? onData, {
Function? onError,
void Function()? onDone,
bool? cancelOnError,
}) {
return port.receivePort.onMessage.map(_extractData).listen(
onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
}
const _Channel();

/// The send port.
SendPort get sendPort => port.sendPort;
factory _Channel.messageChannel() = _MessageChannelWrapper;

/// Close the receive port, ignoring any further messages.
void close() => port.receivePort.close();
factory _Channel.broadcastChannel(String channelName) =
_BroadcastChannelWrapper;
}

/// {@macro flutter_rust_bridge.internal}
ReceivePort broadcastPort(String channelName) =>
ReceivePort(RawReceivePort(Channel.broadcastChannel(channelName)));

/// [html.MessagePort]'s interface.
abstract class PortLike extends EventTarget {
/// {@macro flutter_rust_bridge.only_for_generated_code}
factory PortLike.messagePort(html.MessagePort port) = _MessagePortWrapper;
class _MessageChannelWrapper implements _Channel {
final channel = MessageChannel();

/// {@macro flutter_rust_bridge.only_for_generated_code}
factory PortLike.broadcastChannel(BroadcastChannel channel) =
_BroadcastPortWrapper;
@override
SendPort get sendPort => _PortLike.messagePort(channel.port2);

/// {@macro flutter_rust_bridge.only_for_generated_code}
void postMessage(Object? value);
@override
SendPort get receivePort => _PortLike.messagePort(channel.port1);
}

/// {@macro flutter_rust_bridge.only_for_generated_code}
void close();
class _BroadcastChannelWrapper implements _Channel {
final BroadcastChannel _sendChannel;
final BroadcastChannel _receiveChannel;

/// {@macro flutter_rust_bridge.only_for_generated_code}
NativePortType get nativePort;
}
_BroadcastChannelWrapper(String channelName)
// Note: It is *wrong* to reuse the same HTML BroadcastChannel object,
// because HTML BroadcastChannel spec says that, the event will not be fired
// at the object which sends it. Therefore, we need two different objects.
: _sendChannel = BroadcastChannel(channelName),
_receiveChannel = BroadcastChannel(channelName);

/// Delegates a subset of PortLike methods verbatim.
abstract class _DelegatedPort implements PortLike {
@override
void addEventListener(String type, html.EventListener? listener,
[bool? useCapture]) =>
nativePort.addEventListener(type, listener, useCapture);
SendPort get sendPort => _PortLike.broadcastChannel(_sendChannel);

@override
void removeEventListener(String type, html.EventListener? listener,
[bool? useCapture]) =>
nativePort.removeEventListener(type, listener, useCapture);
SendPort get receivePort => _PortLike.broadcastChannel(_receiveChannel);
}

@override
void close() => nativePort.close();
/// [html.MessagePort]'s interface.
abstract class _PortLike {
const _PortLike._();

@override
bool dispatchEvent(html.Event event) => nativePort.dispatchEvent(event);
factory _PortLike.messagePort(html.MessagePort port) = _MessagePortWrapper;

@override
html.Events get on => nativePort.on;
factory _PortLike.broadcastChannel(BroadcastChannel channel) =
_BroadcastPortWrapper;

void postMessage(Object? value);

void close();

html.EventTarget get nativePort;

Stream<MessageEvent> get onMessage => _kMessageEvent.forTarget(nativePort);
static const _kMessageEvent = EventStreamProvider<MessageEvent>('message');
}

class _MessagePortWrapper extends _DelegatedPort {
class _MessagePortWrapper extends _PortLike {
@override
final html.MessagePort nativePort;

_MessagePortWrapper(this.nativePort);
_MessagePortWrapper(this.nativePort) : super._();

@override
void postMessage(message, [List<Object>? transfer]) =>
nativePort.postMessage(message, transfer);

@override
void close() => nativePort.close();
}

class _BroadcastPortWrapper extends _DelegatedPort {
class _BroadcastPortWrapper extends _PortLike {
@override
final html.BroadcastChannel nativePort;

_BroadcastPortWrapper(this.nativePort);
_BroadcastPortWrapper(this.nativePort) : super._();

/// This presents a limitation of BroadcastChannel,
/// i.e. it cannot carry transferables and will unconditionally clone the items.
Expand All @@ -190,10 +169,7 @@ class _BroadcastPortWrapper extends _DelegatedPort {
}
nativePort.postMessage(message ?? false);
}
}

extension on PortLike {
static const messageEvent = EventStreamProvider<MessageEvent>('message');

Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
@override
void close() => nativePort.close();
}
7 changes: 2 additions & 5 deletions frb_dart/lib/src/loader/_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ FutureOr<ExternalLibrary> loadExternalLibrary(
/// Please see `loadExternalLibrary` for details
Future<ExternalLibrary> loadExternalLibraryRaw(
{required String moduleRoot}) async {
return ExternalLibrary(
wasmModule:
await WasmModule.initialize(kind: Modules.noModules(root: moduleRoot)),
debugInfo: 'moduleRoot=$moduleRoot',
);
await initializeWasmModule(root: moduleRoot);
return ExternalLibrary(debugInfo: 'moduleRoot=$moduleRoot');
}
5 changes: 1 addition & 4 deletions frb_dart/lib/src/platform_types/_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ typedef DartPostCObject = void;
/// {@macro flutter_rust_bridge.only_for_generated_code}
class ExternalLibrary extends BaseExternalLibrary {
/// {@macro flutter_rust_bridge.only_for_generated_code}
final Object wasmModule;

/// {@macro flutter_rust_bridge.only_for_generated_code}
const ExternalLibrary({required this.wasmModule, required super.debugInfo});
const ExternalLibrary({required super.debugInfo});
}

/// {@macro flutter_rust_bridge.internal}
Expand Down
Loading

0 comments on commit 918a23c

Please sign in to comment.