# -*- coding:utf-8 -*- """ @File : common_service @Author : xuxingchen @Version : 2.0 @Contact : xuxingchen@sinochem.com @Desc : 业务逻辑服务层 """ import json import time import traceback import requests import devices.meian_model as meian_data_entity import devices.yunfu_model as yunfu_data_entity import logger from logger import Logger, speed_ms from devices.meian_db import DeviceTable, RegisterTable, GatewayTable, HeartBeatTable, UserInfoTable, RecordTable from devices.common_model import ErrorCode, UserData, UserInfo from utils import generate_token, to_obj, datetime_to_timestamp, generate_time_token, encode_to_base64, \ extract_building_unit, extract_number from config import TIMEOUT_SECOND, SLEEP_TIME, BACKEND_URL, BACKEND_ID, BACKEND_SECRET, GATEWAY_CONFIG class BaseService: def __init__(self): self.table_handler = None self.topic = None self.clients = None def set_meta(self, userdata: UserData): self.table_handler = userdata.table_handler self.topic = userdata.topic self.clients = userdata.clients def handle(self, **kwargs): """must be `override`""" pass def get_owner_house_floor(user_id, project_code: str, device_position_desc: str) -> int: """根据用户ID获取用户房产信息,提取楼层信息并返回 1. 该功能只支持业主使用,访客查询不到,默认返回 """ token_url = f"{BACKEND_URL}/v2/accesskey_auth" owner_info_url = f"{BACKEND_URL}/v3/realty-master-data/owners/{user_id}" house_info_url = f"{BACKEND_URL}/v3/realty-master-data/houses" # get token data = {'id': BACKEND_ID, 'secret': BACKEND_SECRET} token_response = requests.post(token_url, json=data) if token_response.status_code == 200: logger.Logger.debug(f"token 请求成功,响应内容:{token_response.json()}") token = token_response.json()["access_token"] else: logger.Logger.error(f"token 请求失败,状态码: {token_response.status_code}") raise Exception(f"token 请求失败,状态码: {token_response.status_code}") # get house ids headers = { "Accept": "application/json", "Access-Token": token, "Content-Type": "application/json;charset=UTF-8" } owner_info_response = requests.get(owner_info_url, headers=headers) if owner_info_response.status_code == 200: owner_info = owner_info_response.json() logger.Logger.debug(f"owner_info 请求成功,响应内容:{owner_info}") # 根据 project_code 获取 project_id if GATEWAY_CONFIG[project_code][2] == "" or owner_info["data"]["project_id"] == GATEWAY_CONFIG[project_code][2]: house_ids = owner_info["data"]["house_ids"] else: logger.Logger.error(f"project id 不匹配," f"预置:{GATEWAY_CONFIG[project_code][2]}, 用户信息所属:{owner_info['data']['project_id']}") raise Exception(f"project id 不匹配") elif owner_info_response.status_code == 404 and owner_info_response.json()["msg"] == "OWNER_NOT_EXISTS": logger.Logger.warn(f"owner_info 请求成功,但用户ID不存在,非住户") return 1 else: logger.Logger.error(f"token 请求失败,状态码: {token_response.status_code}") raise Exception(f"token 请求失败,状态码: {token_response.status_code}") # 结合设备注册备注 获取楼层信息 data = { "query": { "id": {"$in": house_ids} } } house_info_response = requests.post(house_info_url, json=data, headers=headers) if house_info_response.status_code == 200: logger.Logger.debug(f"house_info 请求成功,响应内容:{house_info_response.json()}") building_number, unit_number = extract_building_unit(device_position_desc) house_info = house_info_response.json()["data"]["list"] floor = 1 for house_item in house_info: building_name = extract_number(house_item["building_name"]).zfill(2) unit_name = extract_number(house_item["unit_name"]).zfill(2) if building_name == building_number and unit_name == unit_number: floor = int(house_item["floor_name"]) break else: logger.Logger.error(f"house_info 请求失败,状态码: {token_response.status_code}") raise Exception(f"house_info 请求失败,状态码: {token_response.status_code}") return floor class Services: """业务逻辑入口""" class HeartBeatService(BaseService): def handle(self, msg_obj: meian_data_entity.HeartBeat): # Logger.debug("设备心跳已接收,正在执行上线 ...", log_path=None) last_time = HeartBeatTable.get_last_time(self.table_handler, msg_obj.device_id) # 若无心跳记录或者距离上次心跳记录时间达到5分钟 if (last_time is None or (time.time() - float( HeartBeatTable.get_last_time(self.table_handler, msg_obj.device_id))) > (60. * 5.)): status = HeartBeatTable.update(self.table_handler, msg_obj, self.topic) if status: # 执行上线操作 project_code = DeviceTable.get_project_code(self.table_handler, msg_obj.device_id) if project_code: gateway_id, _ = GatewayTable.get_gateway(self.table_handler, project_code) if gateway_id is None: Logger.error("网关不存在") return -1 aiot_id = DeviceTable.get_aiot_id(self.table_handler, msg_obj.device_id) if aiot_id is None: Logger.warn("设备未注册,不执行上线操作") return -1 topic = f"/jmlink/{aiot_id}/comm/online" topic_resp = f"/jmlink/{aiot_id}/comm/online_resp" s = time.time() # 获取客户端 client_1 = self.clients[gateway_id][0] userdata = self.clients[gateway_id][1] userdata.set_status_add("status", False) userdata.set_status_add("start_timestamp", time.time()) try: # 订阅回传 client_1.subscribe(topic_resp) Logger.debug(f"subscribe topics: {topic_resp}") # 发布事件 token = generate_token() userdata.set_token(token) online_json = json.dumps(yunfu_data_entity.Online(messageId=token).__dict__) client_1.publish(topic, online_json) while True: if userdata.status["status"]: # 拿到结果后写入到数据库中更新数据 if "code" in userdata.status["response"].keys(): error_code = userdata.status["response"]["code"] if error_code == 0: Logger.info(f"设备 - {aiot_id} 完成上线") else: Logger.error( f"{topic_resp} 返回错误码: {error_code}, " f"{yunfu_data_entity.error_code[error_code]}") break if time.time() - userdata.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出 Logger.debug( f"等待回复超时: {speed_ms(userdata.status['start_timestamp'])}ms") break # Logger.debug(f"{userdata.status} waiting for {topic_resp} ... ") time.sleep(SLEEP_TIME) finally: # 属性复位 client_1.unsubscribe(topic_resp) # Logger.debug(f"移除订阅: {topic_resp}") userdata.set_token(None) userdata.set_status_remove("response") # Logger.debug(f"{speed_ms(s)}ms") else: Logger.warn("上线请求非法,默认无操作") else: Logger.debug("未达到重新上线阈值,默认无操作") pass class RegisterService(BaseService): def handle(self, msg_obj: meian_data_entity.Register): Logger.debug("RegisterService Handle ...") status = RegisterTable.update(self.table_handler, msg_obj, self.topic) if status: if not DeviceTable.get_device_register_type(self.table_handler, msg_obj.device_id): Logger.debug("Execute register ...") project_code = DeviceTable.get_project_code(self.table_handler, msg_obj.device_id) if project_code: gateway_id, _ = GatewayTable.get_gateway(self.table_handler, project_code) if gateway_id is None: Logger.error("网关不存在") return -1 topic = f"/jmlink/{gateway_id}/comm/sub/register" topic_resp = f"/jmlink/{gateway_id}/comm/sub/register_resp" # 将连接信息(网关&网关secret)和回传信息发送给回传监听进程 s = time.time() # 获取客户端 client_1 = self.clients[gateway_id][0] userdata = self.clients[gateway_id][1] userdata.set_status_add("status", False) userdata.set_status_add("start_timestamp", time.time()) try: # 订阅回传 client_1.subscribe(topic_resp) Logger.debug(f"subscribe topics: {topic_resp}") # 发布事件 token = generate_token() userdata.set_token(token) register_json = json.dumps(yunfu_data_entity.CommRegister( messageId=token, params=yunfu_data_entity.RegisterParam( deviceName=msg_obj.device_id, displayName=f"美安-{msg_obj.device_id}-{msg_obj.device_position_desc}" ).__dict__ ).__dict__) Logger.debug(register_json) client_1.publish(topic, register_json) while True: if userdata.status["status"]: # 拿到结果后写入到数据库中更新数据 if "data" in userdata.status["response"].keys(): resp = userdata.status["response"]["data"][0] if resp["code"] == 0: DeviceTable.update_aiot_id(self.table_handler, resp["deviceName"], resp["deviceId"]) Logger.info(f"设备 - {msg_obj.device_id} 完成注册") # 每次完成注册后刷新订阅信息 Logger.debug(f"刷新订阅列表中 ...") sub_aiot_id_list = json.loads( GatewayTable.get_registered_sub_aiot_id(self.table_handler, gateway_id)[ 0]) current_topics = set( [f"/jmlink/{aiot_id}/tml/service/call" for aiot_id in sub_aiot_id_list]) last_topics = set(userdata.topics) topics_to_subscribe = current_topics - last_topics topics_to_unsubscribe = last_topics - current_topics if topics_to_subscribe or topics_to_unsubscribe: # 订阅缺少的主题 for topic in list(topics_to_subscribe): client_1.subscribe(topic) Logger.debug(f"新增订阅: {topic}") # 取消订阅多余的主题 for topic in list(topics_to_unsubscribe): client_1.unsubscribe(topic) Logger.debug(f"移除订阅: {topic}") else: Logger.debug(f"订阅列表无变化") Logger.debug(f"订阅列表刷新完成 ✅") else: Logger.error( f"{topic_resp} 返回错误码: {resp['code']}, " f"{yunfu_data_entity.error_code[resp['code']]}") break if time.time() - userdata.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出 Logger.debug( f"等待回复超时: {speed_ms(userdata.status['start_timestamp'])}ms") break # Logger.debug(f"{userdata.status} waiting for {topic_resp} ... ") time.sleep(SLEEP_TIME) # 实际运行中设为0.1,100ms检测一次 finally: client_1.unsubscribe(topic_resp) Logger.debug(f"移除订阅: {topic_resp}") userdata.set_token(None) userdata.set_status_remove("response") Logger.debug(f"{speed_ms(s)}ms") else: Logger.error("网关配置表中不存在设备关联的项目信息") else: Logger.debug("设备已注册过,默认无操作") class PushRtAccessRecordService(BaseService): def handle(self, msg_obj: meian_data_entity.PushRtAccessRecord): Logger.debug("Execute open_event ...") # 若存在通行记录,但人员信息表中不存在人员信息,则将通行记录本地保存留用 if msg_obj.user_id.startswith("old-"): # 历史遗留在设备中的人员id应当以old-开头进行插入 try: RecordTable.add(self.table_handler, msg_obj) Logger.info("通行事件本地记录成功") return 1 except Exception as e: Logger.error(f"{type(e).__name__}, {e}") if logger.DEBUG: traceback.print_exc() # 查询子设备ID aiot_id = DeviceTable.get_aiot_id(self.table_handler, msg_obj.device_id) if aiot_id is None: Logger.warn(f"Device - {aiot_id} is not registered") return -1 topic = f"/jmlink/{aiot_id}/tml/event/post" topic_resp = f"/jmlink/{aiot_id}/tml/event/post_resp" project_code = DeviceTable.get_project_code(self.table_handler, msg_obj.device_id) if project_code: gateway_id, _ = GatewayTable.get_gateway(self.table_handler, project_code) # 将连接信息(网关&网关secret)和回传信息发送给回传监听进程 s = time.time() # 获取客户端 client_1 = self.clients[gateway_id][0] userdata = self.clients[gateway_id][1] userdata.set_status_add("status", False) userdata.set_status_add("start_timestamp", time.time()) # 订阅回传 client_1.subscribe(topic_resp) Logger.debug(f"subscribe topics: {topic_resp}") try: # 数据转换 open_event = yunfu_data_entity.OpenEvent() open_event.datetime = str(datetime_to_timestamp(msg_obj.time)) open_event.type = yunfu_data_entity.OpenEventType.__dict__[msg_obj.access_mode.upper()].value open_event.certificate_type = yunfu_data_entity.OpenEventCertificateType.__dict__[ msg_obj.access_mode.upper()].value # 若是二维码通信,根据二维码获取用户信息,若是人脸通信,根据userid获取用户信息 if msg_obj.access_mode == "qrCode": user = UserInfoTable.get_user_by_qrcode(self.table_handler, msg_obj.user_id, msg_obj.device_id) open_event.code = user[0] open_event.certificate = user[0] name = user[1] else: name = UserInfoTable.get_name(self.table_handler, msg_obj.user_id, msg_obj.device_id) open_event.code = msg_obj.user_id open_event.certificate = msg_obj.user_id open_event.name = name open_event.check() token = generate_token() userdata.set_token(token) event_json = json.dumps(yunfu_data_entity.EventPost( messageId=token, eventCode="open_event", params=open_event.__dict__ ).__dict__) # 发布事件 client_1.publish(topic, event_json) # 等待回传 while True: if userdata.status["status"]: if "code" in userdata.status["response"].keys(): if userdata.status["response"]["code"] != 0: error_code = userdata.status['response']['errorCode'] Logger.error(f"{topic_resp} 返回错误码: {error_code}, " f"{meian_data_entity.error_code[error_code]}") else: Logger.debug("通行事件推送成功") break if time.time() - userdata.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出 Logger.error("等待回复超时") break # Logger.debug(f"{userdata.status} waiting for {topic_resp} ... ") time.sleep(SLEEP_TIME) finally: # 属性复位 client_1.unsubscribe(topic_resp) Logger.debug(f"移除订阅: {topic_resp}") userdata.set_token(None) userdata.set_status_remove("response") Logger.debug(f"{speed_ms(s)}ms") class GetQrCodeService(BaseService): """获取访客二维码 1. 将接受的用户信息记录追加或更新到本地DB 2. 根据时间戳和访客id生成一个token字符串,作为唯一识别id 3. 将生成的二维码下置给指定设备 4. 将唯一识别id作为二维码字符串返回给平台 """ def handle(self, msg: dict): Logger.debug("Execute Get QrCode ...") code = ErrorCode.SUCCESS device_id = DeviceTable.get_device_id(self.table_handler, self.topic.split("/tml")[0].split("link/")[1]) project_code = DeviceTable.get_project_code(self.table_handler, device_id) gateway_id, _ = GatewayTable.get_gateway(self.table_handler, project_code) success_aiot_list = [] aiot_ids = [] qrcode = None try: # 根据时间戳和访客id生成一个token字符串,作为唯一识别id qrcode = generate_time_token(msg["params"]["user_id"]) # 将生成的二维码下置给指定设备 aiot_ids = json.loads(msg["params"]["device_ids"]) s = time.time() for aiot_id in aiot_ids: # 一般情况 aiot_ids 里应该只有一个值 # 查询对应aiot_id实际的美安设备id和订阅主题 device_id = DeviceTable.get_device_id(self.table_handler, aiot_id) if device_id is None: continue # 将接受的用户信息记录追加或更新到本地DB user_type = 0 if msg["serviceCode"] != "get_visitor_qrcode" else 1 # 业主0 访客1,身份类型在插入后就不会再被更新 device_position_desc = RegisterTable.get_device_position_desc(self.table_handler, device_id) if user_type == 1 or device_position_desc is None: floor = 1 else: floor = get_owner_house_floor(msg["params"]["user_id"], project_code, device_position_desc) user_info = UserInfo( user_id=msg["params"]["user_id"], device_id=device_id, name=msg["params"]["name"], user_type=user_type ) UserInfoTable.update(self.table_handler, user_info) topic, topic_resp = DeviceTable.get_device_topic(self.table_handler, device_id) # 获取客户端 client_0 = self.clients["center"][0] userdata_0 = self.clients["center"][1] userdata_0.set_status_add("status", False) userdata_0.set_status_add("start_timestamp", time.time()) try: Logger.debug(f"subscribe topics: {topic_resp}") # 构建消息体 token = generate_token() # 正式运行应使用 generate_token() userdata_0.set_token(token) userdata_0.set_code("qrCodeDownState") qrcode_json = json.dumps(meian_data_entity.QrCodeInfo( dataType="qrCodeInfo", deviceId=device_id, token=token, userId=qrcode, qrCode=encode_to_base64(qrcode), floor=floor ).__dict__) # 发布事件 client_0.publish(topic, qrcode_json) # 等待回传 while True: if userdata_0.status["status"]: if "errorCode" in userdata_0.status["response"].keys(): if userdata_0.status["response"]["errorCode"] != 0: error_code = userdata_0.status['response']['errorCode'] Logger.error(f"{topic_resp} 返回错误码: {error_code}, " f"{meian_data_entity.error_code[error_code]}") else: Logger.info(f"设备 - {device_id} 二维码 - {qrcode} 完成下置") UserInfoTable.update_qrcode(self.table_handler, user_info.user_id, device_id, qrcode) success_aiot_list.append(aiot_id) break if time.time() - userdata_0.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出 Logger.error("等待回复超时") break # Logger.debug(f"{userdata_0.status} waiting for {topic_resp} ... ") time.sleep(SLEEP_TIME) finally: userdata_0.set_token(None) userdata_0.set_code(None) userdata_0.set_status_remove("response") Logger.debug(f"{speed_ms(s)}ms") except Exception as e: Logger.error(f"{type(e).__name__}, {e}") if type(e).__name__ == "TypeError": code = ErrorCode.INPUT_TYPE_ERROR else: code = ErrorCode.UNKNOWN # 将唯一识别id作为二维码字符串返回给平台 # 获取客户端 client_1 = self.clients[gateway_id][0] userdata = self.clients[gateway_id][1] userdata.set_status_add("status", False) userdata.set_status_add("start_timestamp", time.time()) try: if code == ErrorCode.SUCCESS: if set(success_aiot_list) == set(aiot_ids): # 全部完成下发 Logger.debug("指令完成下发") elif success_aiot_list: # 完成一部分下发 code = ErrorCode.PART_SUCCESS Logger.warn(f"部分成功下发: {success_aiot_list}") UserInfoTable.update_qrcode(self.table_handler, msg["params"]["user_id"], project_code, qrcode) elif len(success_aiot_list) == 0: # 一个都没下发 code = ErrorCode.FAILURE Logger.error("无指令完成下发") aiot_topic = self.topic + "_resp" return_json = json.dumps(yunfu_data_entity.EventPostResp( messageId=msg["messageId"], requestTime=msg["time"], serviceCode=msg["serviceCode"], data=yunfu_data_entity.QrCodeResp(code=code.value, message=code.message, qrcode=qrcode).__dict__ ).__dict__) client_1.publish(aiot_topic, return_json) finally: userdata.set_token(None) userdata.set_status_remove("response") class AddFaceService(BaseService): def handle(self, msg: dict): Logger.debug("Execute Add Face ...") code = ErrorCode.SUCCESS device_id = DeviceTable.get_device_id(self.table_handler, self.topic.split("/tml")[0].split("link/")[1]) project_code = DeviceTable.get_project_code(self.table_handler, device_id) gateway_id, _ = GatewayTable.get_gateway(self.table_handler, project_code) success_aiot_list = [] aiot_ids = json.loads(msg["params"]["device_ids"]) user_id = msg["params"]["user_id"] face_url = f"{msg['params']['face_url']}?x-oss-process=image/resize,m_pad,h_960,w_540,color_FFFFFF" try: # 将人脸下置给指定设备 s = time.time() for aiot_id in aiot_ids: # 查询对应aiot_id实际的美安设备id和订阅主题 device_id = DeviceTable.get_device_id(self.table_handler, aiot_id) if device_id is None: continue # 将接受的用户信息记录追加或更新到本地DB user_info = UserInfo( user_id=user_id, device_id=device_id, name=msg["params"]["name"], user_type=0 ) UserInfoTable.update(self.table_handler, user_info) topic, topic_resp = DeviceTable.get_device_topic(self.table_handler, device_id) # 获取客户端 client_0 = self.clients["center"][0] userdata_0 = self.clients["center"][1] userdata_0.set_status_add("status", False) userdata_0.set_status_add("start_timestamp", time.time()) try: Logger.debug(f"subscribe topics: {topic_resp}") # 构建消息体 token = generate_token() # 正式运行应使用 generate_token() userdata_0.set_token(token) userdata_0.set_code("faceDownState") device_position_desc = RegisterTable.get_device_position_desc(self.table_handler, device_id) if device_position_desc is None: floor = 1 else: floor = get_owner_house_floor(user_id, project_code, device_position_desc) face_json = json.dumps(meian_data_entity.FaceInfo( dataType="faceInfo", deviceId=device_id, token=token, userId=user_id, faceUrl=face_url, floor=floor ).__dict__) # 发布事件 client_0.publish(topic, face_json) Logger.debug(f"{face_json} ==> {topic}") # 等待回传 while True: if userdata_0.status["status"]: if "errorCode" in userdata_0.status["response"].keys(): if userdata_0.status["response"]["errorCode"] != 0: error_code = userdata_0.status['response']['errorCode'] Logger.error(f"{topic_resp} 返回错误码: {error_code}, " f"{meian_data_entity.error_code[error_code]}") else: Logger.info(f"设备 - {device_id} 用户({user_id}) 人脸完成下置") UserInfoTable.update_face_url(self.table_handler, user_id, device_id, face_url) success_aiot_list.append(aiot_id) break if time.time() - userdata_0.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出 Logger.error("等待回复超时") break # Logger.debug(f"{userdata_0.status} waiting for {topic_resp} ... ") time.sleep(SLEEP_TIME) finally: userdata_0.set_token(None) userdata_0.set_code(None) userdata_0.set_status_remove("response") Logger.debug(f"{speed_ms(s)}ms") except Exception as e: Logger.error(f"{type(e).__name__}, {e}") if type(e).__name__ == "TypeError": code = ErrorCode.INPUT_TYPE_ERROR else: code = ErrorCode.UNKNOWN # 将下置结果返回给平台 # 获取客户端 client_1 = self.clients[gateway_id][0] userdata = self.clients[gateway_id][1] userdata.set_status_add("status", False) userdata.set_status_add("start_timestamp", time.time()) try: if code == ErrorCode.SUCCESS: if set(success_aiot_list) == set(aiot_ids): # 全部完成下发 Logger.info("指令完成下发") elif success_aiot_list: # 完成一部分下发 code = ErrorCode.PART_SUCCESS Logger.warn(f"部分成功下发: {success_aiot_list}") else: # 一个都没下发 code = ErrorCode.FAILURE Logger.error("无指令完成下发") aiot_topic = self.topic + "_resp" return_json = json.dumps(yunfu_data_entity.EventPostResp( messageId=msg["messageId"], requestTime=msg["time"], serviceCode=msg["serviceCode"], data=yunfu_data_entity.AddFaceResp(code=code.value, message=code.message).__dict__ ).__dict__) client_1.publish(aiot_topic, return_json) finally: userdata.set_token(None) userdata.set_status_remove("response") class DeleteFaceService(BaseService): def handle(self, msg: dict): Logger.debug("Execute Delete Face ...") code = ErrorCode.SUCCESS device_id = DeviceTable.get_device_id(self.table_handler, self.topic.split("/tml")[0].split("link/")[1]) project_code = DeviceTable.get_project_code(self.table_handler, device_id) gateway_id, _ = GatewayTable.get_gateway(self.table_handler, project_code) success_aiot_list = [] aiot_ids = json.loads(msg["params"]["device_ids"]) user_id = msg["params"]["user_id"] try: s = time.time() # 将人脸删除指令下发指定设备 for aiot_id in aiot_ids: # 查询对应aiot_id实际的美安设备id和订阅主题 device_id = DeviceTable.get_device_id(self.table_handler, aiot_id) if device_id is None: continue # 本地DB判断人脸信息是否存在 if UserInfoTable.exists_face_url(self.table_handler, user_id, device_id): topic, topic_resp = DeviceTable.get_device_topic(self.table_handler, device_id) # 获取客户端 client_0 = self.clients["center"][0] userdata_0 = self.clients["center"][1] userdata_0.set_status_add("status", False) userdata_0.set_status_add("start_timestamp", time.time()) try: Logger.debug(f"subscribe topics: {topic_resp}") # 构建消息体 token = generate_token() # 正式运行应使用 generate_token() userdata_0.set_token(token) userdata_0.set_code("deleteUserState") face_json = json.dumps(meian_data_entity.DeleteUser( dataType="deleteUser", deviceId=device_id, token=token, userId=user_id ).__dict__) # 发布事件 client_0.publish(topic, face_json) # 等待回传 while True: if userdata_0.status["status"]: if "errorCode" in userdata_0.status["response"].keys(): if userdata_0.status["response"]["errorCode"] != 0: error_code = userdata_0.status['response']['errorCode'] Logger.error(f"{topic_resp} 返回错误码: {error_code}, " f"{meian_data_entity.error_code[error_code]}") else: Logger.info(f"设备 - {device_id} 移除用户({user_id})人脸") UserInfoTable.update_face_url(self.table_handler, user_id, device_id, None) success_aiot_list.append(aiot_id) break if time.time() - userdata_0.status["start_timestamp"] > TIMEOUT_SECOND: # 超时跳出 Logger.error("等待回复超时") break # Logger.debug(f"{userdata_0.status} waiting for {topic_resp} ... ") time.sleep(SLEEP_TIME) finally: userdata_0.set_token(None) userdata_0.set_code(None) userdata_0.set_status_remove("response") else: code = ErrorCode.NEVER_POST_FACE Logger.warn(f"本地数据库中未发现下发过人脸信息,默认无操作") Logger.debug(f"{speed_ms(s)}ms") except Exception as e: Logger.error(f"{type(e).__name__}, {e}") if type(e).__name__ == "TypeError": code = ErrorCode.INPUT_TYPE_ERROR else: code = ErrorCode.UNKNOWN # 将下置结果返回给平台 # 获取客户端 client_1 = self.clients[gateway_id][0] userdata = self.clients[gateway_id][1] userdata.set_status_add("status", False) userdata.set_status_add("start_timestamp", time.time()) try: if code == ErrorCode.SUCCESS: if set(success_aiot_list) == set(aiot_ids): # 全部完成下发 Logger.info("指令完成下发") elif success_aiot_list: # 完成一部分下发 code = ErrorCode.PART_SUCCESS Logger.warn(f"部分成功下发: {success_aiot_list}") else: # 一个都没下发 code = ErrorCode.FAILURE Logger.error("无指令完成下发") aiot_topic = self.topic + "_resp" return_json = json.dumps(yunfu_data_entity.EventPostResp( messageId=msg["messageId"], requestTime=msg["time"], serviceCode=msg["serviceCode"], data=yunfu_data_entity.DelFaceResp(code=code.value, message=code.message).__dict__ ).__dict__) client_1.publish(aiot_topic, return_json) finally: userdata.set_token(None) userdata.set_status_remove("response") def auto_service(msg: dict, userdata: UserData): """跟据dataType自动化加载不同的服务层""" if "dataType" in msg.keys(): entity_name = msg["dataType"][0].upper() + msg["dataType"][1:] if entity_name in meian_data_entity.__dict__.keys(): Logger.debug(f"Target service name: {entity_name}") # 转为服务层数据实体 entity_type = meian_data_entity.__dict__[entity_name] msg_obj = to_obj(msg, entity_type) # 构建服务层实体并进行调用 service_name = entity_name + "Service" if service_name in Services.__dict__.keys(): servicer = Services.__dict__[service_name]() servicer.set_meta(userdata) servicer.handle(msg_obj) elif "serviceCode" in msg.keys() and "params" in msg.keys(): # 校验是aiot平台服务调用下发 service_map = { "get_owner_qrcode": "GetQrCodeService", "get_visitor_qrcode": "GetQrCodeService", "add_face": "AddFaceService", "del_face": "DeleteFaceService" } # 构建服务层实体并进行调用 if msg["serviceCode"] in service_map.keys(): service_name = service_map[msg["serviceCode"]] servicer = Services.__dict__[service_name]() servicer.set_meta(userdata) servicer.handle(msg) else: pass