diff --git a/app/lib/util/rust.dart b/app/lib/util/rust.dart index e51d32ad..18004fac 100644 --- a/app/lib/util/rust.dart +++ b/app/lib/util/rust.dart @@ -20,6 +20,19 @@ extension DeviceExt on Device { true => rust_model.ProtocolType.https, }; } + + rust_model.RegisterDto toRegisterDto() { + return rust_model.RegisterDto( + alias: alias, + version: version, + deviceModel: deviceModel, + deviceType: deviceType.toRust(), + token: fingerprint, + port: port, + protocol: getProtocolType(), + hasWebInterface: download, + ); + } } extension DeviceTypeExt on DeviceType { @@ -52,3 +65,33 @@ extension FileDtoExt on FileDto { ); } } + +extension RustDeviceTypeExt on rust_model.DeviceType { + DeviceType toDart() { + return switch (this) { + rust_model.DeviceType.mobile => DeviceType.mobile, + rust_model.DeviceType.desktop => DeviceType.desktop, + rust_model.DeviceType.web => DeviceType.web, + rust_model.DeviceType.headless => DeviceType.headless, + rust_model.DeviceType.server => DeviceType.server, + }; + } +} + +extension RegisterResponseDtoExt on rust_model.RegisterResponseDto { + Device toDevice(String ip, int port, bool https, DiscoveryMethod method) { + return Device( + signalingId: null, + ip: ip, + version: version, + port: port, + https: https, + fingerprint: token, + alias: alias, + deviceModel: deviceModel, + deviceType: deviceType?.toDart() ?? DeviceType.desktop, + download: hasWebInterface, + discoveryMethods: {method}, + ); + } +} diff --git a/app/lib/widget/dialogs/address_input_dialog.dart b/app/lib/widget/dialogs/address_input_dialog.dart index a38fc5fe..59df1892 100644 --- a/app/lib/widget/dialogs/address_input_dialog.dart +++ b/app/lib/widget/dialogs/address_input_dialog.dart @@ -1,15 +1,18 @@ import 'dart:async'; import 'package:collection/collection.dart'; -import 'package:common/isolate.dart'; import 'package:common/model/device.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:localsend_app/config/theme.dart'; import 'package:localsend_app/gen/strings.g.dart'; +import 'package:localsend_app/provider/device_info_provider.dart'; +import 'package:localsend_app/provider/http_provider.dart'; import 'package:localsend_app/provider/last_devices.provider.dart'; import 'package:localsend_app/provider/local_ip_provider.dart'; import 'package:localsend_app/provider/settings_provider.dart'; +import 'package:localsend_app/rust/api/model.dart'; +import 'package:localsend_app/util/rust.dart'; import 'package:localsend_app/widget/dialogs/error_dialog.dart'; import 'package:refena_flutter/refena_flutter.dart'; import 'package:routerino/routerino.dart'; @@ -63,22 +66,24 @@ class _AddressInputDialogState extends State with Refena { Device? foundDevice; String? error; - final List> futures = [ + final payload = ref.read(deviceFullInfoProvider).toRegisterDto(); + + final List> futures = [ for (final ip in candidates) () async { try { - final device = await ref - .redux(parentIsolateProvider) - .dispatchAsyncTakeResult( - IsolateTargetHttpDiscoveryAction( - ip: ip, - port: port, - https: https, - ), + final response = await ref + .read(httpProvider) + .v2 + .register( + protocol: https ? ProtocolType.https : ProtocolType.http, + ip: ip, + port: port, + payload: payload, ); - foundDevice = device; + + foundDevice = response.body.toDevice(ip, port, https, HttpDiscovery(ip: ip)); deviceCompleter.complete(); - return device; } catch (e) { error = e.toString(); rethrow; diff --git a/app/lib/widget/dialogs/favorite_dialog.dart b/app/lib/widget/dialogs/favorite_dialog.dart index a4bce2d2..4b8b79a4 100644 --- a/app/lib/widget/dialogs/favorite_dialog.dart +++ b/app/lib/widget/dialogs/favorite_dialog.dart @@ -1,10 +1,14 @@ -import 'package:common/isolate.dart'; +import 'package:common/model/device.dart'; import 'package:flutter/material.dart'; import 'package:localsend_app/config/theme.dart'; import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/model/persistence/favorite_device.dart'; +import 'package:localsend_app/provider/device_info_provider.dart'; import 'package:localsend_app/provider/favorites_provider.dart'; +import 'package:localsend_app/provider/http_provider.dart'; import 'package:localsend_app/provider/settings_provider.dart'; +import 'package:localsend_app/rust/api/model.dart'; +import 'package:localsend_app/util/rust.dart'; import 'package:localsend_app/widget/dialogs/error_dialog.dart'; import 'package:localsend_app/widget/dialogs/favorite_edit_dialog.dart'; import 'package:refena_flutter/refena_flutter.dart'; @@ -31,18 +35,21 @@ class _FavoritesDialogState extends State with Refena { final https = ref.read(settingsProvider).https; try { - final result = await ref - .redux(parentIsolateProvider) - .dispatchAsyncTakeResult( - IsolateTargetHttpDiscoveryAction( - ip: favorite.ip, - port: favorite.port, - https: https, - ), - ); + final payload = ref.read(deviceFullInfoProvider).toRegisterDto(); + final response = await ref + .read(httpProvider) + .v2 + .register( + protocol: https ? ProtocolType.https : ProtocolType.http, + ip: favorite.ip, + port: favorite.port, + payload: payload, + ); + + final device = response.body.toDevice(favorite.ip, favorite.port, https, HttpDiscovery(ip: favorite.ip)); if (mounted) { - context.pop(result); + context.pop(device); } } catch (e) { setState(() { diff --git a/app/lib/widget/dialogs/favorite_edit_dialog.dart b/app/lib/widget/dialogs/favorite_edit_dialog.dart index 1f27fcbf..f303970c 100644 --- a/app/lib/widget/dialogs/favorite_edit_dialog.dart +++ b/app/lib/widget/dialogs/favorite_edit_dialog.dart @@ -1,11 +1,14 @@ -import 'package:common/isolate.dart'; import 'package:common/model/device.dart'; import 'package:flutter/material.dart'; import 'package:localsend_app/config/theme.dart'; import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/model/persistence/favorite_device.dart'; +import 'package:localsend_app/provider/device_info_provider.dart'; import 'package:localsend_app/provider/favorites_provider.dart'; +import 'package:localsend_app/provider/http_provider.dart'; import 'package:localsend_app/provider/settings_provider.dart'; +import 'package:localsend_app/rust/api/model.dart'; +import 'package:localsend_app/util/rust.dart'; import 'package:localsend_app/widget/dialogs/error_dialog.dart'; import 'package:localsend_app/widget/dialogs/favorite_delete_dialog.dart'; import 'package:refena_flutter/refena_flutter.dart'; @@ -185,15 +188,16 @@ class _FavoriteEditDialogState extends State with Refena { }); try { - final result = await ref - .redux(parentIsolateProvider) - .dispatchAsyncTakeResult( - IsolateTargetHttpDiscoveryAction( - ip: ip, - port: port, - https: https, - ), - ); + final payload = ref.read(deviceFullInfoProvider).toRegisterDto(); + final response = await ref + .read(httpProvider) + .v2 + .register( + protocol: https ? ProtocolType.https : ProtocolType.http, + ip: ip, + port: port, + payload: payload, + ); final name = _aliasController.text.trim(); @@ -202,10 +206,10 @@ class _FavoriteEditDialogState extends State with Refena { .dispatchAsync( AddFavoriteAction( FavoriteDevice.fromValues( - fingerprint: result.fingerprint, + fingerprint: response.body.token, ip: _ipController.text, port: int.parse(_portController.text), - alias: name.isEmpty ? result.alias : name, + alias: name.isEmpty ? response.body.alias : name, ), ), ); diff --git a/app/macos/Podfile.lock b/app/macos/Podfile.lock index ecaddfd8..2c832166 100644 --- a/app/macos/Podfile.lock +++ b/app/macos/Podfile.lock @@ -54,7 +54,7 @@ PODS: - FlutterMacOS - wakelock_plus (0.0.1): - FlutterMacOS - - window_manager (0.2.0): + - window_manager (0.5.0): - FlutterMacOS DEPENDENCIES: @@ -147,9 +147,9 @@ SPEC CHECKSUMS: Defaults: d785e56c0fb8890dc40351603f05c8e1df1bdd45 desktop_drop: e0b672a7d84c0a6cbc378595e82cdb15f2970a43 device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 - dynamic_color: b820c000cc68df65e7ba7ff177cb98404ce56651 + dynamic_color: cb7c2a300ee67ed3bd96c3e852df3af0300bf610 file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 gal: 44e5b10dbd347c8247a2851acee6c1fbe282c1d3 in_app_purchase_storekit: e126ef1b89e4a9fdf07e28f005f82632b4609437 network_info_plus: 21d1cd6a015ccb2fdff06a1fbfa88d54b4e92f61 @@ -159,15 +159,15 @@ SPEC CHECKSUMS: path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413 rhttp: 08d791d6373089de796318f4cfb172cbcf34e78b - rust_lib_localsend_app: 6b270a4b507b1599a1d06c9ebf86d01adfa0e875 + rust_lib_localsend_app: 293779a82668308386129c9669c081d201d3e278 screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166 - uri_content: a2350e4567f5fba3f48bb0f144f277eaddf0aa2c + uri_content: 6c7c098bcc83078659b4d274f42db92691eb9123 url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b wakelock_plus: 21ddc249ac4b8d018838dbdabd65c5976c308497 - window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c + window_manager: b729e31d38fb04905235df9ea896128991cad99e PODFILE CHECKSUM: 5c6550f5101fcba381ddb97e2135e4cacca4f31f diff --git a/common/lib/src/isolate/child/http_target_discovery_isolate.dart b/common/lib/src/isolate/child/http_target_discovery_isolate.dart deleted file mode 100644 index 04673b16..00000000 --- a/common/lib/src/isolate/child/http_target_discovery_isolate.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:common/model/device.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 { - final String ip; - final int port; - final bool https; - - HttpTargetTask({ - required this.ip, - required this.port, - required this.https, - }); -} - -@internal -Future setupHttpTargetDiscoveryIsolate( - Stream>> receiveFromMain, - void Function(IsolateTaskResult) sendToMain, - InitialData initialData, -) async { - await setupChildIsolateHelper( - debugLabel: 'HttpTargetDiscoveryIsolate', - receiveFromMain: receiveFromMain, - sendToMain: sendToMain, - initialData: initialData, - handler: (ref, task) async { - Object? error; - final device = await ref.read(httpTargetDiscoveryProvider).discover( - ip: task.data.ip, - port: task.data.port, - https: task.data.https, - onError: (url, e) => error = e, - ); - - if (error != null || device == null) { - return sendToMain(IsolateTaskErrorResult( - id: task.id, - error: error?.toString() ?? 'Unknown error', - )); - } - - sendToMain(IsolateTaskSuccessResult( - id: task.id, - data: device, - )); - }, - ); -} diff --git a/common/lib/src/isolate/parent/actions.dart b/common/lib/src/isolate/parent/actions.dart index 7d0c41e8..5b4f9b2c 100644 --- a/common/lib/src/isolate/parent/actions.dart +++ b/common/lib/src/isolate/parent/actions.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:common/model/device.dart'; import 'package:common/src/isolate/child/http_scan_discovery_isolate.dart'; -import 'package:common/src/isolate/child/http_target_discovery_isolate.dart'; import 'package:common/src/isolate/child/multicast_discovery_isolate.dart'; import 'package:common/src/isolate/child/upload_isolate.dart'; import 'package:common/src/isolate/dto/isolate_task.dart'; @@ -15,56 +14,6 @@ import 'package:refena/refena.dart'; final _idProvider = IdProvider(); -class IsolateTargetHttpDiscoveryAction extends AsyncReduxActionWithResult { - final String ip; - final int port; - final bool https; - - IsolateTargetHttpDiscoveryAction({ - required this.ip, - required this.port, - required this.https, - }); - - @override - Future<(ParentIsolateState, Device)> reduce() async { - final connection = state.httpTargetDiscovery; - if (connection == null) { - throw StateError('httpTargetDiscovery is not initialized'); - } - - final task = IsolateTask( - id: _idProvider.getNextId(), - data: HttpTargetTask( - ip: ip, - port: port, - https: https, - ), - ); - - // ignore: unawaited_futures - Future.microtask(() { - connection.sendToIsolate(SendToIsolateData( - syncState: null, - data: task, - )); - }); - - await for (final result in connection.receiveFromIsolate) { - if (result.id == task.id) { - switch (result) { - case IsolateTaskSuccessResult(): - return (state, result.data); - case IsolateTaskErrorResult(): - throw result.error; - } - } - } - - throw StateError('Unexpected end of stream'); - } -} - class IsolateInterfaceHttpDiscoveryAction extends ReduxActionWithResult> { final String networkInterface; final int port; diff --git a/common/lib/src/isolate/parent/actions_sync.dart b/common/lib/src/isolate/parent/actions_sync.dart index 54f173a2..44ba314f 100644 --- a/common/lib/src/isolate/parent/actions_sync.dart +++ b/common/lib/src/isolate/parent/actions_sync.dart @@ -115,10 +115,6 @@ class _PublishSyncStateAction extends ReduxAction, SendToIsolateData>>? httpScanDiscovery; - final IsolateConnector, SendToIsolateData>>? httpTargetDiscovery; final IsolateConnector>? multicastDiscovery; final List, SendToIsolateData>>> httpUpload; int get uploadIsolateCount => httpUpload.length; @@ -32,7 +30,6 @@ class ParentIsolateState with ParentIsolateStateMappable { ParentIsolateState({ required this.syncState, required this.httpScanDiscovery, - required this.httpTargetDiscovery, required this.multicastDiscovery, required this.httpUpload, }); @@ -40,14 +37,13 @@ class ParentIsolateState with ParentIsolateStateMappable { static ParentIsolateState initial(SyncState syncState) => ParentIsolateState( syncState: syncState, httpScanDiscovery: null, - httpTargetDiscovery: null, multicastDiscovery: null, httpUpload: [], ); @override String toString() { - return 'ParentIsolateState(syncState: $syncState, httpTargetDiscovery: $httpTargetDiscovery)'; + return 'ParentIsolateState(syncState: $syncState)'; } } @@ -86,14 +82,6 @@ class IsolateSetupAction extends AsyncReduxAction, SendToIsolateData>, InitialData>( - task: setupHttpTargetDiscoveryIsolate, - param: InitialData( - syncState: state.syncState, - logLevel: Logger.root.level, - ), - ); - final multicastDiscovery = await startIsolate, InitialData>( task: setupMulticastDiscoveryIsolate, param: InitialData( @@ -130,7 +118,6 @@ class IsolateSetupAction extends AsyncReduxAction { v.httpScanDiscovery; static const Field, SendToIsolateData>>> _f$httpScanDiscovery = Field('httpScanDiscovery', _$httpScanDiscovery); - static IsolateConnector, SendToIsolateData>>? _$httpTargetDiscovery(ParentIsolateState v) => - v.httpTargetDiscovery; - static const Field, SendToIsolateData>>> - _f$httpTargetDiscovery = Field('httpTargetDiscovery', _$httpTargetDiscovery); static IsolateConnector>? _$multicastDiscovery(ParentIsolateState v) => v.multicastDiscovery; static const Field>> _f$multicastDiscovery = Field('multicastDiscovery', _$multicastDiscovery); @@ -45,7 +41,6 @@ class ParentIsolateStateMapper extends ClassMapperBase { final MappableFields fields = const { #syncState: _f$syncState, #httpScanDiscovery: _f$httpScanDiscovery, - #httpTargetDiscovery: _f$httpTargetDiscovery, #multicastDiscovery: _f$multicastDiscovery, #httpUpload: _f$httpUpload, }; @@ -54,7 +49,6 @@ class ParentIsolateStateMapper extends ClassMapperBase { return ParentIsolateState( syncState: data.dec(_f$syncState), httpScanDiscovery: data.dec(_f$httpScanDiscovery), - httpTargetDiscovery: data.dec(_f$httpTargetDiscovery), multicastDiscovery: data.dec(_f$multicastDiscovery), httpUpload: data.dec(_f$httpUpload)); } @@ -113,7 +107,6 @@ abstract class ParentIsolateStateCopyWith<$R, $In extends ParentIsolateState, $O $R call( {SyncState? syncState, IsolateConnector, SendToIsolateData>>? httpScanDiscovery, - IsolateConnector, SendToIsolateData>>? httpTargetDiscovery, IsolateConnector>? multicastDiscovery, List, SendToIsolateData>>>? httpUpload}); ParentIsolateStateCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t); @@ -138,13 +131,11 @@ class _ParentIsolateStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Pa $R call( {SyncState? syncState, Object? httpScanDiscovery = $none, - Object? httpTargetDiscovery = $none, Object? multicastDiscovery = $none, List, SendToIsolateData>>>? httpUpload}) => $apply(FieldCopyWithData({ if (syncState != null) #syncState: syncState, if (httpScanDiscovery != $none) #httpScanDiscovery: httpScanDiscovery, - if (httpTargetDiscovery != $none) #httpTargetDiscovery: httpTargetDiscovery, if (multicastDiscovery != $none) #multicastDiscovery: multicastDiscovery, if (httpUpload != null) #httpUpload: httpUpload })); @@ -152,7 +143,6 @@ class _ParentIsolateStateCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Pa ParentIsolateState $make(CopyWithData data) => ParentIsolateState( syncState: data.get(#syncState, or: $value.syncState), httpScanDiscovery: data.get(#httpScanDiscovery, or: $value.httpScanDiscovery), - httpTargetDiscovery: data.get(#httpTargetDiscovery, or: $value.httpTargetDiscovery), multicastDiscovery: data.get(#multicastDiscovery, or: $value.multicastDiscovery), httpUpload: data.get(#httpUpload, or: $value.httpUpload));