from app import log, redisObj
from app.app_config import *
import json
import threading
import traceback
import sys

"""
    desc:
        线程封装类,便于更好的捕获子线程跑出的异常
"""
class runFunctionThread(threading.Thread):
    def __init__(self, funcName, *args):
        threading.Thread.__init__(self)
        self.args = args
        self.funcName = funcName
        self.exitcode = 0
        self.exception = None
        self.exc_traceback = ''

    def run(self): #Overwrite run() method, put what you want the thread do here
        try:
            self._run()
        except Exception as e:
            self.exitcode = 1       # 如果线程异常退出，将该标志位设置为1，正常退出为0
            self.exception = e
            self.exc_traceback = ''.join(traceback.format_exception(*sys.exc_info()))  #在改成员变量中记录异常信息
    
    def _run(self):
        try:
            self.funcName(*(self.args)) 
        except Exception as e:
            raise e

"""
    desc:
        用于mqtt指令到达时匹配相应的control函数
"""
class Register(object):
    def __init__(self):
        self.func_dict = {}
 
    def action(self, action):
        def wrapper(func):
            self.func_dict.setdefault(action, func)
            return func
 
        return wrapper

    def recieve_run(self, client, userdata, message):
        redisObj.logpush("MQTT,SERVER COMMAND,%s" % str(message.payload.decode("utf-8")).replace(",", ";").replace('"', ''))
        try:
            data = json.loads(str(message.payload.decode("utf-8")))
            log.logger.info(data)
        except:
            log.logger.error("Recieve data is not json format:%s" % (str(message.payload.decode("utf-8"))))
        if data.get(ACTION_NAME) in self.func_dict:
            try:
                td = runFunctionThread(self.func_dict.get(data.get(ACTION_NAME)), data)
                td.start()
                td.join() 
                if td.exitcode != 0:
                    log.logger.error('Exception in ' + td.getName() + ' (catch by main)')
                    log.logger.error(td.exc_traceback)
                    sys.exit(0)
            except Exception as e:
                log.logger.error(td.exc_traceback)
        else:
            log.logger.error("Not support this action: %s" % (data.get(ACTION_NAME)))