From e1071afbc0a1dab99543880d74bf31b7f575f01c Mon Sep 17 00:00:00 2001 From: Nikita Poltorapavlo Date: Mon, 27 Nov 2023 10:59:29 +0200 Subject: [PATCH 1/4] RDK-45037 : Secure Storage Thunder Plugin Reason for change: Enhancements to PersistentStore plugin to support Scope, Time To Live. Use of the RPC COM and JSON RPC interfaces. Test Procedure: None Risks: None Signed-off-by: Nikita Poltorapavlo --- interfaces/IStore2.h | 54 ++++ interfaces/IStoreInspector.h | 54 ++++ interfaces/Ids.h | 4 + jsonrpc/PersistentStore.json | 480 +++++++++++++++++++++++++++++++++++ 4 files changed, 592 insertions(+) create mode 100644 interfaces/IStore2.h create mode 100644 interfaces/IStoreInspector.h create mode 100644 jsonrpc/PersistentStore.json diff --git a/interfaces/IStore2.h b/interfaces/IStore2.h new file mode 100644 index 00000000..d385231a --- /dev/null +++ b/interfaces/IStore2.h @@ -0,0 +1,54 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Module.h" + +namespace WPEFramework { +namespace Exchange { + + struct EXTERNAL IStore2 : virtual public Core::IUnknown { + enum { ID = ID_STORE2 }; + + virtual ~IStore2() override = default; + + enum class ScopeType : uint8_t { + DEVICE, + ACCOUNT + }; + + struct EXTERNAL INotification : virtual public Core::IUnknown { + enum { ID = ID_STORE2_NOTIFICATION }; + + virtual ~INotification() override = default; + + virtual void ValueChanged(const string& ns, const string& key, const string& value, const ScopeType scope) = 0; + }; + + virtual uint32_t Register(Exchange::IStore2::INotification* notification) = 0; + virtual uint32_t Unregister(Exchange::IStore2::INotification* notification) = 0; + virtual uint32_t SetValue(const string& ns, const string& key, const string& value, const ScopeType scope, const uint32_t ttl) = 0; + virtual uint32_t GetValue(const string& ns, const string& key, const ScopeType scope, string& value /* @out */, uint32_t& ttl /* @out */) = 0; + virtual uint32_t DeleteKey(const string& ns, const string& key, const ScopeType scope) = 0; + virtual uint32_t DeleteNamespace(const string& ns, const ScopeType scope) = 0; + }; + +} // namespace Exchange +} // namespace WPEFramework diff --git a/interfaces/IStoreInspector.h b/interfaces/IStoreInspector.h new file mode 100644 index 00000000..37652ed9 --- /dev/null +++ b/interfaces/IStoreInspector.h @@ -0,0 +1,54 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Module.h" + +// @stubgen:include + +namespace WPEFramework { +namespace Exchange { + + struct EXTERNAL IStoreInspector : virtual public Core::IUnknown { + enum { ID = ID_STORE_INSPECTOR }; + + virtual ~IStoreInspector() override = default; + + enum class ScopeType : uint8_t { + DEVICE, + ACCOUNT + }; + + struct NamespaceSize { + string ns; + uint32_t size; + }; + + using INamespaceSizeIterator = RPC::IIteratorType; + + virtual uint32_t SetNamespaceStorageLimit(const string& ns, const uint32_t size, const ScopeType scope) = 0; + virtual uint32_t GetNamespaceStorageLimit(const string& ns, const ScopeType scope, uint32_t& size /* @out */) = 0; + virtual uint32_t GetKeys(const string& ns, const ScopeType scope, RPC::IStringIterator*& keys /* @out */) = 0; + virtual uint32_t GetNamespaces(const ScopeType scope, RPC::IStringIterator*& namespaces /* @out */) = 0; + virtual uint32_t GetStorageSizes(const ScopeType scope, INamespaceSizeIterator*& storageList /* @out */) = 0; + }; + +} // namespace Exchange +} // namespace WPEFramework diff --git a/interfaces/Ids.h b/interfaces/Ids.h index 0d97ae4d..e6c4856b 100644 --- a/interfaces/Ids.h +++ b/interfaces/Ids.h @@ -317,6 +317,10 @@ namespace Exchange { ID_STORE = RPC::IDS::ID_EXTERNAL_INTERFACE_OFFSET + 0x440, ID_STORE_NOTIFICATION = ID_STORE + 1, ID_STORE_CACHE = ID_STORE + 2, + ID_STORE2 = ID_STORE + 3, + ID_STORE2_NOTIFICATION = ID_STORE + 4, + ID_STORE_INSPECTOR = ID_STORE + 5, + ID_STORE_INSPECTOR_NAMESPACE_SIZE_ITERATOR = ID_STORE + 6, ID_LISA = RPC::IDS::ID_EXTERNAL_INTERFACE_OFFSET + 0x450, ID_LISA_NOTIFICATION = ID_LISA + 1, diff --git a/jsonrpc/PersistentStore.json b/jsonrpc/PersistentStore.json new file mode 100644 index 00000000..0eab3418 --- /dev/null +++ b/jsonrpc/PersistentStore.json @@ -0,0 +1,480 @@ +{ + "$schema": "interface.schema.json", + "jsonrpc": "2.0", + "info": { + "title": "PertsistentStore API", + "class": "PersistentStore", + "description": "Persistent Store JSON-RPC interface" + }, + "common": { + "$ref": "common.json" + }, + "definitions": { + "namespace": { + "summary": "Namespace", + "type": "string", + "example": "ns1" + }, + "key": { + "summary": "Key", + "type": "string", + "example": "key1" + }, + "value": { + "summary": "Value", + "type": "string", + "example": "value1" + }, + "scope": { + "summary": "Scope", + "type": "string", + "enum": [ + "device", + "account" + ], + "default": "device", + "example": "device" + }, + "size": { + "summary": "Size in bytes", + "type": "number", + "example": 100 + }, + "ttl": { + "summary": "Time in seconds", + "type": "number", + "example": 100 + }, + "success": { + "summary": "Legacy parameter (always true)", + "type": "boolean", + "default": true, + "example": true + } + }, + "methods": { + "deleteKey": { + "summary": "Deletes a key from the specified namespace", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "key": { + "$ref": "#/definitions/key" + }, + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [ + "namespace", + "key" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/definitions/success" + } + }, + "required": [ + "success" + ] + }, + "errors": [ + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "deleteNamespace": { + "summary": "Deletes the specified namespace", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [ + "namespace" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/definitions/success" + } + }, + "required": [ + "success" + ] + }, + "errors": [ + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "flushCache": { + "summary": "Flushes the device cache", + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/definitions/success" + } + }, + "required": [ + "success" + ] + }, + "errors": [ + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "getKeys": { + "summary": "Returns the keys that are stored in the specified namespace", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [ + "namespace" + ] + }, + "result": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "items": { + "$ref": "#/definitions/key" + } + }, + "success": { + "$ref": "#/definitions/success" + } + }, + "required": [ + "keys", + "success" + ] + }, + "errors": [ + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "getNamespaces": { + "summary": "Returns the namespaces", + "params": { + "type": "object", + "properties": { + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [] + }, + "result": { + "type": "object", + "properties": { + "namespaces": { + "type": "array", + "items": { + "$ref": "#/definitions/namespace" + } + }, + "success": { + "$ref": "#/definitions/success" + } + }, + "required": [ + "namespaces", + "success" + ] + }, + "errors": [ + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "getStorageSizes": { + "summary": "Returns the size occupied by each namespace", + "params": { + "type": "object", + "properties": { + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [] + }, + "result": { + "type": "object", + "properties": { + "storageList": { + "type": "array", + "items": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "size": { + "$ref": "#/definitions/size" + } + }, + "required": [ + "namespace", + "size" + ] + } + } + }, + "required": [ + "storageList" + ] + }, + "errors": [ + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "getValue": { + "summary": "Returns the value of a key from the specified namespace", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "key": { + "$ref": "#/definitions/key" + }, + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [ + "namespace", + "key" + ] + }, + "result": { + "type": "object", + "properties": { + "value": { + "$ref": "#/definitions/value" + }, + "success": { + "$ref": "#/definitions/success" + }, + "ttl": { + "$ref": "#/definitions/ttl" + } + }, + "required": [ + "value", + "success" + ] + }, + "errors": [ + { + "description": "Time is not synced", + "$ref": "#/common/errors/pendingconditions" + }, + { + "description": "Unknown namespace", + "$ref": "#/common/errors/notexist" + }, + { + "description": "Unknown key", + "$ref": "#/common/errors/unknownkey" + }, + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "setValue": { + "summary": "Sets the value of a key in the the specified namespace", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "key": { + "$ref": "#/definitions/key" + }, + "value": { + "$ref": "#/definitions/value" + }, + "scope": { + "$ref": "#/definitions/scope" + }, + "ttl": { + "$ref": "#/definitions/ttl" + } + }, + "required": [ + "namespace", + "key", + "value" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/definitions/success" + } + }, + "required": [ + "success" + ] + }, + "errors": [ + { + "description": "Time is not synced", + "$ref": "#/common/errors/pendingconditions" + }, + { + "description": "Empty/too large namespace or key, or the storage doesn't have enough space", + "$ref": "#/common/errors/invalidinputlength" + }, + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "setNamespaceStorageLimit": { + "summary": "Sets the storage limit for a given namespace", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "storageLimit": { + "$ref": "#/definitions/size" + }, + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [ + "namespace", + "storageLimit" + ] + }, + "result": { + "$ref": "#/common/results/void" + }, + "errors": [ + { + "description": "Empty/too large namespace, or the storage doesn't have enough space", + "$ref": "#/common/errors/invalidinputlength" + }, + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + }, + "getNamespaceStorageLimit": { + "summary": "Returns the storage limit for a given namespace", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [ + "namespace" + ] + }, + "result": { + "type": "object", + "properties": { + "storageLimit": { + "$ref": "#/definitions/size" + } + }, + "required": [ + "storageLimit" + ] + }, + "errors": [ + { + "description": "Unknown namespace", + "$ref": "#/common/errors/notexist" + }, + { + "description": "Unknown error", + "$ref": "#/common/errors/general" + } + ] + } + }, + "events": { + "onValueChanged": { + "summary": "Triggered whenever any of the values stored are changed using setValue", + "params": { + "type": "object", + "properties": { + "namespace": { + "$ref": "#/definitions/namespace" + }, + "key": { + "$ref": "#/definitions/key" + }, + "value": { + "$ref": "#/definitions/value" + }, + "scope": { + "$ref": "#/definitions/scope" + } + }, + "required": [ + "namespace", + "key", + "value", + "scope" + ] + } + } + } +} \ No newline at end of file From 07a99d847053c3f9f6a2763d3df1b0cc19fdada2 Mon Sep 17 00:00:00 2001 From: Nikita Poltorapavlo Date: Fri, 19 Jan 2024 14:22:35 +0200 Subject: [PATCH 2/4] remove duplicate enum, reorder params --- interfaces/IStore2.h | 12 ++++++------ interfaces/IStoreInspector.h | 13 ++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/interfaces/IStore2.h b/interfaces/IStore2.h index d385231a..f321ec67 100644 --- a/interfaces/IStore2.h +++ b/interfaces/IStore2.h @@ -29,7 +29,7 @@ namespace Exchange { virtual ~IStore2() override = default; - enum class ScopeType : uint8_t { + enum ScopeType : uint8_t { DEVICE, ACCOUNT }; @@ -39,15 +39,15 @@ namespace Exchange { virtual ~INotification() override = default; - virtual void ValueChanged(const string& ns, const string& key, const string& value, const ScopeType scope) = 0; + virtual void ValueChanged(const ScopeType scope, const string& ns, const string& key, const string& value) = 0; }; virtual uint32_t Register(Exchange::IStore2::INotification* notification) = 0; virtual uint32_t Unregister(Exchange::IStore2::INotification* notification) = 0; - virtual uint32_t SetValue(const string& ns, const string& key, const string& value, const ScopeType scope, const uint32_t ttl) = 0; - virtual uint32_t GetValue(const string& ns, const string& key, const ScopeType scope, string& value /* @out */, uint32_t& ttl /* @out */) = 0; - virtual uint32_t DeleteKey(const string& ns, const string& key, const ScopeType scope) = 0; - virtual uint32_t DeleteNamespace(const string& ns, const ScopeType scope) = 0; + virtual uint32_t SetValue(const ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) = 0; + virtual uint32_t GetValue(const ScopeType scope, const string& ns, const string& key, string& value /* @out */, uint32_t& ttl /* @out */) = 0; + virtual uint32_t DeleteKey(const ScopeType scope, const string& ns, const string& key) = 0; + virtual uint32_t DeleteNamespace(const ScopeType scope, const string& ns) = 0; }; } // namespace Exchange diff --git a/interfaces/IStoreInspector.h b/interfaces/IStoreInspector.h index 37652ed9..1ceda0b9 100644 --- a/interfaces/IStoreInspector.h +++ b/interfaces/IStoreInspector.h @@ -21,6 +21,8 @@ #include "Module.h" +#include "IStore2.h" + // @stubgen:include namespace WPEFramework { @@ -31,10 +33,7 @@ namespace Exchange { virtual ~IStoreInspector() override = default; - enum class ScopeType : uint8_t { - DEVICE, - ACCOUNT - }; + using ScopeType = IStore2::ScopeType; struct NamespaceSize { string ns; @@ -43,9 +42,9 @@ namespace Exchange { using INamespaceSizeIterator = RPC::IIteratorType; - virtual uint32_t SetNamespaceStorageLimit(const string& ns, const uint32_t size, const ScopeType scope) = 0; - virtual uint32_t GetNamespaceStorageLimit(const string& ns, const ScopeType scope, uint32_t& size /* @out */) = 0; - virtual uint32_t GetKeys(const string& ns, const ScopeType scope, RPC::IStringIterator*& keys /* @out */) = 0; + virtual uint32_t SetNamespaceStorageLimit(const ScopeType scope, const string& ns, const uint32_t size) = 0; + virtual uint32_t GetNamespaceStorageLimit(const ScopeType scope, const string& ns, uint32_t& size /* @out */) = 0; + virtual uint32_t GetKeys(const ScopeType scope, const string& ns, RPC::IStringIterator*& keys /* @out */) = 0; virtual uint32_t GetNamespaces(const ScopeType scope, RPC::IStringIterator*& namespaces /* @out */) = 0; virtual uint32_t GetStorageSizes(const ScopeType scope, INamespaceSizeIterator*& storageList /* @out */) = 0; }; From 3e809f8444771d7784b33636629b24b95d06d6be Mon Sep 17 00:00:00 2001 From: Nikita Poltorapavlo Date: Fri, 19 Jan 2024 19:28:14 +0200 Subject: [PATCH 3/4] move interfaces to one file because otherwise it doesn't build, move limit apis into a separate interface --- interfaces/IStore2.h | 33 ++++++++++++++++++++++ interfaces/IStoreInspector.h | 53 ------------------------------------ interfaces/Ids.h | 1 + 3 files changed, 34 insertions(+), 53 deletions(-) delete mode 100644 interfaces/IStoreInspector.h diff --git a/interfaces/IStore2.h b/interfaces/IStore2.h index f321ec67..1f1ab92c 100644 --- a/interfaces/IStore2.h +++ b/interfaces/IStore2.h @@ -21,6 +21,8 @@ #include "Module.h" +// @stubgen:include + namespace WPEFramework { namespace Exchange { @@ -44,11 +46,42 @@ namespace Exchange { virtual uint32_t Register(Exchange::IStore2::INotification* notification) = 0; virtual uint32_t Unregister(Exchange::IStore2::INotification* notification) = 0; + virtual uint32_t SetValue(const ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) = 0; virtual uint32_t GetValue(const ScopeType scope, const string& ns, const string& key, string& value /* @out */, uint32_t& ttl /* @out */) = 0; virtual uint32_t DeleteKey(const ScopeType scope, const string& ns, const string& key) = 0; virtual uint32_t DeleteNamespace(const ScopeType scope, const string& ns) = 0; }; + struct EXTERNAL IStoreInspector : virtual public Core::IUnknown { + enum { ID = ID_STORE_INSPECTOR }; + + virtual ~IStoreInspector() override = default; + + struct NamespaceSize { + string ns; + uint32_t size; + }; + + using ScopeType = IStore2::ScopeType; + using IStringIterator = RPC::IIteratorType; + using INamespaceSizeIterator = RPC::IIteratorType; + + virtual uint32_t GetKeys(const ScopeType scope, const string& ns, IStringIterator*& keys /* @out */) = 0; + virtual uint32_t GetNamespaces(const ScopeType scope, IStringIterator*& namespaces /* @out */) = 0; + virtual uint32_t GetStorageSizes(const ScopeType scope, INamespaceSizeIterator*& storageList /* @out */) = 0; + }; + + struct EXTERNAL IStoreLimit : virtual public Core::IUnknown { + enum { ID = ID_STORE_LIMIT }; + + virtual ~IStoreLimit() override = default; + + using ScopeType = IStore2::ScopeType; + + virtual uint32_t SetNamespaceStorageLimit(const ScopeType scope, const string& ns, const uint32_t size) = 0; + virtual uint32_t GetNamespaceStorageLimit(const ScopeType scope, const string& ns, uint32_t& size /* @out */) = 0; + }; + } // namespace Exchange } // namespace WPEFramework diff --git a/interfaces/IStoreInspector.h b/interfaces/IStoreInspector.h deleted file mode 100644 index 1ceda0b9..00000000 --- a/interfaces/IStoreInspector.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2022 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Module.h" - -#include "IStore2.h" - -// @stubgen:include - -namespace WPEFramework { -namespace Exchange { - - struct EXTERNAL IStoreInspector : virtual public Core::IUnknown { - enum { ID = ID_STORE_INSPECTOR }; - - virtual ~IStoreInspector() override = default; - - using ScopeType = IStore2::ScopeType; - - struct NamespaceSize { - string ns; - uint32_t size; - }; - - using INamespaceSizeIterator = RPC::IIteratorType; - - virtual uint32_t SetNamespaceStorageLimit(const ScopeType scope, const string& ns, const uint32_t size) = 0; - virtual uint32_t GetNamespaceStorageLimit(const ScopeType scope, const string& ns, uint32_t& size /* @out */) = 0; - virtual uint32_t GetKeys(const ScopeType scope, const string& ns, RPC::IStringIterator*& keys /* @out */) = 0; - virtual uint32_t GetNamespaces(const ScopeType scope, RPC::IStringIterator*& namespaces /* @out */) = 0; - virtual uint32_t GetStorageSizes(const ScopeType scope, INamespaceSizeIterator*& storageList /* @out */) = 0; - }; - -} // namespace Exchange -} // namespace WPEFramework diff --git a/interfaces/Ids.h b/interfaces/Ids.h index b553e6fe..c2ee007f 100644 --- a/interfaces/Ids.h +++ b/interfaces/Ids.h @@ -322,6 +322,7 @@ namespace Exchange { ID_STORE2_NOTIFICATION = ID_STORE + 4, ID_STORE_INSPECTOR = ID_STORE + 5, ID_STORE_INSPECTOR_NAMESPACE_SIZE_ITERATOR = ID_STORE + 6, + ID_STORE_LIMIT = ID_STORE + 7, ID_LISA = RPC::IDS::ID_EXTERNAL_INTERFACE_OFFSET + 0x450, ID_LISA_NOTIFICATION = ID_LISA + 1, From 17249312cbdf78989e887bc34bb2b316f4e4f7c3 Mon Sep 17 00:00:00 2001 From: Nikita Poltorapavlo Date: Sat, 20 Jan 2024 18:08:09 +0200 Subject: [PATCH 4/4] override implies virtual, remove virtual --- interfaces/IStore2.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interfaces/IStore2.h b/interfaces/IStore2.h index 1f1ab92c..6f4810ed 100644 --- a/interfaces/IStore2.h +++ b/interfaces/IStore2.h @@ -29,7 +29,7 @@ namespace Exchange { struct EXTERNAL IStore2 : virtual public Core::IUnknown { enum { ID = ID_STORE2 }; - virtual ~IStore2() override = default; + ~IStore2() override = default; enum ScopeType : uint8_t { DEVICE, @@ -39,7 +39,7 @@ namespace Exchange { struct EXTERNAL INotification : virtual public Core::IUnknown { enum { ID = ID_STORE2_NOTIFICATION }; - virtual ~INotification() override = default; + ~INotification() override = default; virtual void ValueChanged(const ScopeType scope, const string& ns, const string& key, const string& value) = 0; }; @@ -56,7 +56,7 @@ namespace Exchange { struct EXTERNAL IStoreInspector : virtual public Core::IUnknown { enum { ID = ID_STORE_INSPECTOR }; - virtual ~IStoreInspector() override = default; + ~IStoreInspector() override = default; struct NamespaceSize { string ns; @@ -75,7 +75,7 @@ namespace Exchange { struct EXTERNAL IStoreLimit : virtual public Core::IUnknown { enum { ID = ID_STORE_LIMIT }; - virtual ~IStoreLimit() override = default; + ~IStoreLimit() override = default; using ScopeType = IStore2::ScopeType;