Index: cloud_sync.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloud_sync.py (.../cloud_sync.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloud_sync.py (.../cloud_sync.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -20,78 +20,95 @@ from cloudsync.handlers.ui_cs_request_handler import UICSMessageHandler from cloudsync.busses.file_input_bus import FileInputBus from cloudsync.utils.heartbeat import HeartBeatProvider +from cloudsync.handlers.error import Error -VERSION = "0.2.6" +VERSION = "0.4.3" -arguments = sys.argv -log_level = int(arguments[1]) +try: + arguments = sys.argv + log_level = int(arguments[1]) -logging.basicConfig(filename='cloudsync.log', - level=log_level, - format='[%(asctime)s]: %(levelname)s - %(message)s | {%(pathname)s:%(lineno)d}', - ) + if not os.path.exists(CS_LOG_PATH): + os.makedirs(CS_LOG_PATH) -app = Flask(__name__) -api = Api(app=app, version=VERSION, title="CloudSync Registration API", - description="Interface with DIA Manufacturing Tool") + logging.basicConfig(filename=CS_LOG_FILE, + level=log_level, + format='[%(asctime)s]: %(levelname)s - %(message)s | {%(pathname)s:%(lineno)d}', + ) -for handler in app.logger.handlers: - app.logger.removeHandler(handler) -handler = logging.FileHandler('cloudsync.log') -handler.setLevel(log_level) -default_formatter = logging.Formatter('[%(asctime)s] %(levelname)s in %(module)s: %(message)s') -handler.setFormatter(default_formatter) + app = Flask(__name__) + api = Api(app=app, version=VERSION, title="CloudSync Registration API", + description="Interface with DIA Manufacturing Tool * DCS") -# app.logger.addHandler(handler) -app.logger.setLevel(log_level) + for handler in app.logger.handlers: + app.logger.removeHandler(handler) + handler = logging.FileHandler(CS_LOG_FILE) + handler.setLevel(log_level) + default_formatter = logging.Formatter('[%(asctime)s] %(levelname)s in %(module)s: %(message)s') + handler.setFormatter(default_formatter) -g_utils.add_logger(app.logger) + app.logger.setLevel(log_level) -g_config = helpers_read_config(CONFIG_PATH) + g_utils.add_logger(app.logger) -reachability_provider = ReachabilityProvider(logger=app.logger) + g_config = helpers_read_config(CONFIG_PATH) -g_utils.add_reachability_provider(reachability_provider=reachability_provider) + if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation': + helpers_read_config(OPERATION_CONFIG_FILE_PATH) + CONFIG_PATH = OPERATION_CONFIG_FILE_PATH -output_channel = FileOutputBus(logger=app.logger, max_size=100, file_channels_path=UI2CS_FILE_CHANNELS_PATH) + reachability_provider = ReachabilityProvider(logger=app.logger) -error_handler = ErrorHandler(logger=app.logger, max_size=100, output_channel=output_channel) + g_utils.add_reachability_provider(reachability_provider=reachability_provider) -network_request_handler = NetworkRequestHandler(logger=app.logger, max_size=1, output_channel=output_channel, - reachability_provider=reachability_provider, - error_handler=error_handler) -message_handler = UICSMessageHandler(logger=app.logger, max_size=20, network_request_handler=network_request_handler, - output_channel=output_channel, reachability_provider=reachability_provider, - error_handler=error_handler) -ui_cs_bus = FileInputBus(logger=app.logger, file_channels_path=UI2CS_FILE_CHANNELS_PATH, input_channel_name="inp.buf", - g_config=g_config, message_handler=message_handler) + output_channel = FileOutputBus(logger=app.logger, max_size=100, file_channels_path=UI2CS_FILE_CHANNELS_PATH) -heartbeat_provider = HeartBeatProvider(logger=app.logger, network_request_handler=network_request_handler, - output_channel=output_channel) + error_handler = ErrorHandler(logger=app.logger, max_size=100, output_channel=output_channel) -if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation': - heartbeat_provider.send_heartbeat = True -else: - heartbeat_provider.send_heartbeat = False + network_request_handler = NetworkRequestHandler(logger=app.logger, max_size=1, output_channel=output_channel, + reachability_provider=reachability_provider, + error_handler=error_handler) + message_handler = UICSMessageHandler(logger=app.logger, max_size=20, network_request_handler=network_request_handler, + output_channel=output_channel, reachability_provider=reachability_provider, + error_handler=error_handler) + ui_cs_bus = FileInputBus(logger=app.logger, file_channels_path=UI2CS_FILE_CHANNELS_PATH, input_channel_name="inp.buf", + g_config=g_config, message_handler=message_handler) -parser = reqparse.RequestParser() + heartbeat_provider = HeartBeatProvider(logger=app.logger, network_request_handler=network_request_handler, + output_channel=output_channel) -# START - REGISTRATION ENDPOINTS + if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation': + heartbeat_provider.send_heartbeat = True + else: + heartbeat_provider.send_heartbeat = False + g_utils.logger.debug("Current config path: {0}".format(CONFIG_PATH)) + + parser = reqparse.RequestParser() +except Exception as e: + error = Error("{0},2,{1},Failed to start CS - {2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.GENERIC_ERROR.value, + e)) + self.error_handler.enqueue_error(error=error) + + @api.route("/version") class Version(Resource): @api.response(OK, "Success") def get(self): app.logger.info("Received /version HTTP request") - return { - "version": VERSION - }, OK + if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration': + return { + "version": VERSION + }, OK + +# START - REGISTRATION ENDPOINTS + @api.route("/credentials") class Credentials(Resource): - FIELD_CREDENTIALS = api.model("Credentials", { "certificate": fields.String, "public_key": fields.String, @@ -103,58 +120,71 @@ @api.response(BAD_REQUEST, "Validation Error") def put(self): """ - 4. Update the device's certificate and keys + Update the device's certificate and keys Manufacturing Tool -> Device """ app.logger.info("Received /credentials HTTP request") - payload = request.json - certificate = payload.get("certificate", None) - private_key = payload.get("private_key", None) - public_key = payload.get("public_key", None) - invalid_params = [] - if certificate is None: - invalid_params.append("certificate") - if private_key is None: - invalid_params.append("private_key") - if public_key is None: - invalid_params.append("public_key") - if len(invalid_params) > 0: - return {"invalidAttributes": invalid_params}, BAD_REQUEST - r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_SET_CREDENTIALS, - url=request.url, - payload=payload, - method=request.method, - g_config=g_config, - ) - network_request_handler.enqueue_request(r) + if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration': + payload = request.json + certificate = payload.get("certificate", None) + private_key = payload.get("private_key", None) + public_key = payload.get("public_key", None) + invalid_params = [] + if certificate is None: + invalid_params.append("certificate") + if private_key is None: + invalid_params.append("private_key") + if public_key is None: + invalid_params.append("public_key") + if len(invalid_params) > 0: + error = Error("{0},2,{1}, invalid credentials".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SAVE_CREDENTIALS_ERROR.value, + invalid_params)) + error_handler.enqueue_error(error=error) + return {"invalidAttributes": invalid_params}, BAD_REQUEST - return { - "invalidAttributes": [], - }, OK + try: + helpers_add_to_network_queue(network_request_handler=network_request_handler, + request_type=NetworkRequestType.MFT2CS_REQ_SET_CREDENTIALS, + url=request.url, + payload=payload, + method=request.method, + g_config=g_config, + success_message='CS2MFT_REQ_SET_CREDENTIALS request added to network ' + 'queue') + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SAVE_CREDENTIALS_ERROR.value, + e)) + error_handler.enqueue_error(error=error) + return { + "invalidAttributes": [], + }, OK + @api.route("/validate") class Validate(Resource): @api.response(OK, "Success") def head(self): """ - 5. Initiate device connectivity test + Initiate device connectivity test Manufacturing Tool -> Device """ app.logger.info("Received /validate HTTP request") - r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_INIT_CONNECTIVITY_TEST, - url=request.url, - payload={}, - method=request.method, - g_config=g_config, - ) - network_request_handler.enqueue_request(r) + if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration': + r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_INIT_CONNECTIVITY_TEST, + url=request.url, + payload={}, + method=request.method, + g_config=g_config, + ) + network_request_handler.enqueue_request(r) - # no body is returned - return {}, OK + return {}, OK @api.route("/reset") @@ -163,72 +193,36 @@ @api.response(OK, "Success") def head(self): """ - 13. Initiate a factory reset + Initiate a factory reset Assumes the connectivity test has already been completed Manufacturing Tool -> Device """ app.logger.info("Received /reset HTTP request") - r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_FACTORY_RESET, - url=request.url, - payload={}, - method=request.method, - g_config=g_config, - ) - network_request_handler.enqueue_request(r) + if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration': + r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_FACTORY_RESET, + url=request.url, + payload={}, + method=request.method, + g_config=g_config, + ) + network_request_handler.enqueue_request(r) - heartbeat_provider.send_heartbeat = True + heartbeat_provider.send_heartbeat = True - return {}, OK + return {}, OK + # END - REGISTRATION ENDPOINTS -@api.route("/config") -class Config(Resource): - @api.response(OK, "Success") - def get(self): - """ - Get the current json config - """ - app.logger.info("Received /config HTTP request") - return g_config, OK - - -@api.route("/token") -class Config(Resource): - - @api.response(OK, "Success") - def get(self): - """ - Get the currently stored token - """ - app.logger.info("Received /token HTTP request") - return helpers_read_access_token(DEVICE_KEBORMED_ACCESS_TOKEN_PATH), OK - - -@api.route("/logs") -class Logs(Resource): - - @api.hide - def get(self): - app.logger.info("Received /logs HTTP request") - content = "" - with open(CS_LOG_FILE, 'r') as f: - content = f.read() - return Response(content, mimetype="text/plain") - - def main(): - if DEBUG: + if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration': app.run(debug=False, use_reloader=False, host="0.0.0.0", port=g_config[CONFIG_DEVICE][CONFIG_DEVICE_PORT]) - elif VM: - app.logger.error("VM mode not implemented yet.") - elif SERVER: - app.logger.error("Server mode not implemented yet.") else: - app.logger.error("Production mode not implemented yet.") + while True: + sleep(1) if __name__ == '__main__': Index: cloudsync/busses/file_input_bus.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/busses/file_input_bus.py (.../file_input_bus.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/busses/file_input_bus.py (.../file_input_bus.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -36,7 +36,7 @@ self.message_handler = message_handler self.i = inotify.adapters.Inotify() - print(self.file_channels_path) + # print(self.file_channels_path) self.i.add_watch(self.file_channels_path) self.thread = Thread(target=self.input_channel_handler, daemon=True) @@ -62,7 +62,7 @@ for line in f.readlines(): message_parameters = line.strip().split(',') - print("message parameters: {0}".format(message_parameters)) + # print("message parameters: {0}".format(message_parameters)) if int(message_parameters[1]) > self.last_input_message_id: new_message = UICSMessage(line.strip(), self.g_config) message_added_to_queue = self.message_handler.enqueue_message(new_message) Index: cloudsync/busses/file_output_bus.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/busses/file_output_bus.py (.../file_output_bus.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/busses/file_output_bus.py (.../file_output_bus.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -46,8 +46,7 @@ self.handle_message(message_body) self.event.clear() - def enqueue_message(self, - message_body: str) -> bool: + def enqueue_message(self, message_body: str) -> bool: """ Adds messages to the queue :param str message_body: the data to add to the queue @@ -66,16 +65,16 @@ Parses queue messages and send them downstream :param str message_body: the message body """ - print('Message body: {0}'.format(message_body)) + # print('Message body: {0}'.format(message_body)) self.logger.debug('Message body: {0}'.format(message_body)) try: filename = datetime.datetime.utcnow().date().strftime("%Y_%m_%d_out.buf") message_data = str(round(datetime.datetime.now().timestamp())) + str(self.last_output_message_id) + message_body - message_crc8 = helpers.crc8(message_data.encode('utf-8')) + message_crc8 = helpers.helpers_crc8(message_data.encode('utf-8')) message_body = str(round(datetime.datetime.now().timestamp())) + ',' + str(self.last_output_message_id) + ',' + str(message_crc8) + ',' + message_body self.logger.debug('Full message: {0}'.format(message_body)) - print('Full message: {0}'.format(message_body)) + # print('Full message: {0}'.format(message_body)) f = open(self.file_channels_path + "/" + filename, "a") f.write("{0}\n".format(message_body)) f.close() Index: cloudsync/common/enums.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/common/enums.py (.../enums.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/common/enums.py (.../enums.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -116,4 +116,7 @@ CS_VALIDATE_DEVICE_ERROR = 924 CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR = 925 CS_CREATE_TEMPORARY_PATIENT_ERROR = 926 + CS_SAVE_CREDENTIALS_ERROR = 927 + CS_UNKNOWN_DEVICE_STATE_ERROR = 928 + CS_SAVE_CONFIG_ERROR = 929 Index: cloudsync/config/config.json =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/config/config.json (.../config.json) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/config/config.json (.../config.json) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -1,14 +1,14 @@ { "kebormed_paas": { - "idp_client_secret": "", - "url_mft": "", - "url_dcs": "", - "url_device_identity": "", + "idp_client_secret": "NL2cn6eMyg2WLSB0nhfvbxvM79dvo3ta", + "url_mft": "http://172.31.99.117:3000", + "url_dcs": "https://device-api.diality.staging.kebormed.com", + "url_device_identity": "https://device-identity.diality.staging.kebormed.com/auth/realms/Main/protocol/openid-connect/token", "dia_org_id": 1 }, "device": { "ip": "", - "port": 5001, + "port": 80, "name": "", "hd_serial": "", "dg_serial": "", Index: cloudsync/config/config_STAGING.json =================================================================== diff -u --- cloudsync/config/config_STAGING.json (revision 0) +++ cloudsync/config/config_STAGING.json (revision cc7bbd932684e69aa456c114596625546630903e) @@ -0,0 +1,19 @@ +{ + "kebormed_paas": { + "idp_client_secret": "NL2cn6eMyg2WLSB0nhfvbxvM79dvo3ta", + "url_mft": "", + "url_dcs": "https://device-api.diality.staging.kebormed.com", + "url_device_identity": "https://device-identity.diality.staging.kebormed.com/auth/realms/Main/protocol/openid-connect/token", + "dia_org_id": 1 + }, + "device": { + "ip": "", + "port": 5001, + "name": "", + "hd_serial": "", + "dg_serial": "", + "sw_version": "", + "mode": "registration", + "device_state": "INACTIVE_NOT_OK" + } +} \ No newline at end of file Index: cloudsync/config/treatment_report_template.json =================================================================== diff -u -r5e2872a15167f8d66d074d106f3afc78d1da3dea -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/config/treatment_report_template.json (.../treatment_report_template.json) (revision 5e2872a15167f8d66d074d106f3afc78d1da3dea) +++ cloudsync/config/treatment_report_template.json (.../treatment_report_template.json) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -1,6 +1,7 @@ { "organizationId": "", "serialNumber": "", + "checksum": "", "data": { "patient": { "id": "" Index: cloudsync/handlers/cs_mft_dcs_request_handler.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/handlers/cs_mft_dcs_request_handler.py (.../cs_mft_dcs_request_handler.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/handlers/cs_mft_dcs_request_handler.py (.../cs_mft_dcs_request_handler.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -63,6 +63,8 @@ Called on each timer event. Logs the data currently in deque :return: None """ + + # REGISTRATION MODE if req.request_type == NetworkRequestType.CS2MFT_REQ_REGISTRATION: try: response = cmd_outgoing_register(device_name=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_NAME], @@ -73,151 +75,203 @@ CONFIG_KEBORMED_MFT_URL], data_source_id=req.g_config[CONFIG_KEBORMED][ CONFIG_KEBORMED_DIA_ORG_ID], - headers=req.headers) + headers=req.headers, + error_handler=self.error_handler) self.logger.debug("DRT Request registration resp: {0}".format(response)) except Exception as e: error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_REQ_REGISTRATION_ERROR.value, e)) self.error_handler.enqueue_error(error=error) elif req.request_type == NetworkRequestType.MFT2CS_REQ_SET_CREDENTIALS: - certificate = req.payload.get("certificate") - private_key = req.payload.get("private_key") - public_key = req.payload.get("public_key") - cmd_incoming_set_credentials(certificate=certificate, - private_key=private_key, - public_key=public_key, - output_channel=self.output_channel) + try: + certificate = req.payload.get("certificate") + private_key = req.payload.get("private_key") + public_key = req.payload.get("public_key") + cmd_incoming_set_credentials(certificate=certificate, + private_key=private_key, + public_key=public_key, + output_channel=self.output_channel, + error_handler=self.error_handler) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SAVE_CREDENTIALS_ERROR.value, + e)) + self.error_handler.enqueue_error(error=error) elif req.request_type == NetworkRequestType.MFT2CS_REQ_INIT_CONNECTIVITY_TEST: - url_validate = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DCS_URL] - url_validate = urllib.parse.urljoin(url_validate, "api/device/validate") - cmd_incoming_initiate_connectivity_test( - url_token=req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DEVICE_IDENTITY_URL], - url_validate=url_validate, - hd_serial=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL], - dg_serial=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL], - sw_version=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION], - g_config=req.g_config) + try: + url_validate = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DCS_URL] + url_validate = urllib.parse.urljoin(url_validate, "api/device/validate") + cmd_incoming_initiate_connectivity_test( + url_token=req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DEVICE_IDENTITY_URL], + url_validate=url_validate, + hd_serial=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL], + dg_serial=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL], + sw_version=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION], + g_config=req.g_config, + error_handler=self.error_handler + ) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value, + e)) + self.error_handler.enqueue_error(error=error) elif req.request_type == NetworkRequestType.MFT2CS_REQ_FACTORY_RESET: req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] = 'operation' - helpers_write_config(CONFIG_PATH, req.g_config) + helpers_write_config(None, CONFIG_PATH, req.g_config) + helpers_write_config(OPERATION_CONFIG_PATH, OPERATION_CONFIG_FILE_PATH, req.g_config) cmd_incoming_factory_reset(output_channel=self.output_channel) + # OPERATION MODE elif req.request_type == NetworkRequestType.CS2DCS_REQ_SET_DEVICE_STATE: - device_state = req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_STATE] + try: + device_state = req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_STATE] - base_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DCS_URL] - identity_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DEVICE_IDENTITY_URL] - client_secret = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_IDP_CLIENT_SECRET] - token_verification_url = urllib.parse.urljoin(base_url, "api/common/info") - device_state_url = urllib.parse.urljoin(base_url, "/api/device/state/{0}".format(device_state)) + base_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DCS_URL] + identity_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DEVICE_IDENTITY_URL] + client_secret = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_IDP_CLIENT_SECRET] + token_verification_url = urllib.parse.urljoin(base_url, DEVICE_TOKEN_VALIDATION) + device_state_url = urllib.parse.urljoin(base_url, "/api/device/state/{0}".format(device_state)) - access_token = self.get_valid_token(identity_url=identity_url, - token_verification_url=token_verification_url, - client_secret=client_secret) + access_token = self.get_valid_token(identity_url=identity_url, + token_verification_url=token_verification_url, + client_secret=client_secret) - response = cmd_outgoing_set_device_state(url=device_state_url, - access_token=access_token) + if access_token is not None: + response = cmd_outgoing_set_device_state(url=device_state_url, + access_token=access_token, + error_handler=self.error_handler) - self.logger.debug("DCS Request device state response: {0}".format(response.text)) + self.logger.debug("DCS Request device state response code: {0} & full response: {1}".format(response.status_code, response.text)) + if response.status_code == UNASSIGNED: + error = Error("{0},2,{1}, Invalid device state transition".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value)) + self.error_handler.enqueue_error(error=error) + else: + error = Error( + "{0},2,{1}, Missing access token".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value)) + self.error_handler.enqueue_error(error=error) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value, + e)) + self.error_handler.enqueue_error(error=error) elif req.request_type == NetworkRequestType.CS2DCS_REQ_SEND_TREATMENT_REPORT: - treatment_log_json = req.payload - patient_emr_id = treatment_log_json['data']['patient']['id'] + try: + treatment_log_json = req.payload + patient_emr_id = treatment_log_json['data']['patient']['id'] - base_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DCS_URL] - identity_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DEVICE_IDENTITY_URL] - client_secret = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_IDP_CLIENT_SECRET] - token_verification_url = urllib.parse.urljoin(base_url, "api/common/info") - validate_url = urllib.parse.urljoin(base_url, "api/device/validate") - data_submission_url = urllib.parse.urljoin(base_url, "/api/device/data") + base_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DCS_URL] + identity_url = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_DEVICE_IDENTITY_URL] + client_secret = req.g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_IDP_CLIENT_SECRET] + token_verification_url = urllib.parse.urljoin(base_url, DEVICE_TOKEN_VALIDATION) + validate_url = urllib.parse.urljoin(base_url, "api/device/validate") + data_submission_url = urllib.parse.urljoin(base_url, "/api/device/data") - access_token = self.get_valid_token(identity_url=identity_url, - token_verification_url=token_verification_url, - client_secret=client_secret) + access_token = self.get_valid_token(identity_url=identity_url, + token_verification_url=token_verification_url, + client_secret=client_secret) - # Step #1 - get organization id for current device + # Step #1 - get organization id for current device - response = cmd_outgoing_validate_device(access_token=access_token, - hd_serial_number=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL], - dg_serial_number=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL], - sw_version=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION], - url=validate_url) + response = cmd_outgoing_validate_device(access_token=access_token, + hd_serial_number=req.g_config[CONFIG_DEVICE][ + CONFIG_DEVICE_HD_SERIAL], + dg_serial_number=req.g_config[CONFIG_DEVICE][ + CONFIG_DEVICE_DG_SERIAL], + sw_version=req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION], + url=validate_url, + error_handler=self.error_handler) - invalid_attributes = response.get("invalidAttributes", None) + invalid_attributes = response.get("invalidAttributes", None) - if len(invalid_attributes) > 0: - self.logger.error( - "Device with HD serial number {0}, DG serial number {1}, software version {2} is not a valid device for treatment. Invalid fields: {3}".format( - req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL], - req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL], - req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION], - invalid_attributes)) - return response - else: - organization_id = response.get("associatedOrganizationId", None) - treatment_log_json['organizationId'] = organization_id + if len(invalid_attributes) > 0: + self.logger.error( + "Device with HD serial number {0}, DG serial number {1}, software version {2} is not a valid " + "device for treatment. Invalid fields: {3}".format( + req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL], + req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL], + req.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION], + invalid_attributes)) + return response + else: + organization_id = response.get("associatedOrganizationId", None) + treatment_log_json['organizationId'] = organization_id - # Step #2 - Set patient by patient_emr_id + # Step #2 - Set patient by patient_emr_id - patient_with_emr_id_exists_url = urllib.parse.urljoin(base_url, - "api/device/organization/{0}/patient/{1}".format( - organization_id, patient_emr_id)) - create_temporary_patient_url = urllib.parse.urljoin(base_url, - "api/device/organization/{0}/patient/{1}".format( - organization_id, patient_emr_id)) + patient_with_emr_id_exists_url = urllib.parse.urljoin(base_url, + "api/device/organization/{0}/patient/{1}".format( + organization_id, patient_emr_id)) + create_temporary_patient_url = urllib.parse.urljoin(base_url, + "api/device/organization/{0}/patient/{1}".format( + organization_id, patient_emr_id)) - # Step #2a - Check if patient exists by patient_emr_id + # Step #2a - Check if patient exists by patient_emr_id - response = cmd_outgoing_check_if_patient_with_emr_id_exists(access_token=access_token, - url=patient_with_emr_id_exists_url) + response = cmd_outgoing_check_if_patient_with_emr_id_exists(access_token=access_token, + url=patient_with_emr_id_exists_url, + error_handler=self.error_handler) - # Step #2b - If patient with emr_id doesn't exist, create temporary patient + # Step #2b - If patient with emr_id doesn't exist, create temporary patient - if response.status_code == OK: - patient_id = response.json().get("id", None) - elif response.status_code == NOT_FOUND: - response = cmd_outgoing_create_temporary_patient(access_token=access_token, - url=create_temporary_patient_url) - patient_id = response.get("id", None) - else: - g_utils.logger.error("Patient didn't exist and a temporary patient couldn't be created") - return response + if response.status_code == OK: + patient_id = response.json().get("id", None) + elif response.status_code == NOT_FOUND: + response = cmd_outgoing_create_temporary_patient(access_token=access_token, + url=create_temporary_patient_url, + error_handler=self.error_handler) + patient_id = response.get("id", None) + else: + g_utils.logger.warning("Patient didn't exist and a temporary patient couldn't be created") + return response - patient_device_association_url = urllib.parse.urljoin(base_url, - "/api/device/organization/{0}/patient/{1}/association".format( - organization_id, patient_id)) - # Step #3 - Check if device is associated to patient and if not associate it + patient_device_association_url = urllib.parse.urljoin(base_url, + "/api/device/organization/{0}/patient/{1}/association".format( + organization_id, patient_id)) + # Step #3 - Check if device is associated to patient and if not associate it - response = cmd_outgoing_set_patient_device_association(url=patient_device_association_url, - access_token=access_token, - associate=True) - # Step #4 - Send treatment report + response = cmd_outgoing_set_patient_device_association(url=patient_device_association_url, + access_token=access_token, + associate=True, + error_handler=self.error_handler) + # Step #4 - Send treatment report - treatment_log_json['generatedAt'] = int(round( - time() * S_MS_CONVERSION_FACTOR)) + 30000 # TEMPORARY DELAY TO COMPENSATE FOR DEVICE INTERNAL CLOCK ERROR - TODO REMOVE AFTER FIX - treatment_log_json['completedAt'] = int(round( - time() * S_MS_CONVERSION_FACTOR)) + 31000 # TEMPORAR DELAY TO COMPENSATE FOR DEVICE INTERNAL CLOCK ERROR - TODO REMOVE AFTER FIX + treatment_log_json['generatedAt'] = int(round( + time() * S_MS_CONVERSION_FACTOR)) + 30000 # TEMPORARY DELAY TO COMPENSATE FOR DEVICE INTERNAL CLOCK ERROR - TODO REMOVE AFTER FIX + treatment_log_json['completedAt'] = int(round( + time() * S_MS_CONVERSION_FACTOR)) + 31000 # TEMPORARY DELAY TO COMPENSATE FOR DEVICE INTERNAL CLOCK ERROR - TODO REMOVE AFTER FIX - treatment_log_json = json.dumps(treatment_log_json) + treatment_log_json = json.dumps(treatment_log_json) - self.logger.debug("treatment log: {0}".format(treatment_log_json)) + self.logger.debug("treatment log: {0}".format(treatment_log_json)) - response = cmd_outgoing_send_treatment_report(url=data_submission_url, - access_token=access_token, - treatment_log=treatment_log_json) - treatment_id = response.json().get("reference", None) + response = cmd_outgoing_send_treatment_report(url=data_submission_url, + access_token=access_token, + treatment_log=treatment_log_json, + error_handler=self.error_handler) - # Step #5 - Remove patient/device association + if response is not None: + self.logger.debug("Treatment upload response: {0}".format(response.json())) - response = cmd_outgoing_set_patient_device_association(url=patient_device_association_url, - access_token=access_token, - associate=False) - # Step #6 - Send TX code to UI app + treatment_id = response.json().get("reference", None) - message_body = str(OutboundMessageIDs.CS2UI_REQ_TX_CODE_DISPLAY.value) + ',1,' + treatment_id - self.output_channel.enqueue_message(message_body) + # Step #5 - Remove patient/device association - return response + response = cmd_outgoing_set_patient_device_association(url=patient_device_association_url, + access_token=access_token, + associate=False, + error_handler=self.error_handler) + # Step #6 - Send TX code to UI app + + message_body = str(OutboundMessageIDs.CS2UI_REQ_TX_CODE_DISPLAY.value) + ',1,' + treatment_id + self.output_channel.enqueue_message(message_body) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_TREATMENT_REPORT_ERROR.value, + e)) + self.error_handler.enqueue_error(error=error) else: g_utils.logger.warning("Request type {0} not supported".format(req.request_type)) @@ -229,18 +283,20 @@ path_private_key=CREDENTIALS_PRIVATE_KEY, save=True, url=identity_url, - client_secret=client_secret) + client_secret=client_secret, + error_handler=self.error_handler) else: response = cmd_outgoing_verify_token(url=token_verification_url, - access_token=access_token) + access_token=access_token, + error_handler=self.error_handler) if response.status_code == UNAUTHORIZED: access_token = cmd_outgoing_get_new_token_with_cert(path_certificate=CREDENTIALS_CERTIFICATE_X509, path_private_key=CREDENTIALS_PRIVATE_KEY, save=True, url=identity_url, - client_secret=client_secret) + client_secret=client_secret, + error_handler=self.error_handler) - self.remove_secrets() return access_token def wait_for_network(self, wait_time): @@ -252,15 +308,3 @@ return False else: return True - - def remove_secrets(self): - try: - if os.path.exists(CREDENTIALS_CERTIFICATE_X509): - os.remove(CREDENTIALS_CERTIFICATE_X509) - if os.path.exists(CREDENTIALS_PRIVATE_KEY): - os.remove(CREDENTIALS_PRIVATE_KEY) - if os.path.exists(CREDENTIALS_PUBLIC_KEY): - os.remove(CREDENTIALS_PUBLIC_KEY) - self.logger.info('Credentials deleted locally') - except IOError as er: - self.logger.error('Error removing secrets: {0}'.format(' '.join(er.args))) Index: cloudsync/handlers/incoming/handler_mft_to_cs.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/handlers/incoming/handler_mft_to_cs.py (.../handler_mft_to_cs.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/handlers/incoming/handler_mft_to_cs.py (.../handler_mft_to_cs.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -14,17 +14,21 @@ def cmd_incoming_set_credentials(certificate: str, private_key: str, public_key: str, - output_channel) -> None: + output_channel, + error_handler: ErrorHandler) -> None: """ - Sets device credentials - :param str certificate: the X.509 certificate - :param str private_key: the private key - :param str public_key: the public key + Sets the credentials on the device + :param certificate: The X.509 certificate + :param private_key: The private key + :param public_key: The public key :param output_channel: CS_UI output channel + :param error_handler: global error handler :return: None - :raises IOError: if any of the device credentials can't be saved """ try: + if not os.path.exists(CREDENTIALS_PATH): + os.makedirs(CREDENTIALS_PATH) + f = open(CREDENTIALS_CERTIFICATE_X509, 'w') f.write(certificate) f.close() @@ -37,23 +41,15 @@ f.write(public_key) f.close() - f = open(TEMP_CREDENTIALS_CERTIFICATE_X509, 'w') - f.write(certificate) - f.close() - - f = open(TEMP_CREDENTIALS_PRIVATE_KEY, 'w') - f.write(private_key) - f.close() - - f = open(TEMP_CREDENTIALS_PUBLIC_KEY, 'w') - f.write(public_key) - f.close() - - message_body = str(OutboundMessageIDs.CS2UI_REQ_SAVE_CREDENTIALS.value) + ',3,' + CREDENTIALS_CERTIFICATE_X509 + ',' + CREDENTIALS_PRIVATE_KEY + ',' + CREDENTIALS_PUBLIC_KEY + message_body = str( + OutboundMessageIDs.CS2UI_REQ_SAVE_CREDENTIALS.value) + ',3,' + CREDENTIALS_CERTIFICATE_X509 + ',' + CREDENTIALS_PRIVATE_KEY + ',' + CREDENTIALS_PUBLIC_KEY output_channel.enqueue_message(message_body) except IOError as er: - self.logger.error('Error writing secrets: {0}'.format(' '.join(er.args))) + error = Error("{0},2,{1},Error writing device credentials".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SAVE_CREDENTIALS_ERROR.value)) + error_handler.enqueue_error(error=error) + g_utils.logger.error('Error writing device credentials: {0}'.format(' '.join(er.args))) @log_func @@ -62,86 +58,77 @@ hd_serial: str, dg_serial: str, sw_version: str, - g_config: dict) -> None: + g_config: dict, + error_handler: ErrorHandler) -> None: """ - Initiates the connectivity test on the device - # Step 6. Device Auth (POST /auth/...) - # Step 7. Device Auth Response (access token) - # Step 8. Validate Device (POST /api/device/validate) - # Step 9. Validate Device Response (list of invalid fields) - # Step 10. Validation Result (POST /validation) (list of invalid fields) - :param url_token: The kebormed request new token url - :param username: The username for requesting a token - :param password: The password for requesting a token + Initiates the connectivity test on the device: + - verifies if device can connect to DCS + - verifies if device can obtain a valid token + - verifies if device information (hd serial, dg serial & software version) matches the cloud values + :param url_token: Identity Provider URL + :param url_validate: Device connectivity test URL :param hd_serial: The hd serial number :param dg_serial: The dg serial number :param sw_version: The software version :param g_config: The configuration dictionary + :param error_handler: global error handler :return: None """ - # Step 6. Device Auth (POST /auth/...) - # Step 7. Device Auth Response (access token) - client_secret = g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_IDP_CLIENT_SECRET] - access_token = cmd_outgoing_get_new_token_with_cert(path_certificate=TEMP_CREDENTIALS_CERTIFICATE_X509, - path_private_key=TEMP_CREDENTIALS_PRIVATE_KEY, - save=True, - url=url_token, - client_secret=client_secret) - if access_token is not None: - g_utils.logger.debug("Access token: {0}".format(access_token)) - # Step 8. Validate Device (POST /api/device/validate) - # Step 9. Validate Device Response (list of invalid fields) - response = cmd_outgoing_validate_device(access_token=access_token, - hd_serial_number=hd_serial, - dg_serial_number=dg_serial, - sw_version=sw_version, - url=url_validate) - g_utils.logger.debug("Response: {0}".format(response)) - invalid_attributes = response.get("invalidAttributes", None) + try: + client_secret = g_config[CONFIG_KEBORMED][CONFIG_KEBORMED_IDP_CLIENT_SECRET] + access_token = cmd_outgoing_get_new_token_with_cert(path_certificate=CREDENTIALS_CERTIFICATE_X509, + path_private_key=CREDENTIALS_PRIVATE_KEY, + save=True, + url=url_token, + client_secret=client_secret, + error_handler=error_handler) + if access_token is not None: + g_utils.logger.debug("Access token: {0}".format(access_token)) + response = cmd_outgoing_validate_device(access_token=access_token, + hd_serial_number=hd_serial, + dg_serial_number=dg_serial, + sw_version=sw_version, + url=url_validate, + error_handler=error_handler) + if response is not None: + g_utils.logger.debug("Response: {0}".format(response)) + invalid_attributes = response.get("invalidAttributes", None) + g_utils.logger.info("Invalid fields: {0}".format(invalid_attributes)) - print("invalid attributes: {0}", invalid_attributes) + if invalid_attributes is not None: + json_resp = cmd_outgoing_validation_result(invalid_attributes, hd_serial, g_config, error_handler) + g_utils.logger.debug("Validation result request response (DRT --> CS): {0}".format(json_resp)) + else: + error = Error( + "{0},2,{1},Validation failed due to invalid DCS response format".format( + OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value)) + error_handler.enqueue_error(error=error) + else: + error = Error( + "{0},2,{1},Validation failed due to missing response from DCS".format( + OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value)) + error_handler.enqueue_error(error=error) + else: + error = Error( + "{0},2,{1},Validation failed due to missing token".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value)) + error_handler.enqueue_error(error=error) - g_utils.logger.debug("Invalid fields: {0}".format(invalid_attributes)) - if invalid_attributes is not None: - # Step 10. Validation Result (POST /validation) (list of invalid fields) - json_resp = cmd_outgoing_validation_result(invalid_attributes, hd_serial, g_config) - g_utils.logger.debug("Json response: {0}".format(json_resp)) - else: - g_utils.logger.debug("Access token is None.") + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) @log_func def cmd_incoming_factory_reset(output_channel) -> None: """ Initiates a factory reset on the device - + :param output_channel: CS2UI output channel :return: None """ - try: - if os.path.exists(TEMP_CREDENTIALS_CERTIFICATE_X509): - os.remove(TEMP_CREDENTIALS_CERTIFICATE_X509) - if os.path.exists(TEMP_CREDENTIALS_PRIVATE_KEY): - os.remove(TEMP_CREDENTIALS_PRIVATE_KEY) - if os.path.exists(TEMP_CREDENTIALS_PUBLIC_KEY): - os.remove(TEMP_CREDENTIALS_PUBLIC_KEY) - except IOError as er: - self.logger.error('Error removing secrets: {0}'.format(' '.join(er.args))) - message_body = str(OutboundMessageIDs.CS2UI_REQ_FACTORY_RESET.value) + ',0' output_channel.enqueue_message(message_body) - - -@log_func -def cmd_incoming_update_manufacturing_tool_base_url(url: str, g_config: dict) -> None: - """ - Updates the manufacturing tool base url - - :param url: The new url - :param g_config: The cloudsync config - :return: None - """ - helpers_update_config(path=CONFIG_PATH, - config=g_config, - group=CONFIG_KEBORMED, - section=CONFIG_KEBORMED_MANF_TOOL_URL, - value=url) Index: cloudsync/handlers/outgoing/handler_cs_to_dcs.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/handlers/outgoing/handler_cs_to_dcs.py (.../handler_cs_to_dcs.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/handlers/outgoing/handler_cs_to_dcs.py (.../handler_cs_to_dcs.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -8,120 +8,26 @@ from cloudsync.utils.globals import * from cloudsync.common.enums import * from cloudsync.utils.helpers import * +from cloudsync.handlers.error_handler import ErrorHandler +from cloudsync.handlers.error import Error @log_func -def cmd_outgoing_set_patient_device_association(url: str, access_token: str, associate: bool) -> requests.Response: - try: - headers = { - 'Authorization': "Bearer {0}".format(access_token), - 'Content-Type': 'application/json' - } - payload = {} - - if associate: - resp = requests.head(url=urllib.parse.urljoin(url, "/exists"), - headers=headers, - data=payload, - verify=False) - - if resp.status_code == NOT_FOUND: - resp = requests.put(url=url, - headers=headers, - data=payload, - verify=False) - else: - resp = requests.delete(url=url, - headers=headers, - data=payload, - verify=False) - return resp - except requests.exceptions.Timeout: - error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_SET_PATIENT_DEVICE_ASSOCIATION_ERROR.value)) - self.error_handler.enqueue_error(error=error) - except requests.exceptions.TooManyRedirects: - error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_SET_PATIENT_DEVICE_ASSOCIATION_ERROR.value)) - self.error_handler.enqueue_error(error=error) - - -@log_func -def cmd_outgoing_send_treatment_report(url: str, access_token: str, treatment_log: str) -> requests.Response: - """ - Sends a treatment report to DCS - - :return: requests.Response - """ - try: - headers = { - 'Authorization': "Bearer {0}".format(access_token), - 'Content-Type': 'application/json' - } - - payload = treatment_log - - print("paylod: {0}".format(payload)) - - resp = requests.post(url=url, - headers=headers, - data=payload, - verify=False) - return resp - except requests.exceptions.Timeout: - error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_SEND_TREATMENT_REPORT_ERROR.value)) - self.error_handler.enqueue_error(error=error) - except requests.exceptions.TooManyRedirects: - error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_SEND_TREATMENT_REPORT_ERROR.value)) - self.error_handler.enqueue_error(error=error) - - -@log_func -def cmd_outgoing_set_device_state(url: str, access_token: str) -> requests.Response: - """ - Updates the backend with the current device state - :param current_state: (int) the current device state - :return: The response - """ - try: - headers = { - 'Authorization': "Bearer {0}".format(access_token), - 'Content-Type': 'application/json' - } - payload = {} - resp = requests.put(url=url, - headers=headers, - data=payload, - verify=False) - return resp - except requests.exceptions.Timeout: - error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value)) - self.error_handler.enqueue_error(error=error) - except requests.exceptions.TooManyRedirects: - error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value)) - self.error_handler.enqueue_error(error=error) - - -@log_func def cmd_outgoing_get_new_token_with_cert(path_certificate: str, path_private_key: str, save: bool, url: str, - client_secret: str) -> str: + client_secret: str, + error_handler: ErrorHandler) -> str: """ - Performs the following steps in the device registration sequence diagram: - Step 6. Device Auth - Step 7. Device Auth Response + Obtains authentication token with device certificate & private key - :param path_certificate: The path to the certificate from set credentials - :param path_private_key: The path to the public key form set credentials + :param path_certificate: The path to the certificate + :param path_private_key: The path to the private key :param save: If True, save the token - :param url: The kebormed url to request the new token - :param client_secret: The secret client key + :param url: Identity Provider URL used to request a new token + :param client_secret: Identity Provider client secret for CS app + :param error_handler: global error handler :return: The new token """ try: @@ -133,60 +39,85 @@ } headers = { - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } cert_paths = (path_certificate, path_private_key) + g_utils.logger.debug("Making request: {0}, {1}, {2}, {3}".format(url,headers,payload,cert_paths)) + response = requests.post(url=url, headers=headers, data=payload, cert=cert_paths, - verify=False) + timeout=5) data = response.json() + + g_utils.logger.debug("Keycloak response: {0}".format(data)) + if save: + if not os.path.exists(TOKEN_CACHING_PATH): + os.makedirs(TOKEN_CACHING_PATH) with open(DEVICE_KEBORMED_ACCESS_TOKEN_PATH, 'w') as f: f.write(json.dumps(data, indent=4)) return data.get("access_token", None) except requests.exceptions.Timeout: - error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_GET_NEW_TOKEN_WITH_CERT_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error = Error("{0},2,{1},Obtain token request timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_GET_NEW_TOKEN_WITH_CERT_ERROR.value)) + error_handler.enqueue_error(error=error) + return None except requests.exceptions.TooManyRedirects: error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_GET_NEW_TOKEN_WITH_CERT_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) + return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_GET_NEW_TOKEN_WITH_CERT_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) + return None @log_func -def cmd_outgoing_verify_token(url: str, access_token: str) -> requests.Response: +def cmd_outgoing_verify_token(url: str, + access_token: str, + error_handler: ErrorHandler) -> requests.Response: try: headers = { 'Authorization': "Bearer {0}".format(access_token), - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + "X-OrganizationId" : '1', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } resp = requests.get(url=url, - headers=headers, - verify=False) + headers=headers) return resp except requests.exceptions.Timeout: error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_VERIFY_TOKEN_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) except requests.exceptions.TooManyRedirects: error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_VERIFY_TOKEN_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VERIFY_TOKEN_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) @log_func def cmd_outgoing_validate_device(access_token: str, hd_serial_number: str, dg_serial_number: str, sw_version: str, - url: str) -> dict: + url: str, + error_handler: ErrorHandler) -> dict: """ Step 8. Validate device Step 9. Validate device response (list of invalid fields) @@ -201,109 +132,278 @@ headers = { 'Authorization': "Bearer {0}".format(access_token), - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } response = requests.post(url=url, headers=headers, - data=payload, - verify=False) + data=payload) except requests.exceptions.Timeout: error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) return None except requests.exceptions.TooManyRedirects: error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) try: return response.json() except json.decoder.JSONDecodeError as e: error = Error("{0},3,{1},Could not validate device. Received: {2}:{3},Exception: {4}".format( - OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value, - response.status_code, - response.reason, - e)) - self.error_handler.enqueue_error(error=error) + OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value, + response.status_code, + response.reason, + str(e))) + error_handler.enqueue_error(error=error) return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_VALIDATE_DEVICE_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) # Runtime commands @log_func +def cmd_outgoing_set_device_state(url: str, + access_token: str, + error_handler: ErrorHandler) -> requests.Response: + """ + Updates the backend with the current device state + :param url: set device state URL + :param access_token: access token + :param error_handler: global error handler + :return: The response + """ + try: + headers = { + 'Authorization': "Bearer {0}".format(access_token), + 'Content-Type': 'application/json', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' + } + payload = {} + resp = requests.put(url=url, + headers=headers, + data=payload) + return resp + except requests.exceptions.Timeout: + error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value)) + error_handler.enqueue_error(error=error) + except requests.exceptions.TooManyRedirects: + error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value)) + error_handler.enqueue_error(error=error) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) + + +@log_func def cmd_outgoing_check_if_patient_with_emr_id_exists(access_token: str, - url: str) -> requests.Response: + url: str, + error_handler: ErrorHandler) -> requests.Response: try: headers = { 'Authorization': "Bearer {0}".format(access_token), - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } response = requests.get(url=url, - headers=headers, - verify=False) + headers=headers) except requests.exceptions.Timeout: error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) return None except requests.exceptions.TooManyRedirects: error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) try: return response except json.decoder.JSONDecodeError as e: error = Error("{0},3,{1},Could not check if the patient exists. Received: {2}:{3},Exception: {4}".format( - OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR.value, - response.status_code, - response.reason, - e)) - self.error_handler.enqueue_error(error=error) + OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR.value, + response.status_code, + response.reason, + str(e))) + error_handler.enqueue_error(error=error) return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) @log_func def cmd_outgoing_create_temporary_patient(access_token: str, - url: str) -> dict: + url: str, + error_handler: ErrorHandler) -> dict: try: headers = { 'Authorization': "Bearer {0}".format(access_token), - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } payload = {} response = requests.post(url=url, headers=headers, - data=payload, - verify=False) + data=payload) except requests.exceptions.Timeout: error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_CREATE_TEMPORARY_PATIENT_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) return None except requests.exceptions.TooManyRedirects: error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_CREATE_TEMPORARY_PATIENT_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_CREATE_TEMPORARY_PATIENT_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) try: return response.json() except json.decoder.JSONDecodeError as e: error = Error("{0},3,{1},Could not create temporary patient. Received: {2}:{3},Exception: {4}".format( - OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_CREATE_TEMPORARY_PATIENT_ERROR.value, - response.status_code, - response.reason, - e)) - self.error_handler.enqueue_error(error=error) + OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_CREATE_TEMPORARY_PATIENT_ERROR.value, + response.status_code, + response.reason, + str(e))) + error_handler.enqueue_error(error=error) return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_CREATE_TEMPORARY_PATIENT_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) + + +@log_func +def cmd_outgoing_set_patient_device_association(url: str, + access_token: str, + associate: bool, + error_handler: ErrorHandler) -> requests.Response: + """ + Sets the status of the device & patient association + :param url: set device state URL + :param access_token: access token + :param associate: status of the device & patient association + :param error_handler: global error handler + :return: The response + """ + try: + headers = { + 'Authorization': "Bearer {0}".format(access_token), + 'Content-Type': 'application/json', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' + } + payload = {} + + if associate: + resp = requests.head(url=urllib.parse.urljoin(url, "/exists"), + headers=headers, + data=payload) + + if resp.status_code == NOT_FOUND: + resp = requests.put(url=url, + headers=headers, + data=payload) + else: + resp = requests.delete(url=url, + headers=headers, + data=payload) + return resp + except requests.exceptions.Timeout: + error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SET_PATIENT_DEVICE_ASSOCIATION_ERROR.value)) + error_handler.enqueue_error(error=error) + except requests.exceptions.TooManyRedirects: + error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SET_PATIENT_DEVICE_ASSOCIATION_ERROR.value)) + error_handler.enqueue_error(error=error) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SET_PATIENT_DEVICE_ASSOCIATION_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) + + +@log_func +def cmd_outgoing_send_treatment_report(url: str, + access_token: str, + treatment_log: str, + error_handler: ErrorHandler) -> requests.Response: + """ + Sends a treatment report to DCS + :param url: set device state URL + :param access_token: access token + :param treatment_log: treatment report sent to DCS + :param error_handler: global error handler + :return: The response + """ + try: + headers = { + 'Authorization': "Bearer {0}".format(access_token), + 'Content-Type': 'application/json', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' + } + + payload = treatment_log + + # print("paylod: {0}".format(payload)) + + resp = requests.post(url=url, + headers=headers, + data=payload) + # if resp.status_code == BAD_REQUEST: + # if resp.json().get("code", None) == "bad_checksum": + # g_utils.logger.debug("Returned response") + + return resp + except requests.exceptions.Timeout: + error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_TREATMENT_REPORT_ERROR.value)) + error_handler.enqueue_error(error=error) + return None + except requests.exceptions.TooManyRedirects: + error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_TREATMENT_REPORT_ERROR.value)) + error_handler.enqueue_error(error=error) + return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_TREATMENT_REPORT_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) + return None Index: cloudsync/handlers/outgoing/handler_cs_to_mft.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/handlers/outgoing/handler_cs_to_mft.py (.../handler_cs_to_mft.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/handlers/outgoing/handler_cs_to_mft.py (.../handler_cs_to_mft.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -21,9 +21,10 @@ sw_version: str, manf_tool_base_url: str, data_source_id: int, - headers: dict) -> requests.Response: + headers: dict, + error_handler: ErrorHandler) -> requests.Response: """ - Initiates device registration with the manufacturing tool + Initiates device registration with the device registration tool Device -> Manufacturing Tool :param device_name: the device name @@ -33,9 +34,9 @@ :param manf_tool_base_url: the manufacturing tool base url :param data_source_id: the data source identification number :param headers: the header dictionary + :param error_handler: global error handler :return: requests.Response """ - # print('---Registration request made') try: url = urllib.parse.urljoin(manf_tool_base_url, "register/") data = { @@ -53,30 +54,40 @@ except requests.exceptions.Timeout: error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_REQ_REGISTRATION_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) + return None except requests.exceptions.TooManyRedirects: error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_REQ_REGISTRATION_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) + return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_REQ_REGISTRATION_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) + return None @log_func def cmd_outgoing_validation_result(invalid_attributes: List[str], hd_serial: str, - g_config: dict) -> dict: + g_config: dict, + error_handler: ErrorHandler) -> dict: """ Sends the validation POST to the manf tool :param invalid_attributes: The list of invalid attributes :param hd_serial: The hd serial number :param g_config: The device config + :param error_handler: global error handler :return: The json response """ if (CONFIG_KEBORMED not in g_config.keys() or CONFIG_KEBORMED_MFT_URL not in g_config[CONFIG_KEBORMED]): error = Error("{0},2,{1},Manufacturing tool url not found".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_DEVICE_VALIDATION_RESULT_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) return None try: @@ -103,8 +114,16 @@ except requests.exceptions.Timeout: error = Error("{0},2,{1},Registration timeout".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_DEVICE_VALIDATION_RESULT_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) + return None except requests.exceptions.TooManyRedirects: error = Error("{0},2,{1},Too many redirects".format(OutboundMessageIDs.CS2UI_ERROR.value, ErrorIDs.CS_DEVICE_VALIDATION_RESULT_ERROR.value)) - self.error_handler.enqueue_error(error=error) + error_handler.enqueue_error(error=error) + return None + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_DEVICE_VALIDATION_RESULT_ERROR.value, + str(e))) + error_handler.enqueue_error(error=error) + return None Index: cloudsync/handlers/ui_cs_request_handler.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/handlers/ui_cs_request_handler.py (.../ui_cs_request_handler.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/handlers/ui_cs_request_handler.py (.../ui_cs_request_handler.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -31,7 +31,7 @@ self.event = Event() self.thread.start() - self.logger.info('Created UICS Handler') + self.logger.info('Created UI_CS Handler') def scheduler(self) -> None: """ @@ -49,7 +49,7 @@ def enqueue_message(self, message: UICSMessage) -> bool: """ - :param message: the data to add to the queue + :param message: the message to add to the message queue :return: True upon success, False otherwise """ if len(self.queue) < self.queue.maxlen: @@ -60,14 +60,17 @@ return False def handle_message(self, message: UICSMessage): - self.logger.info('CS Message: {0}'.format(message)) + self.logger.info('UI2CS Message: {0}'.format(message)) message_data = message.timestamp + message.sequence + message.ID + message.size if len(message.parameters) > 0: for param in message.parameters: message_data += param - message_calculated_crc8 = crc8(message_data.encode('utf-8')) + else: + self.logger.debug("UI2CS message has 0 parameters: {0}".format(message)) + message_calculated_crc8 = helpers_crc8(message_data.encode('utf-8')) + if message.CRC != str(message_calculated_crc8): error = Error("{0},4,{1},Bad CRC on message {2}, Message CRC: {3}, Calculated CRC: {4}".format( OutboundMessageIDs.CS2UI_ERROR.value, @@ -76,124 +79,134 @@ message.CRC, str(message_calculated_crc8))) self.error_handler.enqueue_error(error=error) + else: + # REGISTRATION MODE - if (InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_REQ_REGISTRATION) and \ - (message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration'): - self.logger.info('UI2CS_REQ_REGISTRATION request received') - self.logger.debug('Config: {0}'.format(message.g_config)) + # REGISTRATION REQUEST + if (InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_REQ_REGISTRATION) and \ + (message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration'): + self.logger.info('UI2CS_REQ_REGISTRATION request received') + self.logger.debug('Applicable config: {0}'.format(message.g_config)) - if len(message.parameters) != 3: - error = Error("{0},2,{1},invalid # of parameters".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_REQ_REGISTRATION_ERROR.value)) - self.error_handler.enqueue_error(error=error) - else: - message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL] = message.parameters[0] - message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL] = message.parameters[1] - message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION] = message.parameters[2] - message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_NAME] = message.parameters[0] + if (len(message.parameters) != 3) or (message.parameters[0] is None) or (message.parameters[2] is None): + error = Error( + "{0},2,{1},invalid # of parameters for registration".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_REQ_REGISTRATION_ERROR.value)) + self.error_handler.enqueue_error(error=error) + else: + try: + message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL] = message.parameters[0] + if len(message.parameters[1]) > 0: + message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL] = message.parameters[1] + else: + self.logger.debug("Used HD Serial as value for DG Serial") + message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL] = message.parameters[0] + message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION] = message.parameters[2] + message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_NAME] = message.parameters[0] - helpers_write_config(CONFIG_PATH, message.g_config) + device_ip = helpers_get_ip_address() + message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_IP] = device_ip + helpers_write_config(None, CONFIG_PATH, message.g_config) + helpers_write_config(OPERATION_CONFIG_PATH, OPERATION_CONFIG_FILE_PATH, message.g_config) + + helpers_add_to_network_queue(network_request_handler=self.network_request_handler, + request_type=NetworkRequestType.CS2MFT_REQ_REGISTRATION, + url='', + payload={}, + method='', + g_config=message.g_config, + success_message='CS2MFT_REQ_REGISTRATION request added to network ' + 'queue') + except IOError as er: + error = Error( + "{0},2,{1},Error updating device config file".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SAVE_CONFIG_ERROR.value)) + self.error_handler.enqueue_error(error=error) + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_REQ_REGISTRATION_ERROR.value, + e)) + self.error_handler.enqueue_error(error=error) + + # OPERATION MODE + + # SEND DEVICE STATE REQUEST + elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_SEND_DEVICE_STATE and \ + (message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation'): + self.logger.info("UI2CS_SEND_DEVICE_STATE request received") + self.logger.debug("HD Mode: {0}".format(HDOpModes.mapped_str_value(message.parameters[0]))) + self.logger.debug("HD Sub-Mode: {0}".format(HDOpSubModes.mapped_str_value(message.parameters[1]))) + try: + device_state = helpers_device_state_to_cloud_state( + HDOpModes.mapped_str_value(message.parameters[0]), + HDOpSubModes.mapped_str_value(message.parameters[1])) + except: + device_state = DeviceStates.UNKNOWN_STATE + error = Error( + "{0},2,{1},Unknown device state received from UI".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_UNKNOWN_DEVICE_STATE_ERROR.value)) + self.error_handler.enqueue_error(error=error) + + message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_STATE] = device_state.value + self.logger.info("Device state: {0}".format(device_state.name)) + + try: + helpers_write_config(OPERATION_CONFIG_PATH, OPERATION_CONFIG_FILE_PATH, message.g_config) helpers_add_to_network_queue(network_request_handler=self.network_request_handler, - request_type=NetworkRequestType.CS2MFT_REQ_REGISTRATION, + request_type=NetworkRequestType.CS2DCS_REQ_SET_DEVICE_STATE, url='', payload={}, method='', g_config=message.g_config, - success_message='CS2MFT_REQ_REGISTRATION request added to network queue') + success_message='CS2DCS_REQ_SET_DEVICE_STATE request added to network ' + 'queue') except Exception as e: error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, - ErrorIDs.CS_REQ_REGISTRATION_ERROR.value, + ErrorIDs.CS_SEND_DEVICE_STATE_ERROR.value, e)) self.error_handler.enqueue_error(error=error) - elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_SEND_CREDENTIALS_SAVED and \ - (message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'registration'): - self.logger.info('UI2CS_SEND_CREDENTIALS_SAVED request received') - self.remove_secrets() - elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_SEND_CREDENTIALS: - self.logger.info('UI2CS_SEND_CREDENTIALS request received') - source_cert = message.parameters[0] + CERTIFICATE_X509_FILE_NAME - source_private_key = message.parameters[0] + PRIVATE_KEY_FILE_NAME - source_public_key = message.parameters[0] + PUBLIC_KEY_FILE_NAME - self.save_secrets(source_cert, source_private_key, source_public_key) - # OPERATION MODE - elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_SEND_DEVICE_STATE and \ - (message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation'): - self.logger.info("UI2CS_SEND_DEVICE_STATE request received") - self.logger.debug("HD Mode: {0}".format(HDOpModes.mapped_str_value(message.parameters[0]))) - self.logger.debug("HD Sub-Mode: {0}".format(HDOpSubModes.mapped_str_value(message.parameters[1]))) - try: - device_state = helpers_device_state_to_cloud_state( - HDOpModes.mapped_str_value(message.parameters[0]), - HDOpSubModes.mapped_str_value(message.parameters[1])) - except: - device_state = DeviceStates.UNKNOWN_STATE + # SEND TREATMENT REPORT REQUEST + elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_SEND_TREATMENT_REPORT and \ + (message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation'): + self.logger.info("UI2CS_SEND_TREATMENT_REPORT request received") - message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_STATE] = device_state.value - self.logger.info("Device state: {0}".format(device_state.name)) + try: + hd_serial_number = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL] + dg_serial_number = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL] + sw_version = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION] - helpers_write_config(CONFIG_PATH, message.g_config) + self.logger.debug('hd: {0},dg: {1},sw: {2}'.format(hd_serial_number, dg_serial_number, sw_version)) - helpers_add_to_network_queue(network_request_handler=self.network_request_handler, - request_type=NetworkRequestType.CS2DCS_REQ_SET_DEVICE_STATE, - url='', - payload={}, - method='', - g_config=message.g_config, - success_message='CS2DCS_REQ_SET_DEVICE_STATE request added to network queue') - elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_SEND_TREATMENT_REPORT and \ - (message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation'): - self.logger.info("UI2CS_SEND_TREATMENT_REPORT request received") + treatment_log_json = helpers_read_treatment_log_file(message.parameters[0]) + if treatment_log_json: + treatment_log_json['checksum'] = helpers_sha256_checksum(json.dumps(treatment_log_json['data'])) + treatment_log_json['serialNumber'] = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL] - hd_serial_number = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL] - dg_serial_number = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_DG_SERIAL] - sw_version = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_SW_VERSION] + g_utils.logger.debug("Treatment log {0}".format(treatment_log_json)) - self.logger.debug('hd: {0},dg: {1},sw: {2}'.format(hd_serial_number, dg_serial_number, sw_version)) + helpers_add_to_network_queue(network_request_handler=self.network_request_handler, + request_type=NetworkRequestType.CS2DCS_REQ_SEND_TREATMENT_REPORT, + url='', + payload=treatment_log_json, + method='', + g_config=message.g_config, + success_message='CS2DCS_REQ_SEND_TREATMENT_REPORT request added to network' + 'queue') - treatment_log_json = helpers_read_treatment_log_file(message.parameters[0]) - treatment_log_json['serialNumber'] = message.g_config[CONFIG_DEVICE][CONFIG_DEVICE_HD_SERIAL] + except Exception as e: + error = Error("{0},2,{1},{2}".format(OutboundMessageIDs.CS2UI_ERROR.value, + ErrorIDs.CS_SEND_TREATMENT_REPORT_ERROR.value, + e)) + self.error_handler.enqueue_error(error=error) - helpers_add_to_network_queue(network_request_handler=self.network_request_handler, - request_type=NetworkRequestType.CS2DCS_REQ_SEND_TREATMENT_REPORT, - url='', - payload=treatment_log_json, - method='', - g_config=message.g_config, - success_message='CS2DCS_REQ_SEND_TREATMENT_REPORT request added to network ' - 'queue') - elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_ERROR: - error_body = "{0},{1},{2}".format(InboundMessageIDs.UI2CS_ERROR.value, message.size, message.parameters[0]) - if len(message.parameters) > 1: - for parameter in message.parameters[1:]: - error_body += ",{0}".format(parameter) - error = Error(error_body=error_body) - self.error_handler.enqueue_error(error=error) - - def save_secrets(self, source_cert, source_private_key, source_public_key): - try: - shutil.copy(source_cert, CREDENTIALS_CERTIFICATE_X509) - shutil.copy(source_private_key, CREDENTIALS_PRIVATE_KEY) - shutil.copy(source_public_key, CREDENTIALS_PUBLIC_KEY) - - self.logger.info('Credentials saved locally') - - except shutil.SameFileError as er: - self.logger.warning('Source and destination files identical: {0}'.format(' '.join(er.args))) - - except PermissionError as er: - self.logger.error('Permission error: {0}'.format(' '.join(er.args))) - - def remove_secrets(self): - try: - if os.path.exists(CREDENTIALS_CERTIFICATE_X509): - os.remove(CREDENTIALS_CERTIFICATE_X509) - if os.path.exists(CREDENTIALS_PRIVATE_KEY): - os.remove(CREDENTIALS_PRIVATE_KEY) - if os.path.exists(CREDENTIALS_PUBLIC_KEY): - os.remove(CREDENTIALS_PUBLIC_KEY) - self.logger.info('Credentials deleted locally') - except IOError as er: - self.logger.error('Error removing secrets: {0}'.format(' '.join(er.args))) + # ERROR MESSAGE RECEIVED FROM UI + elif InboundMessageIDs.mapped_str_value(message.ID) == InboundMessageIDs.UI2CS_ERROR: + error_body = "{0},{1},{2}".format(InboundMessageIDs.UI2CS_ERROR.value, message.size, message.parameters[0]) + if len(message.parameters) > 1: + for parameter in message.parameters[1:]: + error_body += ",{0}".format(parameter) + error = Error(error_body=error_body) + self.error_handler.enqueue_error(error=error) Index: cloudsync/utils/globals.py =================================================================== diff -u -r3b80d8631090f72584ae2a309efcea2d20b4f62e -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/utils/globals.py (.../globals.py) (revision 3b80d8631090f72584ae2a309efcea2d20b4f62e) +++ cloudsync/utils/globals.py (.../globals.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -1,16 +1,8 @@ """Object holding all application global constants""" import os -import socket -# For running on device both VM & SERVER should be set to False -# For running in PROD DEBUG should be set to False -DEBUG = True -VM = False -SERVER = False - # PATHS PATH_HOME = os.getcwd() + '/' -PATH_CLOUDSYNC = PATH_HOME # Configuration groups CONFIG_DEVICE = 'device' @@ -33,27 +25,36 @@ # CONFIG CONFIG_PATH = os.path.join(PATH_HOME, "cloudsync/config/config.json") +OPERATION_CONFIG_PATH = "/var/configurations/CloudSync/config/" +OPERATION_CONFIG_FILE_PATH = os.path.join(OPERATION_CONFIG_PATH, "config.json") + # LOGS -CS_LOG_FILE = os.path.join(PATH_HOME, "cloudsync.log") +CS_LOG_PATH = "/media/sd-card/cloudsync/log" +CS_LOG_FILE = os.path.join(CS_LOG_PATH, "cloudsync.log") # DEVICE TOKEN -DEVICE_KEBORMED_ACCESS_TOKEN_PATH = os.path.join(PATH_CLOUDSYNC, "data/access_token.json") +TOKEN_CACHING_PATH = "/var/configurations/CloudSync/jwt/" +DEVICE_KEBORMED_ACCESS_TOKEN_PATH = os.path.join(TOKEN_CACHING_PATH, "access_token.json") +DEVICE_TOKEN_VALIDATION = "/api/common/info" + # CREDENTIALS -TEMP_CREDENTIALS_CERTIFICATE_X509 = os.path.join(PATH_CLOUDSYNC, "data/client_certificate.pem") -TEMP_CREDENTIALS_PRIVATE_KEY = os.path.join(PATH_CLOUDSYNC, "data/client_private_key.pem") -TEMP_CREDENTIALS_PUBLIC_KEY = os.path.join(PATH_CLOUDSYNC, "data/client_public_key.pem") +CREDENTIALS_PATH = "/var/configurations/CloudSync/credentials/" -CREDENTIALS_CERTIFICATE_X509 = "/tmp/client_certificate.pem" -CREDENTIALS_PRIVATE_KEY = "/tmp/client_private_key.pem" -CREDENTIALS_PUBLIC_KEY = "/tmp/client_public_key.pem" - CERTIFICATE_X509_FILE_NAME = "client_certificate.pem" PRIVATE_KEY_FILE_NAME = "client_private_key.pem" PUBLIC_KEY_FILE_NAME = "client_public_key.pem" +CREDENTIALS_CERTIFICATE_X509 = os.path.join(CREDENTIALS_PATH, CERTIFICATE_X509_FILE_NAME) +CREDENTIALS_PRIVATE_KEY = os.path.join(CREDENTIALS_PATH, PRIVATE_KEY_FILE_NAME) +CREDENTIALS_PUBLIC_KEY = os.path.join(CREDENTIALS_PATH, PUBLIC_KEY_FILE_NAME) + + + # UI2CS VALUES -UI2CS_FILE_CHANNELS_PATH = "/media/sd-card/cloudsync" +UI2CS_FILE_CHANNELS_PATH = "/media/sd-card/cloudsync/" +# PATH for running off device +# UI2CS_FILE_CHANNELS_PATH = "data/busses" # TREATMENT REPORT SECTIONS @@ -110,6 +111,7 @@ BAD_REQUEST = 400 UNAUTHORIZED = 401 NOT_FOUND = 404 +UNASSIGNED = 427 INTERNAL_SERVER_ERROR = 500 # TIME CONSTANTS Index: cloudsync/utils/helpers.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/utils/helpers.py (.../helpers.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/utils/helpers.py (.../helpers.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -3,6 +3,8 @@ import os import json import datetime +import hashlib +import socket from time import time, sleep from typing import Union, Any @@ -154,7 +156,7 @@ Decommissioned – N/A – HD f/w will not know if system is decommissioned """ - if (hd_mode == HDOpModes.MODE_STAN) and (hd_sub_mode == HDOpSubModes.SUBMODE_WAIT_FOR_TREATMENT): + if hd_mode == HDOpModes.MODE_STAN: return DeviceStates.ACTIVE_READY if (hd_mode == HDOpModes.MODE_TPAR) or (hd_mode == HDOpModes.MODE_PRET) or (hd_mode == HDOpModes.MODE_TREA) or ( hd_mode == HDOpModes.MODE_POST): @@ -171,7 +173,7 @@ :return: The token if found, otherwise returns None """ data = None - print('token path: {0}'.format(DEVICE_KEBORMED_ACCESS_TOKEN_PATH)) + # print('token path: {0}'.format(DEVICE_KEBORMED_ACCESS_TOKEN_PATH)) if not os.path.exists(DEVICE_KEBORMED_ACCESS_TOKEN_PATH): return None with open(DEVICE_KEBORMED_ACCESS_TOKEN_PATH, 'r') as f: @@ -201,15 +203,21 @@ return {} -def helpers_write_config(path: str, config: dict) -> None: +def helpers_write_config(folder_path: str, file_path: str, config: dict) -> None: """ Writes the config to the provided path + If folder_path is provided, it first checks if the folder exists and creates it if it doesn't - :param path: the path where the config json will be written + :param folder_path: the path for the config folder + :param file_path: the path where the config json will be written :param config: the config dictionary :return: None """ - with open(path, 'w') as f: + if folder_path is not None: + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + with open(file_path, 'w') as f: json.dump(config, f, indent=4) @@ -275,148 +283,155 @@ try: f = open(path) - except IOError as er: - self.logger.error('Opening treatment log file error: {0}'.format(' '.join(er.args))) - counter = 0 - treatment_log_lines = f.readlines() + counter = 0 + treatment_log_lines = f.readlines() - # print("log_lines: {0}".format(treatment_log_lines)) + # print("log_lines: {0}".format(treatment_log_lines)) - while counter < len(treatment_log_lines): - line = treatment_log_lines[counter].strip() - print("line {0}: {1}".format(counter, line)) - print("size of log: {0}".format(len(treatment_log_lines))) - - if line.startswith(SECTION_START_CHARACTER) and line.endswith(SECTION_STOP_CHARACTER) and counter < ( - len(treatment_log_lines) - 2): - section = line - section_lines = [] - counter += 1 - section_start_counter = counter + while counter < len(treatment_log_lines): line = treatment_log_lines[counter].strip() - while not (line.startswith(SECTION_START_CHARACTER) and line.endswith( - SECTION_STOP_CHARACTER)) and counter < len(treatment_log_lines) - 1: - section_lines.append(line) + # print("line {0}: {1}".format(counter, line)) + # print("size of log: {0}".format(len(treatment_log_lines))) + + if line.startswith(SECTION_START_CHARACTER) and line.endswith(SECTION_STOP_CHARACTER) and counter < ( + len(treatment_log_lines) - 2): + section = line + section_lines = [] counter += 1 + section_start_counter = counter line = treatment_log_lines[counter].strip() - if len(section_lines) > 0: - if section == TREATMENT_DATA: - for data_line in section_lines: - data_components = data_line.split(',') - data_record = { - "time": int(data_components[0]) * S_MS_CONVERSION_FACTOR, - "bloodFlowRate": float(data_components[1]), - "dialysateFlowRate": float(data_components[2]), - "ultrafiltrationRate": float(data_components[3]), - "arterialPressure": float(data_components[4]), - "venousPressure": float(data_components[5]), - "systolic": float(data_components[6]), - "diastolic": float(data_components[7]), - "heartRate": float(data_components[8]) - } - treatment_data['data']['treatment']['data'].append(data_record) - elif section == TREATMENT_ALARMS: - for data_line in section_lines: - data_components = data_line.split(',') - parameters = [] - if len(data_components) > 2: - parameters = data_components[2:(len(data_components) - 2)] - data_record = { - "time": int(data_components[0]) * S_MS_CONVERSION_FACTOR, - "title": data_components[1], - "parameters": parameters - } - treatment_data['data']['treatment']['alarms'].append(data_record) - elif section == TREATMENT_EVENTS: - for data_line in section_lines: - data_components = data_line.split(',') - parameters = [] - if len(data_components) > 2: - parameters = data_components[2:(len(data_components) - 2)] - data_record = { - "time": int(data_components[0]) * S_MS_CONVERSION_FACTOR, - "title": data_components[1], - "parameters": parameters - } - treatment_data['data']['treatment']['events'].append(data_record) - else: - counter = section_start_counter + while not (line.startswith(SECTION_START_CHARACTER) and line.endswith( + SECTION_STOP_CHARACTER)) and counter < len(treatment_log_lines) - 1: + section_lines.append(line) + counter += 1 + line = treatment_log_lines[counter].strip() + if len(section_lines) > 0: + if section == TREATMENT_DATA: + for data_line in section_lines: + data_components = data_line.split(',') + data_record = { + "time": int(data_components[0]) * S_MS_CONVERSION_FACTOR, + "bloodFlowRate": float(data_components[1]), + "dialysateFlowRate": float(data_components[2]), + "ultrafiltrationRate": float(data_components[3]), + "arterialPressure": float(data_components[4]), + "venousPressure": float(data_components[5]), + "systolic": float(data_components[6]), + "diastolic": float(data_components[7]), + "heartRate": float(data_components[8]) + } + treatment_data['data']['treatment']['data'].append(data_record) + elif section == TREATMENT_ALARMS: + for data_line in section_lines: + data_components = data_line.split(',') + parameters = [] + if len(data_components) > 2: + parameters = data_components[2:(len(data_components) - 2)] + data_record = { + "time": int(data_components[0]) * S_MS_CONVERSION_FACTOR, + "title": data_components[1], + "parameters": parameters + } + treatment_data['data']['treatment']['alarms'].append(data_record) + elif section == TREATMENT_EVENTS: + for data_line in section_lines: + data_components = data_line.split(',') + parameters = [] + if len(data_components) > 2: + parameters = data_components[2:(len(data_components) - 2)] + data_record = { + "time": int(data_components[0]) * S_MS_CONVERSION_FACTOR, + "title": data_components[1], + "parameters": parameters + } + treatment_data['data']['treatment']['events'].append(data_record) + else: + counter = section_start_counter - else: - print('regular line') - if line.startswith(PATIENT_ID): - treatment_data['data']['patient']['id'] = line.split(',')[1] - elif line.startswith(TREATMENT_DURATION): - treatment_data['data']['treatment']['parameters']['treatmentDuration'] = int(line.split(',')[1]) - elif line.startswith(BLOOD_FLOW_RATE): - treatment_data['data']['treatment']['parameters']['bloodFlowRate'] = int(line.split(',')[1]) - elif line.startswith(DIALYSATE_FLOW_RATE): - treatment_data['data']['treatment']['parameters']['dialysateFlowRate'] = int(line.split(',')[1]) - elif line.startswith(ACID_CONCENTRATE_TYPE): - treatment_data['data']['treatment']['parameters']['dialysate']['acidCode'] = line.split(',')[1] - elif line.startswith(BICARBONATE_CONCENTRATE_TYPE): - treatment_data['data']['treatment']['parameters']['dialysate']['bicarbCode'] = line.split(',')[1] - elif line.startswith(POTASSIUM_CONCENTRATION): - treatment_data['data']['treatment']['parameters']['dialysate']['K'] = float(line.split(',')[1]) - elif line.startswith(CALCIUM_CONCENTRATION): - treatment_data['data']['treatment']['parameters']['dialysate']['Ca'] = float(line.split(',')[1]) - elif line.startswith(BICARBONATE_CONCENTRATION): - treatment_data['data']['treatment']['parameters']['dialysate']['HCO3'] = float(line.split(',')[1]) - elif line.startswith(SODIUM_CONCENTRATION): - treatment_data['data']['treatment']['parameters']['dialysate']['Na'] = float(line.split(',')[1]) - elif line.startswith(DIALYSATE_TEMPERATURE): - treatment_data['data']['treatment']['parameters']['dialysateTemp'] = float(line.split(',')[1]) - elif line.startswith(DIALYZER_TYPE): - treatment_data['data']['treatment']['parameters']['dialyzerModel'] = line.split(',')[1] - elif line.startswith(HEPARIN_TYPE): - treatment_data['data']['treatment']['parameters']['heparinType'] = line.split(',')[1] - elif line.startswith(HEPARIN_CONCENTRATION): - treatment_data['data']['treatment']['parameters']['heparinConcentration'] = float(line.split(',')[1]) - elif line.startswith(HEPARIN_BOLUS_VOLUME): - treatment_data['data']['treatment']['parameters']['heparinBolus'] = float(line.split(',')[1]) - elif line.startswith(HEPARIN_DISPENSE_RATE): - treatment_data['data']['treatment']['parameters']['heparinRate'] = float(line.split(',')[1]) - elif line.startswith(HEPARIN_STOP): - treatment_data['data']['treatment']['parameters']['heparinStopBeforeTreatmentEnd'] = int( - line.split(',')[1]) - elif line.startswith(TREATMENT_START_DATE_TIME): - element = datetime.datetime.strptime(line.split(',')[1], "%Y/%m/%d %H:%M") - timestamp = datetime.datetime.timestamp(element) - treatment_data['data']['treatment']['time']['start'] = int(timestamp) * S_MS_CONVERSION_FACTOR - elif line.startswith(TREATMENT_END_DATE_TIME): - element = datetime.datetime.strptime(line.split(',')[1], "%Y/%m/%d %H:%M") - timestamp = datetime.datetime.timestamp(element) - treatment_data['data']['treatment']['time']['end'] = int(timestamp) * S_MS_CONVERSION_FACTOR - elif line.startswith(ACTUAL_TREATMENT_DURATION): - treatment_data['data']['treatment']['time']['treatmentDuration'] = int(line.split(',')[1]) - elif line.startswith(DIALYSATE_VOLUME_USED): - treatment_data['data']['deviceTreatmentData']['dialysateVolumeUsed'] = float(line.split(',')[1]) - elif line.startswith(PRESCRIBED_UF_VOLUME): - treatment_data['data']['deviceTreatmentData']['prescribedUltrafiltrationVolume'] = float( - line.split(',')[1]) - elif line.startswith(TARGET_UF_VOLUME): - treatment_data['data']['deviceTreatmentData']['finalTargetUltrafiltrationVolume'] = float( - line.split(',')[1]) - elif line.startswith(ACTUAL_UF_VOLUME): - treatment_data['data']['deviceTreatmentData']['actualUltrafiltrationVolume'] = float(line.split(',')[1]) - elif line.startswith(PRESCRIBED_UF_RATE): - treatment_data['data']['deviceTreatmentData']['prescribedUltrafiltrationRate'] = float( - line.split(',')[1]) - elif line.startswith(TARGET_UF_RATE): - treatment_data['data']['deviceTreatmentData']['finalTargetUltrafiltrationRate'] = float( - line.split(',')[1]) - elif line.startswith(ACTUAL_UF_RATE): - treatment_data['data']['deviceTreatmentData']['actualUltrafiltrationRate'] = float(line.split(',')[1]) - elif line.startswith(SALINE_BOLUS_VOLUME): - treatment_data['data']['deviceTreatmentData']['salineBolusVolumeGiven'] = float(line.split(',')[1]) - elif line.startswith(HEPARIN_DELIVERED_VOLUME): - treatment_data['data']['deviceTreatmentData']['heparinDelivered'] = float(line.split(',')[1]) - elif line.startswith(WATER_SAMPLE_TEST_RESULT): - treatment_data['data']['diagnostics']['waterSampleTestResult'] = line.split(',')[1] - counter += 1 + else: + # print('regular line') + if line.startswith(PATIENT_ID): + treatment_data['data']['patient']['id'] = line.split(',')[1] + elif line.startswith(TREATMENT_DURATION): + treatment_data['data']['treatment']['parameters']['treatmentDuration'] = int(line.split(',')[1]) + elif line.startswith(BLOOD_FLOW_RATE): + treatment_data['data']['treatment']['parameters']['bloodFlowRate'] = int(line.split(',')[1]) + elif line.startswith(DIALYSATE_FLOW_RATE): + treatment_data['data']['treatment']['parameters']['dialysateFlowRate'] = int(line.split(',')[1]) + elif line.startswith(ACID_CONCENTRATE_TYPE): + treatment_data['data']['treatment']['parameters']['dialysate']['acidCode'] = line.split(',')[1] + elif line.startswith(BICARBONATE_CONCENTRATE_TYPE): + treatment_data['data']['treatment']['parameters']['dialysate']['bicarbCode'] = line.split(',')[1] + elif line.startswith(POTASSIUM_CONCENTRATION): + treatment_data['data']['treatment']['parameters']['dialysate']['K'] = float(line.split(',')[1]) + elif line.startswith(CALCIUM_CONCENTRATION): + treatment_data['data']['treatment']['parameters']['dialysate']['Ca'] = float(line.split(',')[1]) + elif line.startswith(BICARBONATE_CONCENTRATION): + treatment_data['data']['treatment']['parameters']['dialysate']['HCO3'] = float(line.split(',')[1]) + elif line.startswith(SODIUM_CONCENTRATION): + treatment_data['data']['treatment']['parameters']['dialysate']['Na'] = float(line.split(',')[1]) + elif line.startswith(DIALYSATE_TEMPERATURE): + treatment_data['data']['treatment']['parameters']['dialysateTemp'] = float(line.split(',')[1]) + elif line.startswith(DIALYZER_TYPE): + treatment_data['data']['treatment']['parameters']['dialyzerModel'] = line.split(',')[1] + elif line.startswith(HEPARIN_TYPE): + treatment_data['data']['treatment']['parameters']['heparinType'] = line.split(',')[1] + elif line.startswith(HEPARIN_CONCENTRATION): + treatment_data['data']['treatment']['parameters']['heparinConcentration'] = float( + line.split(',')[1]) + elif line.startswith(HEPARIN_BOLUS_VOLUME): + treatment_data['data']['treatment']['parameters']['heparinBolus'] = float(line.split(',')[1]) + elif line.startswith(HEPARIN_DISPENSE_RATE): + treatment_data['data']['treatment']['parameters']['heparinRate'] = float(line.split(',')[1]) + elif line.startswith(HEPARIN_STOP): + treatment_data['data']['treatment']['parameters']['heparinStopBeforeTreatmentEnd'] = int( + line.split(',')[1]) + elif line.startswith(TREATMENT_START_DATE_TIME): + element = datetime.datetime.strptime(line.split(',')[1], "%Y/%m/%d %H:%M") + timestamp = datetime.datetime.timestamp(element) + treatment_data['data']['treatment']['time']['start'] = int(timestamp) * S_MS_CONVERSION_FACTOR + elif line.startswith(TREATMENT_END_DATE_TIME): + element = datetime.datetime.strptime(line.split(',')[1], "%Y/%m/%d %H:%M") + timestamp = datetime.datetime.timestamp(element) + treatment_data['data']['treatment']['time']['end'] = int(timestamp) * S_MS_CONVERSION_FACTOR + elif line.startswith(ACTUAL_TREATMENT_DURATION): + treatment_data['data']['treatment']['time']['treatmentDuration'] = int(line.split(',')[1]) + elif line.startswith(DIALYSATE_VOLUME_USED): + treatment_data['data']['deviceTreatmentData']['dialysateVolumeUsed'] = float(line.split(',')[1]) + elif line.startswith(PRESCRIBED_UF_VOLUME): + treatment_data['data']['deviceTreatmentData']['prescribedUltrafiltrationVolume'] = float( + line.split(',')[1]) + elif line.startswith(TARGET_UF_VOLUME): + treatment_data['data']['deviceTreatmentData']['finalTargetUltrafiltrationVolume'] = float( + line.split(',')[1]) + elif line.startswith(ACTUAL_UF_VOLUME): + treatment_data['data']['deviceTreatmentData']['actualUltrafiltrationVolume'] = float( + line.split(',')[1]) + elif line.startswith(PRESCRIBED_UF_RATE): + treatment_data['data']['deviceTreatmentData']['prescribedUltrafiltrationRate'] = float( + line.split(',')[1]) + elif line.startswith(TARGET_UF_RATE): + treatment_data['data']['deviceTreatmentData']['finalTargetUltrafiltrationRate'] = float( + line.split(',')[1]) + elif line.startswith(ACTUAL_UF_RATE): + treatment_data['data']['deviceTreatmentData']['actualUltrafiltrationRate'] = float( + line.split(',')[1]) + elif line.startswith(SALINE_BOLUS_VOLUME): + treatment_data['data']['deviceTreatmentData']['salineBolusVolumeGiven'] = float(line.split(',')[1]) + elif line.startswith(HEPARIN_DELIVERED_VOLUME): + treatment_data['data']['deviceTreatmentData']['heparinDelivered'] = float(line.split(',')[1]) + elif line.startswith(WATER_SAMPLE_TEST_RESULT): + treatment_data['data']['diagnostics']['waterSampleTestResult'] = line.split(',')[1] + counter += 1 - return treatment_data + return treatment_data + except IOError as er: + g_utils.logger.error('Opening treatment log file error: {0}'.format(' '.join(er.args))) + return None + except Exception as e: + g_utils.logger.error('Error parsing treatment file: {0}'.format(' '.join(e.args))) + return None def helpers_add_to_network_queue(network_request_handler, request_type, url, payload, method, g_config, @@ -453,8 +468,19 @@ g_utils.logger.info(success_message) -def crc8(message_list): +def helpers_sha256_checksum(data: str) -> str: """ + Returns the calculated checksum (SHA256) for input data + @param data: input data + @return:: checksum + """ + + checksum = hashlib.sha256(data.encode()).hexdigest() + return checksum + + +def helpers_crc8(message_list): + """ Returns the calculated crc from a message list @param message_list: is a list of integer numbers containing the message @return:: integer containing an unsigned byte @@ -464,3 +490,9 @@ unsigned_byte = byte ^ crc crc = CRC_LIST[unsigned_byte] return crc + + +def helpers_get_ip_address(): + hostname = socket.gethostname() + ip_address = socket.gethostbyname(hostname) + return ip_address Index: cloudsync/utils/reachability.py =================================================================== diff -u -r4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47 -rcc7bbd932684e69aa456c114596625546630903e --- cloudsync/utils/reachability.py (.../reachability.py) (revision 4ebf654ab1b0d436ce7d171bfe06c6bdc46aca47) +++ cloudsync/utils/reachability.py (.../reachability.py) (revision cc7bbd932684e69aa456c114596625546630903e) @@ -8,10 +8,10 @@ import requests -REACHABILITY_URL = "https://kebormed.com" +REACHABILITY_URL = "https://healthcheck.diality.staging.kebormed.com/" REACHABILITY_CHECK_PAUSE = 5 REACHABILITY_CYCLES = 3 -REACHABILITY_CYCLE_PAUSE= 10 +REACHABILITY_CYCLE_PAUSE = 10 class ReachabilityProvider: @@ -27,8 +27,12 @@ Continuously monitors the connection to REACHABILITY_URL """ while True: + headers = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', + } + try: - response = requests.get(url=REACHABILITY_URL) + response = requests.get(url=REACHABILITY_URL, headers=headers) status_code = response.status_code except requests.exceptions.RequestException as er: status_code = INTERNAL_SERVER_ERROR