@@ -9,27 +9,13 @@ import { profile } from "./bluetooth-profile.js";
9
9
import { ButtonService } from "./button-service.js" ;
10
10
import { BoardVersion , DeviceError } from "./device.js" ;
11
11
import { Logging , NullLogging } from "./logging.js" ;
12
+ import { PromiseQueue } from "./promise-queue.js" ;
12
13
import {
13
14
ServiceConnectionEventMap ,
14
15
TypedServiceEvent ,
15
16
TypedServiceEventDispatcher ,
16
17
} from "./service-events.js" ;
17
18
18
- export interface GattOperationCallback {
19
- resolve : ( result : DataView | void ) => void ;
20
- reject : ( error : DeviceError ) => void ;
21
- }
22
-
23
- export interface GattOperation {
24
- operation : ( ) => Promise < DataView | void > ;
25
- callback : GattOperationCallback ;
26
- }
27
-
28
- interface GattOperations {
29
- busy : boolean ;
30
- queue : GattOperation [ ] ;
31
- }
32
-
33
19
const deviceIdToWrapper : Map < string , BluetoothDeviceWrapper > = new Map ( ) ;
34
20
35
21
const connectTimeoutDuration : number = 10000 ;
@@ -62,7 +48,7 @@ class ServiceInfo<T extends Service> {
62
48
private serviceFactory : (
63
49
gattServer : BluetoothRemoteGATTServer ,
64
50
dispatcher : TypedServiceEventDispatcher ,
65
- queueGattOperation : ( gattOperation : GattOperation ) => void ,
51
+ queueGattOperation : < R > ( action : ( ) => Promise < R > ) => Promise < R > ,
66
52
listenerInit : boolean ,
67
53
) => Promise < T | undefined > ,
68
54
public events : TypedServiceEvent [ ] ,
@@ -75,7 +61,7 @@ class ServiceInfo<T extends Service> {
75
61
async createIfNeeded (
76
62
gattServer : BluetoothRemoteGATTServer ,
77
63
dispatcher : TypedServiceEventDispatcher ,
78
- queueGattOperation : ( gattOperation : GattOperation ) => void ,
64
+ queueGattOperation : < R > ( action : ( ) => Promise < R > ) => Promise < R > ,
79
65
listenerInit : boolean ,
80
66
) : Promise < T | undefined > {
81
67
this . service =
@@ -132,11 +118,22 @@ export class BluetoothDeviceWrapper {
132
118
133
119
boardVersion : BoardVersion | undefined ;
134
120
135
- private gattOperations : GattOperations = {
136
- busy : false ,
137
- queue : [ ] ,
121
+ private disconnectedRejectionErrorFactory = ( ) => {
122
+ return new DeviceError ( {
123
+ code : "device-disconnected" ,
124
+ message : "Error processing gatt operations queue - device disconnected" ,
125
+ } ) ;
138
126
} ;
139
127
128
+ private gattOperations = new PromiseQueue ( {
129
+ abortCheck : ( ) => {
130
+ if ( ! this . device . gatt ?. connected ) {
131
+ return this . disconnectedRejectionErrorFactory ;
132
+ }
133
+ return undefined ;
134
+ } ,
135
+ } ) ;
136
+
140
137
constructor (
141
138
public readonly device : BluetoothDevice ,
142
139
private logging : Logging = new NullLogging ( ) ,
@@ -357,55 +354,10 @@ export class BluetoothDeviceWrapper {
357
354
}
358
355
}
359
356
360
- private queueGattOperation ( gattOperation : GattOperation ) {
361
- this . gattOperations . queue . push ( gattOperation ) ;
362
- this . processGattOperationQueue ( ) ;
363
- }
364
-
365
- private processGattOperationQueue = ( ) : void => {
366
- if ( ! this . device . gatt ?. connected ) {
367
- // No longer connected. Drop queue.
368
- this . clearGattQueueOnDisconnect ( ) ;
369
- return ;
370
- }
371
- if ( this . gattOperations . busy ) {
372
- // We will finish processing the current operation, then
373
- // pick up processing the queue in the finally block.
374
- return ;
375
- }
376
- const gattOperation = this . gattOperations . queue . shift ( ) ;
377
- if ( ! gattOperation ) {
378
- return ;
379
- }
380
- this . gattOperations . busy = true ;
381
- gattOperation
382
- . operation ( )
383
- . then ( ( result ) => {
384
- gattOperation . callback . resolve ( result ) ;
385
- } )
386
- . catch ( ( err ) => {
387
- gattOperation . callback . reject (
388
- new DeviceError ( { code : "background-comms-error" , message : err } ) ,
389
- ) ;
390
- this . logging . error ( "Error processing gatt operations queue" , err ) ;
391
- } )
392
- . finally ( ( ) => {
393
- this . gattOperations . busy = false ;
394
- this . processGattOperationQueue ( ) ;
395
- } ) ;
396
- } ;
397
-
398
- private clearGattQueueOnDisconnect ( ) {
399
- this . gattOperations . queue . forEach ( ( op ) => {
400
- op . callback . reject (
401
- new DeviceError ( {
402
- code : "device-disconnected" ,
403
- message :
404
- "Error processing gatt operations queue - device disconnected" ,
405
- } ) ,
406
- ) ;
407
- } ) ;
408
- this . gattOperations = { busy : false , queue : [ ] } ;
357
+ private queueGattOperation < T > ( action : ( ) => Promise < T > ) : Promise < T > {
358
+ // Previously we wrapped rejections with:
359
+ // new DeviceError({ code: "background-comms-error", message: err }),
360
+ return this . gattOperations . add ( action ) ;
409
361
}
410
362
411
363
private createIfNeeded < T extends Service > (
@@ -441,7 +393,7 @@ export class BluetoothDeviceWrapper {
441
393
442
394
private disposeServices ( ) {
443
395
this . serviceInfo . forEach ( ( s ) => s . dispose ( ) ) ;
444
- this . clearGattQueueOnDisconnect ( ) ;
396
+ this . gattOperations . clear ( this . disconnectedRejectionErrorFactory ) ;
445
397
}
446
398
}
447
399
0 commit comments