fix(lib): add message checks and improve exceptions
This commit is contained in:
+25
-11
@@ -53,15 +53,15 @@ class MyApp extends StatelessWidget {
|
||||
),
|
||||
if (service.currentDeviceInfo != null)
|
||||
Text(
|
||||
'Device Name: ${service.currentDeviceInfo!.displayName}\n'
|
||||
'${Platform.isIOS ? 'Device ID: ${service.currentDeviceInfo!.id}' : ''}',
|
||||
'Device Name: ${service.currentDeviceInfo!.displayName}'
|
||||
'${Platform.isIOS ? '\nDevice ID: ${service.currentDeviceInfo!.id}' : ''}',
|
||||
),
|
||||
if (Platform.isIOS)
|
||||
Text(
|
||||
'You are ${service.isIOSBrowser ? 'going to find your friend' : 'waiting for another user to connect'}',
|
||||
),
|
||||
Text(
|
||||
'Communication channel state: ${service.communicationChannelState.name.toUpperCase()}',
|
||||
'Communication channel state: ${service.communicationChannelState.previewName}',
|
||||
)
|
||||
],
|
||||
),
|
||||
@@ -172,6 +172,16 @@ enum AppState {
|
||||
}
|
||||
}
|
||||
|
||||
extension on CommunicationChannelState {
|
||||
String get previewName {
|
||||
return switch (this) {
|
||||
CommunicationChannelState.notConnected => 'Not connected',
|
||||
CommunicationChannelState.loading => 'Connecting',
|
||||
CommunicationChannelState.connected => 'Connected',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class AppService extends ChangeNotifier {
|
||||
late final _nearbyService = NearbyService.getInstance()
|
||||
..communicationChannelState.addListener(notifyListeners);
|
||||
@@ -187,6 +197,12 @@ class AppService extends ChangeNotifier {
|
||||
StreamSubscription? peersSubscription;
|
||||
StreamSubscription? connectedDeviceSubscription;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
stopListeningAll();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
CommunicationChannelState get communicationChannelState {
|
||||
return _nearbyService.communicationChannelState.value;
|
||||
}
|
||||
@@ -328,7 +344,7 @@ class AppService extends ChangeNotifier {
|
||||
final wasConnected = connectedDevice?.status.isConnected ?? false;
|
||||
final nowConnected = event?.status.isConnected ?? false;
|
||||
if (wasConnected && !nowConnected) {
|
||||
restart();
|
||||
stopListeningAll();
|
||||
return;
|
||||
}
|
||||
connectedDevice = event;
|
||||
@@ -358,7 +374,7 @@ class AppService extends ChangeNotifier {
|
||||
Future<void> startCommunicationChannel({
|
||||
ValueChanged<ReceivedNearbyMessage>? listener,
|
||||
}) async {
|
||||
final eventListener = NearbyServiceStreamListener<ReceivedNearbyMessage>(
|
||||
final eventListener = NearbyServiceStreamListener(
|
||||
onCreated: (_) {
|
||||
updateState(AppState.communicationChannelCreated);
|
||||
},
|
||||
@@ -366,7 +382,7 @@ class AppService extends ChangeNotifier {
|
||||
listener?.call(event);
|
||||
},
|
||||
onError: (e, [StackTrace? s]) {
|
||||
restart();
|
||||
stopListeningAll();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -396,17 +412,15 @@ class AppService extends ChangeNotifier {
|
||||
print(e);
|
||||
}
|
||||
} finally {
|
||||
await restart();
|
||||
await stopListeningAll();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> restart() async {
|
||||
Future<void> stopListeningAll() async {
|
||||
await stopListeningConnectedDevice();
|
||||
await stopListeningPeers();
|
||||
await stopDiscovery();
|
||||
|
||||
await discover();
|
||||
}
|
||||
|
||||
void updateState(AppState state, {bool shouldNotify = true}) {
|
||||
@@ -768,7 +782,7 @@ class _ConnectedSocketBodyState extends State<_ConnectedSocketBody> {
|
||||
if (device == null) {
|
||||
return Center(
|
||||
child: _ActionButton(
|
||||
onTap: service.restart,
|
||||
onTap: service.stopListeningAll,
|
||||
title: 'Restart',
|
||||
),
|
||||
);
|
||||
|
||||
@@ -12,6 +12,13 @@ abstract class NearbyMessage {
|
||||
|
||||
final String value;
|
||||
|
||||
///
|
||||
/// Checks if [value] is not empty
|
||||
///
|
||||
bool get isValid {
|
||||
return value.isNotEmpty;
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
|
||||
@@ -27,6 +27,7 @@ class NearbySocketService {
|
||||
|
||||
String? _connectedDeviceId;
|
||||
WebSocket? _socket;
|
||||
HttpServer? _server;
|
||||
StreamSubscription<ReceivedNearbyMessage>? _messagesSubscription;
|
||||
|
||||
///
|
||||
@@ -72,21 +73,25 @@ class NearbySocketService {
|
||||
/// Add [OutgoingNearbyMessage]'s JSON representation to [_socket].
|
||||
///
|
||||
Future<bool> send(OutgoingNearbyMessage message) async {
|
||||
if (_socket != null && message.receiver.id == _connectedDeviceId) {
|
||||
final sender = await _manager.getCurrentDeviceInfo();
|
||||
if (sender != null) {
|
||||
_socket!.add(
|
||||
jsonEncode(
|
||||
{
|
||||
'message': message.value,
|
||||
'sender': sender.toJson(),
|
||||
},
|
||||
),
|
||||
);
|
||||
if (message.isValid) {
|
||||
if (_socket != null && message.receiver.id == _connectedDeviceId) {
|
||||
final sender = await _manager.getCurrentDeviceInfo();
|
||||
if (sender != null) {
|
||||
_socket!.add(
|
||||
jsonEncode(
|
||||
{
|
||||
'message': message.value,
|
||||
'sender': sender.toJson(),
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
} else {
|
||||
throw NearbyServiceException.invalidMessage(message.value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -96,8 +101,12 @@ class NearbySocketService {
|
||||
try {
|
||||
await _messagesSubscription?.cancel();
|
||||
_messagesSubscription = null;
|
||||
_socket?.close();
|
||||
_socket = null;
|
||||
_server?.close(force: true);
|
||||
_server = null;
|
||||
_connectedDeviceId = null;
|
||||
state.value = CommunicationChannelState.notConnected;
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@@ -142,11 +151,11 @@ class NearbySocketService {
|
||||
required int port,
|
||||
ValueChanged<HttpRequest>? serverListener,
|
||||
}) async {
|
||||
final httpServer = await _network.startServer(
|
||||
_server = await _network.startServer(
|
||||
ownerIpAddress: info.ownerIpAddress,
|
||||
port: port,
|
||||
);
|
||||
httpServer?.listen(
|
||||
_server?.listen(
|
||||
(request) async {
|
||||
serverListener?.call(request);
|
||||
final isPing = await _pingManager.checkPing(request);
|
||||
@@ -156,7 +165,7 @@ class NearbySocketService {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.uri.path == '/ws') {
|
||||
if (request.uri.path == _Urls.ws) {
|
||||
_socket = await WebSocketTransformer.upgrade(request);
|
||||
_createSocketSubscription(socketListener);
|
||||
} else {
|
||||
|
||||
@@ -5,6 +5,10 @@ class _Protocols {
|
||||
static const ws = 'ws://';
|
||||
}
|
||||
|
||||
class _Urls {
|
||||
static const ws = '/ws';
|
||||
}
|
||||
|
||||
class NearbyServiceNetwork {
|
||||
final _httpClient = HttpClient();
|
||||
final _random = Random();
|
||||
@@ -20,7 +24,7 @@ class NearbyServiceNetwork {
|
||||
final response = await request.close();
|
||||
return response;
|
||||
} catch (e) {
|
||||
Logger.error('Server is unreachable');
|
||||
Logger.error('Server is unreachable: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -37,7 +41,7 @@ class NearbyServiceNetwork {
|
||||
required int port,
|
||||
}) async {
|
||||
try {
|
||||
final url = 'ws://$ownerIpAddress:$port';
|
||||
final url = '${_Protocols.ws}$ownerIpAddress:$port';
|
||||
Logger.debug('Starting server on $url');
|
||||
var server = await HttpServer.bind(
|
||||
ownerIpAddress,
|
||||
@@ -47,8 +51,7 @@ class NearbyServiceNetwork {
|
||||
Logger.info('Server running on $url');
|
||||
return server;
|
||||
} catch (e) {
|
||||
Logger.error('Error starting socket: $e');
|
||||
return null;
|
||||
throw NearbyServiceException('Error starting socket: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,14 +61,14 @@ class NearbyServiceNetwork {
|
||||
}) async {
|
||||
try {
|
||||
final connectionId = _random.nextInt(1000) + 100;
|
||||
final url = '${_Protocols.ws}$ownerIpAddress:$port/ws?as=$connectionId';
|
||||
final url =
|
||||
'${_Protocols.ws}$ownerIpAddress:$port${_Urls.ws}?as=$connectionId';
|
||||
Logger.debug('Connecting to $url');
|
||||
final socket = await WebSocket.connect(url);
|
||||
Logger.info('Connected to $url');
|
||||
return socket;
|
||||
} catch (e) {
|
||||
Logger.error('Error connecting to server: $e');
|
||||
return null;
|
||||
throw NearbyServiceException('Error connecting to server: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +201,7 @@ class NearbyIOSService extends NearbyService {
|
||||
FutureOr<bool> endCommunicationChannel() async {
|
||||
await _messagesSubscription?.cancel();
|
||||
_messagesSubscription = null;
|
||||
_state.value = CommunicationChannelState.notConnected;
|
||||
Logger.debug('Communication channel was cancelled');
|
||||
return true;
|
||||
}
|
||||
@@ -211,7 +212,10 @@ class NearbyIOSService extends NearbyService {
|
||||
///
|
||||
@override
|
||||
Future<bool> send(OutgoingNearbyMessage message) {
|
||||
return NearbyServiceIOSPlatform.instance.send(message);
|
||||
if (message.isValid) {
|
||||
return NearbyServiceIOSPlatform.instance.send(message);
|
||||
}
|
||||
throw NearbyServiceException.invalidMessage(message.value);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -242,7 +246,7 @@ class NearbyIOSService extends NearbyService {
|
||||
if (value) {
|
||||
Logger.info(onSuccess);
|
||||
} else {
|
||||
Logger.error(onError);
|
||||
throw NearbyServiceException(onError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class NearbyCommunicationChannelData {
|
||||
///
|
||||
/// Listener for message stream changes.
|
||||
///
|
||||
final NearbyServiceStreamListener<ReceivedNearbyMessage> eventListener;
|
||||
final NearbyServiceStreamListener eventListener;
|
||||
|
||||
///
|
||||
/// Android-specific connection data.
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
|
||||
///
|
||||
/// Stream Subscription Listener.
|
||||
///
|
||||
class NearbyServiceStreamListener<T> {
|
||||
class NearbyServiceStreamListener {
|
||||
///
|
||||
/// It is required to pass the [onData] parameter to process the
|
||||
/// data that came through the stream.
|
||||
@@ -18,8 +19,8 @@ class NearbyServiceStreamListener<T> {
|
||||
this.cancelOnError,
|
||||
});
|
||||
|
||||
final ValueChanged<T> onData;
|
||||
final ValueChanged<StreamSubscription<T>>? onCreated;
|
||||
final ValueChanged<ReceivedNearbyMessage> onData;
|
||||
final ValueChanged<StreamSubscription<ReceivedNearbyMessage>>? onCreated;
|
||||
final VoidCallback? onDone;
|
||||
final void Function(Object, [StackTrace])? onError;
|
||||
final bool? cancelOnError;
|
||||
|
||||
@@ -30,5 +30,11 @@ class NearbyServiceException implements Exception {
|
||||
);
|
||||
}
|
||||
|
||||
factory NearbyServiceException.invalidMessage(String value) {
|
||||
return NearbyServiceException(
|
||||
'The message="$value" is not valid',
|
||||
);
|
||||
}
|
||||
|
||||
final Object? error;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user