-
Notifications
You must be signed in to change notification settings - Fork 2
Plugin internals
Configuration.json specifies two folders, the storage and the index folder.
When it receives dicom files through the Rest API/GUI or DICOM server, it places the dicoms in the storage folder, and updates the SQLite database in the index folder
As Orthanc docs state, the storage folder is designed for exclusive use by Orthanc
Orthanc assigns each unique DICOM file a UUID (in hexadecimal with hyphens) and this is the filename
The standard Orthanc directory structure is a three layer directory structure to help filesystems that don't handle flat directories internally as computationally efficient trees
For the file labeled "cd062f5a-0...63f5", it's expected to have the path: /orthanc-storagedir/cd/06/cd062f5a-0...63f5
This plugin serves the usecase that one would like to make a directory of dicoms available through a dicom server/GUI/rest API
When a folder is added in Configuration.json to be indexed, its subfolders and their subfolders and deeper ones are scanned for dicom files as well.
Hence now there are two points of entry to Orthanc: 1) a dicom file placed inside the indexed folder 2) Orthanc API/GUI/DICOM server
The plugin mimics the usual Orthanc data model for files received through the latter.
In this case, when Orthanc would like to read, the path is simply the storage path plus the UUID of the file (also the subdirs directly inferred from only the UUID)
For the former, Orthanc requests file bytes by UUID, so the plugin stores in its database the UUID->filepath mapping
The plugin also works well if the storage folder is one of the indexed folders as well, which is what we would like for keeping dicoms in a single folder (or its subfolders)
Note that the indexer's behavior, when requested through the GUI/Rest API/DICOM server, for deleting a linked file, is to unlink it and not to delete it, and this can be changed by adding lines, in the LookupExternalDicom branch of StorageRemove, to check (using boot::filesystem) if the "externalPath" still exists, and if so, to delete the file and notify caMicroscope.
The plugin works by doing these two things:
- Registers its StorageCreate, StorageReadWhole, StorageReadRange, StorageRemove
- Makes a thread that scans the indexed directories and their recursive subdirectories
The four storage functions are data handlers for Orthanc for when Orthanc would like to save a dicom file, access it or to delete it.
These are needed because accessing a file is now no longer as simple as appending the file UUID to the storage directory path.
It might be in the storage directory, if the file was added not through scanning, but perhaps the file Orthanc requested is one of the indexed folders (which might include the storage folder as well, in which case simple append might not work)
Hence the plugin needs to handle all file accesses. To understand controlflow of the plugin, one should note that: There are multiple plugins for Orthanc storage handling (such as SQL drivers) but it's unusual for a plugin to add a DICOM file to Orthanc.
Orthanc Plugins API does not have a specialized function for this, so instead, the indexer plugin uses the standard Rest API to add dicom files from indexed folders. Hence when considering controlflow, note that StorageCreate may have been called because 1) User uploaded it via Rest API/GUI/DICOM Server 2) The plugin found a new file in indexed folders hence ProcessFile did RestApiPost. Likewise, StorageRemove may have been called because 1) e.g. user chose from the GUI to delete it 2) the scanner found it removed, hence called ExecuteDelete (that does the cleanup after it vanished from the indexed folder) To remember if a UUID is stored conventionally or if it refers to a file in the indexed folders directory, the plugins keeps two databases: "Files" keeps track of all files encountered in indexed folders, "Attachments" keeps track of all files in indexed folders Orthanc also knows. Attachments hence contains (almost?) only DICOM files. For example, this is how adding new files from a directory works:
- ProcessFile finds a new DICOM file in an indexed folder and adds it to "Files".
- Then it uses the Rest API to "upload" it to Orthanc.
- Orthanc calls StorageCreate of the plugin
- the plugin matches it to that file hence adds it to "Attachments".
The plugin uses a hash it calls "instanceid" which covers SOPInstanceUID as well, hence instanceid is different for every DICOM file and this is how matching works.
caMicroscope uses a single directory where DICOMs are in subdirectories, hence the flat directory is both the storage directory and a directory to be indexed.
The reason a patch is needed is that the StorageCreate function for new dicom files (not indexed files) uses the conventional append to storagedir, whereas this needs to match caMicroscope.
Firstly, for reader compatibility DICOM file names need to end in ".dcm" or ".dic" or ".dicom" and cannot be extensionless.
Secondly, first 10 characters of MD5 of Series Instance UID is the subdir name for caMicroscope, which allows us to keep related DICOM files in the same folder