1+ import importlib
12import ssl
2- import urllib .error
33import urllib .parse
4+ import urllib .error
45import urllib .request
56from http .cookiejar import CookieJar
7+ from xml .etree .ElementTree import Element , SubElement , tostring
68
79REQUESTED_WITH_HEADER = "OpenIntegrationEngine-CI"
10+ MAX_REQUEST_TIMEOUT_SECONDS = 15
811
912
1013class ApiClient :
@@ -18,8 +21,8 @@ def request(
1821 method : str = "GET" ,
1922 data : bytes | None = None ,
2023 content_type : str | None = None ,
21- accept : str = "application/json " ,
22- timeout : int = 15 ,
24+ accept : str = "application/xml " ,
25+ timeout : int = MAX_REQUEST_TIMEOUT_SECONDS ,
2326 ) -> tuple [int , str ]:
2427 headers = {
2528 "Accept" : accept ,
@@ -51,17 +54,88 @@ def create_channel(self, channel_xml: bytes) -> None:
5154 method = "POST" ,
5255 data = channel_xml ,
5356 content_type = "application/xml" ,
54- accept = "application/json " ,
57+ accept = "*/* " ,
5558 )
5659
5760 def deploy_channel (self , channel_id : str ) -> None :
58- self .request (f"/api/channels/{ channel_id } /_deploy" , method = "POST" )
61+ self .request (f"/api/channels/{ channel_id } /_deploy" , method = "POST" , accept = "*/*" )
62+
63+ def get_channel_status (self , channel_id : str ):
64+ _ , body = self .request (
65+ f"/api/channels/{ channel_id } /status" ,
66+ accept = "application/xml" ,
67+ )
68+ return parse_xml (body )
5969
6070 def undeploy_channel (self , channel_id : str ) -> None :
61- self .request (f"/api/channels/{ channel_id } /_undeploy" , method = "POST" )
71+ self .request (f"/api/channels/{ channel_id } /_undeploy" , method = "POST" , accept = "*/*" )
6272
6373 def remove_channel (self , channel_id : str ) -> None :
64- self .request (f"/api/channels/{ channel_id } " , method = "DELETE" )
74+ self .request (f"/api/channels/{ channel_id } " , method = "DELETE" , accept = "*/*" )
75+
76+ def process_message (self , channel_id : str , raw_data : str , source_map : dict [str , object ] | None = None ) -> int :
77+ raw_message_xml = build_raw_message_xml (raw_data , source_map or {})
78+ _ , body = self .request (
79+ f"/api/channels/{ channel_id } /messagesWithObj" ,
80+ method = "POST" ,
81+ data = raw_message_xml ,
82+ content_type = "application/xml" ,
83+ accept = "application/xml" ,
84+ timeout = MAX_REQUEST_TIMEOUT_SECONDS ,
85+ )
86+ return parse_xml (body )
87+
88+ def get_message_content (self , channel_id : str , message_id : int , meta_data_ids : list [int ] | None = None ):
89+ query = ""
90+ if meta_data_ids :
91+ query = "?" + urllib .parse .urlencode ([("metaDataId" , meta_data_id ) for meta_data_id in meta_data_ids ])
92+ _ , body = self .request (
93+ f"/api/channels/{ channel_id } /messages/{ message_id } { query } " ,
94+ accept = "application/xml" ,
95+ timeout = MAX_REQUEST_TIMEOUT_SECONDS ,
96+ )
97+ return parse_xml (body )
98+
99+ def search_message (self , channel_id : str , message_id : int ):
100+ query = urllib .parse .urlencode (
101+ {
102+ "minMessageId" : message_id ,
103+ "maxMessageId" : message_id ,
104+ "includeContent" : "true" ,
105+ "offset" : 0 ,
106+ "limit" : 1 ,
107+ }
108+ )
109+ _ , body = self .request (
110+ f"/api/channels/{ channel_id } /messages?{ query } " ,
111+ accept = "application/xml" ,
112+ timeout = MAX_REQUEST_TIMEOUT_SECONDS ,
113+ )
114+ return parse_xml (body )
115+
116+
117+ def parse_xml (body : str ):
118+ etree = importlib .import_module ("lxml.etree" )
119+ return etree .fromstring (body .encode ("utf-8" ))
120+
121+
122+ def build_raw_message_xml (raw_data : str , source_map : dict [str , object ]) -> bytes :
123+ raw_message = Element ("com.mirth.connect.donkey.model.message.RawMessage" )
124+ SubElement (raw_message , "overwrite" ).text = "false"
125+ SubElement (raw_message , "imported" ).text = "false"
126+ SubElement (raw_message , "rawData" ).text = raw_data
127+
128+ source_map_element = SubElement (raw_message , "sourceMap" )
129+ source_map_element .set ("class" , "linked-hash-map" )
130+ for key , value in source_map .items ():
131+ if isinstance (value , dict ):
132+ raise RuntimeError (f"Nested source metadata is not supported for message submission: { key } " )
133+ entry = SubElement (source_map_element , "entry" )
134+ SubElement (entry , "string" ).text = str (key )
135+ SubElement (entry , "string" ).text = str (value )
136+
137+ SubElement (raw_message , "binary" ).text = "false"
138+ return tostring (raw_message , encoding = "utf-8" , xml_declaration = True )
65139
66140
67141def build_opener () -> urllib .request .OpenerDirector :
0 commit comments