From b282e89db0b7160ea6302bf8ef3a35121d29be90 Mon Sep 17 00:00:00 2001 From: Tien Do Nam Date: Sat, 1 Feb 2025 02:15:40 +0100 Subject: [PATCH] feat: show found webrtc devices --- app/lib/config/init.dart | 61 +----- app/lib/model/state/nearby_devices_state.dart | 37 ++++ app/lib/pages/receive_page_controller.dart | 2 + app/lib/pages/tabs/send_tab.dart | 4 +- app/lib/pages/tabs/send_tab_vm.dart | 2 +- app/lib/provider/device_info_provider.dart | 1 + .../network/nearby_devices_provider.dart | 37 +++- .../network/webrtc/signaling_provider.dart | 177 ++++++++++++++++-- app/lib/provider/persistence_provider.dart | 8 +- app/lib/rust/frb_generated.dart | 2 +- .../widget/list_tile/device_list_tile.dart | 2 +- app/rust/src/api/logging.rs | 8 +- app/rust/src/frb_generated.rs | 12 +- app/test/mocks.mocks.dart | 20 -- .../provider/last_devices_provider_test.dart | 1 + .../unit/util/api_route_builder_test.dart | 1 + common/lib/model/device.dart | 8 + common/lib/model/device.mapper.dart | 12 +- common/lib/model/dto/info_dto.dart | 1 + common/lib/model/dto/info_register_dto.dart | 1 + common/lib/model/dto/multicast_dto.dart | 1 + common/lib/model/dto/register_dto.dart | 1 + 22 files changed, 290 insertions(+), 109 deletions(-) diff --git a/app/lib/config/init.dart b/app/lib/config/init.dart index a867281a..4a6239fd 100644 --- a/app/lib/config/init.dart +++ b/app/lib/config/init.dart @@ -21,6 +21,7 @@ import 'package:localsend_app/provider/app_arguments_provider.dart'; import 'package:localsend_app/provider/device_info_provider.dart'; import 'package:localsend_app/provider/network/nearby_devices_provider.dart'; import 'package:localsend_app/provider/network/server/server_provider.dart'; +import 'package:localsend_app/provider/network/webrtc/signaling_provider.dart'; import 'package:localsend_app/provider/persistence_provider.dart'; // [FOSS_REMOVE_START] @@ -32,8 +33,6 @@ import 'package:localsend_app/provider/settings_provider.dart'; import 'package:localsend_app/provider/tv_provider.dart'; import 'package:localsend_app/provider/window_dimensions_provider.dart'; import 'package:localsend_app/rust/api/logging.dart' as rust_logging; -import 'package:localsend_app/rust/api/model.dart' as model; -import 'package:localsend_app/rust/api/webrtc.dart' as webrtc; import 'package:localsend_app/rust/frb_generated.dart'; import 'package:localsend_app/util/i18n.dart'; import 'package:localsend_app/util/native/autostart_helper.dart'; @@ -65,55 +64,13 @@ Future preInit(List args) async { await RustLib.init(); - await rust_logging.enableDebugLogging(); - - webrtc.LsSignalingConnection? connection; - final stream = webrtc.connect( - uri: 'wss://public.localsend.org/v1/ws', - info: webrtc.ClientInfoWithoutId( - alias: 'alias', - version: 'version', - deviceModel: 'deviceModel', - deviceType: webrtc.PeerDeviceType.mobile, - fingerprint: 'fingerprint', - ), - onConnection: (c) { - connection = c; - print('Got connection'); - }, - ); - - const stunServers = ['stun:stun.l.google.com:19302']; - - stream.listen((message) async { - print('Got message: $message'); - webrtc.WsServerMessage; - await message.when( - hello: (_, __) {}, - joined: (j) async { - await connection?.sendOffer( - stunServers: stunServers, - target: j.id, - files: [ - model.FileDto( - id: '1', - fileName: 'test.mp4', - size: BigInt.from(1), - fileType: 'fileType', - ), - ], - ); - }, - left: (l) {}, - offer: (o) async { - await connection?.acceptOffer(stunServers: stunServers, offer: o); - }, - answer: (a) {}, - error: (e) {}, - ); - }, onDone: () { - print('Done!!!'); - }); + if (kDebugMode) { + try { + await rust_logging.enableDebugLogging(); + } catch (e) { + _logger.warning('Enabling debug logging failed', e); + } + } await Rhttp.init(); @@ -259,6 +216,8 @@ Future postInit(BuildContext context, Ref ref, bool appStart) async { _logger.warning('Starting multicast listener failed', e); } + ref.redux(signalingProvider).dispatch(SetupSignalingConnection()); + if (appStart) { if (defaultTargetPlatform == TargetPlatform.macOS) { // handle dropped files diff --git a/app/lib/model/state/nearby_devices_state.dart b/app/lib/model/state/nearby_devices_state.dart index a32c2c6e..3ac4c967 100644 --- a/app/lib/model/state/nearby_devices_state.dart +++ b/app/lib/model/state/nearby_devices_state.dart @@ -20,4 +20,41 @@ class NearbyDevicesState with NearbyDevicesStateMappable { required this.devices, required this.signalingDevices, }); + + Map get allDevices { + final Map allDevices = {}; + allDevices.addAll(devices); + for (final devices in signalingDevices.values) { + for (final device in devices) { + final currentDevice = allDevices[device.fingerprint]; + if (currentDevice != null && currentDevice.alias == device.alias) { + allDevices[device.fingerprint] = currentDevice.merge(device); + } else { + allDevices[device.fingerprint] = device; + } + } + } + return allDevices; + } +} + +extension on Device { + Device merge(Device other) { + return Device( + signalingId: signalingId ?? other.signalingId, + ip: ip ?? other.ip, + version: version, + port: port, + https: https, + fingerprint: fingerprint, + alias: alias, + deviceModel: deviceModel, + deviceType: deviceType, + download: download, + discoveryMethods: { + ...discoveryMethods, + ...other.discoveryMethods, + }, + ); + } } diff --git a/app/lib/pages/receive_page_controller.dart b/app/lib/pages/receive_page_controller.dart index c203934a..27904bec 100644 --- a/app/lib/pages/receive_page_controller.dart +++ b/app/lib/pages/receive_page_controller.dart @@ -62,6 +62,7 @@ class ReceivePageController extends ReduxNotifier { return ReceivePageVm( status: SessionStatus.waiting, sender: const Device( + signalingId: null, ip: '0.0.0.0', version: '1.0.0', port: 8080, @@ -155,6 +156,7 @@ class InitReceivePageFromHistoryMessageAction extends ReduxAction await vm.onToggleFavorite(context, device), + onFavoriteTap: device.ip == null ? null : () async => await vm.onToggleFavorite(context, device), onTap: () async => await vm.onTapDevice(context, device), ), ), @@ -534,7 +534,7 @@ class _MultiSendDeviceListTile extends StatelessWidget { progress: progress, isFavorite: isFavorite, nameOverride: nameOverride, - onFavoriteTap: () async => await vm.onToggleFavorite(context, device), + onFavoriteTap: device.ip == null ? null : () async => await vm.onToggleFavorite(context, device), onTap: () async => await vm.onTapDeviceMultiSend(context, device), ); } diff --git a/app/lib/pages/tabs/send_tab_vm.dart b/app/lib/pages/tabs/send_tab_vm.dart index 6eb357cf..80174ed6 100644 --- a/app/lib/pages/tabs/send_tab_vm.dart +++ b/app/lib/pages/tabs/send_tab_vm.dart @@ -56,7 +56,7 @@ final sendTabVmProvider = ViewProvider((ref) { final sendMode = ref.watch(settingsProvider.select((s) => s.sendMode)); final selectedFiles = ref.watch(selectedSendingFilesProvider); final localIps = ref.watch(localIpProvider).localIps; - final nearbyDevices = ref.watch(nearbyDevicesProvider).devices.values; + final nearbyDevices = ref.watch(nearbyDevicesProvider).allDevices.values; final favoriteDevices = ref.watch(favoritesProvider); return SendTabVm( diff --git a/app/lib/provider/device_info_provider.dart b/app/lib/provider/device_info_provider.dart index fe245f62..73db79bd 100644 --- a/app/lib/provider/device_info_provider.dart +++ b/app/lib/provider/device_info_provider.dart @@ -32,6 +32,7 @@ final deviceFullInfoProvider = ViewProvider((ref) { final rawInfo = ref.watch(deviceInfoProvider); final securityContext = ref.read(securityProvider); return Device( + signalingId: null, ip: networkInfo.localIps.firstOrNull ?? '-', version: protocolVersion, port: serverState?.port ?? -1, diff --git a/app/lib/provider/network/nearby_devices_provider.dart b/app/lib/provider/network/nearby_devices_provider.dart index 655e791e..3448a738 100644 --- a/app/lib/provider/network/nearby_devices_provider.dart +++ b/app/lib/provider/network/nearby_devices_provider.dart @@ -79,7 +79,7 @@ class RegisterDeviceAction extends AsyncReduxAction reduce() async { - assert(device.ip?.isNotEmpty ?? false); + assert(device.ip?.isNotEmpty ?? false, 'IP must not be empty'); final favoriteDevice = notifier._favoriteService.state.firstWhereOrNull((e) => e.fingerprint == device.fingerprint); if (favoriteDevice != null && !favoriteDevice.customAlias) { @@ -94,6 +94,41 @@ class RegisterDeviceAction extends AsyncReduxAction { + final Device device; + + RegisterSignalingDeviceAction(this.device); + + @override + NearbyDevicesState reduce() { + final Set existingDevices = state.signalingDevices[device.fingerprint] ?? {}; + existingDevices.add(device); + + return state.copyWith( + signalingDevices: { + ...state.signalingDevices, + device.fingerprint: existingDevices, + }, + ); + } +} + +class UnregisterSignalingDeviceAction extends ReduxAction { + final String signalingId; + + UnregisterSignalingDeviceAction(this.signalingId); + + @override + NearbyDevicesState reduce() { + return state.copyWith( + signalingDevices: { + for (final entry in state.signalingDevices.entries) entry.key: entry.value.where((e) => e.signalingId != signalingId).toSet(), + }, + ); + } +} + /// It does not really "scan". /// It just sends an announcement which will cause a response on every other LocalSend member of the network. class StartMulticastScan extends ReduxAction { diff --git a/app/lib/provider/network/webrtc/signaling_provider.dart b/app/lib/provider/network/webrtc/signaling_provider.dart index 4c7e42e3..1f3deca8 100644 --- a/app/lib/provider/network/webrtc/signaling_provider.dart +++ b/app/lib/provider/network/webrtc/signaling_provider.dart @@ -1,16 +1,19 @@ +import 'dart:async'; + +import 'package:common/constants.dart'; +import 'package:common/model/device.dart'; +import 'package:common/model/device_info_result.dart'; import 'package:dart_mappable/dart_mappable.dart'; +import 'package:localsend_app/provider/device_info_provider.dart'; +import 'package:localsend_app/provider/network/nearby_devices_provider.dart'; import 'package:localsend_app/provider/persistence_provider.dart'; +import 'package:localsend_app/provider/security_provider.dart'; +import 'package:localsend_app/provider/settings_provider.dart'; import 'package:localsend_app/rust/api/webrtc.dart'; import 'package:refena_flutter/refena_flutter.dart'; part 'signaling_provider.mapper.dart'; -final signalingProvider = ReduxProvider((ref) { - return SignalingService( - persistence: ref.read(persistenceProvider), - ); -}); - @MappableClass() class SignalingState with SignalingStateMappable { final List signalingServers; @@ -24,26 +27,50 @@ class SignalingState with SignalingStateMappable { }); } +final signalingProvider = ReduxProvider((ref) { + return SignalingService( + persistence: ref.read(persistenceProvider), + nearbyDevices: ref.notifier(nearbyDevicesProvider), + settings: ref.notifier(settingsProvider), + deviceInfo: ref.accessor(deviceInfoProvider), + security: ref.notifier(securityProvider), + ); +}); + class SignalingService extends ReduxNotifier { final PersistenceService _persistence; + final NearbyDevicesService _nearbyDevices; + final SettingsService _settings; + final StateAccessor _deviceInfo; + final SecurityService _security; - SignalingService({required PersistenceService persistence}) : _persistence = persistence; + SignalingService({ + required PersistenceService persistence, + required NearbyDevicesService nearbyDevices, + required SettingsService settings, + required StateAccessor deviceInfo, + required SecurityService security, + }) : _persistence = persistence, + _nearbyDevices = nearbyDevices, + _settings = settings, + _deviceInfo = deviceInfo, + _security = security; @override SignalingState init() { return SignalingState( - signalingServers: _persistence.getSignalingServers(), - stunServers: _persistence.getStunServers(), + signalingServers: _persistence.getSignalingServers() ?? ['wss://public.localsend.org/v1/ws'], + stunServers: _persistence.getStunServers() ?? ['stun:stun.localsend.org:5349'], connections: {}, ); } } -class SetupSignalingConnection extends AsyncReduxAction { +class SetupSignalingConnection extends ReduxAction { @override - Future reduce() async { + SignalingState reduce() { for (final signalingServer in state.signalingServers) { - // ignore: unawaited_futures + // ignore: discarded_futures dispatchAsync(_SetupSignalingConnection(signalingServer: signalingServer)); } return state; @@ -62,19 +89,133 @@ class _SetupSignalingConnection extends AsyncReduxAction { + final String signalingServer; + final LsSignalingConnection connection; + + _SetConnectionAction({ + required this.signalingServer, + required this.connection, + }); + + @override + SignalingState reduce() { + return state.copyWith( + connections: { + ...state.connections, + signalingServer: connection, + }, + ); + } +} + +class _RemoveConnectionAction extends ReduxAction { + final String signalingServer; + + _RemoveConnectionAction({required this.signalingServer}); + + @override + SignalingState reduce() { + return state.copyWith( + connections: { + for (final entry in state.connections.entries) + if (entry.key != signalingServer) entry.key: entry.value, + }, + ); + } +} + +extension on ClientInfo { + Device toDevice(String signalingServer) { + return Device( + signalingId: id.uuid, + ip: null, + version: version, + port: -1, + https: false, + fingerprint: fingerprint, + alias: alias, + deviceModel: deviceModel, + deviceType: deviceType?.toDeviceType() ?? DeviceType.desktop, + download: false, + discoveryMethods: { + SignalingDiscovery( + signalingServer: signalingServer, + ), + }, + ); + } +} + +extension on PeerDeviceType { + DeviceType toDeviceType() { + return switch (this) { + PeerDeviceType.mobile => DeviceType.mobile, + PeerDeviceType.desktop => DeviceType.desktop, + PeerDeviceType.web => DeviceType.web, + PeerDeviceType.headless => DeviceType.headless, + PeerDeviceType.server => DeviceType.server, + }; + } +} + +extension on DeviceType { + PeerDeviceType toPeerDeviceType() { + return switch (this) { + DeviceType.mobile => PeerDeviceType.mobile, + DeviceType.desktop => PeerDeviceType.desktop, + DeviceType.web => PeerDeviceType.web, + DeviceType.headless => PeerDeviceType.headless, + DeviceType.server => PeerDeviceType.server, + }; + } +} diff --git a/app/lib/provider/persistence_provider.dart b/app/lib/provider/persistence_provider.dart index b4622923..ec063173 100644 --- a/app/lib/provider/persistence_provider.dart +++ b/app/lib/provider/persistence_provider.dart @@ -212,10 +212,10 @@ class PersistenceService { await _prefs.setString(_securityContext, jsonEncode(context)); } - List getSignalingServers() { + List? getSignalingServers() { final serversRaw = _prefs.getString(_signalingServers); if (serversRaw == null) { - return []; + return null; } return (jsonDecode(serversRaw) as List).cast(); @@ -225,10 +225,10 @@ class PersistenceService { await _prefs.setString(_signalingServers, jsonEncode(servers)); } - List getStunServers() { + List? getStunServers() { final serversRaw = _prefs.getString(_stunServers); if (serversRaw == null) { - return []; + return null; } return (jsonDecode(serversRaw) as List).cast(); diff --git a/app/lib/rust/frb_generated.dart b/app/lib/rust/frb_generated.dart index a30f5194..c1cd634d 100644 --- a/app/lib/rust/frb_generated.dart +++ b/app/lib/rust/frb_generated.dart @@ -565,7 +565,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }, codec: SseCodec( decodeSuccessData: sse_decode_unit, - decodeErrorData: null, + decodeErrorData: sse_decode_AnyhowException, ), constMeta: kCrateApiLoggingEnableDebugLoggingConstMeta, argValues: [], diff --git a/app/lib/widget/list_tile/device_list_tile.dart b/app/lib/widget/list_tile/device_list_tile.dart index a1e40979..da9a6e6e 100644 --- a/app/lib/widget/list_tile/device_list_tile.dart +++ b/app/lib/widget/list_tile/device_list_tile.dart @@ -59,7 +59,7 @@ class DeviceListTile extends StatelessWidget { foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer, label: '#${device.ip!.visualId}', ) - else + else DeviceBadge( backgroundColor: badgeColor, foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer, diff --git a/app/rust/src/api/logging.rs b/app/rust/src/api/logging.rs index f915e972..124507fb 100644 --- a/app/rust/src/api/logging.rs +++ b/app/rust/src/api/logging.rs @@ -1,7 +1,11 @@ +use anyhow::Result; use tracing::Level; -pub fn enable_debug_logging() { +pub fn enable_debug_logging() -> Result<()> { tracing_subscriber::fmt() .with_max_level(Level::DEBUG) - .init(); + .try_init() + .map_err(|e| anyhow::anyhow!(e.to_string()))?; + + Ok(()) } diff --git a/app/rust/src/frb_generated.rs b/app/rust/src/frb_generated.rs index 4c9201af..fe09223b 100644 --- a/app/rust/src/frb_generated.rs +++ b/app/rust/src/frb_generated.rs @@ -1007,12 +1007,12 @@ fn wire__crate__api__logging__enable_debug_logging_impl( flutter_rust_bridge::for_generated::SseDeserializer::new(message); deserializer.end(); move |context| { - transform_result_sse::<_, ()>((move || { - let output_ok = Result::<_, ()>::Ok({ - crate::api::logging::enable_debug_logging(); - })?; - Ok(output_ok) - })()) + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = crate::api::logging::enable_debug_logging()?; + Ok(output_ok) + })(), + ) } }, ) diff --git a/app/test/mocks.mocks.dart b/app/test/mocks.mocks.dart index 34080148..54b440c0 100644 --- a/app/test/mocks.mocks.dart +++ b/app/test/mocks.mocks.dart @@ -94,16 +94,6 @@ class MockPersistenceService extends _i1.Mock implements _i3.PersistenceService returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); - @override - List getSignalingServers() => (super.noSuchMethod( - Invocation.method( - #getSignalingServers, - [], - ), - returnValue: [], - returnValueForMissingStub: [], - ) as List); - @override _i4.Future setSignalingServers(List? servers) => (super.noSuchMethod( Invocation.method( @@ -114,16 +104,6 @@ class MockPersistenceService extends _i1.Mock implements _i3.PersistenceService returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); - @override - List getStunServers() => (super.noSuchMethod( - Invocation.method( - #getStunServers, - [], - ), - returnValue: [], - returnValueForMissingStub: [], - ) as List); - @override _i4.Future setStunServers(List? servers) => (super.noSuchMethod( Invocation.method( diff --git a/app/test/unit/provider/last_devices_provider_test.dart b/app/test/unit/provider/last_devices_provider_test.dart index c1535eb6..2068ec04 100644 --- a/app/test/unit/provider/last_devices_provider_test.dart +++ b/app/test/unit/provider/last_devices_provider_test.dart @@ -52,6 +52,7 @@ void main() { Device _createDevice(String ip) { return Device( + signalingId: null, ip: ip, version: '1', port: 123, diff --git a/app/test/unit/util/api_route_builder_test.dart b/app/test/unit/util/api_route_builder_test.dart index 6e9ddfba..e99073c6 100644 --- a/app/test/unit/util/api_route_builder_test.dart +++ b/app/test/unit/util/api_route_builder_test.dart @@ -46,6 +46,7 @@ Device _target({ required bool https, }) { return Device( + signalingId: null, ip: '0.0.0.0', version: version, port: 8080, diff --git a/common/lib/model/device.dart b/common/lib/model/device.dart index 78f1b0e7..c99e66eb 100644 --- a/common/lib/model/device.dart +++ b/common/lib/model/device.dart @@ -24,6 +24,7 @@ class MulticastDiscovery extends DiscoveryMethod with MulticastDiscoveryMappable @MappableClass() class HttpDiscovery extends DiscoveryMethod with HttpDiscoveryMappable { final String ip; + const HttpDiscovery({required this.ip}); } @@ -47,7 +48,13 @@ enum TransmissionMethod { /// It gets not serialized. @MappableClass() class Device with DeviceMappable { + /// A unique ID provided by the signaling server. + final String? signalingId; + + /// The IP address of the device. + /// Is null when found via signaling. final String? ip; + final String version; final int port; final bool https; @@ -82,6 +89,7 @@ class Device with DeviceMappable { } const Device({ + required this.signalingId, required this.ip, required this.version, required this.port, diff --git a/common/lib/model/device.mapper.dart b/common/lib/model/device.mapper.dart index 3edea99b..6acc184a 100644 --- a/common/lib/model/device.mapper.dart +++ b/common/lib/model/device.mapper.dart @@ -399,6 +399,8 @@ class DeviceMapper extends ClassMapperBase { @override final String id = 'Device'; + static String? _$signalingId(Device v) => v.signalingId; + static const Field _f$signalingId = Field('signalingId', _$signalingId); static String? _$ip(Device v) => v.ip; static const Field _f$ip = Field('ip', _$ip); static String _$version(Device v) => v.version; @@ -422,6 +424,7 @@ class DeviceMapper extends ClassMapperBase { @override final MappableFields fields = const { + #signalingId: _f$signalingId, #ip: _f$ip, #version: _f$version, #port: _f$port, @@ -436,6 +439,7 @@ class DeviceMapper extends ClassMapperBase { static Device _instantiate(DecodingData data) { return Device( + signalingId: data.dec(_f$signalingId), ip: data.dec(_f$ip), version: data.dec(_f$version), port: data.dec(_f$port), @@ -492,7 +496,8 @@ extension DeviceValueCopy<$R, $Out> on ObjectCopyWith<$R, Device, $Out> { abstract class DeviceCopyWith<$R, $In extends Device, $Out> implements ClassCopyWith<$R, $In, $Out> { $R call( - {String? ip, + {String? signalingId, + String? ip, String? version, int? port, bool? https, @@ -512,7 +517,8 @@ class _DeviceCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Device, $Out> late final ClassMapperBase $mapper = DeviceMapper.ensureInitialized(); @override $R call( - {Object? ip = $none, + {Object? signalingId = $none, + Object? ip = $none, String? version, int? port, bool? https, @@ -523,6 +529,7 @@ class _DeviceCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Device, $Out> bool? download, Set? discoveryMethods}) => $apply(FieldCopyWithData({ + if (signalingId != $none) #signalingId: signalingId, if (ip != $none) #ip: ip, if (version != null) #version: version, if (port != null) #port: port, @@ -536,6 +543,7 @@ class _DeviceCopyWithImpl<$R, $Out> extends ClassCopyWithBase<$R, Device, $Out> })); @override Device $make(CopyWithData data) => Device( + signalingId: data.get(#signalingId, or: $value.signalingId), ip: data.get(#ip, or: $value.ip), version: data.get(#version, or: $value.version), port: data.get(#port, or: $value.port), diff --git a/common/lib/model/dto/info_dto.dart b/common/lib/model/dto/info_dto.dart index 9bbbbd7d..d9203c9c 100644 --- a/common/lib/model/dto/info_dto.dart +++ b/common/lib/model/dto/info_dto.dart @@ -30,6 +30,7 @@ extension InfoToDeviceExt on InfoDto { /// Since this HTTP request was successful, the [port] and [https] are known. Device toDevice(String ip, int port, bool https, DiscoveryMethod method) { return Device( + signalingId: null, ip: ip, version: version ?? fallbackProtocolVersion, port: port, diff --git a/common/lib/model/dto/info_register_dto.dart b/common/lib/model/dto/info_register_dto.dart index 79095705..18c3c816 100644 --- a/common/lib/model/dto/info_register_dto.dart +++ b/common/lib/model/dto/info_register_dto.dart @@ -36,6 +36,7 @@ class InfoRegisterDto with InfoRegisterDtoMappable { extension InfoRegisterDtoExt on InfoRegisterDto { Device toDevice(String ip, int ownPort, bool ownHttps, DiscoveryMethod? method) { return Device( + signalingId: null, ip: ip, version: version ?? fallbackProtocolVersion, port: port ?? ownPort, diff --git a/common/lib/model/dto/multicast_dto.dart b/common/lib/model/dto/multicast_dto.dart index bbe98449..fcca038b 100644 --- a/common/lib/model/dto/multicast_dto.dart +++ b/common/lib/model/dto/multicast_dto.dart @@ -39,6 +39,7 @@ class MulticastDto with MulticastDtoMappable { extension MulticastDtoToDeviceExt on MulticastDto { Device toDevice(String ip, int ownPort, bool ownHttps) { return Device( + signalingId: null, ip: ip, version: version ?? fallbackProtocolVersion, port: port ?? ownPort, diff --git a/common/lib/model/dto/register_dto.dart b/common/lib/model/dto/register_dto.dart index c7fcf56f..93ef6805 100644 --- a/common/lib/model/dto/register_dto.dart +++ b/common/lib/model/dto/register_dto.dart @@ -33,6 +33,7 @@ class RegisterDto with RegisterDtoMappable { extension RegisterDtoExt on RegisterDto { Device toDevice(String ip, int ownPort, bool ownHttps, DiscoveryMethod method) { return Device( + signalingId: null, ip: ip, version: version ?? fallbackProtocolVersion, port: port ?? ownPort,