'''
Author: your name
Date: 2021-06-29 19:33:41
LastEditTime: 2021-06-29 19:55:22
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\view\monitor.py
'''
import tornado.ioloop
import tornado.web
from tornado.web import RequestHandler, StaticFileHandler
from tornado.websocket import WebSocketHandler, WebSocketClosedError
import json
import signal
import logging
import pprint
from datetime import datetime
from controller.monitor import insert_data

logger = logging.getLogger(__name__)

class ObjectDict(dict):
    """Makes a dictionary behave like an object, with attribute-style access.
    """
    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        self[name] = value

class GracefulExit(SystemExit):
    code = 1

def raise_graceful_exit(*args):
    tornado.ioloop.IOLoop.current().stop()
    print("Gracefully shutdown", args)
    raise GracefulExit()

class BaseHandler(RequestHandler):
    """解决JS跨域请求问题"""
    def set_default_headers(self):
        self.set_header('Access-Control-Allow-Origin', '*')
        self.set_header('Access-Control-Allow-Methods', 'POST, GET')
        self.set_header('Access-Control-Max-Age', 1000)
        self.set_header('Access-Control-Allow-Headers', '*')
        self.set_header('Content-type', 'application/json')

class WebsocketResponse(ObjectDict):
    def __init__(self, type="Response", api_code=-1, message='fail', data=None, traceback=""):
        super(WebsocketResponse, self).__init__()
        self.type = type
        self.code = api_code
        self.message = message
        self.data = data
        self.traceback = traceback
        if isinstance(self.data, list):
            self.count = len(self.data)

def pushmessage(func):
    def send(*agrs, **kwargs):
        self = agrs[0]
        ret = func(*agrs, **kwargs)
        if ret:
            msg, binary = ret
            try:
                if isinstance(msg, WebsocketResponse) or isinstance(msg, dict):
                    self.write_message(json.dumps(msg), binary)
                elif isinstance(msg, str) or isinstance(msg, str):
                    self.write_message(msg, binary)
                else:
                    self.write_message(repr(msg), binary)
            except WebSocketClosedError as e:
                logger.error(e)
                self.on_close()
    return send

class BaseWebsocket(WebSocketHandler):
    handlers = {}
    def open(self):
        className = self.__class__.__name__
        logger.warning("websocket of %s is opened" % className)
        if className not in self.handlers:
            self.handlers[className] = set()
        self.handlers[className].add(self)
        pprint.pprint(self.handlers)

    @pushmessage
    def send(self, message, binary=False):
        return message, binary

    def on_close(self):
        className = self.__class__.__name__
        logger.warning("websocket of %s is closed" % className)
        if className in self.handlers:
            self.handlers[className].remove(self)

    def check_origin(self, origin):
        logger.info(origin)
        return True

    @classmethod
    def broadcastMessage(cls, message, binary=False):
        className = cls.__name__
        pprint.pprint(cls.handlers)

        message = json.dumps(message)

        if className in cls.handlers:
            for handler in cls.handlers[className]:
                handler.send(message, binary)

class NotifyHandler(BaseWebsocket):
    """
        建立与web前端的通信连接，发送状态信息报文
    """
    def open(self):
        super(NotifyHandler, self).open()

    def on_message(self, message):
        print("hello,world", message)
        logger.info(message)

class MainHandler(BaseHandler):
    def get(self, *args, **kwargs):
        print("#############", args)
        print("/////////////", kwargs)
        print(self.request.path)    # 请求路径
        print(self.request.method)  # 请求方法
        print(self.request.host)    # IP地址
        print(self.request.protocol)
        self.write("Hello, world")

    def post(self):
        data = tornado.escape.json_decode(self.request.body)
        print("=====>", data, type(data))
        
        self.write(json.dumps({ 'code': 100, 'message': 'success' }))

        message = {'imei': '12345678900005', 'system': {'free_size': 0}, 'lvgl': {'total_size': 5242880, 'free_cnt': 31, 'free_size': 1279664, 'free_biggest_size': 1205448, 'used_cnt': 832, 'used_pct': 76, 'frag_pct': 6}, 'evm': {'total_size': 2097152, 'free_size': 0, 'gc_usage': 50}, 'image': [{'uri': 'evue_launcher', 'length': 1043, 'png_total_count': 0, 'png_uncompressed_size': 0, 'png_file_size': 0}, {'uri': 'kdgs_1_storyList', 'length': 9608, 'png_total_count': 193, 'png_uncompressed_size': 370884, 'png_file_size': 209807}]}
        insert_data(message)
        NotifyHandler.broadcastMessage(message)

class DeviceMessageHandler(BaseHandler):
    def get(self):
        self.write("Hello, world")

    def post(self):
        data = tornado.escape.json_decode(self.request.body)
        print("=====>", data, type(data))

        request = {
            'host': self.request.remote_ip,
            'path': self.request.path,
            'protocol': self.request.protocol
        }

        data.update({ 'request': request })

        insert_data(data)

        data['request'].update({ 'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S") })
        NotifyHandler.broadcastMessage(data)
        self.write(json.dumps({ 'code': 100, 'message': 'success' }))

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
        (r"/api/v1/evm_store/monitor", DeviceMessageHandler),
        (r"/ws/v1/notify", NotifyHandler),
        (r"/dist/(.*)", StaticFileHandler, { "path": "dist" }),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(5001)

    signal.signal(signal.SIGINT, raise_graceful_exit)
    signal.signal(signal.SIGTERM, raise_graceful_exit)

    tornado.ioloop.IOLoop.current().start()