Plugin-Referenz¶
Diese Referenz richtet sich an Anwenderinnen und Anwender, die die Routing-Regeln des DICOM-Routers konfigurieren. Sie beschreibt die mitgelieferten Plugins und ihre Konfiguration — jeweils mit Anwendungsfall, den einstellbaren Feldern und einem vollständigen YAML-Beispiel. Die allgemeine Config-Syntax (Filter, Ziele, Reload) steht in configuration.md.
So werden Plugins aktiviert¶
Ein Plugin wird nicht global eingeschaltet, sondern pro Verbindung über zwei Blöcke in der Konfiguration verdrahtet:
- Der
actions:-Block definiert Instanzen. Jede benannte Action ist eine Liste von Plugin-Einträgen; jeder Eintrag nennt die Plugin-Klasse (plugin:) und ihre Parameter (config:). - Eine
filter:-Regel referenziert eine oder mehrere Actions über ihren Namen. Nur wenn eine Verbindung auf die Filter-Regel passt, laufen deren Actions.
Dasselbe Plugin lässt sich mehrfach mit unterschiedlicher Config definieren
(Multi-Instance): einmal als tapAlles mit weiter Whitelist, einmal als tapSr
nur für Befunde. Welches Gerät welche Variante bekommt, entscheidet die
Filter-Regel. Die Reihenfolge der Actions in einer Filter-Regel ist die
Ausführungsreihenfolge.
Details zu Filter-Feldern (callingAET, calledAET, IP-/Port-Kriterien,
regex:-Präfix), Zielen und dem Hot-Reload per dicom-router-ctl reload stehen
in configuration.md.
Ein zu grosses Feld kostet nie die Verbindung. Der Router materialisiert
Elementwerte erst beim Zugriff und verweigert das oberhalb von
router.materialization-threshold bzw. jenseits von router.max-elements (siehe
configuration.md). Die Rewrite-Plugins behandeln ein so
verweigertes Element wie ein fehlendes: die betroffene Änderung entfällt, die
Nachricht wird unverändert weitergeleitet, und die Association läuft weiter.
QrFieldRewriteStage geht einen Schritt vorsichtiger vor und überspringt die
Operation, die dieses Feld anspricht, statt das Feld als fehlend zu behandeln — sonst
würde ein set ein Element überschreiben, von dem gar nicht feststeht, ob es etwa eine
Sequenz ist. Die übrigen Operationen greifen normal. Mit den Vorgabewerten (1 MB) ist der Fall praktisch
nicht erreichbar — er wird relevant, wenn die Schwellen deutlich kleiner gesetzt
sind.
Achtung, zwei Paket-Namen: Die meisten Plugins liegen unter
ch.immeditech.imconnect.dicomrouter.plugin.…, die Beispiel-PluginsPduLoggingStagePluginundExamplePluginStagedagegen unterch.immeditech.imconnect.plugins.…— am sichersten dieplugin:-Zeilen aus den Beispielen dieser Referenz kopieren.
PduLoggingStage¶
Was es tut¶
Schreibt Protokoll-Mitschnitte einer Verbindung — entweder als Zusammenfassung ins Anwendungslog oder als binäre PDU-Dumps in eine Datei. Nutzt man zur Fehlersuche, wenn eine Gegenstelle sich nicht wie erwartet verhält und man den DICOM-Handshake nachvollziehen muss. Payload/Patientendaten landen nie im Anwendungslog.
Plugin-Klasse¶
Wichtig: Mitschneiden geht auch ganz ohne dieses Plugin¶
Die Mitschnitt-Funktion ist in jede Verbindung fest eingebaut — es genügt,
in der Filter-Regel logLevel zu setzen; eine Action ist dafür nicht
nötig. Dieses Plugin fügt lediglich zusätzliche, benannte Logger-Instanzen
hinzu (z. B. mit eigenem stageName zur Zuordnung im Log). Auch für die
Plugin-Instanzen gilt: Was sie mitschneiden, steuert der logLevel der
Filter-Regel — bei logLevel: 0 schneiden weder die eingebauten noch die
zusätzlichen Logger etwas mit.
Steuerung über den Filter-logLevel¶
Was tatsächlich mitgeschnitten wird, steuert das Feld logLevel der
Filter-Regel, nicht die Plugin-Config:
| logLevel | Wirkung |
|---|---|
| 0 | Kein Logging |
| 1 | Eingehend, als Zusammenfassung ins Anwendungslog |
| 2 | Ausgehend, als Zusammenfassung ins Anwendungslog |
| 3 | Ein- und ausgehend, als Zusammenfassung ins Anwendungslog |
| 5 | Eingehend, als binärer PDU-Dump in router.log-folder |
| 6 | Ausgehend, als binärer PDU-Dump in router.log-folder |
| 7 | Ein- und ausgehend, als binärer PDU-Dump |
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
stageName |
Default PduLoggingStage |
Frei wählbarer Name der Instanz; erscheint im Log zur Zuordnung. |
firstLogger |
Default true |
true = Instanz für die eingehende Seite, false = für die ausgehende. |
enabled |
Default true |
Schaltet diese Instanz aus, ohne sie aus der Config zu nehmen. |
Für vollständige In- und Outbound-Mitschnitte definiert man üblicherweise zwei
Einträge in derselben Action — einen mit firstLogger: true, einen mit false.
Beispiel¶
actions:
protocolLogging:
- plugin: ch.immeditech.imconnect.plugins.PduLoggingStagePlugin
config:
stageName: "InboundProtocolLogger"
firstLogger: true
enabled: true
- plugin: ch.immeditech.imconnect.plugins.PduLoggingStagePlugin
config:
stageName: "OutboundProtocolLogger"
firstLogger: false
enabled: true
filter:
- callingAET: MRI1
calledAET: PACS
logLevel: 3 # Zusammenfassung ins Anwendungslog
actions:
- "protocolLogging"
destination:
- "pacs1"
Hinweise¶
- Binäre Dumps (logLevel 5/6/7) landen im Verzeichnis
router.log-folder. Sie können Patientendaten enthalten und sind entsprechend zu schützen. - Dieses Plugin ersetzt nicht den DICOM-Tap: Es dient dem Protokoll-Debugging, nicht der Ablage fachlich verwertbarer DICOM-Dateien.
AETitleRewriteStage¶
Was es tut¶
Schreibt den Calling- und/oder Called-AE-Titel um, mit dem der Router die Verbindung zum Ziel-PACS aufbaut. Typischer Fall: Ein Gerät sendet mit einem AE-Titel, den das PACS nicht kennt oder nicht akzeptiert — der Router ersetzt ihn nach aussen durch einen abgestimmten Wert. Auf dem Rückweg stellt der Router die ursprünglichen AE-Titel für das Gerät wieder her, sodass das Gerät nichts von der Umschreibung merkt.
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
callingAetOverride |
optional | Neuer Calling-AET nach aussen. Leer/weggelassen = ursprünglicher Wert bleibt erhalten. |
calledAetOverride |
optional | Neuer Called-AET nach aussen. Leer/weggelassen = ursprünglicher Wert bleibt erhalten. |
logRewrites |
Default true |
Protokolliert jede Umschreibung. |
enabled |
Default true |
Schaltet das Plugin aus, ohne es aus der Config zu nehmen. |
AE-Titel dürfen höchstens 16 Zeichen lang sein.
Beispiel¶
actions:
aetRewrite_ultrasound:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.AETitleRewriteStage
config:
callingAetOverride: "US_GATEWAY"
calledAetOverride: "PACS_PROD"
logRewrites: true
enabled: true
filter:
- callingAET: US1
calledAET: PACS
actions:
- "aetRewrite_ultrasound"
destination:
- "pacs1"
Hinweise¶
- Nur eines der beiden Override-Felder zu setzen ist zulässig — das jeweils andere bleibt dann unverändert.
- Wird zusätzlich C-MOVE oder eine Worklist über den Router geführt, sind meist
die Plugins
CMoveDestinationRewriteStagebzw.WorklistAetRewriteStagenötig, weil die umgeschriebenen AE-Titel sonst in den Nachrichteninhalten nicht mitgezogen werden (siehe unten).
WorklistAetRewriteStage¶
Was es tut¶
Schreibt in Worklist-Abfragen (C-FIND MWL) den Stations-AE-Titel
ScheduledStationAETitle um. Anwendungsfall: Der Router schreibt den AE-Titel der
Modality per AETitleRewriteStage um, sodass das RIS die Modality nur noch unter
dem RIS-seitigen AET kennt. Ohne dieses Plugin fragt die Modality mit ihrem
eigenen AET als Suchschlüssel und bekommt eine leere Worklist; ausserdem verwirft
sie gelieferte Einträge, weil deren Stations-AET nicht zu ihrem eigenen passt.
Das Plugin schreibt den AET in der Abfrage vorwärts (Modality → RIS) und in den
Antworten zurück (RIS → Modality), sodass die Worklist-Antworten die
Original-AETs des Geräts tragen.
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
aetMapping |
Pflicht | Zuordnung Modality-AET → RIS-AET für die Abfragerichtung. |
responseMapping |
optional | Explizite Rückrichtung RIS-AET → Modality-AET. Hat Vorrang vor der automatischen Umkehrung von aetMapping. |
logRewrites |
Default true |
Protokolliert jede Umschreibung. |
enabled |
Default true |
Schaltet das Plugin aus. Bei enabled: true muss aetMapping mindestens einen Eintrag haben. |
Beispiel¶
Das vollständige Setup kombiniert beide Plugins in einer Action: Die
AETitleRewriteStage schreibt den Calling-AET der Verbindung um (das RIS sieht
US_GATEWAY als Absender), die WorklistAetRewriteStage zieht denselben Wert
im Nachrichteninhalt nach (Suchschlüssel ScheduledStationAETitle hin, Antworten
zurück). Nur die WorklistAetRewriteStage allein genügt, wenn das RIS den
Original-Calling-AET der Modality akzeptiert und lediglich der Stations-AET in
den Worklist-Einträgen abweicht.
actions:
worklistRewrite:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.AETitleRewriteStage
config:
callingAetOverride: "US_GATEWAY" # Verbindungs-Ebene: Absender-AET nach aussen
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.WorklistAetRewriteStage
config:
aetMapping: # Nachrichten-Ebene: Modality-AET -> RIS-AET
US1: "US_GATEWAY"
# responseMapping: # optional; nur nötig bei mehrdeutiger Rückrichtung
# US_GATEWAY: "US1"
logRewrites: true
enabled: true
filter:
- callingAET: US1
calledAET: RIS
actions:
- "worklistRewrite"
destination:
- "ris1"
Hinweise¶
- Die Rückrichtung wird normalerweise automatisch aus
aetMappinggebildet. - Bilden mehrere Modality-AETs auf denselben RIS-AET ab (Pool), ist die Umkehrung
mehrdeutig. Dann trägt man
responseMappingexplizit nach; andernfalls können betroffene Antwortwerte nicht eindeutig zurückgeschrieben werden und bleiben unverändert (Warnung beim Laden der Konfiguration). - Nicht-Worklist-Verkehr und nicht zuordenbare Werte werden unverändert durchgereicht; das Plugin verwirft nie Nachrichten.
QrFieldRewriteStage¶
Was es tut¶
Allgemeiner Feld-Umschreiber für Abfrage-Verkehr (C-FIND, C-MOVE, C-GET). Damit
lassen sich einzelne Felder in Abfragen und Antworten setzen, mit einem
Standardwert vorbelegen oder entfernen — etwa um eine Abfrage auf bestimmte
Modalitäten einzuschränken, eine feste Retrieve-AE in Antworten zu ergänzen oder
ein Feld herauszunehmen. Ohne weitere Angabe wirkt das Plugin auf die
Query/Retrieve-Modelle (Patient Root und Study Root); über sopClasses lässt es
sich auf andere Abfrage-Klassen ausdehnen, z. B. Worklist-Abfragen (MWL).
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
applyTo |
Default [C-FIND, C-MOVE, C-GET] |
Auf welche Operationen das Plugin wirkt. |
sopClasses |
Default: die sechs Q/R-Modelle (Patient/Study Root) | Whitelist von SOP-Class-UIDs, gegen die die Abfrage-Klasse geprüft wird. Eine eigene Liste ersetzt den Default — wer die Q/R-Modelle behalten und z. B. MWL (1.2.840.10008.5.1.4.31) ergänzen will, listet beide auf. |
request |
optional | Regeln für eingehende Abfrage-Identifier. Enthält set, default, remove. |
response |
optional | Regeln für ausgehende (Pending-)Antwort-Identifier. Enthält set, default, remove. |
fail-open |
Default false |
true = ein Fehler beim Verarbeiten überspringt nur diese Regel, statt die Verbindung abzubrechen. |
logRewrites |
Default true |
Protokolliert eine Zusammenfassung pro Datensatz (ohne Werte). |
enabled |
Default true |
Bei enabled: true muss mindestens eine Regel unter request: oder response: stehen. |
Innerhalb von request: und response: gibt es drei Operationen:
set— Feld überschreiben oder neu anlegen.default— Feld nur setzen, wenn es noch nicht vorhanden ist.remove— Feld entfernen.
Feld-/Pfad-Schreibweise: Tags werden als "GGGG,EEEE" (oder 8 Hex-Ziffern)
angegeben.
Manche DICOM-Felder sind Sequenzen: Statt eines einfachen Wertes (Text, Zahl,
UID) enthalten sie eine Liste von Items, und jedes Item ist ein eigener kleiner
Datensatz mit wiederum eigenen Feldern. Beispiel: Die „Referenced Study Sequence"
(0008,1110) enthält pro referenzierter Studie ein Item, und darin stehen dann die
eigentlichen Felder (etwa die Studien-UID). In solche Strukturen steigt man mit
/-getrennten Pfaden ab: "<sequenz-tag>/<item-index oder *>/<tag>", beliebig
tief; * steht für alle vorhandenen Items. Pfade steigen nur in bereits
vorhandene Sequenzen und Items ab — set/default können einfache Felder neu
anlegen, aber keine Sequenz-Struktur und keine Items erzeugen; ein Pfad in eine
nicht vorhandene Sequenz bewirkt schlicht nichts.
VR-Angabe: Jedes DICOM-Feld hat einen Datentyp (VR, z.B. AE für AE-Titel,
LO für kurzen Text, UI für UIDs). Für alle Standard-DICOM-Felder (das
komplette Standard-Dictionary, PS3.6) kennt der Router den Typ selbst — dann
genügt die Kurzform ("0008,0061": "CT\\MR" oder "0008,0054": "ROUTER").
Nur für private und exotische Felder (die nicht im Standard-Dictionary stehen
oder dort keinen eindeutigen Typ haben) ist die erweiterte Form mit ausdrücklicher
VR Pflicht ({ value: "XYZ", vr: LO }) — fehlt sie, lehnt der Router die
Konfiguration beim Start bzw. beim reload mit einer klaren Fehlermeldung ab; zur
Laufzeit kann dadurch nichts schiefgehen. Eine erweiterte Form, deren VR dem
Standard-Dictionary widerspricht, wird ebenfalls abgelehnt. Felder mit binärem
Datentyp (z.B. US, OW) lassen sich mit set/default grundsätzlich nicht
schreiben — die Rewrite-Werte sind Text; solche Einträge werden beim Laden
abgelehnt. Mehrere Werte werden mit Backslash getrennt.
Beispiel¶
actions:
qrFieldRewrite:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.QrFieldRewriteStage
config:
applyTo: ["C-FIND"]
request:
set:
"0008,0061": "CT\\MR" # ModalitiesInStudy (Kurzform)
remove:
- "0010,1000" # OtherPatientIDs
response:
set:
"0008,0054": "ROUTER" # RetrieveAETitle (Kurzform)
default:
"0008,0080": "KLINIK_A" # InstitutionName (Kurzform)
"0009,1001": # privates Feld - erweiterte Form mit VR
value: "ZUWEISER-A"
vr: LO
remove:
- "0008,1120/*/0010,0020" # in allen Items der Sequenz
fail-open: false
logRewrites: true
enabled: true
filter:
- callingAET: WS1
calledAET: PACS
actions:
- "qrFieldRewrite"
destination:
- "pacs1"
Hinweise¶
- Die Konfiguration wird streng beim Laden geprüft: ungültige Pfade oder
VR-Codes, fehlende VR bei unbekannten Feldern, leere Werte und sich
überschneidende Regeln (etwa
setunddefaultauf dasselbe Feld) werden schon beim Start bzw. Reload abgelehnt — nicht erst zur Laufzeit. - Verkehr ausserhalb der
sopClasses-Whitelist, unlesbare Nachrichten und fehlende Felder sind erwartbare Zustände und führen zu unverändertem Durchreichen, nie zu einem Abbruch. - ISO-2022-Zeichensätze: Deklariert ein Gerät einen nicht unterstützten
Mehrwert-Zeichensatz (ISO-2022-Code-Extensions, z.B.
ISO 2022 IR 6\ISO 2022 IR 87), kann der Router Textfelder nicht sicher dekodieren — die Stage wird für dieses Objekt übersprungen (WARN im Log, Original wird byte-exakt weitergeleitet). Das betrifft alle Standard-Textfelder, auch bei Implicit-VR-Übertragung. - Setzt
setdenselben Wert, der ohnehin schon vorhanden ist, entsteht keine Änderung. - Wirken auf derselben Verbindung sowohl
QrFieldRewriteStage(mit MWL insopClasses) als auchWorklistAetRewriteStageauf Worklist-Abfragen, laufen sie in der Reihenfolge, in der die Actions in der Filterregel stehen.
CMoveDestinationRewriteStage¶
Was es tut¶
Schreibt in eingehenden C-MOVE-Anfragen das Ziel-Feld MoveDestination um.
Anwendungsfall: Wird der AE-Titel per AETitleRewriteStage umgeschrieben, trägt
die C-MOVE-Anfrage noch den ursprünglichen Ziel-AET, den das PACS nach der
Umschreibung nicht mehr kennt. Dieses Plugin ersetzt den Ziel-AET durch einen
Wert, den das PACS erreichen kann (typischerweise den Pool- bzw. Router-AET).
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
destinationMapping |
optional | Genaue Zuordnung ursprünglicher Ziel-AET → neuer Ziel-AET. Hat Vorrang vor destinationOverride. |
destinationOverride |
optional | Fester Ersatz-AET für jeden Ziel-AET ohne Mapping-Eintrag. |
logRewrites |
Default true |
Protokolliert jede Umschreibung. |
enabled |
Default true |
Bei enabled: true muss mindestens eines von destinationMapping/destinationOverride gesetzt sein. |
Beispiel¶
actions:
cmoveRewrite_us:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.CMoveDestinationRewriteStage
config:
destinationOverride: "US_POOL"
# destinationMapping:
# US1: "RTR_US1"
# US2: "RTR_US2"
logRewrites: true
enabled: true
filter:
- callingAET: US1
calledAET: PACS
actions:
- "cmoveRewrite_us"
destination:
- "pacs1"
Hinweise¶
- Ist zu einem Ziel-AET weder ein Mapping-Eintrag noch ein Override vorhanden, bleibt die Anfrage unverändert (mit Warnung im Log).
- C-MOVE-Antworten tragen kein Ziel-Feld und werden nicht angefasst; andere Nachrichtentypen werden unverändert durchgereicht.
CMoveTrackingStage¶
Was es tut¶
Bereitet den Rückweg eines C-MOVE für die Q/R-Bridge vor. Das Plugin macht in
einem Schritt dreierlei: Es schreibt MoveDestination genauso um wie die
CMoveDestinationRewriteStage (die es in diesem Szenario ersetzt), tauscht
zusätzlich die MessageID der C-MOVE-Anfrage gegen eine router-eigene,
cluster-weit eindeutige Nummer aus und merkt sich zu dieser Nummer, an welches
Ziel die zurückkommenden Bilder gehören. Ein normkonformes PACS trägt die
Nummer in jede zurückgesendete Bild-Nachricht ein, wodurch der Router die
zweite, unabhängige Verbindung wieder der ursprünglichen Anfrage zuordnen kann.
Füllt das PACS das Feld nicht oder mit einem eigenen Wert, ordnet der Router
das Bild ersatzweise über die Studien-UID dem jüngsten passenden C-MOVE zu.
C-MOVE-Antworten und ein allfälliges C-CANCEL des Geräts werden automatisch
zurück- bzw. mitgeschrieben; das Gerät sieht durchgehend seine eigene
Nachrichtennummer.
Stand dieser Version: Der Weg ist durchgehend: Das Plugin legt den
Tracking-Eintrag an, der Router nimmt die Rückverbindung des PACS selbst an,
löst pro Bild die Zuordnung auf und sendet das Bild an das Gerät weiter
(Destination-Typ qr-bridge, siehe
configuration.md). Das Gerät erhält dabei
seine eigene Nachrichtennummer und seinen eigenen AE-Title zurück, und der
Status, mit dem das Gerät ein Bild quittiert, wird unverändert ans PACS
weitergereicht — Warnungen bleiben Warnungen. Die Aktivierung sollte wegen der
Presentation-Context-Konfiguration weiterhin mit dem Support abgestimmt werden.
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
destinationMapping |
optional | Genaue Zuordnung ursprünglicher Ziel-AET → neuer Ziel-AET. Hat Vorrang vor destinationOverride. |
destinationOverride |
optional | Fester Ersatz-AET für jeden Ziel-AET ohne Mapping-Eintrag (typischerweise der Router-AET). |
returnDestination |
Pflicht | Name eines Eintrags aus destinations: vom Typ forward — dorthin gehören die zurückkommenden Bilder. Ein Tippfehler wie auch ein Verweis auf eine qr-bridge- oder reject-Destination lässt die Konfiguration bewusst scheitern; sonst fiele der Fehler erst Stunden später auf dem Rückweg auf. |
store |
Default memory |
memory für einen einzelnen Router, database im Cluster (gemeinsame Datenbank; erfordert eine aktive Datenbank). Muss mit dem store: der qr-bridge-Destination übereinstimmen — jeder benutzte Store muss von einer Bridge gelesen werden. |
ttl |
Default 24h |
Gültigkeitsdauer eines Tracking-Eintrags (ms/s/m/h/d, maximal 30 Tage). |
logRewrites |
Default true |
Protokolliert jede Umschreibung. |
enabled |
Default true |
Bei enabled: true müssen returnDestination und mindestens eines von destinationMapping/destinationOverride gesetzt sein. |
Beispiel¶
actions:
cmoveTracking_us1:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.CMoveTrackingStage
config:
destinationOverride: "ROUTER"
returnDestination: "us1"
store: memory
ttl: 24h
filter:
- callingAET: US1
calledAET: PACS
actions:
- "aetRewrite_us"
- "cmoveTracking_us1"
destination:
- "pacs1"
Hinweise¶
- Ist zu einem Ziel-AET weder ein Mapping-Eintrag noch ein Override vorhanden, bleibt die Anfrage vollständig unverändert (mit Warnung im Log) — es wird dann auch nichts nachverfolgt.
- Lässt sich keine Nummer vergeben (Datenbank nicht erreichbar), wird die Anfrage ebenfalls unverändert weitergeleitet und ein Fehler protokolliert. Die Verbindung bleibt in jedem Fall bestehen.
- Ein Wechsel von
store: memoryaufdatabase(oder umgekehrt) erfordert einen Neustart. Ebenso neustartpflichtig ist das Entfernen oder Umbenennen eines solchen Eintrags, wenn im selbenreloadkein Eintrag mit demselben Store an seine Stelle tritt — die Speicher-Instanzen sind an den Start gebunden, und Umbenennen ist von Entfernen nicht unterscheidbar. Alle übrigen Felder lassen sich perreloadändern. - Der
store-Wert muss mit dem derqr-bridge-Destination übereinstimmen, die den Rückweg annimmt — sonst schreibt die eine Seite in einen anderen Speicher als die andere liest. Die Konfigurationsprüfung lehnt eine solche Kombination ab. Umgekehrt ist eineqr-bridge-Destination ohne dieses Plugin erlaubt: im Cluster kann ein Knoten die Rückverbindungen annehmen, während eine andere Instanz die Einträge schreibt. - Die Tracking-Einträge überleben die Verbindung bewusst — das PACS meldet sich oft erst Stunden später zurück. Aufgeräumt wird über die Gültigkeitsdauer und die betreiberseitige Datenbank-Bereinigung.
- Wie lange der Router auf ein langsames Gerät wartet und ab wie vielen unzustellbaren
Bytes er eine Rückverbindung abbricht, wird nicht hier, sondern an der
qr-bridge-Destination eingestellt (timeouts:undmax-drain-bytes, siehe configuration.md).
DicomTapStage¶
Was es tut¶
Zweigt Daten der getappten Verbindung als byte-exakte DICOM-Dateien (Part-10) in
eine konfigurierbare Ablage ab oder versendet sie zusätzlich an ein Fremdsystem —
ohne die eigentliche Weiterleitung zu beeinflussen. Anwendungsfall: Daten für ein
Fremdsystem, Archiv oder eine Auswertung abzweigen, ohne den produktiven Fluss zum
PACS zu verändern. Standardmässig werden die gespeicherten Bilder (C-STORE)
abgezweigt; über commands: lassen sich auch andere Nachrichten (etwa
Abfrage-Inhalte) mitschneiden. Die Wire-Transfer-Syntax wird 1:1 übernommen, es
findet keine Umkodierung statt.
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
pathTemplate |
Pflicht, falls kein forward |
Absolutes Pfad-Template mit Platzhaltern für die Ablage. Mindestens eines von pathTemplate/forward muss gesetzt sein. |
sopClasses |
optional | Whitelist von SOP-Class-UIDs (exakte UIDs, keine Wildcards). Fehlt sie, wird jede ausgewählte Nachricht abgezweigt. |
dataSetFilters |
optional | Filter über Data-Set-Felder: Liste von {tag, values}-Einträgen. Nur Objekte, deren Data-Set alle Einträge erfüllt, werden abgezweigt (Semantik siehe unten). |
commands |
Default [C-STORE-RQ] |
Welche DIMSE-Nachrichten abgezweigt werden (z. B. C-FIND-RQ, C-FIND-RSP, C-MOVE-RQ). |
finalize |
Default on-success |
on-success = erst nach erfolgreicher Speicher-Bestätigung der weitergeleiteten Verbindung ablegen und versenden; always = sofort. |
quotaMb |
optional | Obergrenze (in MB) für den Plattenverbrauch der Ablage. Bei Überschreitung setzt der Tap aus, bis der Verbrauch sinkt. |
forward |
optional | Block zum Versand der Captures als C-STORE an ein Ziel (siehe unten). |
enabled |
Default true |
Schaltet den Tap aus. |
Platzhalter im pathTemplate: benannte Aliase <callingAet>, <calledAet>
(die Original-AETs des Geräts vor jeder Umschreibung), <sopClassUid>,
<sopInstanceUid>, <studyInstanceUid>, <seriesInstanceUid>, <modality>,
<date>/<time> (Empfangszeitpunkt), <command> (DIMSE-Name wie C-FIND-RSP),
<messageId> (Kennung des Austauschs; Anfrage und Antwort gruppieren sich
dadurch), <seq> (4-stelliger Zähler pro Austausch), <associationId>
(Verbindungs-Kennung) sowie generisch <tag:GGGG,EEEE> für beliebige
Header-Tags. Fehlt ein Wert, wird UNKNOWN eingesetzt.
„Alle Structured Reports" auswählen: sopClasses vergleicht exakte UIDs —
eine Kategorie-Auswahl („alle SR") gibt es nicht. Als Referenz die gängigen
SR-SOP-Klassen aus dem DICOM-Standard (für klassische Befund-SRs genügen meist
die ersten drei; welche Klassen ein Gerät tatsächlich erzeugt, steht in dessen
DICOM Conformance Statement):
| UID | Bedeutung |
|---|---|
1.2.840.10008.5.1.4.1.1.88.11 |
Basic Text SR |
1.2.840.10008.5.1.4.1.1.88.22 |
Enhanced SR |
1.2.840.10008.5.1.4.1.1.88.33 |
Comprehensive SR |
1.2.840.10008.5.1.4.1.1.88.34 |
Comprehensive 3D SR |
1.2.840.10008.5.1.4.1.1.88.35 |
Extensible SR |
1.2.840.10008.5.1.4.1.1.88.40 |
Procedure Log |
1.2.840.10008.5.1.4.1.1.88.50 |
Mammography CAD SR |
1.2.840.10008.5.1.4.1.1.88.59 |
Key Object Selection Document |
1.2.840.10008.5.1.4.1.1.88.65 |
Chest CAD SR |
1.2.840.10008.5.1.4.1.1.88.67 |
X-Ray Radiation Dose SR |
1.2.840.10008.5.1.4.1.1.88.68 |
Radiopharmaceutical Radiation Dose SR |
1.2.840.10008.5.1.4.1.1.88.69 |
Colon CAD SR |
1.2.840.10008.5.1.4.1.1.88.73 |
Patient Radiation Dose SR |
dataSetFilters: — Auswahl nach Data-Set-Feldern: Zusätzlich zur
SOP-Klassen-Whitelist lässt sich nach Inhalten des Data-Sets filtern — der
Haupt-Anwendungsfall ist die Modalität (0008,0060):
dataSetFilters:
- tag: "0008,0060" # Modality
values: [CT, MR]
- tag: "0008,0016" # SOP Class UID per Regex (MR Image Storage + Enhanced)
values: ["regex:1\\.2\\.840\\.10008\\.5\\.1\\.4\\.1\\.1\\.4(\\..*)?"]
Semantik:
- Jeder Eintrag besteht aus
tag(Top-Level-Tag in Hex-Schreibweise"GGGG,EEEE"oder als 8 Hex-Ziffern"GGGGEEEE", auch private Tags erlaubt; kein Abstieg in Sequenzen) undvalues(mindestens ein Wert). - Mehrere Einträge müssen alle zutreffen (UND); mehrere Werte eines Eintrags sind Alternativen (ODER). Derselbe Tag darf in mehreren Einträgen stehen (auch die zählen als UND — erfüllbar über mehrwertige Attribute).
- Verglichen wird die Text-Repräsentation des Werts, exakt (nach Entfernen
umgebender Leerzeichen). Ein Wert mit dem Präfix
regex:ist ein regulärer Ausdruck und muss den gesamten Wert matchen — gleiche Präfix-Konvention wie bei den AE-Titeln der Filter-Regeln; anders als dort ist*hier aber kein Wildcard, sondern ein gewöhnliches Zeichen (nurregex:ist speziell). - Tags mit binärer VR (z. B. Rows
US, PixelDataOW) können nie als Text matchen und werden beim Config-Load abgelehnt; numerische String-VRs wieIS/DS(z. B. SeriesNumber) funktionieren normal. - Bei mehrwertigen Attributen (Backslash-getrennt, z. B. Modality
CT\MR) genügt ein passendes Element. - Fehlt das Attribut im Data-Set oder ist es leer (auch: besteht nur aus Füll-Leerzeichen), wird das Objekt nicht abgezweigt (Vermerk im Anwendungslog auf DEBUG-Stufe). Auch ein Lesefehler beim Filter-Check überspringt nur dieses Capture (erster Vorfall als Warnung im Log) — die Weiterleitung ist wie immer nie betroffen.
- Ohne
dataSetFiltersbleibt das Verhalten unverändert (jede ausgewählte Nachricht wird abgezweigt). Der Filter gilt auch fürcommands:-Captures — dort wird gegen die Felder des mitgeschnittenen Data-Sets geprüft (z. B. die Schlüssel eines Abfrage-Identifiers). Achtung bei C-FIND-Anfragen (C-FIND-RQ): Return-Keys wie die Modalität sind in der Anfrage üblicherweise leer (Universal Matching) — ein Filter darauf erfasst bei RQ-Captures daher nie etwas; sinnvoll ist er dort nur für tatsächlich gefüllte Matching-Keys. Antworten (C-FIND-RSP) tragen die Werte gefüllt.
Grenzen: Bei privaten oder dem Router unbekannten Tags wird der Wert als roher
Latin-1-Text verglichen — Umlaute/Sonderzeichen matchen dort unter Umständen
nicht; ohne Zeichensatz-Deklaration (0008,0005) wird ASCII angenommen.
Extrem grosse Attributwerte werden nicht gelesen (zählt als Lesefehler → nie
erfasst), und einzelne Werte über 1024 Zeichen matchen nie.
forward:-Block:
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
destination |
Pflicht | Name eines Ziels aus destinations:; muss vom Typ forward sein. |
spoolPath |
Pflicht | Absolutes Verzeichnis für die Warteschlange; ein eigenes Verzeichnis pro Action. |
onSuccess |
Default delete |
delete = versendete Dateien löschen; done = nach <spool>/done/ verschieben. |
spoolMaxMb |
optional | Obergrenze der Warteschlange; darüber setzt das Spooling aus (Warnung). Zählt nur die aktive Warteschlange — done/ und failed/ zählen nicht mit. |
callingAet |
Default AET des Router-Listeners | Calling-AET beim Versand. |
calledAet |
Default AET des Ziels | Called-AET beim Versand. |
Beispiel¶
actions:
tapSr: # nur Befunde (SR) ablegen
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.DicomTapStage
config:
pathTemplate: "/var/imconnect/tap/sr/<callingAet>/<studyInstanceUid>/<sopInstanceUid>.dcm"
sopClasses:
- "1.2.840.10008.5.1.4.1.1.88.11" # Basic Text SR
- "1.2.840.10008.5.1.4.1.1.88.22" # Enhanced SR
- "1.2.840.10008.5.1.4.1.1.88.33" # Comprehensive SR
finalize: on-success
quotaMb: 10240
tapForward: # Captures an ein Fremdsystem versenden
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.DicomTapStage
config:
forward:
destination: pacs2
spoolPath: /var/imconnect/tap-spool/sr
onSuccess: delete
spoolMaxMb: 4096
tapQueries: # C-FIND-Austausch beidseitig ablegen
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.DicomTapStage
config:
pathTemplate: "/var/imconnect/tap/queries/<callingAet>/<date>/<messageId>/<command>-<seq>.dcm"
commands: ["C-FIND-RQ", "C-FIND-RSP"]
filter:
- callingAET: US1
calledAET: PACS
actions:
- "tapSr"
destination:
- "pacs1"
Hinweise¶
- Atomare Dateien: Eine abgelegte Datei erscheint erst vollständig am Zielpfad. Nachgelagerte Skripte oder inotify-Watcher sehen nie eine partielle Datei.
finalize: Beion-success(Default) wird ein Capture erst wirksam, wenn die erfolgreiche Speicher-Bestätigung (C-STORE-Antwort, Success oder Warning) des Ziels der weitergeleiteten Verbindung eintrifft — also vom Primärziel der Filter-Regel, nicht vomforward:-Ziel. Das Gating gilt für beide Ausgänge gleichermassen: Weder wird die Datei abgelegt noch etwas in den Versand-Spool gestellt, solange die Bestätigung aussteht; ein Fehlschlag oder Verbindungsabbruch verwirft das Capture. Beialwayswird sofort abgelegt, unabhängig vom Ergebnis.- Ablage und Versand kombinieren:
pathTemplateundforwarddürfen in derselben Instanz stehen (mindestens eines von beiden muss konfiguriert sein) — dann wird jedes Capture abgelegt und versendet. Getrennte Action-Einträge braucht es nur, wenn Ablage und Versand unterschiedliche Selektionen (sopClasses,commands) haben sollen. - Der Tap beobachtet nur: Die Verbindung braucht immer ein normales
Weiterleitungs-Ziel in der Filter-Regel — „nur abzweigen, ohne weiterzuleiten"
gibt es nicht (ein
reject-Ziel würde die Verbindung ablehnen, bevor Daten fliessen). - Zielverzeichnisse und Schreibrechte: Der Router legt Unterverzeichnisse
unterhalb des Template-Stammverzeichnisses selbst an; das Stammverzeichnis
muss für den Dienst-Benutzer beschreibbar sein. Achtung mit der
mitgelieferten systemd-Unit: Sie erlaubt Schreibzugriffe nur unter
/var/imconnectund/var/log/imconnect(ProtectSystem=strict). Soll die Ablage woanders liegen (z. B./data/...), muss der Pfad in der Unit unterReadWritePaths=ergänzt werden — sonst setzt der Tap mit einer Warnung im Anwendungslog aus, während die Weiterleitung normal weiterläuft. Captures landen nur für den Dienst-Benutzer lesbar (Dateien0600, vom Router selbst angelegte Verzeichnisse0700) — die Dateien enthalten Patientendaten. Holt ein Konsument die Dateien unter einem anderen Konto ab, braucht er ausdrücklich eingeräumten Zugriff, etwa über die Gruppe oder eine ACL (setfacl) auf dem Ablageverzeichnis, oder er läuft unter dem Konto des Routers; bereits vorhandene, betreiberseitig angelegte Verzeichnisse behalten ihre Rechte. - Nie störend: Jeder Tap-Fehler (volle Platte, unbeschreibbares Verzeichnis) wird protokolliert, setzt den Tap für die Verbindung aus und lässt die Weiterleitung unverändert weiterlaufen. Die produktive Route ist nie betroffen.
- Fehlgeschlagene Sendungen (
failed/): Sendungen, die das Ziel dauerhaft ablehnt (z. B. nicht unterstützte Transfer-Syntax oder wiederholt fehlgeschlagene Speicherversuche), verschiebt der Versand nach<spool>/failed/und protokolliert eine Warnung — sie blockieren die Warteschlange nicht und werden nicht automatisch erneut versucht. Dasselbe gilt, wenn das Ziel auf einen Speicherversuch protokollwidrig antwortet: das Bild ist zu diesem Zeitpunkt bereits vollständig übertragen, nur die Quittung ist unbrauchbar. Ein erneuter Versuch würde deshalb nur eine weitere Kopie im Ziel erzeugen — der Eintrag wandert direkt nachfailed/. Bricht das Ziel die Verbindung dagegen mitten in der Übertragung ab, zählt das als ein fehlgeschlagener Zustellversuch wie eine reguläre Fehlerantwort: ein Abbruch kann vorübergehend sein (ein Gerät, das gerade neu startet), deshalb wird wiederholt und der Eintrag erst nach fünf Versuchen abgelegt. - Quota/Aufräumen: Das regelmässige Aufräumen der Ablage sowie der
done/- undfailed/-Verzeichnisse ist Aufgabe des Konsumenten bzw. Betreibers —done/undfailed/zählen nicht gegenspoolMaxMbund wachsen sonst unbegrenzt.quotaMbundspoolMaxMbgelten je Action-Eintrag (jeder Eintrag hat sein eigenes Stamm- bzw. Spool-Verzeichnis); sie sind ein Schutz gegen Volllaufen, kein Retention-Mechanismus. - PHI-Hinweis: Werden PHI-tragende Tags (z. B. Patientenname) ins
pathTemplateaufgenommen, landen Patientendaten in Dateinamen. Ob das zulässig ist und wie das Ablageverzeichnis abgesichert wird, ist eine bewusste Betreiber-Entscheidung. - Query-Capture (
commands:): Beim Mitschneiden von Abfragen gelten für daspathTemplatePflichtplatzhalter, damit sich Captures nicht überschreiben: Beim Mitschneiden von Antworten sind<seq>und<messageId>erforderlich (eine Abfrage liefert viele Antworten, und<seq>beginnt pro Austausch neu); beim Mitschneiden mehrerer Kommandos ist<command>erforderlich. Sollen sich Captures verschiedener Verbindungen nie überschreiben, gehört zusätzlich<associationId>ins Template. - Versand über Loopback: Soll der Versand durch weitere Umschreibe-Plugins laufen, zeigt die Forward-Destination auf einen Router-Listener; eine passende Filter-Regel hängt dort die gewünschten Actions an. Diese Loopback-Regel darf selbst keine Tap-Forward-Action referenzieren, sonst entsteht eine Endlosschleife (der Config-Load warnt bei dieser Konstellation).
CharsetTranscodePlugin¶
Was es tut¶
Kodiert die Textwerte ausgewählter DICOM-Nachrichten von einem Zeichensatz in
einen anderen um und schreibt die Zeichensatz-Deklaration (0008,0005) passend
nach. Anwendungsfall: Ein Gerät kann UTF-8 (ISO_IR 192) nicht darstellen —
z. B. zeigt eine Modality Worklist-Antworten mit Umlauten falsch an, weil ihr
Anzeigeteil nur Latin-1 (ISO_IR 100) beherrscht. Das Plugin kodiert die
Worklist-Antworten auf dem Weg zum Gerät um; das Quellsystem (RIS/PACS) bleibt
unangetastet.
Umkodiert werden alle Text-Felder mit erweitertem Zeichenvorrat (Personennamen,
Beschreibungen, Kommentare — die VRs PN/LO/SH/ST/LT/UT/UC), auch innerhalb von
Sequenzen. Datensätze ohne Zeichensatz-Deklaration oder mit einer Deklaration,
die nicht in from steht, werden byte-identisch durchgereicht. Ist der
Ziel-Zeichensatz ISO_IR 6 (Standard-Repertoire ASCII), wird (0008,0005)
entfernt — so verlangt es der DICOM-Standard.
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
from |
Pflicht | Quell-Zeichensätze (DICOM-Terme, z. B. ISO_IR 192). Nur Datensätze, deren (0008,0005) einen dieser Terme deklariert, werden umkodiert. |
to |
Pflicht | Ziel-Zeichensatz (DICOM-Term). ISO_IR 6 entfernt die Deklaration. Darf nicht gleichzeitig in from stehen. |
commands |
Default ["C-FIND-RSP"] |
Welche DIMSE-Nachrichten umkodiert werden (z. B. C-FIND-RSP, C-FIND-RQ, C-STORE-RQ). Die Richtung ergibt sich aus RQ/RSP. |
sopClasses |
optional (leer = alle) | Einschränkung auf bestimmte SOP-Klassen (Affected SOP Class UID des Kommandos), z. B. 1.2.840.10008.5.1.4.31 für die Modality Worklist. |
replacement |
Default ? |
Ersatzzeichen für Zeichen, die der Ziel-Zeichensatz nicht darstellen kann (genau ein Zeichen; kein DICOM-Trennzeichen \, ^, = und kein Steuerzeichen). Ersetzungen werden einmal pro Verbindung als Warnung protokolliert (nur Tag-Nummern, nie Werte). |
transliterate |
Default false |
Transliteriert nicht darstellbare Zeichen, bevor replacement greift: zuerst die eingebaute Tabelle (ä→ae, ö→oe, ü→ue, Ä→Ae, Ö→Oe, Ü→Ue, ß→ss, ẞ→SS), dann generisches Entfernen von Akzenten (é→e, à→a, ç→c, ñ→n, …). Beispiel: Mueller^Joerg statt M?ller^J?rg für ein Nur-ASCII-Gerät. Ohne das Flag verhält sich das Plugin exakt wie bisher. |
transliterations |
optional (leer) | Eigene Einträge, die die eingebaute Tabelle ergänzen oder überschreiben (z. B. "ø": "oe"). Schlüssel: genau ein Zeichen; Wert: Text, der im Ziel-Zeichensatz darstellbar ist und keine DICOM-Trennzeichen (\, ^, =) oder Steuerzeichen enthält. Nur zusammen mit transliterate: true erlaubt. |
logTranscodes |
Default true |
Protokolliert jede umkodierte Nachricht (ohne Inhalte). |
enabled |
Default true |
Schaltet das Plugin aus. |
Unterstützte Zeichensatz-Terme: ISO_IR 6 (ASCII), die Einzelbyte-Familie
ISO_IR 100/101/109/110/144/127/126/138/148/166/203 sowie
ISO_IR 192 (UTF-8), GB18030 und GBK. Unbekannte Terme lehnt der
Config-Load ab.
Beispiel¶
Worklist-Antworten für ein Latin-1-Gerät umkodieren:
actions:
worklistLatin1:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.charset.CharsetTranscodePlugin
config:
enabled: true
commands: ["C-FIND-RSP"] # Default
sopClasses: ["1.2.840.10008.5.1.4.31"] # Modality Worklist
from: ["ISO_IR 192"]
to: "ISO_IR 100"
replacement: "?"
filter:
- callingAET: US1
actions:
- "worklistLatin1"
destination:
- "ris1"
Welches Gerät die Umkodierung bekommt, steuert wie immer die Filter-Regel — es braucht keine eigene AET-Logik im Plugin.
Für ein Nur-ASCII-Gerät liefert transliterate: true lesbare Namen statt
Ersatzzeichen — Mueller^Joerg statt M?ller^J?rg:
actions:
worklistAscii:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.charset.CharsetTranscodePlugin
config:
commands: ["C-FIND-RSP"]
sopClasses: ["1.2.840.10008.5.1.4.31"]
from: ["ISO_IR 192", "ISO_IR 100"]
to: "ISO_IR 6"
transliterate: true
# transliterations: # optional: eingebaute Tabelle ergänzen/überschreiben
# "ø": "oe"
Hinweise¶
- Achtung, verlustbehaftete Ziele: Ein Ziel wie
ISO_IR 100kann nicht jedes Quell-Zeichen darstellen — nicht darstellbare Zeichen werden unwiderruflich durch das Ersatzzeichen ersetzt. Verlustbehaftete Umkodierungen deshalb nur in Richtung Anzeigegeräte einsetzen (Worklist, Query-Antworten). In Richtung Archiv/PACS ist nur das verlustfreie ZielISO_IR 192(UTF-8) vertretbar — archivierte Objekte mit ersetzten Zeichen sind dauerhaft beschädigt. - Transliteration greift nur bei nicht darstellbaren Zeichen: Ein Ziel wie
ISO_IR 100kannüdarstellen — dort bleibtüerhalten, auch mittransliterate: true.ueentsteht nur, wenn das Ziel das Zeichen nicht kennt (z. B.ISO_IR 6/ASCII). Bei Grossbuchstaben passt sich die Ersetzung dem Umfeld an:MÜLLERwirdMUELLER,MüllerwirdMueller— das gilt auch fürßin Grossbuchstaben-Umgebung (STRAßEwirdSTRASSE). Eigenetransliterations:-Einträge werden dagegen immer exakt wie konfiguriert eingesetzt — ohne Gross-/Kleinschreibungs-Anpassung. - Kürzung überlanger Werte (nur mit
transliterate: true): Transliteration kann Werte verlängern (aus einem Zeichen werden zwei). Wächst ein Wert dadurch über die vom DICOM-Standard erlaubte Maximallänge seines Feldtyps (Personenname und lange Beschreibung 64 Bytes, kurze Beschreibung 16 Bytes, Kurztext 1024 Bytes, Langtext 10240 Bytes; unbegrenzte Textfelder werden nie gekürzt), wird er am Ende abgeschnitten — bei mehrwertigen Feldern jeder Wert einzeln, die Trenner bleiben erhalten. Kürzungen werden einmal pro Verbindung als Warnung protokolliert (nur Tag-Nummern, nie Werte). Ohnetransliterate: truewird nie gekürzt. - Abgleich mit RIS/PACS: Das Gerät zeigt nach der Transliteration
Mueller, während RIS und PACS weiterhinMüllerführen. Schickt das Gerät den Patientennamen zurück (z. B. in MPPS oder in den Bildern), weicht er vom Auftragssystem ab — der Abgleich läuft in der Praxis über Patient-ID und Accession Number, nicht über den Namen. GegenüberM?llerist die Transliteration deterministisch und lesbar. - ISO 2022 ist nicht unterstützt: Mehrwertige
(0008,0005)-Deklarationen (Code-Extensions, z. B.\ISO 2022 IR 100oder japanische/koreanische Mehrbyte-Sätze) werden nicht umkodiert — solche Datensätze passieren unverändert, mit einer Warnung im Log (einmal pro Verbindung). - Grenze bei Implicit VR: Bei Implicit-VR-Übertragung steht der Feldtyp nicht im Datenstrom. Standard-Tags erkennt das Plugin über eine eingebaute Tabelle; private und unbekannte Tags bleiben bei Implicit VR unangetastet (bei Explicit VR werden sie normal umkodiert). Nicht auflösbare Sequenzen unbekannter Tags bleiben ebenfalls unangetastet.
- Alles oder nichts: Ein Datensatz wird entweder vollständig umkodiert oder vollständig unverändert durchgereicht. Bei jedem unerwarteten Problem (z. B. ein pathologisch grosser Textwert) passiert der Datensatz unverändert — das Plugin verwirft nie Nachrichten und bricht nie Verbindungen ab.
- Sequenz-Items mit eigener
(0008,0005)-Deklaration werden mit dieser umkodiert, sofern sie infromsteht; deklariert ein Item einen Zeichensatz ausserhalb vonfrom, bleibt das ganze Item unangetastet (Warnung im Log). - Es findet keine Transfer-Syntax-Konvertierung statt — nur die Zeichenkodierung der Textwerte ändert sich.
CharsetDeclarePlugin¶
Was es tut¶
Setzt oder überschreibt ausschliesslich die Zeichensatz-Deklaration
(0008,0005) ausgewählter DICOM-Nachrichten — die Textwerte selbst werden
nie umkodiert (das ist die Aufgabe des
CharsetTranscodePlugin). Zwei Anwendungsfälle:
mode: if-absent(Default): Eine Abfrage (z. B. ein Worklist-C-FIND-RQ) ohne Zeichensatz-Deklaration bekommt eine — viele RIS/PACS liefern ihre Antworten dann gleich im gewünschten Zeichensatz, transkodieren also selbst an der Quelle. Damit erübrigt sich oft das Umkodieren der Antworten im Router.mode: always: Korrigiert lügende Deklarationen — ein Gerät deklariert z. B.ISO_IR 100, sendet aber tatsächlich UTF-8-Bytes. Das Plugin schreibt die Deklaration auf den tatsächlichen Zeichensatz um, ohne die Bytes anzufassen.
Ist der konfigurierte Zeichensatz ISO_IR 6 (Standard-Repertoire ASCII), wird
(0008,0005) entfernt statt gesetzt — so verlangt es der DICOM-Standard
(das Standard-Repertoire wird durch Abwesenheit der Deklaration ausgedrückt).
Plugin-Klasse¶
Config-Felder¶
| Feld | Pflicht/Default | Bedeutung |
|---|---|---|
charset |
Pflicht | Der zu deklarierende Zeichensatz (DICOM-Term, z. B. ISO_IR 100). ISO_IR 6 entfernt die Deklaration (nur mit mode: always). |
mode |
Default if-absent |
if-absent: nur setzen, wenn (0008,0005) fehlt oder leer ist (mit ASCII-Prüfung, siehe Hinweise). always: vorhandene Deklaration immer überschreiben. |
commands |
Default ["C-FIND-RQ"] |
Welche DIMSE-Nachrichten die Deklaration bekommen (z. B. C-FIND-RQ, C-FIND-RSP, C-STORE-RQ). Die Richtung ergibt sich aus RQ/RSP. |
sopClasses |
optional (leer = alle) | Einschränkung auf bestimmte SOP-Klassen (Affected SOP Class UID des Kommandos), z. B. 1.2.840.10008.5.1.4.31 für die Modality Worklist. |
logDeclares |
Default true |
Protokolliert jede gesetzte/entfernte Deklaration (ohne Inhalte). |
enabled |
Default true |
Schaltet das Plugin aus. |
Unterstützte Zeichensatz-Terme: dieselben wie beim
CharsetTranscodePlugin (ISO_IR 6, die
Einzelbyte-Familie ISO_IR 100–203, ISO_IR 192, GB18030, GBK).
Unbekannte Terme lehnt der Config-Load ab.
Beispiel¶
Worklist-Abfragen eines Latin-1-Geräts bekommen eine Zeichensatz-Deklaration, damit das RIS seine Antworten selbst in Latin-1 liefert; als Fallback für RIS-Systeme, die den Abfrage-Zeichensatz ignorieren, kodiert das CharsetTranscodePlugin die Antworten zusätzlich um:
actions:
worklistCharset:
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.charset.CharsetDeclarePlugin
config:
commands: ["C-FIND-RQ"] # Default
sopClasses: ["1.2.840.10008.5.1.4.31"] # Modality Worklist
charset: "ISO_IR 100"
mode: if-absent
- plugin: ch.immeditech.imconnect.dicomrouter.plugin.charset.CharsetTranscodePlugin
config:
commands: ["C-FIND-RSP"] # Fallback: Antworten umkodieren
sopClasses: ["1.2.840.10008.5.1.4.31"]
from: ["ISO_IR 192"]
to: "ISO_IR 100"
filter:
- callingAET: US1
actions:
- "worklistCharset"
destination:
- "ris1"
Welches Gerät die Deklaration bekommt, steuert wie immer die Filter-Regel.
Hinweise¶
- Es werden nie Bytes umkodiert. Das Plugin ändert nur die Deklaration
(0008,0005); alle Textwerte passieren byte-identisch. Sollen die Werte selbst umkodiert werden, ist das CharsetTranscodePlugin zuständig. - ASCII-Prüfung bei
if-absent: Bevor eine Deklaration gesetzt wird, prüft das Plugin alle erkannten Textwerte (die VRs PN/LO/SH/ST/LT/UT/UC, auch in Sequenzen). Enthält irgendein Wert ein Byte ausserhalb von ASCII, wird nichts gesetzt und die Nachricht passiert unverändert (Warnung im Log, einmal pro Verbindung) — Bytes unbekannter Kodierung werden nicht umgedeutet. Beimode: alwaysentfällt diese Prüfung bewusst: das Umdeklarieren vorhandener Nicht-ASCII-Bytes ist dort gerade der Zweck. - Sequenz-Items mit eigener
(0008,0005)-Deklaration bleiben in beiden Modi unangetastet (Warnung im Log) — nur die Deklaration auf oberster Ebene wird geschrieben; die eigene Deklaration des Items gilt für dessen Werte weiter. - Grenze bei Implicit VR: Bei Implicit-VR-Übertragung steht der Feldtyp nicht im Datenstrom; Textfelder erkennt die ASCII-Prüfung über eine eingebaute Tabelle der Standard-Tags. Private und unbekannte Tags werden nicht geprüft — die Prüfung ist konservativ auf die erkannten Textwerte beschränkt.
ISO_IR 6entfernt: Der Standard-Zeichensatz wird auf dem Draht durch Abwesenheit von(0008,0005)ausgedrückt;charset: "ISO_IR 6"entfernt deshalb eine vorhandene Deklaration, statt eine zu setzen. Das wirkt nur mitmode: always— die Kombination mitif-absentwäre garantiert wirkungslos (bei fehlender Deklaration gibt es nichts zu entfernen) und wird beim Config-Load abgelehnt.- Erst prüfen, ob die Modalität es selbst kann: Viele Geräte können den gewünschten Abfrage-Zeichensatz selbst konfigurieren — das ist die sauberste Lösung. Das Plugin ist für Geräte gedacht, bei denen das nicht möglich ist.
- Bei jedem unerwarteten Problem passiert die Nachricht unverändert — das Plugin verwirft nie Nachrichten und bricht nie Verbindungen ab.