@@ -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