[Bluetooth] Reregister read/write value request callbacks on server start 81/244281/6
authorPawel Wasowski <p.wasowski2@samsung.com>
Wed, 16 Sep 2020 04:04:54 +0000 (06:04 +0200)
committerPiotr Kosko <p.kosko@samsung.com>
Mon, 21 Sep 2020 08:16:36 +0000 (08:16 +0000)
This commit implements reregistering read/write value callbacks,
that were once registered before a BluetoothGATTServer::stop() call.

[Verification] Tested in Chrome DevTools, callbacks are reregistered
after restarting the server

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

index 152454f..1e0b5f5 100755 (executable)
@@ -4023,6 +4023,52 @@ var ResultCallbacksAggregator = function(callbacksNum, onAllSucceeded, onFailure
     };
 };
 
+function _getServicesUnregisteredInNativeLayer() {
+    var servicesUnregisteredInNativeLayer = [];
+    for (var i = 0; i < _BluetoothGATTServerServices.length; ++i) {
+        if (
+            !_BluetoothGATTServerServicesRegisteredInNativeLayer[
+                _BluetoothGATTServerServices[i]._id
+            ]
+        ) {
+            servicesUnregisteredInNativeLayer.push(_BluetoothGATTServerServices[i]);
+        }
+    }
+    return servicesUnregisteredInNativeLayer;
+}
+
+function _getIdsToReregisterReadWriteCallbacks(servicesUnregisteredInNativeLayer) {
+    var idsToRegisterWriteValueCallbacks = [];
+    var idsToRegisterReadValueCallbacks = [];
+
+    for (var i = 0; i < servicesUnregisteredInNativeLayer.length; ++i) {
+        var serviceComponentIds = _getIncludedServicesAndItsComponentsIdsRecursively(
+            servicesUnregisteredInNativeLayer[i]
+        );
+
+        for (var j = 0; j < serviceComponentIds.length; ++j) {
+            var _id = serviceComponentIds[j];
+            var callbackName = 'ReadValueCallback' + _id;
+
+            /*
+             * Only some of the serviceComponentIds are characteristics and descriptors
+             * and within them, only some have read/write callbacks registered.
+             * We have to check if the callbacks were registered for each id.
+             */
+            if (callbackName in _BluetoothGATTServerReadWriteValueRequestCallbacks) {
+                idsToRegisterReadValueCallbacks.push(_id);
+            }
+
+            callbackName = 'WriteValueCallback' + _id;
+            if (callbackName in _BluetoothGATTServerReadWriteValueRequestCallbacks) {
+                idsToRegisterWriteValueCallbacks.push(_id);
+            }
+        }
+    }
+
+    return [idsToRegisterReadValueCallbacks, idsToRegisterWriteValueCallbacks];
+}
+
 var BluetoothGATTServer_valid_start_errors = [
     'InvalidStateError',
     'NotSupportedError',
@@ -4034,6 +4080,33 @@ var BluetoothGATTServer_valid_start_exceptions = [
     'SecurityError'
 ];
 
+function _reregisterCallback(_id, nativeFunction, successCallback, errorCallback) {
+    /*
+     * This function should only be used to reregister read/write value request
+     * callbacks in native layer for characteristics/descriptors, that have
+     * had such callbacks registered before the last server's stop().
+     * As JS listeners corresponding to these callbacks already exist in JS,
+     * only C++ callbacks have to be reregistered.
+     */
+    var callback = function(result) {
+        if (native.isFailure(result)) {
+            errorCallback(native.getErrorObject(result));
+        } else {
+            successCallback();
+        }
+    };
+
+    var result = native.call(nativeFunction, { _id: _id }, callback);
+
+    if (native.isFailure(result)) {
+        throw native.getErrorObjectAndValidate(
+            result,
+            BluetoothGATTServer_valid_start_exceptions,
+            AbortError
+        );
+    }
+}
+
 BluetoothGATTServer.prototype.start = function() {
     privUtils_.log('Entered BluetoothGATTServer.start()');
     var args = AV.validateArgs(arguments, [
@@ -4051,16 +4124,19 @@ BluetoothGATTServer.prototype.start = function() {
         }
     ]);
 
-    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 servicesUnregisteredInNativeLayer = _getServicesUnregisteredInNativeLayer();
+    /*
+     * Characteristics and descriptors that were registered in the server before the last stop() call
+     * could have had read/write value request callbacks registered.
+     * These callbacks have to be reregistered (only) in native layer.
+     * These arrays contain _ids of characteristics and descriptors, that will have their callbacks
+     * reregistered.
+     */
+    var idsToReregisterReadWriteValueCallbacks = _getIdsToReregisterReadWriteCallbacks(
+        servicesUnregisteredInNativeLayer
+    );
+    var idsToReregisterReadValueCallbacks = idsToReregisterReadWriteValueCallbacks[0];
+    var idsToReregisterWriteValueCallbacks = idsToReregisterReadWriteValueCallbacks[1];
 
     var startServerCallback = function(result) {
         if (native.isFailure(result)) {
@@ -4078,8 +4154,12 @@ BluetoothGATTServer.prototype.start = function() {
     };
 
     if (servicesUnregisteredInNativeLayer.length) {
+        var numberOfCallbacksToWaitFor =
+            servicesUnregisteredInNativeLayer.length +
+            idsToReregisterReadValueCallbacks.length +
+            idsToReregisterWriteValueCallbacks.length;
         var registerServiceCallbacksAggregator = new ResultCallbacksAggregator(
-            servicesUnregisteredInNativeLayer.length,
+            numberOfCallbacksToWaitFor,
             function onAllSucceeded() {
                 var result = native.call(
                     'BluetoothGATTServerStart',
@@ -4109,13 +4189,7 @@ BluetoothGATTServer.prototype.start = function() {
 
         var registerServicesCallback = function(result) {
             if (native.isFailure(result)) {
-                registerServiceCallbacksAggregator.errorCallback(
-                    native.getErrorObjectAndValidate(
-                        result,
-                        BluetoothGATTServer_valid_start_errors,
-                        AbortError
-                    )
-                );
+                registerServiceCallbacksAggregator.errorCallback(result);
             } else {
                 registerServiceCallbacksAggregator.successCallback();
             }
@@ -4135,6 +4209,24 @@ BluetoothGATTServer.prototype.start = function() {
                 );
             }
         }
+
+        for (var i = 0; i < idsToReregisterReadValueCallbacks.length; ++i) {
+            _reregisterCallback(
+                idsToReregisterReadValueCallbacks[i],
+                'BluetoothGATTServerSetReadValueRequestCallback',
+                registerServiceCallbacksAggregator.successCallback,
+                registerServiceCallbacksAggregator.errorCallback
+            );
+        }
+
+        for (var i = 0; i < idsToReregisterWriteValueCallbacks.length; ++i) {
+            _reregisterCallback(
+                idsToReregisterWriteValueCallbacks[i],
+                'BluetoothGATTServerSetWriteValueRequestCallback',
+                registerServiceCallbacksAggregator.successCallback,
+                registerServiceCallbacksAggregator.errorCallback
+            );
+        }
     } else {
         var result = native.call('BluetoothGATTServerStart', {}, startServerCallback);
 
index e39e858..fe05c02 100644 (file)
@@ -450,6 +450,11 @@ PlatformResult BluetoothGATTServerService::SetReadValueRequestCallback(
   auto _id = static_cast<int>(args.get(kId).get<double>());
   LoggerD("Setting read value request callback for a GATT entity with _id: %d", _id);
 
+  if (gatt_objects_.find(_id) == gatt_objects_.end()) {
+    LoggerE("No GATT handle for entity with _id [%d]", _id);
+    return common::PlatformResult{ErrorCode::ABORT_ERR, "Failed to set read value request callback"};
+  }
+
   auto gatt_handle = gatt_objects_[_id];
   callback_names_[std::make_pair(gatt_handle, kReadCallback)] =
       "ReadValueRequestCallback_" + std::to_string(_id);
@@ -502,6 +507,11 @@ PlatformResult BluetoothGATTServerService::SetWriteValueRequestCallback(
   auto _id = static_cast<int>(args.get(kId).get<double>());
   LoggerD("Setting write value request callback for a GATT entity with _id: %d", _id);
 
+  if (gatt_objects_.find(_id) == gatt_objects_.end()) {
+    LoggerE("No GATT handle for entity with _id [%d]", _id);
+    return common::PlatformResult{ErrorCode::ABORT_ERR, "Failed to set write value request callback"};
+  }
+
   auto gatt_handle = gatt_objects_[_id];
   callback_names_[std::make_pair(gatt_handle, kWriteCallback)] =
       "WriteValueRequestCallback_" + std::to_string(_id);