From 42b211772521f913e992c2120f54ab8d4e82de4e Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Fri, 9 Feb 2024 17:42:57 +0100 Subject: [PATCH] refactor: move security context to common, more common models --- app/lib/provider/dio_provider.dart | 2 +- app/lib/provider/persistence_provider.dart | 1 - app/lib/provider/security_provider.dart | 2 +- app/lib/util/security_helper.dart | 2 +- app/pubspec.lock | 8 +- app/pubspec.yaml | 2 +- app/test/mocks.mocks.dart | 10 +- common/build.yaml | 10 + common/lib/common.dart | 1 + common/lib/src/isolate_manager.dart | 61 ++++++ .../src/model/state/isolate_common_state.dart | 14 ++ .../state/isolate_common_state.mapper.dart | 126 +++++++++++++ .../model/state/isolate_managed_state.dart | 16 ++ .../state/isolate_managed_state.mapper.dart | 139 ++++++++++++++ .../model/state/isolate_manager_state.dart | 25 +++ .../state/isolate_manager_state.mapper.dart | 175 ++++++++++++++++++ common/lib/src/model/state/isolate_state.dart | 33 ++++ .../src/model/state/isolate_state.mapper.dart | 123 ++++++++++++ .../lib/src/model/state/isolate_sync_dto.dart | 16 ++ .../model/state/isolate_sync_dto.mapper.dart | 141 ++++++++++++++ .../src/model}/stored_security_context.dart | 0 .../stored_security_context.mapper.dart | 0 common/lib/src/util/id_provider.dart | 10 + common/lib/src/util/isolate_helper.dart | 18 +- common/pubspec.yaml | 4 +- 25 files changed, 916 insertions(+), 23 deletions(-) create mode 100644 common/build.yaml create mode 100644 common/lib/src/isolate_manager.dart create mode 100644 common/lib/src/model/state/isolate_common_state.dart create mode 100644 common/lib/src/model/state/isolate_common_state.mapper.dart create mode 100644 common/lib/src/model/state/isolate_managed_state.dart create mode 100644 common/lib/src/model/state/isolate_managed_state.mapper.dart create mode 100644 common/lib/src/model/state/isolate_manager_state.dart create mode 100644 common/lib/src/model/state/isolate_manager_state.mapper.dart create mode 100644 common/lib/src/model/state/isolate_state.dart create mode 100644 common/lib/src/model/state/isolate_state.mapper.dart create mode 100644 common/lib/src/model/state/isolate_sync_dto.dart create mode 100644 common/lib/src/model/state/isolate_sync_dto.mapper.dart rename {app/lib/model/persistence => common/lib/src/model}/stored_security_context.dart (100%) rename {app/lib/model/persistence => common/lib/src/model}/stored_security_context.mapper.dart (100%) create mode 100644 common/lib/src/util/id_provider.dart diff --git a/app/lib/provider/dio_provider.dart b/app/lib/provider/dio_provider.dart index c2ef79be..fa4bab2b 100644 --- a/app/lib/provider/dio_provider.dart +++ b/app/lib/provider/dio_provider.dart @@ -1,8 +1,8 @@ import 'dart:io'; +import 'package:common/common.dart'; import 'package:dio/dio.dart'; import 'package:dio/io.dart'; -import 'package:localsend_app/model/persistence/stored_security_context.dart'; import 'package:localsend_app/provider/logging/http_logs_provider.dart'; import 'package:localsend_app/provider/security_provider.dart'; import 'package:refena_flutter/refena_flutter.dart'; diff --git a/app/lib/provider/persistence_provider.dart b/app/lib/provider/persistence_provider.dart index 490e6bfe..0009a6c9 100644 --- a/app/lib/provider/persistence_provider.dart +++ b/app/lib/provider/persistence_provider.dart @@ -8,7 +8,6 @@ import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/model/persistence/color_mode.dart'; import 'package:localsend_app/model/persistence/favorite_device.dart'; import 'package:localsend_app/model/persistence/receive_history_entry.dart'; -import 'package:localsend_app/model/persistence/stored_security_context.dart'; import 'package:localsend_app/model/send_mode.dart'; import 'package:localsend_app/provider/window_dimensions_provider.dart'; import 'package:localsend_app/util/alias_generator.dart'; diff --git a/app/lib/provider/security_provider.dart b/app/lib/provider/security_provider.dart index 95b45f7c..744b65cd 100644 --- a/app/lib/provider/security_provider.dart +++ b/app/lib/provider/security_provider.dart @@ -1,4 +1,4 @@ -import 'package:localsend_app/model/persistence/stored_security_context.dart'; +import 'package:common/common.dart'; import 'package:localsend_app/provider/persistence_provider.dart'; import 'package:localsend_app/util/security_helper.dart'; import 'package:refena_flutter/refena_flutter.dart'; diff --git a/app/lib/util/security_helper.dart b/app/lib/util/security_helper.dart index 6c6a6aeb..257512e0 100644 --- a/app/lib/util/security_helper.dart +++ b/app/lib/util/security_helper.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:basic_utils/basic_utils.dart'; -import 'package:localsend_app/model/persistence/stored_security_context.dart'; +import 'package:common/common.dart'; /// Generates a random [SecurityContextResult]. StoredSecurityContext generateSecurityContext([AsymmetricKeyPair? keyPair]) { diff --git a/app/pubspec.lock b/app/pubspec.lock index 3bbaa15f..f6abf4a0 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1145,18 +1145,18 @@ packages: dependency: transitive description: name: refena - sha256: dad98c0d372617054a86b33a504fb973ba083c21b7a2b321a4b2142fae3342a2 + sha256: a29603854d785e5259c6fb99268847e918f54463a861accc36cc913daea95cb8 url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.6.1" refena_flutter: dependency: "direct main" description: name: refena_flutter - sha256: fcd8e28e50515182a40abc2718600bbac11ba4757c2b2b92b71177fbc2ee9721 + sha256: "2bee85271c8d8ced0238d98c1c056dbabfd4af207f9cc248d10af5a37820ae3e" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.6.0" refena_inspector: dependency: "direct dev" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index cb9b6e46..bed26647 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -45,7 +45,7 @@ dependencies: path_provider: 2.1.1 permission_handler: 11.0.1 pretty_qr_code: 3.0.0 - refena_flutter: 1.5.0 + refena_flutter: 1.6.0 refena_inspector_client: 1.2.0 routerino: 0.8.0 screen_retriever: 0.1.9 diff --git a/app/test/mocks.mocks.dart b/app/test/mocks.mocks.dart index 14d5b5ff..52a82b0f 100644 --- a/app/test/mocks.mocks.dart +++ b/app/test/mocks.mocks.dart @@ -6,20 +6,18 @@ import 'dart:async' as _i4; import 'dart:ui' as _i12; -import 'package:common/common.dart' as _i13; +import 'package:common/common.dart' as _i2; import 'package:flutter/material.dart' as _i8; import 'package:localsend_app/gen/strings.g.dart' as _i10; import 'package:localsend_app/model/persistence/color_mode.dart' as _i9; import 'package:localsend_app/model/persistence/favorite_device.dart' as _i6; import 'package:localsend_app/model/persistence/receive_history_entry.dart' as _i5; -import 'package:localsend_app/model/persistence/stored_security_context.dart' - as _i2; import 'package:localsend_app/model/send_mode.dart' as _i11; import 'package:localsend_app/provider/persistence_provider.dart' as _i3; import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/src/dummies.dart' as _i7; -import 'package:shared_preferences/shared_preferences.dart' as _i14; +import 'package:shared_preferences/shared_preferences.dart' as _i13; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -589,7 +587,7 @@ class MockPersistenceService extends _i1.Mock ) as bool); @override - _i4.Future setDeviceType(_i13.DeviceType? deviceType) => + _i4.Future setDeviceType(_i2.DeviceType? deviceType) => (super.noSuchMethod( Invocation.method( #setDeviceType, @@ -623,7 +621,7 @@ class MockPersistenceService extends _i1.Mock /// A class which mocks [SharedPreferences]. /// /// See the documentation for Mockito's code generation for more information. -class MockSharedPreferences extends _i1.Mock implements _i14.SharedPreferences { +class MockSharedPreferences extends _i1.Mock implements _i13.SharedPreferences { @override Set getKeys() => (super.noSuchMethod( Invocation.method( diff --git a/common/build.yaml b/common/build.yaml new file mode 100644 index 00000000..e939605e --- /dev/null +++ b/common/build.yaml @@ -0,0 +1,10 @@ +targets: + $default: + builders: + dart_mappable_builder: + options: + renameMethods: + fromJson: deserialize + toJson: serialize + fromMap: fromJson + toMap: toJson diff --git a/common/lib/common.dart b/common/lib/common.dart index fbb8fc0d..dc86cf62 100644 --- a/common/lib/common.dart +++ b/common/lib/common.dart @@ -11,3 +11,4 @@ export 'package:common/src/model/dto/register_dto.dart'; export 'package:common/src/model/file_status.dart'; export 'package:common/src/model/file_type.dart'; export 'package:common/src/model/session_status.dart'; +export 'package:common/src/model/stored_security_context.dart'; diff --git a/common/lib/src/isolate_manager.dart b/common/lib/src/isolate_manager.dart new file mode 100644 index 00000000..b11ffe97 --- /dev/null +++ b/common/lib/src/isolate_manager.dart @@ -0,0 +1,61 @@ +import 'package:common/src/model/state/isolate_common_state.dart'; +import 'package:common/src/model/state/isolate_managed_state.dart'; +import 'package:common/src/model/state/isolate_manager_state.dart'; +import 'package:common/src/model/state/isolate_state.dart'; +import 'package:common/src/model/state/isolate_sync_dto.dart'; +import 'package:common/src/util/id_provider.dart'; +import 'package:common/src/util/isolate_helper.dart'; +import 'package:refena/refena.dart'; + +final _idProvider = IdProvider(); + +final isolateManagerProvider = ReduxProvider((ref) { + return IsolateManager(); +}); + +class IsolateManager extends ReduxNotifier { + @override + IsolateManagerState init() => IsolateManagerState( + commonState: IsolateCommonState( + securityContext: null, + ), + isolateStates: {}, + currentIsolateState: null, + ); +} + +/// Starts the required isolates. +/// Should be called by the main isolate. +class IsolateSetupAction extends AsyncReduxAction { + @override + Future reduce() async { + final communication = await startIsolate(task: _task); + final isolateId = _idProvider.getNextId(); + return state.copyWith( + isolateStates: { + isolateId: IsolateManagedState( + communication: communication, + isolateState: IsolateState( + isolateId: isolateId, + isolateType: IsolateType.multicast, + ), + ), + }, + ); + } +} + +Future _task( + Stream receiveFromMain, + void Function(Object) sendToMain, + IsolateSyncDto? initialData, +) async { + +} + +// class _IsolateSetupWorkerAction extends ReduxAction { +// @override +// IsolateManagerState reduce() { +// return state; +// } +// } diff --git a/common/lib/src/model/state/isolate_common_state.dart b/common/lib/src/model/state/isolate_common_state.dart new file mode 100644 index 00000000..69792ab4 --- /dev/null +++ b/common/lib/src/model/state/isolate_common_state.dart @@ -0,0 +1,14 @@ +import 'package:common/src/model/stored_security_context.dart'; +import 'package:dart_mappable/dart_mappable.dart'; + +part 'isolate_common_state.mapper.dart'; + +/// The state that is synced across all isolates. +@MappableClass() +class IsolateCommonState with IsolateCommonStateMappable { + final StoredSecurityContext? securityContext; + + const IsolateCommonState({ + required this.securityContext, + }); +} diff --git a/common/lib/src/model/state/isolate_common_state.mapper.dart b/common/lib/src/model/state/isolate_common_state.mapper.dart new file mode 100644 index 00000000..49b885b6 --- /dev/null +++ b/common/lib/src/model/state/isolate_common_state.mapper.dart @@ -0,0 +1,126 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'isolate_common_state.dart'; + +class IsolateCommonStateMapper extends ClassMapperBase { + IsolateCommonStateMapper._(); + + static IsolateCommonStateMapper? _instance; + static IsolateCommonStateMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = IsolateCommonStateMapper._()); + StoredSecurityContextMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'IsolateCommonState'; + + static StoredSecurityContext? _$securityContext(IsolateCommonState v) => + v.securityContext; + static const Field + _f$securityContext = Field('securityContext', _$securityContext); + + @override + final Map> fields = const { + #securityContext: _f$securityContext, + }; + + static IsolateCommonState _instantiate(DecodingData data) { + return IsolateCommonState(securityContext: data.dec(_f$securityContext)); + } + + @override + final Function instantiate = _instantiate; + + static IsolateCommonState fromJson(Map map) { + return ensureInitialized().decodeMap(map); + } + + static IsolateCommonState deserialize(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin IsolateCommonStateMappable { + String serialize() { + return IsolateCommonStateMapper.ensureInitialized() + .encodeJson(this as IsolateCommonState); + } + + Map toJson() { + return IsolateCommonStateMapper.ensureInitialized() + .encodeMap(this as IsolateCommonState); + } + + IsolateCommonStateCopyWith + get copyWith => _IsolateCommonStateCopyWithImpl( + this as IsolateCommonState, $identity, $identity); + @override + String toString() { + return IsolateCommonStateMapper.ensureInitialized() + .stringifyValue(this as IsolateCommonState); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (runtimeType == other.runtimeType && + IsolateCommonStateMapper.ensureInitialized() + .isValueEqual(this as IsolateCommonState, other)); + } + + @override + int get hashCode { + return IsolateCommonStateMapper.ensureInitialized() + .hashValue(this as IsolateCommonState); + } +} + +extension IsolateCommonStateValueCopy<$R, $Out> + on ObjectCopyWith<$R, IsolateCommonState, $Out> { + IsolateCommonStateCopyWith<$R, IsolateCommonState, $Out> + get $asIsolateCommonState => + $base.as((v, t, t2) => _IsolateCommonStateCopyWithImpl(v, t, t2)); +} + +abstract class IsolateCommonStateCopyWith<$R, $In extends IsolateCommonState, + $Out> implements ClassCopyWith<$R, $In, $Out> { + StoredSecurityContextCopyWith<$R, StoredSecurityContext, + StoredSecurityContext>? get securityContext; + $R call({StoredSecurityContext? securityContext}); + IsolateCommonStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _IsolateCommonStateCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, IsolateCommonState, $Out> + implements IsolateCommonStateCopyWith<$R, IsolateCommonState, $Out> { + _IsolateCommonStateCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + IsolateCommonStateMapper.ensureInitialized(); + @override + StoredSecurityContextCopyWith<$R, StoredSecurityContext, + StoredSecurityContext>? + get securityContext => $value.securityContext?.copyWith + .$chain((v) => call(securityContext: v)); + @override + $R call({Object? securityContext = $none}) => $apply(FieldCopyWithData( + {if (securityContext != $none) #securityContext: securityContext})); + @override + IsolateCommonState $make(CopyWithData data) => IsolateCommonState( + securityContext: data.get(#securityContext, or: $value.securityContext)); + + @override + IsolateCommonStateCopyWith<$R2, IsolateCommonState, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _IsolateCommonStateCopyWithImpl($value, $cast, t); +} diff --git a/common/lib/src/model/state/isolate_managed_state.dart b/common/lib/src/model/state/isolate_managed_state.dart new file mode 100644 index 00000000..444acdb0 --- /dev/null +++ b/common/lib/src/model/state/isolate_managed_state.dart @@ -0,0 +1,16 @@ +import 'package:common/src/model/state/isolate_state.dart'; +import 'package:common/src/util/isolate_helper.dart'; +import 'package:dart_mappable/dart_mappable.dart'; + +part 'isolate_managed_state.mapper.dart'; + +@MappableClass() +class IsolateManagedState with IsolateManagedStateMappable { + final IsolateCommunication communication; + final IsolateState isolateState; + + const IsolateManagedState({ + required this.communication, + required this.isolateState, + }); +} diff --git a/common/lib/src/model/state/isolate_managed_state.mapper.dart b/common/lib/src/model/state/isolate_managed_state.mapper.dart new file mode 100644 index 00000000..94a4fa55 --- /dev/null +++ b/common/lib/src/model/state/isolate_managed_state.mapper.dart @@ -0,0 +1,139 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'isolate_managed_state.dart'; + +class IsolateManagedStateMapper extends ClassMapperBase { + IsolateManagedStateMapper._(); + + static IsolateManagedStateMapper? _instance; + static IsolateManagedStateMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = IsolateManagedStateMapper._()); + IsolateStateMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'IsolateManagedState'; + + static IsolateCommunication _$communication( + IsolateManagedState v) => + v.communication; + static const Field> _f$communication = + Field('communication', _$communication); + static IsolateState _$isolateState(IsolateManagedState v) => v.isolateState; + static const Field _f$isolateState = + Field('isolateState', _$isolateState); + + @override + final Map> fields = const { + #communication: _f$communication, + #isolateState: _f$isolateState, + }; + + static IsolateManagedState _instantiate(DecodingData data) { + return IsolateManagedState( + communication: data.dec(_f$communication), + isolateState: data.dec(_f$isolateState)); + } + + @override + final Function instantiate = _instantiate; + + static IsolateManagedState fromJson(Map map) { + return ensureInitialized().decodeMap(map); + } + + static IsolateManagedState deserialize(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin IsolateManagedStateMappable { + String serialize() { + return IsolateManagedStateMapper.ensureInitialized() + .encodeJson(this as IsolateManagedState); + } + + Map toJson() { + return IsolateManagedStateMapper.ensureInitialized() + .encodeMap(this as IsolateManagedState); + } + + IsolateManagedStateCopyWith + get copyWith => _IsolateManagedStateCopyWithImpl( + this as IsolateManagedState, $identity, $identity); + @override + String toString() { + return IsolateManagedStateMapper.ensureInitialized() + .stringifyValue(this as IsolateManagedState); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (runtimeType == other.runtimeType && + IsolateManagedStateMapper.ensureInitialized() + .isValueEqual(this as IsolateManagedState, other)); + } + + @override + int get hashCode { + return IsolateManagedStateMapper.ensureInitialized() + .hashValue(this as IsolateManagedState); + } +} + +extension IsolateManagedStateValueCopy<$R, $Out> + on ObjectCopyWith<$R, IsolateManagedState, $Out> { + IsolateManagedStateCopyWith<$R, IsolateManagedState, $Out> + get $asIsolateManagedState => + $base.as((v, t, t2) => _IsolateManagedStateCopyWithImpl(v, t, t2)); +} + +abstract class IsolateManagedStateCopyWith<$R, $In extends IsolateManagedState, + $Out> implements ClassCopyWith<$R, $In, $Out> { + IsolateStateCopyWith<$R, IsolateState, IsolateState> get isolateState; + $R call( + {IsolateCommunication? communication, + IsolateState? isolateState}); + IsolateManagedStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _IsolateManagedStateCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, IsolateManagedState, $Out> + implements IsolateManagedStateCopyWith<$R, IsolateManagedState, $Out> { + _IsolateManagedStateCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + IsolateManagedStateMapper.ensureInitialized(); + @override + IsolateStateCopyWith<$R, IsolateState, IsolateState> get isolateState => + $value.isolateState.copyWith.$chain((v) => call(isolateState: v)); + @override + $R call( + {IsolateCommunication? communication, + IsolateState? isolateState}) => + $apply(FieldCopyWithData({ + if (communication != null) #communication: communication, + if (isolateState != null) #isolateState: isolateState + })); + @override + IsolateManagedState $make(CopyWithData data) => IsolateManagedState( + communication: data.get(#communication, or: $value.communication), + isolateState: data.get(#isolateState, or: $value.isolateState)); + + @override + IsolateManagedStateCopyWith<$R2, IsolateManagedState, $Out2> + $chain<$R2, $Out2>(Then<$Out2, $R2> t) => + _IsolateManagedStateCopyWithImpl($value, $cast, t); +} diff --git a/common/lib/src/model/state/isolate_manager_state.dart b/common/lib/src/model/state/isolate_manager_state.dart new file mode 100644 index 00000000..a1cfdcaf --- /dev/null +++ b/common/lib/src/model/state/isolate_manager_state.dart @@ -0,0 +1,25 @@ +import 'package:common/src/model/state/isolate_common_state.dart'; +import 'package:common/src/model/state/isolate_managed_state.dart'; +import 'package:common/src/model/state/isolate_state.dart'; +import 'package:dart_mappable/dart_mappable.dart'; + +part 'isolate_manager_state.mapper.dart'; + +@MappableClass() +class IsolateManagerState with IsolateManagerStateMappable { + final IsolateCommonState commonState; + + /// Isolate Id -> Isolate State + /// Non-empty if the current isolate is the main isolate. + final Map isolateStates; + + /// The current isolate state. + /// Only non-null if the current isolate is not the main isolate. + final IsolateState? currentIsolateState; + + const IsolateManagerState({ + required this.commonState, + required this.isolateStates, + required this.currentIsolateState, + }); +} diff --git a/common/lib/src/model/state/isolate_manager_state.mapper.dart b/common/lib/src/model/state/isolate_manager_state.mapper.dart new file mode 100644 index 00000000..1b7fc641 --- /dev/null +++ b/common/lib/src/model/state/isolate_manager_state.mapper.dart @@ -0,0 +1,175 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'isolate_manager_state.dart'; + +class IsolateManagerStateMapper extends ClassMapperBase { + IsolateManagerStateMapper._(); + + static IsolateManagerStateMapper? _instance; + static IsolateManagerStateMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = IsolateManagerStateMapper._()); + IsolateCommonStateMapper.ensureInitialized(); + IsolateManagedStateMapper.ensureInitialized(); + IsolateStateMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'IsolateManagerState'; + + static IsolateCommonState _$commonState(IsolateManagerState v) => + v.commonState; + static const Field _f$commonState = + Field('commonState', _$commonState); + static Map _$isolateStates(IsolateManagerState v) => + v.isolateStates; + static const Field> + _f$isolateStates = Field('isolateStates', _$isolateStates); + static IsolateState? _$currentIsolateState(IsolateManagerState v) => + v.currentIsolateState; + static const Field _f$currentIsolateState = + Field('currentIsolateState', _$currentIsolateState); + + @override + final Map> fields = const { + #commonState: _f$commonState, + #isolateStates: _f$isolateStates, + #currentIsolateState: _f$currentIsolateState, + }; + + static IsolateManagerState _instantiate(DecodingData data) { + return IsolateManagerState( + commonState: data.dec(_f$commonState), + isolateStates: data.dec(_f$isolateStates), + currentIsolateState: data.dec(_f$currentIsolateState)); + } + + @override + final Function instantiate = _instantiate; + + static IsolateManagerState fromJson(Map map) { + return ensureInitialized().decodeMap(map); + } + + static IsolateManagerState deserialize(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin IsolateManagerStateMappable { + String serialize() { + return IsolateManagerStateMapper.ensureInitialized() + .encodeJson(this as IsolateManagerState); + } + + Map toJson() { + return IsolateManagerStateMapper.ensureInitialized() + .encodeMap(this as IsolateManagerState); + } + + IsolateManagerStateCopyWith + get copyWith => _IsolateManagerStateCopyWithImpl( + this as IsolateManagerState, $identity, $identity); + @override + String toString() { + return IsolateManagerStateMapper.ensureInitialized() + .stringifyValue(this as IsolateManagerState); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (runtimeType == other.runtimeType && + IsolateManagerStateMapper.ensureInitialized() + .isValueEqual(this as IsolateManagerState, other)); + } + + @override + int get hashCode { + return IsolateManagerStateMapper.ensureInitialized() + .hashValue(this as IsolateManagerState); + } +} + +extension IsolateManagerStateValueCopy<$R, $Out> + on ObjectCopyWith<$R, IsolateManagerState, $Out> { + IsolateManagerStateCopyWith<$R, IsolateManagerState, $Out> + get $asIsolateManagerState => + $base.as((v, t, t2) => _IsolateManagerStateCopyWithImpl(v, t, t2)); +} + +abstract class IsolateManagerStateCopyWith<$R, $In extends IsolateManagerState, + $Out> implements ClassCopyWith<$R, $In, $Out> { + IsolateCommonStateCopyWith<$R, IsolateCommonState, IsolateCommonState> + get commonState; + MapCopyWith< + $R, + int, + IsolateManagedState, + IsolateManagedStateCopyWith<$R, IsolateManagedState, + IsolateManagedState>> get isolateStates; + IsolateStateCopyWith<$R, IsolateState, IsolateState>? get currentIsolateState; + $R call( + {IsolateCommonState? commonState, + Map? isolateStates, + IsolateState? currentIsolateState}); + IsolateManagerStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _IsolateManagerStateCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, IsolateManagerState, $Out> + implements IsolateManagerStateCopyWith<$R, IsolateManagerState, $Out> { + _IsolateManagerStateCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + IsolateManagerStateMapper.ensureInitialized(); + @override + IsolateCommonStateCopyWith<$R, IsolateCommonState, IsolateCommonState> + get commonState => + $value.commonState.copyWith.$chain((v) => call(commonState: v)); + @override + MapCopyWith< + $R, + int, + IsolateManagedState, + IsolateManagedStateCopyWith<$R, IsolateManagedState, + IsolateManagedState>> get isolateStates => MapCopyWith( + $value.isolateStates, + (v, t) => v.copyWith.$chain(t), + (v) => call(isolateStates: v)); + @override + IsolateStateCopyWith<$R, IsolateState, IsolateState>? + get currentIsolateState => $value.currentIsolateState?.copyWith + .$chain((v) => call(currentIsolateState: v)); + @override + $R call( + {IsolateCommonState? commonState, + Map? isolateStates, + Object? currentIsolateState = $none}) => + $apply(FieldCopyWithData({ + if (commonState != null) #commonState: commonState, + if (isolateStates != null) #isolateStates: isolateStates, + if (currentIsolateState != $none) + #currentIsolateState: currentIsolateState + })); + @override + IsolateManagerState $make(CopyWithData data) => IsolateManagerState( + commonState: data.get(#commonState, or: $value.commonState), + isolateStates: data.get(#isolateStates, or: $value.isolateStates), + currentIsolateState: + data.get(#currentIsolateState, or: $value.currentIsolateState)); + + @override + IsolateManagerStateCopyWith<$R2, IsolateManagerState, $Out2> + $chain<$R2, $Out2>(Then<$Out2, $R2> t) => + _IsolateManagerStateCopyWithImpl($value, $cast, t); +} diff --git a/common/lib/src/model/state/isolate_state.dart b/common/lib/src/model/state/isolate_state.dart new file mode 100644 index 00000000..3a5ca411 --- /dev/null +++ b/common/lib/src/model/state/isolate_state.dart @@ -0,0 +1,33 @@ +import 'package:dart_mappable/dart_mappable.dart'; + +part 'isolate_state.mapper.dart'; + +enum IsolateType { + /// The multicast isolate is responsible for sending and receiving multicast messages. + /// There is only one multicast isolate per device. + multicast, + + /// The isolate is responsible for discovering other devices on the network by + /// sending HTTP requests to the other devices. + /// There is only one discovery isolate per device. + httpDiscovery, + + /// The isolate where the HTTP server is running. + /// There is as many isolates as there are CPU cores. + httpServer, + + /// The isolate where data is sent to the server. + /// There is as many isolates as there are CPU cores. + httpClient, +} + +@MappableClass() +class IsolateState with IsolateStateMappable { + final int? isolateId; + final IsolateType? isolateType; + + const IsolateState({ + required this.isolateId, + required this.isolateType, + }); +} diff --git a/common/lib/src/model/state/isolate_state.mapper.dart b/common/lib/src/model/state/isolate_state.mapper.dart new file mode 100644 index 00000000..3b612934 --- /dev/null +++ b/common/lib/src/model/state/isolate_state.mapper.dart @@ -0,0 +1,123 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'isolate_state.dart'; + +class IsolateStateMapper extends ClassMapperBase { + IsolateStateMapper._(); + + static IsolateStateMapper? _instance; + static IsolateStateMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = IsolateStateMapper._()); + } + return _instance!; + } + + @override + final String id = 'IsolateState'; + + static int? _$isolateId(IsolateState v) => v.isolateId; + static const Field _f$isolateId = + Field('isolateId', _$isolateId); + static IsolateType? _$isolateType(IsolateState v) => v.isolateType; + static const Field _f$isolateType = + Field('isolateType', _$isolateType); + + @override + final Map> fields = const { + #isolateId: _f$isolateId, + #isolateType: _f$isolateType, + }; + + static IsolateState _instantiate(DecodingData data) { + return IsolateState( + isolateId: data.dec(_f$isolateId), + isolateType: data.dec(_f$isolateType)); + } + + @override + final Function instantiate = _instantiate; + + static IsolateState fromJson(Map map) { + return ensureInitialized().decodeMap(map); + } + + static IsolateState deserialize(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin IsolateStateMappable { + String serialize() { + return IsolateStateMapper.ensureInitialized() + .encodeJson(this as IsolateState); + } + + Map toJson() { + return IsolateStateMapper.ensureInitialized() + .encodeMap(this as IsolateState); + } + + IsolateStateCopyWith get copyWith => + _IsolateStateCopyWithImpl(this as IsolateState, $identity, $identity); + @override + String toString() { + return IsolateStateMapper.ensureInitialized() + .stringifyValue(this as IsolateState); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (runtimeType == other.runtimeType && + IsolateStateMapper.ensureInitialized() + .isValueEqual(this as IsolateState, other)); + } + + @override + int get hashCode { + return IsolateStateMapper.ensureInitialized() + .hashValue(this as IsolateState); + } +} + +extension IsolateStateValueCopy<$R, $Out> + on ObjectCopyWith<$R, IsolateState, $Out> { + IsolateStateCopyWith<$R, IsolateState, $Out> get $asIsolateState => + $base.as((v, t, t2) => _IsolateStateCopyWithImpl(v, t, t2)); +} + +abstract class IsolateStateCopyWith<$R, $In extends IsolateState, $Out> + implements ClassCopyWith<$R, $In, $Out> { + $R call({int? isolateId, IsolateType? isolateType}); + IsolateStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); +} + +class _IsolateStateCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, IsolateState, $Out> + implements IsolateStateCopyWith<$R, IsolateState, $Out> { + _IsolateStateCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + IsolateStateMapper.ensureInitialized(); + @override + $R call({Object? isolateId = $none, Object? isolateType = $none}) => + $apply(FieldCopyWithData({ + if (isolateId != $none) #isolateId: isolateId, + if (isolateType != $none) #isolateType: isolateType + })); + @override + IsolateState $make(CopyWithData data) => IsolateState( + isolateId: data.get(#isolateId, or: $value.isolateId), + isolateType: data.get(#isolateType, or: $value.isolateType)); + + @override + IsolateStateCopyWith<$R2, IsolateState, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _IsolateStateCopyWithImpl($value, $cast, t); +} diff --git a/common/lib/src/model/state/isolate_sync_dto.dart b/common/lib/src/model/state/isolate_sync_dto.dart new file mode 100644 index 00000000..89da5ab7 --- /dev/null +++ b/common/lib/src/model/state/isolate_sync_dto.dart @@ -0,0 +1,16 @@ +import 'package:common/src/model/state/isolate_common_state.dart'; +import 'package:common/src/model/state/isolate_state.dart'; +import 'package:dart_mappable/dart_mappable.dart'; + +part 'isolate_sync_dto.mapper.dart'; + +@MappableClass() +class IsolateSyncDto with IsolateSyncDtoMappable { + final IsolateState isolateState; + final IsolateCommonState isolateCommonState; + + const IsolateSyncDto({ + required this.isolateState, + required this.isolateCommonState, + }); +} diff --git a/common/lib/src/model/state/isolate_sync_dto.mapper.dart b/common/lib/src/model/state/isolate_sync_dto.mapper.dart new file mode 100644 index 00000000..7f4c5af3 --- /dev/null +++ b/common/lib/src/model/state/isolate_sync_dto.mapper.dart @@ -0,0 +1,141 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, unnecessary_cast +// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter + +part of 'isolate_sync_dto.dart'; + +class IsolateSyncDtoMapper extends ClassMapperBase { + IsolateSyncDtoMapper._(); + + static IsolateSyncDtoMapper? _instance; + static IsolateSyncDtoMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = IsolateSyncDtoMapper._()); + IsolateStateMapper.ensureInitialized(); + IsolateCommonStateMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'IsolateSyncDto'; + + static IsolateState _$isolateState(IsolateSyncDto v) => v.isolateState; + static const Field _f$isolateState = + Field('isolateState', _$isolateState); + static IsolateCommonState _$isolateCommonState(IsolateSyncDto v) => + v.isolateCommonState; + static const Field _f$isolateCommonState = + Field('isolateCommonState', _$isolateCommonState); + + @override + final Map> fields = const { + #isolateState: _f$isolateState, + #isolateCommonState: _f$isolateCommonState, + }; + + static IsolateSyncDto _instantiate(DecodingData data) { + return IsolateSyncDto( + isolateState: data.dec(_f$isolateState), + isolateCommonState: data.dec(_f$isolateCommonState)); + } + + @override + final Function instantiate = _instantiate; + + static IsolateSyncDto fromJson(Map map) { + return ensureInitialized().decodeMap(map); + } + + static IsolateSyncDto deserialize(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin IsolateSyncDtoMappable { + String serialize() { + return IsolateSyncDtoMapper.ensureInitialized() + .encodeJson(this as IsolateSyncDto); + } + + Map toJson() { + return IsolateSyncDtoMapper.ensureInitialized() + .encodeMap(this as IsolateSyncDto); + } + + IsolateSyncDtoCopyWith + get copyWith => _IsolateSyncDtoCopyWithImpl( + this as IsolateSyncDto, $identity, $identity); + @override + String toString() { + return IsolateSyncDtoMapper.ensureInitialized() + .stringifyValue(this as IsolateSyncDto); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (runtimeType == other.runtimeType && + IsolateSyncDtoMapper.ensureInitialized() + .isValueEqual(this as IsolateSyncDto, other)); + } + + @override + int get hashCode { + return IsolateSyncDtoMapper.ensureInitialized() + .hashValue(this as IsolateSyncDto); + } +} + +extension IsolateSyncDtoValueCopy<$R, $Out> + on ObjectCopyWith<$R, IsolateSyncDto, $Out> { + IsolateSyncDtoCopyWith<$R, IsolateSyncDto, $Out> get $asIsolateSyncDto => + $base.as((v, t, t2) => _IsolateSyncDtoCopyWithImpl(v, t, t2)); +} + +abstract class IsolateSyncDtoCopyWith<$R, $In extends IsolateSyncDto, $Out> + implements ClassCopyWith<$R, $In, $Out> { + IsolateStateCopyWith<$R, IsolateState, IsolateState> get isolateState; + IsolateCommonStateCopyWith<$R, IsolateCommonState, IsolateCommonState> + get isolateCommonState; + $R call({IsolateState? isolateState, IsolateCommonState? isolateCommonState}); + IsolateSyncDtoCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _IsolateSyncDtoCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, IsolateSyncDto, $Out> + implements IsolateSyncDtoCopyWith<$R, IsolateSyncDto, $Out> { + _IsolateSyncDtoCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + IsolateSyncDtoMapper.ensureInitialized(); + @override + IsolateStateCopyWith<$R, IsolateState, IsolateState> get isolateState => + $value.isolateState.copyWith.$chain((v) => call(isolateState: v)); + @override + IsolateCommonStateCopyWith<$R, IsolateCommonState, IsolateCommonState> + get isolateCommonState => $value.isolateCommonState.copyWith + .$chain((v) => call(isolateCommonState: v)); + @override + $R call( + {IsolateState? isolateState, + IsolateCommonState? isolateCommonState}) => + $apply(FieldCopyWithData({ + if (isolateState != null) #isolateState: isolateState, + if (isolateCommonState != null) #isolateCommonState: isolateCommonState + })); + @override + IsolateSyncDto $make(CopyWithData data) => IsolateSyncDto( + isolateState: data.get(#isolateState, or: $value.isolateState), + isolateCommonState: + data.get(#isolateCommonState, or: $value.isolateCommonState)); + + @override + IsolateSyncDtoCopyWith<$R2, IsolateSyncDto, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _IsolateSyncDtoCopyWithImpl($value, $cast, t); +} diff --git a/app/lib/model/persistence/stored_security_context.dart b/common/lib/src/model/stored_security_context.dart similarity index 100% rename from app/lib/model/persistence/stored_security_context.dart rename to common/lib/src/model/stored_security_context.dart diff --git a/app/lib/model/persistence/stored_security_context.mapper.dart b/common/lib/src/model/stored_security_context.mapper.dart similarity index 100% rename from app/lib/model/persistence/stored_security_context.mapper.dart rename to common/lib/src/model/stored_security_context.mapper.dart diff --git a/common/lib/src/util/id_provider.dart b/common/lib/src/util/id_provider.dart new file mode 100644 index 00000000..d04a9609 --- /dev/null +++ b/common/lib/src/util/id_provider.dart @@ -0,0 +1,10 @@ +/// A simple class that provides an id. +class IdProvider { + int _id = 0; + + /// Returns the next id. + int getNextId() => _id++; + + /// Resets the id to 0. + void reset() => _id = 0; +} diff --git a/common/lib/src/util/isolate_helper.dart b/common/lib/src/util/isolate_helper.dart index e2f5d52c..d1c9d75c 100644 --- a/common/lib/src/util/isolate_helper.dart +++ b/common/lib/src/util/isolate_helper.dart @@ -20,11 +20,13 @@ class IsolateCommunication { /// Starts an isolate and setups the [SendPort] and [ReceivePort] to communicate with it. /// [R] is the type of the messages that the main isolate will **receive** from the spawned isolate. /// [S] is the type of the messages that the main isolate will **send** to the spawned isolate. -Future> startIsolate({ - required Future Function(Stream receiveFromMain, void Function(R) sendToMain) task, +/// [P] is the type of the parameter that is passed to the spawned isolate. +Future> startIsolate({ + required Future Function(Stream receiveFromMain, void Function(R) sendToMain, P? param) task, + P? param, }) async { final receivePort = ReceivePort(); - final isolate = await Isolate.spawn((param) => _isolateRunner(param), _IsolateParam(receivePort.sendPort, task)); + final isolate = await Isolate.spawn((param) => _isolateRunner(param), _IsolateParam(receivePort.sendPort, task, param)); final receiveFromIsolateController = StreamController(); final sendToIsolateCompleter = Completer(); @@ -55,17 +57,18 @@ Future> startIsolate({ ); } -class _IsolateParam { +class _IsolateParam { final SendPort _sendToMain; - final Future Function(Stream, void Function(R) sendToMain) task; + final Future Function(Stream, void Function(R) sendToMain, P? param) task; + final P? param; - _IsolateParam(this._sendToMain, this.task); + _IsolateParam(this._sendToMain, this.task, this.param); } /// A message that is sent to the isolate to signal that the [SendPort] is ready. class _SendToIsolateReceived {} -Future _isolateRunner(_IsolateParam params) async { +Future _isolateRunner(_IsolateParam params) async { final receivePort = ReceivePort(); params._sendToMain.send(receivePort.sendPort); @@ -86,5 +89,6 @@ Future _isolateRunner(_IsolateParam params) async { await params.task( receiveFromMainController.stream, (data) => params._sendToMain.send(data), + params.param, ); } diff --git a/common/pubspec.yaml b/common/pubspec.yaml index 8231e7ee..9fed830f 100644 --- a/common/pubspec.yaml +++ b/common/pubspec.yaml @@ -1,5 +1,5 @@ name: common -description: A starting point for Dart libraries or applications. +description: Common code used by the app and by the cli. version: 1.0.0 publish_to: "none" @@ -9,7 +9,9 @@ environment: dependencies: collection: ^1.17.2 # allow newer versions, so it can compile with newer Flutter versions dart_mappable: 4.0.1 + logging: 1.2.0 mime: 1.0.4 + refena: 1.6.1 dev_dependencies: build_runner: 2.4.7