def add_linkage_command_body(product_id, dev_id, command_list): lk = DevCommandQueueMng.get_exe_locker(dev_id) try: ts = time.time() MyLog.logger.info(f'添加联动指令, 等待获取锁({ts}), 设备id:{dev_id}') lk.acquire() MyLog.logger.info(f'添加联动指令, 获得锁({ts}), 设备id:{dev_id}') need_add_to_command_queue_list = [] dev_command_queue = DevCommandQueueMng.get_dev_command_queue( dev_id) if not dev_command_queue: dict = {} dict["dev_id"] = dev_id dev_command_queue = DevCommandQueue(product_id, dev_id) dict["dev_command_queue"] = dev_command_queue g_dev_command_queue_list.append(dict) for command in command_list: need_exe = True current_running_command = dev_command_queue.get_current_running_command( command.command) if current_running_command: MyLog.logger.info( 'command.command = %s, command.priority = %d, current_running_command.priority = %d' % (command.command, command.priority, current_running_command.priority)) if current_running_command and command.priority <= current_running_command.priority: EventReport.report_rule_command_ignore_event( dev_id, command.command, command.uuid, current_running_command.uuid) need_exe = False if need_exe: need_retry, service_has_recv, ret = DevCommandQueueMng.command_exe( dev_id, command) if service_has_recv: dev_command_queue.clear_linkage_command( command.command) need_add_to_command_queue_list.append(command) if need_add_to_command_queue_list: MyLog.logger.info( 'dev_command_queue.add_linkage_command_list size: %d' % (len(need_add_to_command_queue_list))) dev_command_queue.add_linkage_command_list( need_add_to_command_queue_list) name_list = dev_command_queue.get_all_command_name_list() DevCommandQueueMng.__reset_dev_timer(dev_id) lk.release() MyLog.logger.info(f'添加联动指令, 释放锁({ts}), 设备id:{dev_id}') except Exception as e: msg = MyLog.color_red( 'add_linkage_command_body has exception: ' + str(e)) MyLog.logger.error(msg) lk.release()
def add_manual_command_body(product_id, dev_id, command_list): lk = DevCommandQueueMng.get_exe_locker(dev_id) try: ts = time.time() MyLog.logger.info(f'添加手动指令, 等待获取锁({ts}), 设备id:{dev_id}') lk.acquire() MyLog.logger.info(f'添加手动指令, 获得锁({ts}), 设备id:{dev_id}') need_add_to_command_queue_list = [] dev_command_queue = DevCommandQueueMng.get_dev_command_queue( dev_id) if not dev_command_queue: dict = {} dict["dev_id"] = dev_id dev_command_queue = DevCommandQueue(product_id, dev_id) dict["dev_command_queue"] = dev_command_queue g_dev_command_queue_list.append(dict) for command in command_list: command.uuid = 'manual' need_exe = True current_running_command = dev_command_queue.get_current_running_command( command.command) # 同一优先级的临时手动命令需要更新执行 if current_running_command and current_running_command.effective and \ (( current_running_command.type == 'manual' and command.priority < current_running_command.priority) or \ ( current_running_command.type != 'manual' and command.priority <= current_running_command.priority)): EventReport.report_rule_command_ignore_event( dev_id, command.command, command.uuid, current_running_command.uuid) need_exe = False if need_exe: need_retry, service_has_recv, ret = DevCommandQueueMng.command_exe( dev_id, command, force=True) if service_has_recv: # 如果执行临时手动指令,则联动指令已被顶替失效,删除 dev_command_queue.clear_linkage_command( command.command) need_add_to_command_queue_list.append(command) if need_add_to_command_queue_list: dev_command_queue.add_manual_command_list( need_add_to_command_queue_list) DevCommandQueueMng.__reset_dev_timer(dev_id) lk.release() MyLog.logger.info(f'添加手动指令, 释放锁({ts}), 设备id:{dev_id}') except Exception as e: msg = MyLog.color_red( 'add_manual_command_body has exception: ' + str(e)) MyLog.logger.error(msg) lk.release()
def clear_all_running_rule_endtime(): g_lk.acquire() for rule in g_running_rule_endtime_list: g_running_rule_endtime_list.remove(rule) EventReport.report_rule_end_event(rule['uuid']) break g_lk.release() global g_running_rule_endtime_handle_timer if g_running_rule_endtime_handle_timer: g_running_rule_endtime_handle_timer.cancel() g_running_rule_endtime_handle_timer = Timer(0, running_rule_endtime_handle) g_running_rule_endtime_handle_timer.start()
def remove_running_rule_endtime(uuid_list): g_lk.acquire() for uuid in uuid_list: for rule in g_running_rule_endtime_list: if rule['uuid'] == uuid: g_running_rule_endtime_list.remove(rule) EventReport.report_rule_end_event(rule['uuid']) break g_lk.release() global g_running_rule_endtime_handle_timer if g_running_rule_endtime_handle_timer: g_running_rule_endtime_handle_timer.cancel() g_running_rule_endtime_handle_timer = Timer(0, running_rule_endtime_handle) g_running_rule_endtime_handle_timer.start()
def add_timer_command(product_id, dev_id, command_list) -> None: MyLog.logger.info('添加定时指令 产品ID:%s, 设备ID:%s' % (product_id, dev_id)) dev_command_queue = DevCommandQueueMng.get_dev_command_queue(dev_id) if not dev_command_queue: dict = {} dict["dev_id"] = dev_id dev_command_queue = DevCommandQueue(product_id, dev_id) dict["dev_command_queue"] = dev_command_queue g_dev_command_queue_list.append(dict) for command in command_list: current_running_command = dev_command_queue.get_current_running_command( command.command) if current_running_command and current_running_command.effective and command.priority <= current_running_command.priority: EventReport.report_rule_command_ignore_event( dev_id, command.command, command.uuid, current_running_command.uuid) dev_command_queue.add_timer_command_list(command_list)
def running_rule_endtime_handle(): MyLog.logger.info("运行中的规则结束处理") current_ts = time.time() smallest_ts = 0 uuid_list = [] to_del_rule = [] g_lk.acquire() for rule in g_running_rule_endtime_list: MyLog.logger.info(f'rule:{rule}') if rule['end_ts'] < current_ts: MyLog.logger.info("规则(%s)结束" % (rule['uuid'])) # g_running_rule_endtime_list.remove(rule) # 遍历列表过程中改变列表size!!! to_del_rule.append(rule) uuid_list.append(rule['uuid']) # 上报规则结束事件 EventReport.report_rule_end_event(rule['uuid']) else: if smallest_ts == 0: smallest_ts = rule['end_ts'] elif rule['end_ts'] < smallest_ts: smallest_ts = rule['end_ts'] # to fix the bug referred above for del_rule in to_del_rule: g_running_rule_endtime_list.remove(del_rule) g_lk.release() if uuid_list: # 删除结束规则的指令 DevCommandQueueMng.clear_command_by_rule_uuid(uuid_list) # 所有设备队列重新执行指令决策 DevCommandQueueMng.all_dev_exe() global g_running_rule_endtime_handle_timer if g_running_rule_endtime_handle_timer: g_running_rule_endtime_handle_timer.cancel() ts = smallest_ts - current_ts if ts > 0: g_running_rule_endtime_handle_timer = Timer( ts, running_rule_endtime_handle) g_running_rule_endtime_handle_timer.start()
def command_exe(dev_id, command: CommandInfo, force=False): try: MyLog.logger.info( f'指令执行 设备id:{dev_id}, 指令名称:{command.command}, 规则:{command.uuid}, force:{force}' ) # 先获取指令名称 command_name = command.command # 从该设备的指令队列中查询该指令名称正在执行的指令 dev_command_queue = DevCommandQueueMng.get_dev_command_queue( dev_id) running_command = dev_command_queue.get_current_running_command( command_name) need_exe = False need_report_rule_command_cover_event = False if force: need_exe = True if running_command.priority < command.priority: need_report_rule_command_cover_event = True elif running_command: # 判断是否为同一个规则指令,如果不是才允许执行 MyLog.logger.info('running_command: %s, command:%s' % (running_command.uuid, command.uuid)) MyLog.logger.info( f'running_command_effective:{running_command.effective}') if not running_command.effective or running_command.uuid != command.uuid: need_exe = True else: msg = MyLog.color_green( '指令执行 设备id:%s, 指令名称:%s, 规则:%s 已经在执行中,不需要重新下发' % (dev_id, command.command, command.uuid)) MyLog.logger.info(msg) if running_command.priority < command.priority: need_report_rule_command_cover_event = True else: need_exe = True result = g_retValue.qjBoxOpcodeSucess.value need_retry = False service_has_recv = False if need_exe: if command.default_param: # 执行默认参数 msg = MyLog.color_green( '下发默认参数指令(%s)给设备(%s)服务, 指令优先级:%d' % (command.command, dev_id, command.priority)) MyLog.logger.info(msg) need_retry, service_has_recv, result, data = DevCall.call_service( dev_id, command.command, command.type, default=True) msg = MyLog.color_green('下发默认参数指令(%s)给设备(%s)服务, 返回:%d' % (command.command, dev_id, result)) MyLog.logger.info(msg) EventReport.report_default_command_status_event( dev_id, command.command, result) else: # 执行规则配置参数 msg = MyLog.color_green( '下发规则(%s)指令(%s)给设备(%s)服务, 指令优先级:%d' % (command.uuid, command.command, dev_id, command.priority)) MyLog.logger.info(msg) need_retry, service_has_recv, result, data = DevCall.call_service( dev_id, command.command, command.type, command.params) msg = MyLog.color_green( '下发规则(%s)指令(%s)给设备(%s)服务, 返回:%d' % (command.uuid, command.command, dev_id, result)) MyLog.logger.info(msg) # 上报ruleCommandStatus event EventReport.report_rule_command_status_event( command.uuid, dev_id, command.command, result) if service_has_recv: dev_command_queue.set_current_running_command( command_name, command) # 更新规则指令状态 CmdRecorder.update_cmd(dev_id, command) if need_report_rule_command_cover_event: EventReport.report_rule_command_cover_event( dev_id, command.command, running_command.uuid, command.uuid) return need_retry, service_has_recv, result except BaseException as e: msg = MyLog.color_red('command_exe has except: ' + str(e)) MyLog.logger.error(msg) return False, False, g_retValue.qjBoxOpcodeExcept.value
def outside_linkage(cls, services) -> int: try: keys = {'uuid', 'priority', 'script'} for service_dict in services: if not cls.__check_keys_exists(service_dict, keys): # 返回参数错误 msg = MyLog.color_red('必要参数不存在') MyLog.logger.error(msg) return g_retValue.qjBoxOpcodeInputParamErr.value if type(service_dict['uuid'] ) != str or service_dict['uuid'] == '': msg = MyLog.color_red('uuid param is invalid') MyLog.logger.error(msg) return g_retValue.qjBoxOpcodeInputParamErr.value if type(service_dict['script'] ) != str or service_dict['script'] == '': msg = MyLog.color_red('script param is invalid') MyLog.logger.error(msg) return g_retValue.qjBoxOpcodeInputParamErr.value if type(service_dict['priority']) != int or service_dict[ 'priority'] < 1 or service_dict['priority'] > 99: msg = MyLog.color_red('priority param is invalid') MyLog.logger.error(msg) return g_retValue.qjBoxOpcodeInputParamErr.value for service_dict in services: uuid = service_dict['uuid'] py_path = "/tmp/" + uuid + '.py' pyc_path = "/tmp/" + uuid + '.pyc' conver_to_py(service_dict['script'], py_path) if not os.path.exists(py_path): msg = MyLog.color_red( "outside_linkage: py(%s) is not exist" % (py_path)) MyLog.logger.error(msg) continue # 执行脚本 file = importlib.import_module(uuid) importlib.reload(file) # dev_command_list = [{'product_id': '', 'dev_id': "", "command_list":[{'service':'', 'param':'', 'time':10 }]}] dev_command_list, event_list, attr_list = file.script_fun() MyLog.logger.debug('dev_command_list size: %d' % (len(dev_command_list))) if dev_command_list or event_list: current_ts = time.time() # 上报规则开始执行 EventReport.report_rule_start_event(uuid) continue_time = 1 for dev_command in dev_command_list: command_info_list = [] for command in dev_command['command_list']: if continue_time < command['time']: continue_time = command['time'] command_info = CommandInfo( uuid, command['service'], command['param'], current_ts, current_ts + command['time'], service_dict['priority'], 'linkage') MyLog.logger.debug("append command priority = %d" % (service_dict['priority'])) command_info_list.append(command_info) if command_info_list: MyLog.logger.debug('#add_linkage_command') DevCommandQueueMng.add_linkage_command( dev_command['product_id'], dev_command['dev_id'], command_info_list) end_ts = current_ts + continue_time uuid_endtime_list = [{'uuid': uuid, 'end_ts': end_ts}] add_running_rule_endtime(uuid_endtime_list) for custom_event in event_list: EventReport.report_linkage_custom_event( custom_event['event_id'], custom_event['src_dev_list']) if os.path.exists(py_path): os.remove(py_path) if os.path.exists(pyc_path): os.remove(pyc_path) return g_retValue.qjBoxOpcodeSucess.value except Exception as e: msg = MyLog.color_red('outside_linkage in rule_mng has except: ' + str(e)) MyLog.logger.error(msg) return g_retValue.qjBoxOpcodeExcept.value
def run_linkage_rule_by_devid(cls, dev_id, attrs) -> None: try: MyLog.logger.info( f'##########run_linkage_rule_by_devid({dev_id} attrs: {attrs})############' ) uuid_list = SqliteInterface.get_current_linkage_rule_by_src_devid( dev_id) msg = f"get_current_linkage_rule_by_src_devid({dev_id}, sizeof uuid_list = {len(uuid_list)})" MyLog.logger.debug(msg) for uuid in uuid_list: py_path = RULE_PY_SCRIPT_FOLDER + "/" + uuid + '.py' if not os.path.exists(py_path): msg = MyLog.color_red( "run_linkage_rule_by_devid: py(%s) is not exist" % (py_path)) MyLog.logger.error(msg) continue # 执行脚本 py_import_path = RULE_PY_MODEL_PATH + uuid MyLog.logger.debug('py_import_path: ' + py_import_path) file = importlib.import_module(py_import_path) importlib.reload(file) MyLog.logger.debug('run script fun') # dev_command_list = [{'product_id': '', 'dev_id': "", "command_list":[{'service':'', 'param':'', 'time':10 }]}] dev_command_list, event_list, attr_list = file.script_fun() msg = f'dev_command_list size: {len(dev_command_list)}, event_list size: {len(event_list)}' MyLog.logger.debug(msg) # 如果相同的联动策略已经在运行中了,那么这个策略的所有服务都被忽略 if find_running_rule_by_uuid(uuid): for dev_commands_dict in dev_command_list: __, dev_id, service_list = dev_commands_dict.values() for command_dict in service_list: MyLog.logger.debug( f'dev_id:{dev_id},cmd:{command_dict["service"]},uuid:{uuid}' ) EventReport.report_rule_command_ignore_event( dev_id, command_dict['service'], uuid, uuid) continue if attrs: allow_exe = RuleMng.attrs_has_one_in_changed( dev_id, attr_list, attrs) else: allow_exe = True MyLog.logger.debug(f'allow exe: {allow_exe}') if allow_exe and (dev_command_list or event_list): priority = SqliteInterface.get_priority_by_uuid(uuid) if priority < 0: continue current_ts = time.time() # 上报规则开始执行 EventReport.report_rule_start_event(uuid) continue_time = 1 for dev_command in dev_command_list: command_info_list = [] for command in dev_command['command_list']: if continue_time < command['time']: continue_time = command['time'] command_info = CommandInfo( uuid, command['service'], command['param'], current_ts, current_ts + command['time'], priority, 'linkage') command_info_list.append(command_info) if command_info_list: DevCommandQueueMng.add_linkage_command( dev_command['product_id'], dev_command['dev_id'], command_info_list) end_ts = current_ts + continue_time uuid_endtime_list = [{'uuid': uuid, 'end_ts': end_ts}] add_running_rule_endtime(uuid_endtime_list) for custom_event in event_list: EventReport.report_linkage_custom_event( custom_event['event_id'], custom_event['src_dev_list']) MyLog.logger.info( f'##########run_linkage_rule_by_devid finished({dev_id} attrs: {attrs})############' ) except Exception as e: msg = MyLog.color_red('run_linkage_rule_by_devid has except: ' + str(e)) MyLog.logger.error(msg)
def timer_rule_decision(cls) -> None: try: MyLog.logger.info('进行定时规则决策') # 计算出下一次最近的执行时间戳,启动定时器 next_decision_time = cls.get_closest_timestamp() if next_decision_time > 0.0: RuleMng.start_new_rule_decision_timer(next_decision_time) # 获取符合要求的uuid列表 uuid_list = SqliteInterface.get_current_timer_rule() # 执行规则,将规则指令下发给指令管理器 MyLog.logger.info('uuid_list size: ' + str(len(uuid_list))) dev_id_list = [] rule_endtime_list = [] for uuid in uuid_list: MyLog.logger.info('===开始执行规则(%s)===' % (uuid)) priority = SqliteInterface.get_priority_by_uuid(uuid) if priority < 0: continue py_model = RULE_PY_MODEL_PATH + uuid # 如果已经添加到了g_running_rule_endtime_list里,说明这个定时策略早就开始执行了 if not find_running_rule_by_uuid(uuid): EventReport.report_rule_start_event(uuid) # 记录规则结束时间戳到全局变量g_running_rule,等待结束上报结束事件 start_ts, end_ts = cls.get_rule_timestamp(uuid) MyLog.logger.info('规则(%s)结束时间戳:%d' % (uuid, end_ts)) if end_ts > 0: rule_endtime_list.append({ 'uuid': uuid, "end_ts": end_ts }) # 执行脚本 file = importlib.import_module(py_model) importlib.reload(file) # dev_command_list = [{'product_id': '', 'dev_id': "", "command_list":[{'service':'', 'param': , 'time': 10}]}] # event_list = event_list = [{"event_id":"", "src_dev_list":[{"productId":"p_id", "deviceId":"d_id"}]}] dev_command_list, event_list, attr_list = file.script_fun() ts = time.time() for dev_command in dev_command_list: command_info_list = [] for command in dev_command['command_list']: command_info = CommandInfo(uuid, command['service'], command['param'], ts, ts + command['time'], priority, 'timer') command_info_list.append(command_info) if command_info_list: # 如果已经添加到了g_running_rule_endtime_list里,说明联动事件已经添加到命令队列里了 if not find_running_rule_by_uuid(uuid): DevCommandQueueMng.add_timer_command( dev_command['product_id'], dev_command['dev_id'], command_info_list) # dev_id_list.append(dev_command['dev_id']) DevCommandQueueMng.dev_exe_by_command_list( dev_command['dev_id'], command_info_list) # 如果已经添加到了g_running_rule_endtime_list里,说明联动事件已经上报过了 if not find_running_rule_by_uuid(uuid): for custom_event in event_list: EventReport.report_linkage_custom_event( custom_event['event_id'], custom_event['src_dev_list']) MyLog.logger.info('===结束执行规则(%s)===' % (uuid)) add_running_rule_endtime(rule_endtime_list) except Exception as e: msg = MyLog.color_red("timer_rule_decision has except: " + str(e)) MyLog.logger.error(msg)