mirror of
https://github.com/localsend/localsend.git
synced 2026-06-23 04:10:07 +00:00
refactor: encapsulate isolate container
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import 'package:common/model/device.dart';
|
||||
import 'package:common/src/discovery/http_scan_discovery.dart';
|
||||
import 'package:common/src/isolate/child/main.dart';
|
||||
import 'package:common/src/isolate/dto/isolate_task.dart';
|
||||
import 'package:common/src/isolate/dto/isolate_task_stream_result.dart';
|
||||
import 'package:common/src/isolate/dto/send_to_isolate_data.dart';
|
||||
import 'package:common/src/task/discovery/http_scan_discovery.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
sealed class HttpScanTask {}
|
||||
@@ -41,14 +41,14 @@ Future<void> setupHttpScanDiscoveryIsolate(
|
||||
receiveFromMain: receiveFromMain,
|
||||
sendToMain: sendToMain,
|
||||
initialData: initialData,
|
||||
handler: (task) async {
|
||||
handler: (ref, task) async {
|
||||
final stream = switch (task.data) {
|
||||
HttpInterfaceScanTask data => isolateContainer.read(httpScanDiscoveryProvider).getStream(
|
||||
HttpInterfaceScanTask data => ref.read(httpScanDiscoveryProvider).getStream(
|
||||
networkInterface: data.networkInterface,
|
||||
port: data.port,
|
||||
https: data.https,
|
||||
),
|
||||
HttpFavoriteScanTask data => isolateContainer.read(httpScanDiscoveryProvider).getFavoriteStream(
|
||||
HttpFavoriteScanTask data => ref.read(httpScanDiscoveryProvider).getFavoriteStream(
|
||||
devices: data.favorites,
|
||||
https: data.https,
|
||||
),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:common/model/device.dart';
|
||||
import 'package:common/src/discovery/http_target_discovery.dart';
|
||||
import 'package:common/src/isolate/child/main.dart';
|
||||
import 'package:common/src/isolate/dto/isolate_task.dart';
|
||||
import 'package:common/src/isolate/dto/isolate_task_result.dart';
|
||||
import 'package:common/src/isolate/dto/send_to_isolate_data.dart';
|
||||
import 'package:common/src/task/discovery/http_target_discovery.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
class HttpTargetTask {
|
||||
@@ -29,8 +29,8 @@ Future<void> setupHttpTargetDiscoveryIsolate(
|
||||
receiveFromMain: receiveFromMain,
|
||||
sendToMain: sendToMain,
|
||||
initialData: initialData,
|
||||
handler: (task) async {
|
||||
final device = await isolateContainer.read(httpTargetDiscoveryProvider).discover(
|
||||
handler: (ref, task) async {
|
||||
final device = await ref.read(httpTargetDiscoveryProvider).discover(
|
||||
ip: task.data.ip,
|
||||
port: task.data.port,
|
||||
https: task.data.https,
|
||||
|
||||
@@ -7,11 +7,11 @@ import 'package:logging/logging.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:refena/refena.dart';
|
||||
|
||||
@internal
|
||||
final isolateContainer = RefenaContainer();
|
||||
|
||||
final _logger = Logger('ChildIsolateMain');
|
||||
|
||||
/// The container for the child isolate.
|
||||
final _isolateContainer = RefenaContainer();
|
||||
|
||||
class InitialData {
|
||||
final SyncState syncState;
|
||||
final Level logLevel;
|
||||
@@ -26,6 +26,9 @@ class InitialData {
|
||||
/// constructing an endless running task that listens to [receiveFromMain]
|
||||
/// and calls [handler] for each message (usually calling [sendToMain] in the [handler]).
|
||||
///
|
||||
/// The provided [Ref]s in the [handler] and [init] functions are instance of the child isolate [RefenaContainer],
|
||||
/// therefore, they can be safely used to call providers in the task directory.
|
||||
///
|
||||
/// An optional [init] function can be provided to run before the endless loop.
|
||||
@internal
|
||||
Future<void> setupChildIsolateHelper<S, R>({
|
||||
@@ -33,12 +36,12 @@ Future<void> setupChildIsolateHelper<S, R>({
|
||||
required Stream<SendToIsolateData<S>> receiveFromMain,
|
||||
required void Function(R) sendToMain,
|
||||
required InitialData initialData,
|
||||
Future<void> Function()? init,
|
||||
required Future<void> Function(S data) handler,
|
||||
Future<void> Function(Ref ref)? init,
|
||||
required Future<void> Function(Ref ref, S data) handler,
|
||||
}) async {
|
||||
initLogger(initialData.logLevel);
|
||||
|
||||
isolateContainer.set(
|
||||
_isolateContainer.set(
|
||||
syncProvider.overrideWithNotifier(
|
||||
(ref) => SyncService(
|
||||
initial: initialData.syncState,
|
||||
@@ -47,7 +50,7 @@ Future<void> setupChildIsolateHelper<S, R>({
|
||||
);
|
||||
|
||||
if (init != null) {
|
||||
await init();
|
||||
await init(_isolateContainer);
|
||||
}
|
||||
|
||||
_logger.info('Child isolate is ready: $debugLabel (logLevel: ${initialData.logLevel})');
|
||||
@@ -58,16 +61,16 @@ Future<void> setupChildIsolateHelper<S, R>({
|
||||
}
|
||||
|
||||
// separate function to avoid blocking the for loop
|
||||
void _handleMessage<S>(String debugLabel, SendToIsolateData<S> message, Future<void> Function(S data) handler) async {
|
||||
void _handleMessage<S>(String debugLabel, SendToIsolateData<S> message, Future<void> Function(Ref ref, S data) handler) async {
|
||||
final syncState = message.syncState;
|
||||
if (syncState != null) {
|
||||
isolateContainer.redux(syncProvider).dispatch(UpdateSyncStateAction(syncState));
|
||||
_isolateContainer.redux(syncProvider).dispatch(UpdateSyncStateAction(syncState));
|
||||
}
|
||||
|
||||
final data = message.data;
|
||||
if (data != null) {
|
||||
try {
|
||||
await handler(data);
|
||||
await handler(_isolateContainer, data);
|
||||
} catch (e) {
|
||||
_logger.severe('Error in $debugLabel: $e', e);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import 'package:common/model/device.dart';
|
||||
import 'package:common/src/discovery/multicast_discovery.dart';
|
||||
import 'package:common/src/isolate/child/main.dart';
|
||||
import 'package:common/src/isolate/dto/send_to_isolate_data.dart';
|
||||
import 'package:common/src/task/discovery/multicast_discovery.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Sends an announcement to all devices to all network interfaces.
|
||||
/// They will respond with their device information.
|
||||
///
|
||||
/// This is not wrapped in an [IsolateTask] because
|
||||
/// - (1) it is not important if the device was found by this specific announcement or another one
|
||||
/// - (2) it is not 100% accurate to know if a device was found by this announcement or another one
|
||||
class MulticastAnnouncementTask {
|
||||
static const instance = MulticastAnnouncementTask._();
|
||||
|
||||
@@ -23,13 +27,13 @@ Future<void> setupMulticastDiscoveryIsolate(
|
||||
receiveFromMain: receiveFromMain,
|
||||
sendToMain: sendToMain,
|
||||
initialData: initialData,
|
||||
init: () async {
|
||||
isolateContainer.read(multicastDiscoveryProvider).startListener().listen((event) {
|
||||
init: (ref) async {
|
||||
ref.read(multicastDiscoveryProvider).startListener().listen((event) {
|
||||
sendToMain(event);
|
||||
});
|
||||
},
|
||||
handler: (_) async {
|
||||
await isolateContainer.read(multicastDiscoveryProvider).sendAnnouncement();
|
||||
handler: (ref, task) async {
|
||||
await ref.read(multicastDiscoveryProvider).sendAnnouncement();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import 'package:common/src/isolate/dto/isolate_task_result.dart';
|
||||
import 'package:common/src/isolate/dto/isolate_task_stream_result.dart';
|
||||
|
||||
/// A data structure that can be sent to an isolate.
|
||||
/// This is used to represent the following schemas:
|
||||
///
|
||||
/// Main sends an [IsolateTask] -> Isolate responds with an [IsolateTaskResult]
|
||||
/// Main sends an [IsolateTask] -> Isolate responds with an [IsolateTaskStreamResult]
|
||||
///
|
||||
/// Generally speaking, we need an exact request-response pair.
|
||||
class IsolateTask<T> {
|
||||
/// The id of the task to be matched with [IsolateTaskResult.id] or [IsolateTaskStreamResult.id].
|
||||
final int id;
|
||||
|
||||
/// The payload of the request.
|
||||
final T data;
|
||||
|
||||
IsolateTask({
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import 'package:common/src/isolate/dto/isolate_task.dart';
|
||||
|
||||
/// The response data structure from an [IsolateTask].
|
||||
class IsolateTaskResult<T> {
|
||||
/// The id of the task to be matched with [IsolateTask.id].
|
||||
final int id;
|
||||
|
||||
/// The payload of the response.
|
||||
final T data;
|
||||
|
||||
IsolateTaskResult({
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'package:common/src/isolate/dto/isolate_task.dart';
|
||||
import 'package:common/src/isolate/dto/isolate_task_result.dart';
|
||||
|
||||
/// Stream version of [IsolateTaskResult].
|
||||
class IsolateTaskStreamResult<T> {
|
||||
/// The id of the task.
|
||||
/// Corresponds to [IsolateTask.id] that started the stream.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
All files in this directory should only call utility functions.
|
||||
|
||||
Isolate logic is prohibited in this directory.
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import 'package:common/model/device.dart';
|
||||
import 'package:common/src/discovery/http_target_discovery.dart';
|
||||
import 'package:common/src/task/discovery/http_target_discovery.dart';
|
||||
import 'package:common/util/task_runner.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:refena/refena.dart';
|
||||
Reference in New Issue
Block a user