Multiple local AETs

Is it possible for Orthanc to have two local AETs that can receive images via DICOM and then when queried (ideally via DICOM:AET and via API) returns each AETs individual data sets?

I’m using the MySQL connector on Linux.

To explain:

  1. I send a US to AET1 on my Orthanc server.
  2. I send a MG to AET2 on the same Orthanc server.
  3. When I query AET1 (via DICOM or API) I only see the US study and not the MG.
    I have an application that needs to be able to query what’s received on each individual AET as there’s different processes for what’s been received. I could install two instances of Orthanc which I’d rather not do if there’s a way of doing this natively.

Thoughts?

Hi,

As far as I know, the purpose of an AET is to identify an application, so you can have only one AET per application, and hence per Orthanc server.

So you would need to go for 2 Orthanc servers.

Or you could develop a plugin that will fake AETs and do what you want.

Kind regards,

Michel

You might be able to do this with a bit of work. If you set Orthanc to accept any AET, then in a Lua script incomingfindrequestfilter/outgoing filter based on the requesting AET for a dicom c-find.

Bryan, I’ve been thinking about this and was wondering if/how to store the AET of the client in a “C-Store” request and filter on it in a “C-Find”.
Probably slightly different (using the client AET rather server AET) than the original post question but seems related.

Any thoughts?

Ah, sorry. Yes, I understand what you need. So whoever stores the study is the one who can see it?
Yes, I don’t think my idea would work as IncomingFindRequestFilter does not have a tag option and I was thinking you wanted a certain AET to only search for US, my bad.

I wonder if we can, when sending to Orthanc based on Origin store as a private tag using OnStoredInstance and when performing the c-find add the private tag Origin to the query for IncomingFindRequestFilter?

I guess this might actually work assuming Orthanc can match on my private tag. Do you know if Orthanc support querying on a private tag OOTB or do I need to do any special configuration to support that kind of matching?

I gave it a quick test and it worked:

  1. For OnStoredInstance I stored the Origin AET in 2100,070
  2. For IncomingFindRequestFilter I did:

`
local varquery = query
local varorigin = origin
varquery[‘2100,0070’] = varorigin[‘RemoteAet’]
return varquery

`

Worked like a charm.

Brilliant, thank you very much Bryan!

@Bryan / @Zaid: Storing the ReceivedAET is how other DICOM servers (eg DCM4CHEE) do this and so wondered how to apply this to Orthanc - and was exactly what I was getting at in my original post.

Before I go ahead and test this out myself using DICOM, does querying Orthanc via the API also work: I’m not sure you can restrict the API call using the called AET … unless I’m sadly mistaken?

No, as the API would not be providing a called AET. You would most likely have to do it programatically instead. Possibly via REST you would have to query the list, then query for more info in order to get that tag as I believe it is not a study based tag which is searchable in a ORTHANC query. It would very much depend on how you are accessing it.

Yup, that’s what I thought - the API doesn’t make all DICOM tags readily available immediately (although I do vaguely remember there’s a way of adding certain tags to the “core” lookups within Orthanc, so that may be a way to go):

  1. Configure Orthanc to capture the CallingAET as a core database field
  2. Capture the CallingAET as the instance is stored to disk
  3. Utilize the CallingAET field within the API lookup.
    @Sebastien - am I correct about being able to add certain tags to the core database fields for lookup?

Dave

You can do QIDO-RS and search and parse the JSON/XML response:

http://localhost:8042/dicom-web/studies?21000070=Gateway

Will be looking at this later - and will report back…

The “CallingAET” or “CalledAET” fields are metadata that is not always available (e.g. if the DICOM instances are uploaded using the REST API). Furthermore, they can vary depending on the DICOM instance (even in the same series/study). They are not part of the DICOM tags as well, so they are not indexed inside the database:
https://book.orthanc-server.com/faq/features.html#metadata-attachments

In your context, you could create a plugin that registers a new callback in the REST API, and that would (1) call “/tools/find” at the instance level to filter the DICOM tags using “OrthancPluginRestApiPost()”, then (2) for each matching instance, retrieve the “CallingAET” metadata using “OrthancPluginRestApiGet()”, and finally (3) reports only the matching instances.

Hi Sebastien,
Would you see any problems with this:

  1. Incoming study, calling AET is placed in a tag, for example 2100,0070
  2. Via C-Find Calling AET will only see studies with their AET by using Lua: IncomingFindRequestFilter as noted in my e-mail above.
  3. Via API, using QIDO-RS you can only see studies list by queuing such as: http://localhost:8042/dicom-web/studies?21000070=AET1

This would meet all the needs without issue correct?

With the understanding that of course, if an instance was sent to Orthanc via the REST API, there’d be no CallingAET as that’d be a DICOM protocol only value anyway…

Hi.
I had only taken your 3 points into account, where you would only be retrieving via REST. For storing, you could do #4

  1. Incoming study, calling AET is placed in a tag, for example 2100,0070
  2. Via C-Find Calling AET will only see studies with their AET by using Lua: IncomingFindRequestFilter as noted in my e-mail above.
  3. Retrieving via API, using QIDO-RS you can only see studies list by queuing such as: http://localhost:8042/dicom-web/studies?21000070=AET1
    4. Storing via API, using restAPI, origin would be IP address and username. Within the Lua script retrieve the Origin Username and use the same username as the AET.

@Bryan
I’m completely new to Lua. Could I trouble you to post the scripts that you have that outline your #1 and #2 please?

TIA

Dave

Here is a quick, non tested script for #1:

`
function OnStoredInstance(instanceId, tags, metadata, origin)
– Ignore the instances that result from the present Lua script to
– avoid infinite loops
if origin[‘RequestOrigin’] ~= ‘Lua’ then

– The tags to be replaced
local replace = {}
replace[‘2100-0070’] = origin[‘CalledAet’]

– Modify the instance
local command = {}
command[‘Replace’] = replace
command[‘Remove’] = remove
local modifiedFile = RestApiPost(‘/instances/’ … instanceId … ‘/modify’, DumpJson(command, true))

– Upload the modified instance to the Orthanc database so that
– it can be sent by Orthanc to other modalities
local modifiedId = ParseJson(RestApiPost(‘/instances/’, modifiedFile)) [‘ID’]

– Delete the original and the modified instances
RestApiDelete(‘/instances/’ … instanceId)
end
end
`

And for #2:

local varquery = query local varorigin = origin varquery['2100,0070'] = varorigin['RemoteAet'] return varquery