[Bluetooth] Implement re-registering GATT services on server start 87/240887/14
authorPawel Wasowski <p.wasowski2@samsung.com>
Wed, 12 Aug 2020 10:48:16 +0000 (12:48 +0200)
committerPiotr Kosko <p.kosko@samsung.com>
Wed, 9 Sep 2020 06:21:38 +0000 (06:21 +0000)
The services, that are once successfully registered on the local GATT
server will be present on it and re-registered on each start() call.
This commit implements re-registering services on start.

[Verification] Reregistering works - services that were present before
stop() are reregistered in the server after start().

Change-Id: I973ab73f652a8faa72fa2c933ae27666e1fe611a
Signed-off-by: Pawel Wasowski <p.wasowski2@samsung.com>
src/bluetooth/bluetooth_api.js

index 5cd6005..d030dca 100755 (executable)
@@ -3221,6 +3221,13 @@ BluetoothAdapter.prototype.getBluetoothProfileHandler = function() {
 // class BluetoothGATTServer ////////////////////////
 var _BluetoothGATTServerServices = [];
 
+/*
+ * This set is used in BluetoothGATTServer::start() to check which services
+ * from BluetoothGATTServer::services have already been registered in native
+ * layer and which have to be registered.
+ */
+var _BluetoothGATTServerServicesRegisteredInNativeLayer = {};
+
 var BluetoothGATTServer = function() {
     Object.defineProperties(this, {
         services: {
@@ -3296,6 +3303,46 @@ BluetoothGATTServer.prototype.registerService = function() {
     }
 };
 
+/*
+ * Objects of this class are used to wait for multiple callbacks results.
+ *
+ * Its successCallback and errorCallback members should be passed as
+ * the success and error callbacks, respectively, to the functions we wait for.
+ * When the functions we wait for are called callbacksNum times, either
+ * onAllSucceeded or onFailure is called, depending on whether only
+ * successCallback was called or not.
+ *
+ * For the usage example, take a look at BluetoothGATTServer.prototype.start,
+ * where it's used to wait for registration of multiple services.
+ */
+var ResultCallbacksAggregator = function(callbacksNum, onAllSucceeded, onFailure) {
+    var _callbacksNum = callbacksNum;
+    var _allSucceeded = true;
+    var _error;
+
+    this.successCallback = function (){
+      _callbacksNum--;
+
+      if (!_callbacksNum) {
+        if (_allSucceeded) {
+          onAllSucceeded();
+        } else {
+          onFailure(_error);
+        }
+      }
+    };
+
+    this.errorCallback = function(error) {
+      _callbacksNum--;
+      _allSucceeded = false;
+      _error = error;
+
+      if (!_callbacksNum) {
+          onFailure(_error);
+      }
+    };
+};
+
 var BluetoothGATTServer_valid_start_errors = ['InvalidStateError', 'NotSupportedError', 'AbortError'];
 var BluetoothGATTServer_valid_start_exceptions = ['InvalidStateError', 'TypeMismatchError', 'SecurityError'];
 
@@ -3316,7 +3363,16 @@ BluetoothGATTServer.prototype.start = function() {
         }
     ]);
 
-    var callback = function(result) {
+    var servicesUnregisteredInNativeLayer = [];
+    for (var i = 0; i < this.services.length; ++i) {
+        if(this.services[i]) {
+            if (!_BluetoothGATTServerServicesRegisteredInNativeLayer[this.services[i]._id]) {
+                servicesUnregisteredInNativeLayer.push(this.services[i]);
+            }
+        }
+    }
+
+    var startServerCallback = function(result) {
         if (native.isFailure(result)) {
             native.callIfPossible(args.errorCallback,
                                   native.getErrorObjectAndValidate(result,
@@ -3326,9 +3382,48 @@ BluetoothGATTServer.prototype.start = function() {
         }
     };
 
-    var result = native.call('BluetoothGATTServerStart', {}, callback);
-    if (native.isFailure(result)) {
-        throw native.getErrorObjectAndValidate(result, BluetoothGATTServer_valid_start_exceptions, AbortError);
+    if (servicesUnregisteredInNativeLayer.length) {
+      var registerServiceCallbacksAggregator = new ResultCallbacksAggregator(servicesUnregisteredInNativeLayer.length,
+          function onAllSucceeded() {
+
+              var result = native.call('BluetoothGATTServerStart', {}, startServerCallback);
+
+              if (native.isFailure(result)) {
+                  throw native.getErrorObjectAndValidate(result, BluetoothGATTServer_valid_start_exceptions, AbortError);
+              }
+          },
+          function onFailure(error) {
+              native.callIfPossible(args.errorCallback,
+                                    native.getErrorObjectAndValidate(error,
+                                      BluetoothGATTServer_valid_start_errors, AbortError));
+          });
+
+      var registerServicesCallback = function(result) {
+          if (native.isFailure(result)) {
+              registerServiceCallbacksAggregator.errorCallback(
+                                    native.getErrorObjectAndValidate(result,
+                                      BluetoothGATTServer_valid_start_errors, AbortError));
+          } else {
+              registerServiceCallbacksAggregator.successCallback();
+          }
+      };
+
+      for (var i = 0; i < servicesUnregisteredInNativeLayer.length; ++i) {
+        var result = native.call('BluetoothGATTServerRegisterService', servicesUnregisteredInNativeLayer[i], registerServicesCallback);
+        if (native.isFailure(result)) {
+            throw native.getErrorObjectAndValidate(
+                result,
+                BluetoothGATTServer_valid_registerService_exceptions,
+                AbortError
+            );
+        }
+      }
+    } else {
+        var result = native.call('BluetoothGATTServerStart', {}, startServerCallback);
+
+        if (native.isFailure(result)) {
+            throw native.getErrorObjectAndValidate(result, BluetoothGATTServer_valid_start_exceptions, AbortError);
+        }
     }
 }
 
@@ -3358,6 +3453,7 @@ BluetoothGATTServer.prototype.stop = function() {
                                   native.getErrorObjectAndValidate(result,
                                     BluetoothGATTServer_valid_stop_errors, AbortError));
         } else {
+            _BluetoothGATTServerServicesRegisteredInNativeLayer = {};
             native.callIfPossible(args.successCallback);
         }
     };