def handle_message(self, msgobj): global devices global process_list cmd = msgobj.get("cmd") if not cmd: print(shgutil.current_time(), "指令未找到", json.dumps(msgobj, ensure_ascii=False)) error_msg = self.para_factory.log( "指令未找到: " + json.dumps(msgobj, ensure_ascii=False), 2) self.pipeline.putTask(json.dumps(error_msg, ensure_ascii=False)) return False handler = self.switchDic.get(cmd) if not handler: print(shgutil.current_time(), "指令不支持") error_msg = self.para_factory.log("指令不支持") self.pipeline.putTask(json.dumps(error_msg, ensure_ascii=False)) return False try: ret = handler(msgobj) print(shgutil.current_time(), "消息 %s 处理结果 %s" % (cmd, ret)) return ret except Exception as err: print(shgutil.current_time(), "指令处理异常", err) traceback.print_exc() error_msg = self.para_factory.log("指令处理异常: " + str(err)) self.pipeline.putTask(json.dumps(error_msg, ensure_ascii=False)) return False
def on_connect(mqttClient, obj, flags, rc): mqttClient.connected = True # 设置连接标志 print(shgutil.current_time(), "云端" if mqttClient.insType == 1 else "本地", "mqtt连接已建立") if mqttClient.subscribeList and len(mqttClient.subscribeList) > 0: for topic in mqttClient.subscribeList: if topic: mqttClient.subscribe(topic, 0) print(shgutil.current_time(), "云端" if mqttClient.insType == 1 else "本地", "mqtt提交订阅", topic) # 发送上线通知 online_para = para_factory_local.online() content = json.dumps(online_para, ensure_ascii=False) mqttClient.send(content)
def init_mqtt_cloud(): global config_data global mqtt_client_to_cloud global send_pipeline_thread global para_factory # 云端的mqtt, 默认以websocket协议连接 #config_data["mqtt"]["topicLocal"] = str(uuid.uuid1()) mqttConfig = config_data["mqtt"] mqtt_client_to_cloud = mqttclient.MqttClient( mqttConfig["host"], mqttConfig["port"], mqttConfig["username"], mqttConfig["password"], mqttConfig["topicServer"], insType=1, subscribeList=[mqttConfig["topicLocal"]], para_factory=para_factory) # 启动mqtt连接, 并设置服务下线的遗嘱消息 willMsg = json.dumps(para_factory.will_msg, ensure_ascii=False) mqtt_client_to_cloud.start(on_message_from_server, willMsg) # 启动消息发送流水线线程 send_pipeline_thread = mqttpipe.SendPipeLineThread(config_data, mqtt_client_to_cloud) send_pipeline_thread.setDaemon(True) send_pipeline_thread.start() print(shgutil.current_time(), "发送线程已启动") # 发送推送服务启动通知 online_msg = para_factory.online() send_pipeline_thread.putTask(json.dumps(online_msg, ensure_ascii=False))
def main(): global config_data global mqtt_client_to_cloud global pid global send_pipeline_thread global heartbeat_thread global status_thread global msg_handler global para_factory global udp_server # sys.excepthook = shgutil.globalExceptHook print(shgutil.current_time(), "版权所属: 飞牛智能科技(南京)有限公司, www.fcow-it.com, 2018~2019") pid = os.getpid() print(shgutil.current_time(), "进程号: ", pid) # Reading config from file print(shgutil.current_time(), "读取配置") config_data = shgutil.read_config() config_data["running"] = True config_data["cwd"] = os.path.abspath('.') config_data["vcwd"] = os.path.abspath('.') # 初始化参数工厂 para_factory = parafactory.ParaFactory(config_data) # 连接云端mqtt服务器 print(shgutil.current_time(), "开始建立通信信道") init_mqtt_cloud() print(shgutil.current_time(), "通信信道连接结束") # 初始化消息处理对象 msg_handler = msghandler.MsgHandler(config_data, send_pipeline_thread, para_factory) # 启动心跳线程 heartbeat_thread = mqttpipe.MqttHeartbeatThread(config_data, send_pipeline_thread, para_factory, mqtt_client_to_cloud) heartbeat_thread.setDaemon(True) heartbeat_thread.start() print(shgutil.current_time(), "心跳线程已启动") # 启动状态线程 status_thread = mqttpipe.DeviceStatusReportThread(config_data, send_pipeline_thread, para_factory, mqtt_client_to_cloud) status_thread.setDaemon(True) status_thread.start() print(shgutil.current_time(), "状态报告线程已启动") # 使用一个UDP server来阻塞主线程 print(shgutil.current_time(), "阻塞主线程") host, port = "localhost", 50000 udp_server = socketserver.UDPServer((host, port), shgutil.MyTCPHandler) # Activate the server; this will keep running until you # interrupt the program with Ctrl-C udp_server.serve_forever() config_data["running"] = False # close mqtt mqtt_client_to_cloud.stop()
def on_message_from_server(client, obj, msg): global msg_handler global config_data if not msg_handler: return False msgstr = str(msg.payload, encoding='utf-8') print(shgutil.current_time(), "云端mqtt接收: ", msgstr) # 过滤非法消息 try: msgobj = json.loads(msgstr, encoding="utf-8") if msgobj["data"]["cmd"] == constants.EXIT: print(shgutil.current_time(), "退出指令") config_data["running"] = False sys.exit(0) shgutil.kill_proc_force(pid) return True return msg_handler.handle_message(msgobj) except Exception as err: print(shgutil.current_time(), "云端mqtt分析异常", err) traceback.print_exc() return False
def do_cmd_one(cmd, config_data, pipeline, para_factory): print(shgutil.current_time(), "执行: ", cmd) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, env=os.environ, shell=True, cwd=config_data["vcwd"]) while config_data["running"] and process.poll() is None: line = process.stdout.readline() if line == b'': if process.poll() is not None: break content = str(line, encoding="utf-8") print(shgutil.current_time(), content) if not cmd.startswith("cd "): log_msg = para_factory.log(content, 0) pipeline.putTask(json.dumps(log_msg, ensure_ascii=False)) output = process.communicate() if output: content = str(output[0], encoding="utf-8") print(shgutil.current_time(), content) if not cmd.startswith("cd "): log_msg = para_factory.log(content, 0) pipeline.putTask(json.dumps(log_msg, ensure_ascii=False)) if cmd.startswith("cd "): target_dir = cmd[3:] if target_dir != ".": if target_dir == "..": target_dir = os.path.abspath( os.path.join(config_data["vcwd"], "..")) if not os.path.exists(target_dir): target_dir = config_data["vcwd"] + "/" + target_dir config_data["vcwd"] = target_dir shgutil.write_config(config_data) log_msg = para_factory.log(config_data["vcwd"], 0) pipeline.putTask(json.dumps(log_msg, ensure_ascii=False)) print(shgutil.current_time(), "指令执行结束") return True
def do_cmd(self, msgobj, alone=True, restart=False): print(shgutil.current_time(), "执行指令") try: cmd = msgobj.get("data").get("cmd") if not cmd: print(shgutil.current_time(), "指令缺失") error_msg = self.para_factory.log("指令缺失", 2) self.pipeline.putTask(json.dumps(error_msg, ensure_ascii=False)) return False if cmd in unsupport_cmds: print(shgutil.current_time(), "指令不支持") error_msg = self.para_factory.log("指令不支持: ", 2) self.pipeline.putTask(json.dumps(error_msg, ensure_ascii=False)) return False # 执行 if not os.path.exists(self.config_data["vcwd"]): self.config_data["vcwd"] = os.getcwd() if cmd.startswith("../"): pdir = os.path.abspath( os.path.join(self.config_data["vcwd"], "..")) + "/" cmd = cmd.replace("../", pdir) elif cmd.startswith("./"): cmd = cmd.replace("../", self.config_data["vcwd"] + "/") # 创建线程02,指定参数,注意逗号不要少,否则不是一个tuple thread_02 = Thread(target=do_cmd_one, args=(cmd, self.config_data, self.pipeline, self.para_factory)) thread_02.setDaemon(True) thread_02.start() return True except Exception as err: print(shgutil.current_time(), "执行指令异常", err) traceback.print_exc() error_msg = self.para_factory.log("执行指令异常: " + str(err), 2) self.pipeline.putTask(json.dumps(error_msg, ensure_ascii=False)) return False
def run(self): print(shgutil.current_time(), "状态报告线程启动") while self.config_data.get("running"): # 睡眠3秒 itv = self.config_data["statusReportInterval"] if not itv or itv < 1: itv = 1 print(shgutil.current_time(), "等待", itv) time.sleep(itv) # 发送报告 try: if self.config_data.get("reportStatus"): status_info = self.para_factory.report_status() status_info_string = json.dumps(status_info, ensure_ascii=False) self.pipeline.putTask(status_info_string) else: print(shgutil.current_time(), "配置不发送状态") except Exception as err: print(shgutil.current_time(), "状态报告线程异常: ", err) traceback.print_exc() time.sleep(1) print(shgutil.current_time(), "状态报告线程退出")
def run(self): print(shgutil.current_time(), "心跳线程启动") heartbeat_para = self.para_factory.heartbeat() while self.config_data.get("running"): # 睡眠10秒 itv = self.config_data["heartbeatInterval"] if not itv or itv < 1: itv = 1 time.sleep(itv) # 发送心跳 try: if self.config_data.get("heartbeat"): heartbeat_para["data"]["n"] = parafactory.get_counter() heartbeat_string = json.dumps(heartbeat_para, ensure_ascii=False) self.pipeline.putTask(heartbeat_string) if self.config_data.get("debug"): print(shgutil.current_time(), "消息队列长度: ", self.pipeline.qsize()) except Exception as err: print(shgutil.current_time(), "心跳线程异常: ", err) traceback.print_exc() print(shgutil.current_time(), "心跳线程退出")
def send(self, content, topic=None, qos=1, retain=False): if not content: return None #if not self.mqttClient.connected: # print(shgutil.current_time(), "mqtt无发送, 发送任务取消") try: if topic is None: self.mqttClient.publish(self.serverTopic, content, qos, retain) else: self.mqttClient.publish(topic, content, qos, retain) return True except Exception as err: print(shgutil.current_time(), "mqtt发送异常1", err) return False
def run(self): print(shgutil.current_time(), "发送线程启动") while self.config_data.get("running"): # 睡眠20毫秒 time.sleep(0.02) if self.sendQueue.empty(): continue if not self.mclient: continue if not self.mclient.connected(): continue try: # 取出一个发送任务 task = self.sendQueue.get() # 执行发送 if task: self.mclient.send(task[1], task[0], self.config_data["mqtt"]["qosSend"]) if self.config_data.get("debug"): print(shgutil.current_time(), "[DEBUG]发送任务", task[1]) except Exception as err: print(shgutil.current_time(), "发送异常: ", err) traceback.print_exc() print(shgutil.current_time(), "发送线程退出")
para_factory, mqtt_client_to_cloud) status_thread.setDaemon(True) status_thread.start() print(shgutil.current_time(), "状态报告线程已启动") # 使用一个UDP server来阻塞主线程 print(shgutil.current_time(), "阻塞主线程") host, port = "localhost", 50000 udp_server = socketserver.UDPServer((host, port), shgutil.MyTCPHandler) # Activate the server; this will keep running until you # interrupt the program with Ctrl-C udp_server.serve_forever() config_data["running"] = False # close mqtt mqtt_client_to_cloud.stop() # 执行main函数 if __name__ == '__main__': try: main() except Exception as err: print(shgutil.current_time(), "[主]执行异常, 系统退出", err) traceback.print_exc() try: config_data["running"] = False udp_server.shutdown() mqtt_client_to_cloud.stop() finally: sys.exit(-255)
def on_disconnect(mqttClient, userdata, rc): mqttClient.connected = False # 设置连接标志 print(shgutil.current_time(), "云端" if mqttClient.insType == 1 else "本地", "mqtt连接断开!")
def on_log(mqttClient, obj, level, string): print(shgutil.current_time(), "云端" if mqttClient.insType == 1 else "本地", "mqtt日志", string)
def on_subscribe(mqttClient, obj, mid, granted_qos): print(shgutil.current_time(), "云端" if mqttClient.insType == 1 else "本地", "订阅成功")
def on_publish(mqttClient, obj, mid): print(shgutil.current_time(), "云端" if mqttClient.insType == 1 else "本地", "发送成功")
def on_message(mqttClient, obj, msg): print(shgutil.current_time(), "云端" if mqttClient.insType == 1 else "本地", "mqtt接收: ", str(msg.payload, encoding='utf-8'))