Improve disconnect api (#192)
* Improve disconnect api * Get disconnection event on Web from callback * Wait for disconnection result on calling disconnect * Improve linux disconnection * Update Changelog * Fix Ai comments
This commit is contained in:
+95
-39
@@ -120,42 +120,18 @@ class UniversalBle {
|
||||
Duration? timeout,
|
||||
}) async {
|
||||
timeout ??= const Duration(seconds: 60);
|
||||
StreamSubscription? connectionSubscription;
|
||||
Completer<bool> completer = Completer();
|
||||
Completer<bool> completer =
|
||||
_connectionEventCompleter(deviceId, timeout: timeout);
|
||||
|
||||
void handleError(dynamic error) {
|
||||
if (completer.isCompleted) return;
|
||||
connectionSubscription?.cancel();
|
||||
completer.completeError(ConnectionException(error));
|
||||
}
|
||||
_platform.connect(deviceId, connectionTimeout: timeout).catchError(
|
||||
(error) {
|
||||
if (completer.isCompleted) return;
|
||||
completer.completeError(ConnectionException(error));
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
connectionSubscription = _platform
|
||||
.bleConnectionUpdateStreamController.stream
|
||||
.where((e) => e.deviceId == deviceId)
|
||||
.listen(
|
||||
(e) {
|
||||
if (e.error != null) {
|
||||
handleError(e.error);
|
||||
} else {
|
||||
if (!completer.isCompleted) {
|
||||
completer.complete(e.isConnected);
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: handleError,
|
||||
cancelOnError: true,
|
||||
);
|
||||
|
||||
_platform
|
||||
.connect(deviceId, connectionTimeout: timeout)
|
||||
.catchError(handleError);
|
||||
|
||||
if (!await completer.future.timeout(timeout)) {
|
||||
throw ConnectionException("Failed to connect");
|
||||
}
|
||||
} finally {
|
||||
connectionSubscription?.cancel();
|
||||
if (!await completer.future.timeout(timeout)) {
|
||||
throw ConnectionException("Failed to connect");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,11 +141,45 @@ class UniversalBle {
|
||||
String deviceId, {
|
||||
Duration? timeout,
|
||||
}) async {
|
||||
return await _bleCommandQueue.queueCommand(
|
||||
() => _platform.disconnect(deviceId),
|
||||
timeout: timeout,
|
||||
deviceId: deviceId,
|
||||
);
|
||||
timeout ??= const Duration(seconds: 60);
|
||||
BleConnectionState? connectionState;
|
||||
try {
|
||||
connectionState = await _platform.getConnectionState(deviceId);
|
||||
} catch (e) {
|
||||
UniversalLogger.logError("Get connection state failed: $e");
|
||||
}
|
||||
|
||||
if (connectionState == BleConnectionState.disconnected ||
|
||||
connectionState == BleConnectionState.disconnecting) {
|
||||
_platform.updateConnection(deviceId, false);
|
||||
UniversalLogger.logInfo(
|
||||
"Device $deviceId already disconnected: $connectionState",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Completer<bool> completer =
|
||||
_connectionEventCompleter(deviceId, timeout: timeout);
|
||||
|
||||
await _bleCommandQueue
|
||||
.queueCommand(() => _platform.disconnect(deviceId),
|
||||
timeout: timeout, deviceId: deviceId)
|
||||
.catchError(
|
||||
(error) {
|
||||
if (completer.isCompleted) return;
|
||||
completer.completeError(ConnectionException(error));
|
||||
},
|
||||
);
|
||||
|
||||
if (await completer.future.timeout(timeout)) {
|
||||
UniversalLogger.logError(
|
||||
"Device $deviceId is still connected after disconnect attempt",
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
UniversalLogger.logError("Disconnect failed: $e");
|
||||
}
|
||||
}
|
||||
|
||||
/// Discover services of a device.
|
||||
@@ -505,6 +515,52 @@ class UniversalBle {
|
||||
return read(deviceId, service, characteristic, timeout: timeout);
|
||||
}
|
||||
|
||||
static Completer<bool> _connectionEventCompleter(
|
||||
String deviceId, {
|
||||
Duration? timeout,
|
||||
}) {
|
||||
timeout ??= const Duration(seconds: 60);
|
||||
StreamSubscription? connectionSubscription;
|
||||
Completer<bool> completer = Completer();
|
||||
|
||||
void cancelSubscription() {
|
||||
connectionSubscription?.cancel();
|
||||
connectionSubscription = null;
|
||||
}
|
||||
|
||||
void handleError(dynamic error) {
|
||||
cancelSubscription();
|
||||
if (completer.isCompleted) return;
|
||||
completer.completeError(ConnectionException(error));
|
||||
}
|
||||
|
||||
connectionSubscription = _platform
|
||||
.bleConnectionUpdateStreamController.stream
|
||||
.where((e) => e.deviceId == deviceId)
|
||||
.listen(
|
||||
(e) {
|
||||
cancelSubscription();
|
||||
if (e.error != null) {
|
||||
handleError(e.error);
|
||||
} else {
|
||||
if (!completer.isCompleted) {
|
||||
completer.complete(e.isConnected);
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: handleError,
|
||||
cancelOnError: true,
|
||||
);
|
||||
|
||||
completer.future.timeout(timeout).then((_) {
|
||||
cancelSubscription();
|
||||
}).catchError((_) {
|
||||
cancelSubscription();
|
||||
});
|
||||
|
||||
return completer;
|
||||
}
|
||||
|
||||
static Future<void> _sendBleInputPropertyCommand(
|
||||
String deviceId,
|
||||
String service,
|
||||
|
||||
@@ -133,10 +133,7 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
|
||||
@override
|
||||
Future<BleConnectionState> getConnectionState(String deviceId) async {
|
||||
BlueZDevice? device = _devices[deviceId] ??
|
||||
_client.devices.cast<BlueZDevice?>().firstWhere(
|
||||
(device) => device?.address == deviceId,
|
||||
orElse: () => null);
|
||||
BlueZDevice? device = _getDeviceById(deviceId);
|
||||
bool connected = device?.connected ?? false;
|
||||
return connected
|
||||
? BleConnectionState.connected
|
||||
@@ -155,12 +152,11 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
|
||||
@override
|
||||
Future<void> disconnect(String deviceId) async {
|
||||
final device = _findDeviceById(deviceId);
|
||||
if (!device.connected) {
|
||||
updateConnection(deviceId, false);
|
||||
return;
|
||||
final device = _getDeviceById(deviceId);
|
||||
if (device?.connected == true) {
|
||||
await device?.disconnect();
|
||||
}
|
||||
await device.disconnect();
|
||||
updateConnection(deviceId, false);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -414,11 +410,10 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
: AvailabilityState.poweredOff;
|
||||
}
|
||||
|
||||
/// Find device by id from cache or from client
|
||||
/// Throws exception if device not found
|
||||
BlueZDevice _findDeviceById(String deviceId) {
|
||||
final device = _devices[deviceId] ??
|
||||
_client.devices.cast<BlueZDevice?>().firstWhere(
|
||||
(device) => device?.address == deviceId,
|
||||
orElse: () => null);
|
||||
final device = _getDeviceById(deviceId);
|
||||
if (device == null) {
|
||||
throw UniversalBleException(
|
||||
code: UniversalBleErrorCode.deviceNotFound,
|
||||
@@ -428,6 +423,14 @@ class UniversalBleLinux extends UniversalBlePlatform {
|
||||
return device;
|
||||
}
|
||||
|
||||
/// Get device by id from cache or from client
|
||||
BlueZDevice? _getDeviceById(String deviceId) {
|
||||
return _devices[deviceId] ??
|
||||
_client.devices.cast<BlueZDevice?>().firstWhere(
|
||||
(device) => device?.address == deviceId,
|
||||
orElse: () => null);
|
||||
}
|
||||
|
||||
Future<void> _ensureInitialized() async {
|
||||
if (isInitialized) return;
|
||||
|
||||
|
||||
@@ -58,8 +58,6 @@ class UniversalBleWeb extends UniversalBlePlatform {
|
||||
|
||||
@override
|
||||
Future<void> disconnect(String deviceId) async {
|
||||
_cleanConnection(deviceId);
|
||||
updateConnection(deviceId, false);
|
||||
_getDeviceById(deviceId)?.disconnect();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user