@@ -9,27 +9,13 @@ import { profile } from "./bluetooth-profile.js";
99import { ButtonService } from "./button-service.js" ;
1010import { BoardVersion , DeviceError } from "./device.js" ;
1111import { Logging , NullLogging } from "./logging.js" ;
12+ import { PromiseQueue } from "./promise-queue.js" ;
1213import {
1314 ServiceConnectionEventMap ,
1415 TypedServiceEvent ,
1516 TypedServiceEventDispatcher ,
1617} from "./service-events.js" ;
1718
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-
3319const deviceIdToWrapper : Map < string , BluetoothDeviceWrapper > = new Map ( ) ;
3420
3521const connectTimeoutDuration : number = 10000 ;
@@ -62,7 +48,7 @@ class ServiceInfo<T extends Service> {
6248 private serviceFactory : (
6349 gattServer : BluetoothRemoteGATTServer ,
6450 dispatcher : TypedServiceEventDispatcher ,
65- queueGattOperation : ( gattOperation : GattOperation ) => void ,
51+ queueGattOperation : < R > ( action : ( ) => Promise < R > ) => Promise < R > ,
6652 listenerInit : boolean ,
6753 ) => Promise < T | undefined > ,
6854 public events : TypedServiceEvent [ ] ,
@@ -75,7 +61,7 @@ class ServiceInfo<T extends Service> {
7561 async createIfNeeded (
7662 gattServer : BluetoothRemoteGATTServer ,
7763 dispatcher : TypedServiceEventDispatcher ,
78- queueGattOperation : ( gattOperation : GattOperation ) => void ,
64+ queueGattOperation : < R > ( action : ( ) => Promise < R > ) => Promise < R > ,
7965 listenerInit : boolean ,
8066 ) : Promise < T | undefined > {
8167 this . service =
@@ -132,11 +118,22 @@ export class BluetoothDeviceWrapper {
132118
133119 boardVersion : BoardVersion | undefined ;
134120
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+ } ) ;
138126 } ;
139127
128+ private gattOperations = new PromiseQueue ( {
129+ abortCheck : ( ) => {
130+ if ( ! this . device . gatt ?. connected ) {
131+ return this . disconnectedRejectionErrorFactory ;
132+ }
133+ return undefined ;
134+ } ,
135+ } ) ;
136+
140137 constructor (
141138 public readonly device : BluetoothDevice ,
142139 private logging : Logging = new NullLogging ( ) ,
@@ -357,55 +354,10 @@ export class BluetoothDeviceWrapper {
357354 }
358355 }
359356
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 ) ;
409361 }
410362
411363 private createIfNeeded < T extends Service > (
@@ -441,7 +393,7 @@ export class BluetoothDeviceWrapper {
441393
442394 private disposeServices ( ) {
443395 this . serviceInfo . forEach ( ( s ) => s . dispose ( ) ) ;
444- this . clearGattQueueOnDisconnect ( ) ;
396+ this . gattOperations . clear ( this . disconnectedRejectionErrorFactory ) ;
445397 }
446398}
447399
0 commit comments