Developing a plugin, help to start

Hi all,

I’ve decided to create a plugin, but my skills with c++ are zero, so i need advice on how to start.

Some background on what i want to do: 3 orthanc servers + 1 radiology workstation. One terminal is running 2 orthanc, the first one(number 1) on index-only mode(no image) with tons of studies indexed and the other (number 2) full-index mode (with image). The studies on this orthanc will last only 1 week. The other orthanc (number 3) will be on remote, with all the studies of those 2 orthanc indexed with image + some others (study purposes).

The most common case is this, workstation ask for a study/series to the orthanc #2, in case it has the study, it will send it to workstation (a normal c-move). In case it does not, it will retrieve the study/series from the orthanc #3 (this one will always have the required study, if correct). Beside this, the plugin have to retrieve all the studies from the patient (for this is the orthanc #1, to check all the uid and retrieve it from orthanc #3). Those other studies from the patient will be indexed in orthanc#2 + sent to workstation.

The logic is simple, but i have no idea how to work with the orthanc SDK.

Right now, i only have:

#include “Resource/OrthancContext.h”

extern “C”
{
ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
{
OrthancContext::GetInstance().Initialize(context);
OrthancContext::GetInstance().LogWarning(“Initializing sample”);
return 0;
}

ORTHANC_PLUGINS_API void OrthancPluginFinalize()
{
OrthancContext::GetInstance().LogWarning(“Finalizing sample”);
OrthancContext::GetInstance().Finalize();
}

ORTHANC_PLUGINS_API const char* OrthancPluginGetName()
{
return “sample”;
}

ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion()
{
return “1.0”;
}

}

Now the questions:

1- Since the plugin only need to do its logic after a move, what should i do now? i’ve read about the c-move in the sdk page. Do i have to implement OrthancPluginRegisterMoveCallback on this file?

2- What do i have to include to work via dicom protocol?

3- I’ve got ORthancContext.h from the source of wado server (this Implementing a WADO Server using Orthanc - CodeProject). Is it ok or should i get it from other source?

Thanks for reading this and any help will be appreciated.

Hello,

1- Since the plugin only need to do its logic after a move, what should i do now? i’ve read about the c-move in the sdk page. Do i have to implement OrthancPluginRegisterMoveCallback on this file?

In your case, the first thing to do is obviously to learn C/C++. Creating an Orthanc plugin is clearly not a simple way to learn such a complex language.

Once you are knowledgeable of C/C++, read the following documentation:
http://book.orthanc-server.com/developers/creating-plugins.html

https://www.codeproject.com/Articles/797118/Implementing-a-WADO-Server-using-Orthanc

And have a look at the source code of the official plugins:
http://book.orthanc-server.com/plugins.html#overview

Hint: instead of directly playing with the C functions of the Orthanc SDK, I highly recommend you to use the simpler C++ wrapper around this SDK, that is available in the source distribution of Orthanc, and that will save you a lot of time:
https://bitbucket.org/sjodogne/orthanc/src/default/Plugins/Samples/Common/OrthancPluginException.h

https://bitbucket.org/sjodogne/orthanc/src/default/Plugins/Samples/Common/OrthancPluginCppWrapper.h

https://bitbucket.org/sjodogne/orthanc/src/default/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp

2- What do i have to include to work via dicom protocol?

If I correctly understand the goal of your development:

  • Your plugin only runs in “Orthanc #2” (that acts as a DICOM buffer).

  • Your plugin forwards all the C-FIND requests to “Orthanc #1” (that acts as an index-only server).

  • On C-MOVE requests, two cases arise:

  1. If “Orthanc #2” already has the data locally, it sends the data directly with a C-STORE to the calling AET.
  2. If “Orthanc #2” does not have the data locally:

In the C-FIND callback, your plugin would call the REST API of “Orthanc #1” using its “/tools/find” URI. To this end, use the “OrthancPlugins::RestApiPost()” function of the C++ wrapper mentioned earlier. Check out the integration test “test_rest_find” to have samples for this URI:
https://bitbucket.org/sjodogne/orthanc-tests/src/b90e001d43bdd9cac7724f3b4af629cdc6989bb2/Tests/Tests.py#lines-1516

To handle the C-MOVE requests, your plugin must call “OrthancPluginRegisterMoveCallback()”:
http://sdk.orthanc-server.com/group__DicomCallbacks.html#ga2e9d921421fb9e4687017fb7d1f599c1

To check whether the data is available locally, make a REST API call to the local “/tools/find” URI. If the data is available, use the local “/modalities/{originator}/store” URI to send data back to the caller (*). The symbolic name of the “{originator}” can be derived from the “originatorAet” provided to the C-MOVE callback, by inspecting the configuration file of Orthanc with “OrthancPluginGetConfiguration()”:
http://sdk.orthanc-server.com/group__Toolbox.html#gad573a8a861f0053250ef1d328a55ac5d

If the data is not available in “Orthanc #2”, retrieve the data from “Orthanc #3” by POST-ing to the remote URI “/peers/orthanc-2/store”. The “Orthanc #2” can compute the Orthanc identifier of the study/series/instance of interest by implementing the hashing scheme of Orthanc in its C-MOVE callback:
http://book.orthanc-server.com/faq/orthanc-ids.html

Once the “/peers/orthanc-2/store” is over, do the same as (*).

3- I’ve got ORthancContext.h from the source of wado server (this https://www.codeproject.com/Articles/797118/Implementing-a-WADO-Server-using-Orthanc). Is it ok or should i get it from other source?

You must use the official “OrthancCPlugin.h” SDK from Orthanc >= 1.1.0, which was the first release to include support for C-MOVE callbacks (the CodeProject page comes with a :
https://bitbucket.org/sjodogne/orthanc/src/Orthanc-1.1.0/Plugins/Include/orthanc/OrthancCPlugin.h

The “OrthancContext.h” file is an old version of the “OrthancPluginCppWrapper.h” mentioned above, so use the latter instead.

HTH,
Sébastien-

Thanks for your answer, but now maybe it is too late. I have to get the system done and document it in a month. I end up parsing logs in verbose (was the only way at that time), but anyway thanks to answer. Not sure if i will try the plugin or not.
PD: You answer in other post not to use DCMTK. Is any problem with that toolkit or it was because it is better to use a plugin?

Sorry for the delay, but given the high success and the various use cases of Orthanc, I can’t personally answer each and every answer on a daily basis.

To put this into perspective, you must know that this discussion group represents an amount of > 180 posts per month, since March 2018. I personally read each of those messages, mostly on my spare time. This represents a huge amount of volunteer job, so please be comprehensive.

I suggest not use use DCMTK, as the REST API should be favored in scenarios where there are only Orthanc servers, and as your are dealing with a “remote” scenario for which encryption is necessary:
https://groups.google.com/d/msg/orthanc-users/4upRZ5BK2Nw/IuwdXIQoAgAJ

Do not worry. This group has helped me a lot and i understand answer this type of wuestions are no one job.
Since In my system i would use VPN to transfer data with remote encryption would not be a problem. Right now I use DCMTK to work with DICOM protocol + the orthanc should be with users and “admin” accounts with lua scripts to limit the post&delete request via https. I don’t like to store the username and pass in a readable file, it makes me uneasy.

Note that if you don’t want to use the HTTP basic authentication that is built in Orthanc as it stores its credentials in plain text, you can always setup a nginx/Apache proxy:
http://book.orthanc-server.com/faq/https.html

That being said, if DCMTK serves your purpose, go with it.

I got the idea to use the reverse-proxy to enable https, but is it really posible to rely authentication to apache using a database?

Yes, check out e.g.:
https://httpd.apache.org/docs/2.4/en/mod/mod_authn_dbd.html
https://httpd.apache.org/docs/2.4/en/mod/mod_authnz_ldap.html

uh, cool. Will the lua scripts work even with auth in the reverse proxy?

Yes, it should. Give a try.