Mercurial > hg > orthanc
changeset 6104:49674012ab49 attach-custom-data
wip: queues for plugins
line wrap: on
line diff
--- a/NEWS Fri May 09 09:16:09 2025 +0200 +++ b/NEWS Fri May 09 16:14:42 2025 +0200 @@ -6,15 +6,13 @@ * SQLite default DB engine now supports metadata and attachment revisions. * Upgraded the DB to allow plugins to store customData for each attachment. -* New sample Advanced Storage plugin that allows: - - using multiple disk for image storage, - - use more human friendly storage structure (experimental feature). Plugins ------- -* New database plugin SDK (vX) to handle customData for attachments and key-value store. +* New database plugin SDK (vX) to handle customData for attachments, key-value stores and queues. * New storage plugin SDK (v3) to handle customData for attachments. +* New functions available to all plugins to store key-values and queues. Version 1.12.7 (2025-04-07)
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Fri May 09 16:14:42 2025 +0200 @@ -1451,26 +1451,39 @@ throw OrthancException(ErrorCode_InternalError); // Not supported } - virtual void StoreKeyValue(const std::string& pluginId, + virtual void StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_InternalError); // Not supported } - virtual void DeleteKeyValue(const std::string& pluginId, + virtual void DeleteKeyValue(const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_InternalError); // Not supported } virtual bool GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_InternalError); // Not supported } + virtual void EnqueueValue(const std::string& queueId, + const std::string& value) ORTHANC_OVERRIDE + { + throw OrthancException(ErrorCode_InternalError); // Not supported + } + + virtual bool DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin) ORTHANC_OVERRIDE + { + throw OrthancException(ErrorCode_InternalError); // Not supported + } + };
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Fri May 09 16:14:42 2025 +0200 @@ -1064,26 +1064,39 @@ throw OrthancException(ErrorCode_InternalError); // Not supported } - virtual void StoreKeyValue(const std::string& pluginId, + virtual void StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_InternalError); // Not supported } - virtual void DeleteKeyValue(const std::string& pluginId, + virtual void DeleteKeyValue(const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_InternalError); // Not supported } virtual bool GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_InternalError); // Not supported } + virtual void EnqueueValue(const std::string& queueId, + const std::string& value) ORTHANC_OVERRIDE + { + throw OrthancException(ErrorCode_InternalError); // Not supported + } + + virtual bool DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin) ORTHANC_OVERRIDE + { + throw OrthancException(ErrorCode_InternalError); // Not supported + } + };
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Fri May 09 16:14:42 2025 +0200 @@ -1808,26 +1808,39 @@ } } - virtual void StoreKeyValue(const std::string& pluginId, + virtual void StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_NotImplemented); // TODO_ATTACH_CUSTOM_DATA } - virtual void DeleteKeyValue(const std::string& pluginId, + virtual void DeleteKeyValue(const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_NotImplemented); // TODO_ATTACH_CUSTOM_DATA } virtual bool GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { throw OrthancException(ErrorCode_NotImplemented); // TODO_ATTACH_CUSTOM_DATA } + virtual void EnqueueValue(const std::string& queueId, + const std::string& value) ORTHANC_OVERRIDE + { + throw OrthancException(ErrorCode_InternalError); // Not supported + } + + virtual bool DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin) ORTHANC_OVERRIDE + { + throw OrthancException(ErrorCode_InternalError); // Not supported + } + }; @@ -1919,6 +1932,7 @@ dbCapabilities_.SetHasExtendedChanges(systemInfo.has_extended_changes()); dbCapabilities_.SetHasFindSupport(systemInfo.supports_find()); dbCapabilities_.SetHasKeyValueStore(systemInfo.has_key_value_store()); + dbCapabilities_.SetHasQueue(systemInfo.has_queue()); } open_ = true;
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Fri May 09 16:14:42 2025 +0200 @@ -4720,6 +4720,38 @@ } } + bool OrthancPlugins::HasQueue() + { + PImpl::ServerContextReference lock(*pimpl_); + + return lock.GetContext().GetIndex().HasQueue(); + } + + void OrthancPlugins::ApplyEnqueueValue(const _OrthancPluginEnqueueValue& parameters) + { + PImpl::ServerContextReference lock(*pimpl_); + std::string value(parameters.value, parameters.valueSize); + + lock.GetContext().GetIndex().EnqueueValue(parameters.pluginIdentifier, value); + } + + bool OrthancPlugins::ApplyDequeueValue(const _OrthancPluginDequeueValue& parameters) + { + PImpl::ServerContextReference lock(*pimpl_); + + std::string value; + + if (lock.GetContext().GetIndex().DequeueValue(value, parameters.pluginIdentifier, Plugins::Convert(parameters.origin))) + { + CopyToMemoryBuffer(*parameters.value, value.size() > 0 ? value.c_str() : NULL, value.size()); + return true; + } + else + { + return false; + } + } + void OrthancPlugins::ApplyLoadDicomInstance(const _OrthancPluginLoadDicomInstance& params) { std::unique_ptr<IDicomInstance> target; @@ -5844,6 +5876,40 @@ } } + case _OrthancPluginService_EnqueueValue: + { + if (!HasQueue()) + { + LOG(ERROR) << "The DB engine does not support Queues"; + return false; + } + + const _OrthancPluginEnqueueValue& p = + *reinterpret_cast<const _OrthancPluginEnqueueValue*>(parameters); + ApplyEnqueueValue(p); + return true; + } + + case _OrthancPluginService_DequeueValue: + { + if (!HasQueue()) + { + LOG(ERROR) << "The DB engine does not support Queues"; + return false; + } + + const _OrthancPluginDequeueValue& p = + *reinterpret_cast<const _OrthancPluginDequeueValue*>(parameters); + if (ApplyDequeueValue(p)) + { + return true; + } + else + { + throw OrthancException(ErrorCode_UnknownResource); + } + } + default: return false; }
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Fri May 09 16:14:42 2025 +0200 @@ -233,6 +233,12 @@ bool ApplyGetKeyValue(const _OrthancPluginGetKeyValue& parameters); + bool HasQueue(); + + void ApplyEnqueueValue(const _OrthancPluginEnqueueValue& parameters); + + bool ApplyDequeueValue(const _OrthancPluginDequeueValue& parameters); + void ComputeHash(_OrthancPluginService service, const void* parameters);
--- a/OrthancServer/Plugins/Engine/PluginsEnumerations.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsEnumerations.cpp Fri May 09 16:14:42 2025 +0200 @@ -745,5 +745,35 @@ } } + OrthancPluginQueueOrigin Convert(QueueOrigin origin) + { + switch (origin) + { + case QueueOrigin_Front: + return OrthancPluginQueueOrigin_Front; + + case QueueOrigin_Back: + return OrthancPluginQueueOrigin_Back; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + QueueOrigin Convert(OrthancPluginQueueOrigin origin) + { + switch (origin) + { + case OrthancPluginQueueOrigin_Front: + return QueueOrigin_Front; + + case OrthancPluginQueueOrigin_Back: + return QueueOrigin_Back; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + } }
--- a/OrthancServer/Plugins/Engine/PluginsEnumerations.h Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsEnumerations.h Fri May 09 16:14:42 2025 +0200 @@ -81,6 +81,10 @@ OrthancPluginStoreStatus Convert(StoreStatus type); StoreStatus Convert(OrthancPluginStoreStatus type); + + OrthancPluginQueueOrigin Convert(QueueOrigin type); + + QueueOrigin Convert(OrthancPluginQueueOrigin type); } }
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Fri May 09 16:14:42 2025 +0200 @@ -473,6 +473,8 @@ _OrthancPluginService_StoreKeyValue = 47, /* New in Orthanc 1.12.99 */ _OrthancPluginService_DeleteKeyValue = 48, /* New in Orthanc 1.12.99 */ _OrthancPluginService_GetKeyValue = 49, /* New in Orthanc 1.12.99 */ + _OrthancPluginService_EnqueueValue = 50, /* New in Orthanc 1.12.99 */ + _OrthancPluginService_DequeueValue = 51, /* New in Orthanc 1.12.99 */ /* Registration of callbacks */ @@ -1144,10 +1146,25 @@ OrthancPluginStoreStatus_AlreadyStored = 1, /*!< The file has already been stored/adopted (only if OverwriteInstances is set to false)*/ OrthancPluginStoreStatus_Failure = 2, /*!< The file could not be stored/adopted */ OrthancPluginStoreStatus_FilteredOut = 3, /*!< The file has been filtered out by a lua script or a plugin */ - OrthancPluginStoreStatus_StorageFull = 4 /*!< The storage is full (only if MaximumStorageSize/MaximumPatientCount is set and MaximumStorageMode is Reject)*/ + OrthancPluginStoreStatus_StorageFull = 4, /*!< The storage is full (only if MaximumStorageSize/MaximumPatientCount is set and MaximumStorageMode is Reject)*/ + + _OrthancPluginStoreStatus_INTERNAL = 0x7fffffff } OrthancPluginStoreStatus; /** + * The supported types of enqueuing + **/ + typedef enum + { + OrthancPluginQueueOrigin_Front = 0, /*!< Pop from the front of the queue */ + OrthancPluginQueueOrigin_Back = 1, /*!< Pop from the back of the queue */ + + _OrthancPluginQueueOrigin_INTERNAL = 0x7fffffff + } OrthancPluginQueueOrigin; + + + + /** * @brief A 32-bit memory buffer allocated by the core system of Orthanc. * * A memory buffer allocated by the core system of Orthanc. When the @@ -9832,7 +9849,10 @@ * @brief Tell Orthanc to store a key-value in its store. * * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). -TODO_ATTACH_CUSTOM_DATA TODO TODO + * @param pluginIdentifier A unique identifier identifying both the plugin and the store + * @param key The key of the value to store (Note: pluginIdentifier + key must be unique) + * @param value The value to store + * @param valueSize The lenght of the value to store **/ ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStoreKeyValue( OrthancPluginContext* context, @@ -9860,7 +9880,8 @@ * @brief Tell Orthanc to delete a key-value from its store. * * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). -TODO_ATTACH_CUSTOM_DATA TODO TODO + * @param pluginIdentifier A unique identifier identifying both the plugin and the store + * @param key The key of the value to store (Note: pluginIdentifier + key must be unique) **/ ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginDeleteKeyValue( OrthancPluginContext* context, @@ -9885,7 +9906,9 @@ * @brief Get the value associated to this key in the key-value store. * * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). -TODO_ATTACH_CUSTOM_DATA TODO TODO + * @param pluginIdentifier A unique identifier identifying both the plugin and the store + * @param key The key of the value to retrieve from the store (Note: pluginIdentifier + key must be unique) + * @param value The value retrieved from the store **/ ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetKeyValue( OrthancPluginContext* context, @@ -9901,6 +9924,65 @@ return context->InvokeService(context, _OrthancPluginService_GetKeyValue, ¶ms); } + + typedef struct + { + const char* pluginIdentifier; + const char* value; + uint64_t valueSize; + } _OrthancPluginEnqueueValue; + + /** + * @brief Tell Orthanc to store a value in a queue. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param pluginIdentifier A unique identifier identifying both the plugin and the queue + * @param value The value to store + * @param valueSize The lenght of the value to store + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginEnqueueValue( + OrthancPluginContext* context, + const char* pluginIdentifier, /* in */ + const char* value, /* in */ + uint64_t valueSize /* in */) + { + _OrthancPluginEnqueueValue params; + params.pluginIdentifier = pluginIdentifier; + params.value = value; + params.valueSize = valueSize; + + return context->InvokeService(context, _OrthancPluginService_EnqueueValue, ¶ms); + } + + typedef struct + { + const char* pluginIdentifier; + OrthancPluginQueueOrigin origin; + OrthancPluginMemoryBuffer* value; + } _OrthancPluginDequeueValue; + + /** + * @brief Dequeue a value from a queue. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param pluginIdentifier A unique identifier identifying both the plugin and the store + * @param origin The extremity of the queue the value is dequeue from (back for LIFO or front for FIFO) + * @param value The value retrieved from the queue + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginDequeueValue( + OrthancPluginContext* context, + const char* pluginIdentifier, /* in */ + OrthancPluginQueueOrigin origin, /* in */ + OrthancPluginMemoryBuffer* value /* out */) + { + _OrthancPluginDequeueValue params; + params.pluginIdentifier = pluginIdentifier; + params.origin = origin; + params.value = value; + + return context->InvokeService(context, _OrthancPluginService_DequeueValue, ¶ms); + } + #ifdef __cplusplus } #endif
--- a/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto Fri May 09 16:14:42 2025 +0200 @@ -95,6 +95,11 @@ ORDERING_CAST_FLOAT = 2; } +enum QueueOrigin { + QUEUE_ORIGIN_FRONT = 0; + QUEUE_ORIGIN_BACK = 1; +} + message ServerIndexChange { int64 seq = 1; int32 change_type = 2; // opaque "ChangeType" in Orthanc @@ -168,6 +173,7 @@ bool supports_find = 8; // New in Orthanc 1.12.5 bool has_extended_changes = 9; // New in Orthanc 1.12.5 bool has_key_value_store = 10; // New in Orthanc 1.12.99 + bool has_queue = 11; // New in Orthanc 1.12.99 } } @@ -326,6 +332,8 @@ OPERATION_STORE_KEY_VALUE = 53; // New in Orthanc 1.12.99 OPERATION_DELETE_KEY_VALUE = 54; // New in Orthanc 1.12.99 OPERATION_GET_KEY_VALUE = 55; // New in Orthanc 1.12.99 + OPERATION_ENQUEUE_VALUE = 56; // New in Orthanc 1.12.99 + OPERATION_DEQUEUE_VALUE = 57; // New in Orthanc 1.12.99 } message Rollback { @@ -1011,6 +1019,26 @@ } } +message EnqueueValue { + message Request { + string plugin_id = 1; + string value = 2; + } + + message Response { + } +} + +message DequeueValue { + message Request { + string plugin_id = 1; + QueueOrigin origin = 2; + } + + message Response { + string value = 1; + } +} message TransactionRequest { sfixed64 transaction = 1; @@ -1072,6 +1100,8 @@ StoreKeyValue.Request store_key_value = 153; DeleteKeyValue.Request delete_key_value = 154; GetKeyValue.Request get_key_value = 155; + EnqueueValue.Request enqueue_value = 156; + DequeueValue.Request dequeue_value = 157; } message TransactionResponse { @@ -1131,6 +1161,8 @@ StoreKeyValue.Response store_key_value = 153; DeleteKeyValue.Response delete_key_value = 154; GetKeyValue.Response get_key_value = 155; + EnqueueValue.Request enqueue_value = 156; + DequeueValue.Request dequeue_value = 157; } enum RequestType {
--- a/OrthancServer/Sources/Database/IDatabaseWrapper.h Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/Database/IDatabaseWrapper.h Fri May 09 16:14:42 2025 +0200 @@ -58,6 +58,7 @@ bool hasExtendedChanges_; bool hasAttachmentCustomDataSupport_; bool hasKeyValueStore_; + bool hasQueue_; public: Capabilities() : @@ -70,7 +71,8 @@ hasFindSupport_(false), hasExtendedChanges_(false), hasAttachmentCustomDataSupport_(false), - hasKeyValueStore_(false) + hasKeyValueStore_(false), + hasQueue_(false) { } @@ -173,6 +175,16 @@ { return hasKeyValueStore_; } + + void SetHasQueue(bool value) + { + hasQueue_ = value; + } + + bool HasQueue() const + { + return hasQueue_; + } }; @@ -416,18 +428,28 @@ const std::set<ChangeType>& filterType) = 0; // New in Orthanc 1.12.99 - virtual void StoreKeyValue(const std::string& pluginId, + virtual void StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value) = 0; // New in Orthanc 1.12.99 - virtual void DeleteKeyValue(const std::string& pluginId, + virtual void DeleteKeyValue(const std::string& storeId, const std::string& key) = 0; // New in Orthanc 1.12.99 virtual bool GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key) = 0; + + // New in Orthanc 1.12.99 + virtual void EnqueueValue(const std::string& queueId, + const std::string& value) = 0; + + // New in Orthanc 1.12.99 + virtual bool DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin) = 0; + };
--- a/OrthancServer/Sources/Database/InstallKeyValueStore.sql Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/Database/InstallKeyValueStore.sql Fri May 09 16:14:42 2025 +0200 @@ -19,11 +19,19 @@ -- along with this program. If not, see <http://www.gnu.org/licenses/>. -CREATE TABLE KeyValueStore( - pluginId TEXT NOT NULL, +CREATE TABLE KeyValueStores( + storeId TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, - PRIMARY KEY(pluginId, key) -- Prevents duplicates + PRIMARY KEY(storeId, key) -- Prevents duplicates ); -CREATE INDEX KeyValueStoreIndex ON KeyValueStore (pluginId, key); +CREATE INDEX KeyValueStoresIndex ON KeyValueStores (storeId, key); + +CREATE TABLE Queues ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + queueId TEXT NOT NULL, + value TEXT +); + +CREATE INDEX QueuesIndex ON Queues (queueId, id);
--- a/OrthancServer/Sources/Database/PrepareDatabase.sql Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/Database/PrepareDatabase.sql Fri May 09 16:14:42 2025 +0200 @@ -160,15 +160,24 @@ END; -- new in Orthanc 1.12.99 -CREATE TABLE KeyValueStore( - pluginId TEXT NOT NULL, +CREATE TABLE KeyValueStores( + storeId TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, - PRIMARY KEY(pluginId, key) -- Prevents duplicates + PRIMARY KEY(storeId, key) -- Prevents duplicates ); -- new in Orthanc 1.12.99 -CREATE INDEX KeyValueStoreIndex ON KeyValueStore (pluginId, key); +CREATE INDEX KeyValueStoresIndex ON KeyValueStore (storeId, key); + +-- new in Orthanc 1.12.99 +CREATE TABLE Queues ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + queueId TEXT NOT NULL, + value TEXT +); + +CREATE INDEX QueuesIndex ON Queues (queueId, id); -- Set the version of the database schema -- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Fri May 09 16:14:42 2025 +0200 @@ -2103,33 +2103,33 @@ } } - virtual void StoreKeyValue(const std::string& pluginId, + virtual void StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value) ORTHANC_OVERRIDE { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO KeyValueStore (pluginId, key, value) VALUES(?, ?, ?)"); - s.BindString(0, pluginId); + SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO KeyValueStore (storeId, key, value) VALUES(?, ?, ?)"); + s.BindString(0, storeId); s.BindString(1, key); s.BindString(2, value); s.Run(); } - virtual void DeleteKeyValue(const std::string& pluginId, + virtual void DeleteKeyValue(const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM KeyValueStore WHERE pluginId = ? AND key = ?"); - s.BindString(0, pluginId); + SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM KeyValueStore WHERE storeId = ? AND key = ?"); + s.BindString(0, storeId); s.BindString(1, key); s.Run(); } virtual bool GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key) ORTHANC_OVERRIDE { SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM KeyValueStore WHERE pluginId=? AND key=?"); - s.BindString(0, pluginId); + "SELECT value FROM KeyValueStore WHERE storeId=? AND key=?"); + s.BindString(0, storeId); s.BindString(1, key); if (!s.Step()) @@ -2144,6 +2144,58 @@ } } + // New in Orthanc 1.12.99 + virtual void EnqueueValue(const std::string& queueId, + const std::string& value) ORTHANC_OVERRIDE + { + SQLite::Statement s(db_, SQLITE_FROM_HERE, + "INSERT INTO Queues (queueId, value) VALUES (?, ?)"); + s.BindString(0, queueId); + s.BindString(1, value); + s.Run(); + } + + // New in Orthanc 1.12.99 + virtual bool DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin) ORTHANC_OVERRIDE + { + int64_t rowId; + std::unique_ptr<SQLite::Statement> s; + + switch (origin) + { + case QueueOrigin_Front: + s.reset(new SQLite::Statement(db_, SQLITE_FROM_HERE, "SELECT id, value FROM KeyValueStore WHERE queueId=? ORDER BY id ASC LIMIT 1")); + break; + case QueueOrigin_Back: + s.reset(new SQLite::Statement(db_, SQLITE_FROM_HERE, "SELECT id, value FROM KeyValueStore WHERE queueId=? ORDER BY id DESC LIMIT 1")); + break; + default: + throw OrthancException(ErrorCode_InternalError); + } + + s->BindString(0, queueId); + if (!s->Step()) + { + // No value found + return false; + } + else + { + rowId = s->ColumnInt64(0); + value = s->ColumnString(1); + + SQLite::Statement s2(db_, SQLITE_FROM_HERE, + "DELETE FROM Queues WHERE id = ?"); + s2.BindInt64(0, rowId); + s2.Run(); + + return true; + } + } + + }; @@ -2344,6 +2396,7 @@ dbCapabilities_.SetHasExtendedChanges(true); dbCapabilities_.SetHasFindSupport(HasIntegratedFind()); dbCapabilities_.SetHasKeyValueStore(true); + dbCapabilities_.SetHasQueue(true); db_.Open(path); } @@ -2359,6 +2412,7 @@ dbCapabilities_.SetHasExtendedChanges(true); dbCapabilities_.SetHasFindSupport(HasIntegratedFind()); dbCapabilities_.SetHasKeyValueStore(true); + dbCapabilities_.SetHasQueue(true); db_.OpenInMemory(); }
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Fri May 09 16:14:42 2025 +0200 @@ -3206,6 +3206,12 @@ return db_.GetDatabaseCapabilities().HasKeyValueStore(); } + bool StatelessDatabaseOperations::HasQueue() + { + boost::shared_lock<boost::shared_mutex> lock(mutex_); + return db_.GetDatabaseCapabilities().HasQueue(); + } + void StatelessDatabaseOperations::ExecuteCount(uint64_t& count, const FindRequest& request) { @@ -3327,22 +3333,22 @@ } } - void StatelessDatabaseOperations::StoreKeyValue(const std::string& pluginId, + void StatelessDatabaseOperations::StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value) { class Operations : public IReadWriteOperations { private: - const std::string& pluginId_; + const std::string& storeId_; const std::string& key_; const std::string& value_; public: - Operations(const std::string& pluginId, + Operations(const std::string& storeId, const std::string& key, const std::string& value) : - pluginId_(pluginId), + storeId_(storeId), key_(key), value_(value) { @@ -3350,43 +3356,43 @@ virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE { - transaction.StoreKeyValue(pluginId_, key_, value_); + transaction.StoreKeyValue(storeId_, key_, value_); } }; - Operations operations(pluginId, key, value); + Operations operations(storeId, key, value); Apply(operations); } - void StatelessDatabaseOperations::DeleteKeyValue(const std::string& pluginId, + void StatelessDatabaseOperations::DeleteKeyValue(const std::string& storeId, const std::string& key) { class Operations : public IReadWriteOperations { private: - const std::string& pluginId_; + const std::string& storeId_; const std::string& key_; public: - Operations(const std::string& pluginId, + Operations(const std::string& storeId, const std::string& key) : - pluginId_(pluginId), + storeId_(storeId), key_(key) { } virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE { - transaction.DeleteKeyValue(pluginId_, key_); + transaction.DeleteKeyValue(storeId_, key_); } }; - Operations operations(pluginId, key); + Operations operations(storeId, key); Apply(operations); } bool StatelessDatabaseOperations::GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key) { class Operations : public ReadOnlyOperationsT3<std::string&, const std::string&, const std::string& > @@ -3410,10 +3416,76 @@ }; Operations operations; - operations.Apply(*this, value, pluginId, key); + operations.Apply(*this, value, storeId, key); return operations.HasFound(); } + void StatelessDatabaseOperations::EnqueueValue(const std::string& queueId, + const std::string& value) + { + class Operations : public IReadWriteOperations + { + private: + const std::string& queueId_; + const std::string& value_; + + public: + Operations(const std::string& queueId, + const std::string& value) : + queueId_(queueId), + value_(value) + { + } + + virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE + { + transaction.EnqueueValue(queueId_, value_); + } + }; + + Operations operations(queueId, value); + Apply(operations); + } + + bool StatelessDatabaseOperations::DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin) + { + class Operations : public IReadWriteOperations + { + private: + const std::string& queueId_; + std::string& value_; + QueueOrigin origin_; + bool found_; + + public: + Operations(std::string& value, + const std::string& queueId, + QueueOrigin origin) : + queueId_(queueId), + value_(value), + origin_(origin), + found_(false) + { + } + + bool HasFound() + { + return found_; + } + + virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE + { + found_ = transaction.DequeueValue(value_, queueId_, origin_); + } + }; + + Operations operations(value, queueId, origin); + Apply(operations); + + return operations.HasFound(); + } }
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Fri May 09 16:14:42 2025 +0200 @@ -295,10 +295,10 @@ } bool GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key) { - return transaction_.GetKeyValue(value, pluginId, key); + return transaction_.GetKeyValue(value, storeId, key); } }; @@ -437,19 +437,33 @@ transaction_.RemoveLabel(id, label); } - void StoreKeyValue(const std::string& pluginId, + void StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value) { - transaction_.StoreKeyValue(pluginId, key, value); + transaction_.StoreKeyValue(storeId, key, value); + } + + void DeleteKeyValue(const std::string& storeId, + const std::string& key) + { + transaction_.DeleteKeyValue(storeId, key); } - void DeleteKeyValue(const std::string& pluginId, - const std::string& key) + void EnqueueValue(const std::string& queueId, + const std::string& value) { - transaction_.DeleteKeyValue(pluginId, key); + transaction_.EnqueueValue(queueId, value); } + bool DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin) + { + return transaction_.DequeueValue(value, queueId, origin); + } + + }; @@ -568,6 +582,8 @@ bool HasFindSupport(); bool HasKeyValueStore(); + + bool HasQueue(); void GetExportedResources(Json::Value& target, int64_t since, @@ -749,16 +765,23 @@ void ExecuteCount(uint64_t& count, const FindRequest& request); - void StoreKeyValue(const std::string& pluginId, + void StoreKeyValue(const std::string& storeId, const std::string& key, const std::string& value); - void DeleteKeyValue(const std::string& pluginId, + void DeleteKeyValue(const std::string& storeId, const std::string& key); bool GetKeyValue(std::string& value, - const std::string& pluginId, + const std::string& storeId, const std::string& key); + void EnqueueValue(const std::string& queueId, + const std::string& value); + + bool DequeueValue(std::string& value, + const std::string& queueId, + QueueOrigin origin); + }; }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp Fri May 09 16:14:42 2025 +0200 @@ -96,6 +96,7 @@ static const char* const CAPABILITIES = "Capabilities"; static const char* const HAS_EXTENDED_CHANGES = "HasExtendedChanges"; static const char* const HAS_KEY_VALUE_STORE = "HasKeyValueStore"; + static const char* const HAS_QUEUE = "HasQueue"; static const char* const HAS_EXTENDED_FIND = "HasExtendedFind"; static const char* const READ_ONLY = "ReadOnly"; @@ -213,6 +214,7 @@ result[CAPABILITIES][HAS_EXTENDED_CHANGES] = OrthancRestApi::GetIndex(call).HasExtendedChanges(); result[CAPABILITIES][HAS_EXTENDED_FIND] = OrthancRestApi::GetIndex(call).HasFindSupport(); result[CAPABILITIES][HAS_KEY_VALUE_STORE] = OrthancRestApi::GetIndex(call).HasKeyValueStore(); + result[CAPABILITIES][HAS_QUEUE] = OrthancRestApi::GetIndex(call).HasQueue(); call.GetOutput().AnswerJson(result); }
--- a/OrthancServer/Sources/ServerEnumerations.h Fri May 09 09:16:09 2025 +0200 +++ b/OrthancServer/Sources/ServerEnumerations.h Fri May 09 16:14:42 2025 +0200 @@ -259,6 +259,11 @@ Warnings_007_MissingRequestedTagsNotReadFromDisk // new in Orthanc 1.12.5 }; + enum QueueOrigin + { + QueueOrigin_Front, + QueueOrigin_Back + }; void InitializeServerEnumerations();