Commit 65cb9a19 authored by wanli's avatar wanli

🐞 fix(monitor.py): 修复资源监视器前端bug

parent 45d223b9
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-07-03 11:53:43
LastEditTime: 2021-08-07 17:42:43
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\app\signal_manager.py
......@@ -18,6 +18,11 @@ class SignalManager(object):
actionApplicationBuild = PySignal()
actionGetConvertString = PySignal()
actionOpqcp = PySignal()
actionGetMonitor = PySignal()
actionPostMonitor = PySignal()
actionReceiveMessage = PySignal()
actionBroadcateMessage = PySignal()
actionCheckClient = PySignal()
# 登录模块
actionLogin = PySignal()
......
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-07-03 11:53:04
LastEditTime: 2021-08-07 17:44:21
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\controller\__init__.py
......@@ -20,6 +20,7 @@ from .download_manager import downloadManager
from .login_logs_manager import loginLogsManager
from .app_logs_manager import appLogsManager
from .build_logs_manager import buildLogsManager
from .monitor import monitorManager
logger = logging.getLogger(__name__)
......@@ -29,6 +30,11 @@ def initConnect():
signalManager.actionGetConvertString.connect(apiManager.get_escape_text)
signalManager.actionUpdatePassword.connect(apiManager.update_user_password)
signalManager.actionOpqcp.connect(apiManager.opqcp)
signalManager.actionGetMonitor.connect(monitorManager.get)
signalManager.actionPostMonitor.connect(monitorManager.post)
signalManager.actionReceiveMessage.connect(monitorManager.receive_message)
signalManager.actionBroadcateMessage.connect(monitorManager.broadcast_message)
signalManager.actionCheckClient.connect(monitorManager.check_client)
# 登录模块
signalManager.actionLogin.connect(loginManager.login)
......
'''
Author: your name
Date: 2021-06-29 19:24:32
LastEditTime: 2021-07-23 22:26:56
LastEditTime: 2021-08-07 18:05:28
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\controller\monitor.py
'''
import jwt
import json
import time
import logging
from app import config
from model.monitor import session, System, Lvgl, Evm, Image, Device, Request, User
logger = logging.getLogger(__name__)
......@@ -113,39 +116,6 @@ lvglResource = LvglResource()
evmResource = EvmResource()
imageResource = ImageResource()
def insert_data(msg):
# 先判断手表imei是否存在,不存在则先注册手表IMEI
watch_id = -1
if msg.get("imei"):
result = session.query(Device).filter_by(imei=msg.get("imei")).first()
if result:
watch_id = result.id
else:
logger.info("设备不存在")
return None
if msg.get("request"):
msg.get("request").update({ "watch": watch_id })
result = Request(**msg.get("request"))
session.add(result)
session.flush()
session.commit()
if msg.get("system"):
msg.get("system").update({ "watch": watch_id })
systemResource.post(msg.get("system"))
if msg.get("lvgl"):
msg.get("lvgl").update({ "watch": watch_id })
lvglResource.post(msg.get("lvgl"))
if msg.get("evm"):
msg.get("evm").update({ "watch": watch_id })
evmResource.post(msg.get("evm"))
if msg.get("image"):
imageResource.post_array(msg.get("image"), watch_id)
def get_watch_list():
result = session.query(Device).all()
tmp = []
......@@ -224,3 +194,116 @@ def get_monitor_list(watch, category, start, end):
'lvgl': lvgl_data(watch, start, end),
'image': image_data(watch, start, end)
}
class MonitorManager(object):
def __init__(self):
pass
def get(self, data):
watch = data.get("watch")
category = data.get("category")
start = data.get("start")
end = data.get("end")
# 判断watch是否存在
w = session.query(Device).filter(Device.id==watch).first()
if not w:
return []
if category == "system":
return []
elif category == "image":
return image_data(watch, start, end)
elif category == "lvgl":
return lvgl_data(watch, start, end)
elif category == "evm":
return evm_data(watch, start, end)
else:
return {
'evm': evm_data(watch, start, end),
'lvgl': lvgl_data(watch, start, end),
'image': image_data(watch, start, end)
}
def post(self, msg):
# 先判断手表imei是否存在,不存在则先注册手表IMEI
watch_id = -1
if msg.get("imei"):
result = session.query(Device).filter_by(imei=msg.get("imei")).first()
if result:
watch_id = result.id
else:
logger.info("设备不存在")
return None
if msg.get("request"):
msg.get("request").update({ "watch": watch_id })
result = Request(**msg.get("request"))
session.add(result)
session.flush()
session.commit()
if msg.get("system"):
msg.get("system").update({ "watch": watch_id })
systemResource.post(msg.get("system"))
if msg.get("lvgl"):
msg.get("lvgl").update({ "watch": watch_id })
lvglResource.post(msg.get("lvgl"))
if msg.get("evm"):
msg.get("evm").update({ "watch": watch_id })
evmResource.post(msg.get("evm"))
if msg.get("image"):
imageResource.post_array(msg.get("image"), watch_id)
def check_client(self, instance):
index = -1
for i, c in enumerate(instance._clients):
if id(instance) == id(c.get("context")):
index = i
break
return index
def receive_message(self, instance, message):
print(instance._clients, message)
if message.get("type") and message.get("token"):
# 获取token值,检验正确与否,获取uuid
payload = jwt.decode(message.get("token"), config['SECRET_KEY'], verify=True, algorithms=['HS256'], options={ 'verify_aud': False })
# 认证包,认证不通过,则剔除该连接
if message.get("type") == "auth":
if not message.get("token"):
return json.dumps({ "code": 400, "data": None, "msg": "token can not be null" })
user = session.query(User).filter(User.id == payload.get("data").get("id")).one_or_none()
if not user:
return json.dumps({ "code": 400, "data": None, "msg": "user not exists" })
# 查询该用户可查看设备
devices = session.query(Device).filter(Device.create_by==payload.get("data").get("id")).all()
if len(devices):
instance._clients.append({
'uuid': payload.get("data").get("uuid"),
'context': instance,
'devices': list(map(lambda d:d.imei, devices)),
'ts': int(time.time())
})
return json.dumps({ 'code': 200, 'data': None, 'msg': 'auth passed' })
else: # 没有设备,是否断开连接
return json.dumps({ 'code': 400, 'data': None, 'msg': 'no devices' })
else:
return json.dumps({ 'code': 200, 'data': None, 'msg': 'unkonw message packet, disconnect by server' })
def broadcast_message(self, clients, message):
print(clients, message)
if not message.get("imei"):
return False
for item in clients:
if message.get("imei") in item.get("devices", []):
item.get("context").write_message(json.dumps(message))
monitorManager = MonitorManager()
\ No newline at end of file
'''
Author: your name
Date: 2021-06-29 19:33:41
LastEditTime: 2021-07-26 17:28:30
LastEditTime: 2021-08-07 18:06:46
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\view\monitor.py
'''
import tornado.ioloop
import tornado.web
from tornado import httputil
from tornado.web import RequestHandler, StaticFileHandler
from tornado.websocket import WebSocketHandler, WebSocketClosedError
import json
import signal
import time
......@@ -18,18 +14,14 @@ import pprint
import traceback
import jwt
from typing import ( Any,)
from threading import Timer
from datetime import datetime, timedelta
from app import config
import tornado.ioloop
import tornado.web
from tornado import httputil
from tornado.web import RequestHandler, StaticFileHandler
from tornado.websocket import WebSocketHandler, WebSocketClosedError
from fullstack.log import logger
from model.monitor import session, Device, User
from controller.monitor import insert_data, get_monitor_list, get_watch_list
def datetime2secs(mydate):
return time.mktime(mydate.timetuple())
def secs2datetime(ts):
return datetime.fromtimestamp(ts)
from app.signal_manager import signalManager
class ObjectDict(dict):
"""
......@@ -92,18 +84,18 @@ def pushmessage(func):
return send
class BaseWebsocket(WebSocketHandler):
_clients = []
handlers = {}
def check_origin(self, origin):
logger.info(origin)
return True
def open(self):
# 新加入一个连接后,设置一个接收消息时间戳
# 同时查询改用可以查看哪些设备
# 当有消息到来时,遍历用户列表,将设备IMEI与每个用户的IMEI列表比对
# 如果用户列表有这个IMEI,则需要向该用户广播消息
# 列表 [里面存放字典]
# 字典 { 'uuid': '', 'context': self, 'devices': ['imei', 'imei'], 'ts': '接收消息时间戳' }
className = self.__class__.__name__
logger.warning("websocket of %s is opened" % className)
if className not in self.handlers:
......@@ -122,109 +114,49 @@ class BaseWebsocket(WebSocketHandler):
if className in self.handlers and self in self.handlers[className]:
# 更加健壮的处理是,这里需要增加一个self是否存在的判断
self.handlers[className].remove(self)
for i, c in enumerate(self._clients):
if id(self) == id(c.get("context")):
del self._clients[i]
def check_origin(self, origin):
logger.info(origin)
return True
@classmethod
def broadcastMessage(cls, message):
# pprint.pprint(cls.handlers)
# pprint.pprint(message)
logger.info(cls._clients)
if not message.get("imei"):
return False
for item in cls._clients:
if message.get("imei") in item.get("devices", []):
item.get("context").write_message(json.dumps(message))
# className = cls.__name__
# message = json.dumps(message)
# if className in cls.handlers:
# for handler in cls.handlers[className]:
# # 判断用户能否查看该设备
# handler.send(message, binary)
className = cls.__name__
message = json.dumps(message)
if className in cls.handlers:
for handler in cls.handlers[className]:
# 判断用户能否查看该设备
handler.send(message)
# 建立与web前端的通信连接,发送状态信息报文
class NotifyHandler(BaseWebsocket):
"""
建立与web前端的通信连接,发送状态信息报文
保存uuid与self以及imei的映射关系
"""
_timer = None
_clients = []
def __init__(self, application: tornado.web.Application, request: httputil.HTTPServerRequest, **kwargs: Any) -> None:
super().__init__(application, request, **kwargs)
self.on_heartbeat()
def open(self):
super(NotifyHandler, self).open()
# 列表 [字典] [{ 'uuid': '', 'context': self, 'devices': ['imei', 'imei'], 'ts': '接收消息时间戳' }]
# super(NotifyHandler, self).open()
logger.info("new client connect......")
def on_close(self):
# super(NotifyHandler, self).on_close()
index = signalManager.actionCheckClient.emit(self)
if index >= 0:
del self._clients[index]
logger.info("client disconnect")
def on_message(self, message):
try:
className = self.__class__.__name__
message = json.loads(message)
# 判断消息类型
if message.get("type") and message.get("token"):
# 获取token值,检验正确与否,获取uuid
payload = jwt.decode(message.get("token"), config['SECRET_KEY'], verify=True, algorithms=['HS256'], options={ 'verify_aud': False })
# 认证包,认证不通过,则剔除该连接
if message.get("type") == "auth":
if not message.get("token"):
self.write_message(json.dumps({ "code": 400, "data": None, "msg": "token can not be null" }))
return
message = signalManager.actionReceiveMessage.emit(self, message)
if message:
self.write_message(message)
user = session.query(User).filter(User.id == payload.get("data").get("id")).one_or_none()
if not user:
self.write_message(json.dumps({ "code": 400, "data": None, "msg": "user not exists" }))
# self.close()
return
# 查询该用户可查看设备
devices = session.query(Device).filter(Device.create_by==payload.get("data").get("id")).all()
if len(devices):
self._clients.append({
'uuid': payload.get("data").get("uuid"),
'context': self,
'devices': list(map(lambda d:d.imei, devices)),
'ts': int(time.time())
})
self.write_message(json.dumps({ 'code': 200, 'data': None, 'msg': 'auth passed' }))
else: # 没有设备,是否断开连接
self.write_message(json.dumps({ 'code': 400, 'data': None, 'msg': 'no devices' }))
# self.close()
elif message.get("type") == "heartbeat": # 心跳包
exists_flag = False
# 收到心跳包消息,更新接收数据时间
for c in self._clients:
if c.get("uuid") == payload.get("data").get("uuid"):
c["ts"] = int(time.time())
self.write_message(json.dumps({ 'code': 200, 'data': None, 'msg': 'update session timestamp success' }))
exists_flag = True
if not exists_flag and message.get("token"):
payload = jwt.decode(message.get("token"), config['SECRET_KEY'], verify=True, algorithms=['HS256'], options={ 'verify_aud': False })
user = session.query(User).filter(User.id == payload.get("data").get("id")).one_or_none()
if not user:
self.write_message(json.dumps({ 'code': 402, 'data': None, 'msg': 'user not exists' }))
return
devices = session.query(Device).filter(Device.create_by==payload.get("data").get("id")).all()
if len(devices):
self._clients.append({
'uuid': payload.get("data").get("uuid"),
'context': self,
'devices': list(map(lambda d:d.imei, devices)),
'ts': int(time.time())
})
self.write_message(json.dumps({ 'code': 200, 'data': None, 'msg': 'auth passed' }))
else: # 没有设备,是否断开连接
self.write_message(json.dumps({ 'code': 400, 'data': None, 'msg': 'no devices' }))
else:
self.write_message(json.dumps({ 'code': 200, 'data': None, 'msg': 'unkonw message packet, disconnect by server' }))
self.handlers[className].remove(self)
logger.info(self._clients)
except jwt.exceptions.InvalidSignatureError as e:
logger.error(e)
self.write_message(json.dumps({ 'code': 401, 'data': None, 'msg': 'auth failed' }))
......@@ -235,73 +167,13 @@ class NotifyHandler(BaseWebsocket):
traceback.print_exc()
logger.info(message)
def on_heartbeat(self):
# 心跳定时器,固定间隔扫描连接列表,当连接超时,主动剔除该连接
for i in range(len(self._clients) - 1, -1, -1):
if int(time.time()) - self._clients[i].get("ts") > 30:
# self._clients.pop(i)
del self._clients[i]
className = self.__class__.__name__
if self.handlers.get(className, None) and self in self.handlers[className]:
self.handlers[className].remove(self)
self._timer = Timer(1, self.on_heartbeat)
self._timer.start()
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.get_query_argument('a', value)
# self.get_body_argument()
# self.request.files
self.write(json.dumps({ "msg": "Hello, world" }))
def post(self):
if not self.request.body:
return None
try:
data = tornado.escape.json_decode(self.request.body)
logger.info(data)
self.write(json.dumps({ 'code': 100, 'data': data, 'msg': 'success' }))
message = {'imei': '12345678900005', 'type': 'report', '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)
except Exception as e:
logger.info(self.request.body)
logger.error(e)
traceback.print_exc()
class WatchHandler(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)
@classmethod
def broadcastMessage(cls, message):
pprint.pprint(cls.handlers)
pprint.pprint(message)
logger.info(cls._clients)
try:
result = get_watch_list()
if result:
self.write(json.dumps({ 'code': 200, 'data': result, 'msg': 'success' }))
else:
self.write(json.dumps({ 'code': 204, 'data': None, 'msg': 'no data' }))
except Exception as e:
logger.error(e)
self.write(json.dumps({ 'code': 500, 'data': None, 'msg': 'server error' }))
def post(self):
data = tornado.escape.json_decode(self.request.body)
self.write(json.dumps({ 'code': 100, 'data': data, 'msg': 'success' }))
signalManager.actionBroadcateMessage.emit(cls._clients, message)
class DeviceMessageHandler(BaseHandler):
def get(self):
......@@ -325,7 +197,13 @@ class DeviceMessageHandler(BaseHandler):
end = time.localtime(int(end))
end = time.strftime("%Y-%m-%d %H:%M:%S", end)
result = get_monitor_list(int(watch), category, start, end)
data = {
'watch': int(watch),
'category': category,
'start': start,
'end': end
}
result = signal.actionGetMonitor.emit(data)
if result:
self.write(json.dumps({ 'code': 200, 'data': result, 'msg': 'success', 'type': 'array' if isinstance(result, list) else 'object' }))
else:
......@@ -356,8 +234,7 @@ class DeviceMessageHandler(BaseHandler):
'path': self.request.path,
'protocol': self.request.protocol
})
insert_data(data)
signalManager.actionPostMonitor.emit(data)
data['type'] = 'report'
data['system'].update({ 'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S") })
NotifyHandler.broadcastMessage(data)
......@@ -366,6 +243,60 @@ class DeviceMessageHandler(BaseHandler):
traceback.print_exc()
logger.info(self.request.body)
logger.error(e)
self.write(json.dumps({ 'code': 500, 'message': 'error' }))
# ========================>调试接口
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.get_query_argument('a', value)
# self.get_body_argument()
# self.request.files
self.write(json.dumps({ "msg": "Hello, world" }))
def post(self):
if not self.request.body:
return None
try:
data = tornado.escape.json_decode(self.request.body)
logger.info(data)
self.write(json.dumps({ 'code': 100, 'data': data, 'msg': 'success' }))
message = {'imei': '12345678900005', 'type': 'report', '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}]}
signalManager.actionPostMonitor.emit(message)
# 这里不能使用广播,得点对点发送,有此设备的账号才能看到调试信息
NotifyHandler.broadcastMessage(message)
except Exception as e:
logger.info(self.request.body)
logger.error(e)
traceback.print_exc()
# ========================>调试接口
class WatchHandler(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)
try:
self.write(json.dumps({ 'code': 204, 'data': None, 'msg': 'no data' }))
except Exception as e:
logger.error(e)
self.write(json.dumps({ 'code': 500, 'data': None, 'msg': 'server error' }))
def post(self):
data = tornado.escape.json_decode(self.request.body)
self.write(json.dumps({ 'code': 100, 'data': data, 'msg': 'success' }))
def make_app():
return tornado.web.Application([
......
/*
* @Author: your name
* @Date: 2021-07-01 15:02:16
* @LastEditTime: 2021-07-28 10:42:15
* @LastEditTime: 2021-08-07 18:29:02
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \evm-store\frontend\src\utils\eventBus.js
*/
import Vue from "vue";
import store from "@/store";
// import store from "@/store";
export let wsNotify = new WebSocket(
`ws://${window.location.hostname}:3000/ws/v1/notify`
......@@ -23,14 +23,14 @@ wsNotify.eventBus.$on("reconnect", () => {
);
})
let timer = null;
// let timer = null;
wsNotify.onopen = function (event) {
console.log("websocket is conneted!", event);
wsNotify.eventBus.$emit("open", event);
timer = setInterval(function() {
wsNotify.send(JSON.stringify({ type: 'heartbeat', ts: Date.now(), token: store.getters.token }))
}, 1000)
// timer = setInterval(function() {
// wsNotify.send(JSON.stringify({ type: 'heartbeat', ts: Date.now(), token: store.getters.token }))
// }, 1000)
};
wsNotify.onmessage = function (event) {
......@@ -41,11 +41,11 @@ wsNotify.onmessage = function (event) {
wsNotify.onerror = function (error) {
console.log(error);
wsNotify.eventBus.$emit("error", error);
if (timer) clearInterval(timer);
// if (timer) clearInterval(timer);
};
wsNotify.onclose = function (event) {
console.log("websocket is colosed!", event);
wsNotify.eventBus.$emit("close", event);
if (timer) clearInterval(timer);
// if (timer) clearInterval(timer);
};
......@@ -949,8 +949,6 @@ export default {
}
});
if (m) {
if (m.evm) this.evm = m.evm;
if (m.lvgl) this.lvgl = m.lvgl;
......@@ -959,32 +957,7 @@ export default {
}
},
},
mounted() {
this.socket = wsNotify;
wsNotify.eventBus.$on("exported", (res) => {
if (res.type === "evm") result.evmImg = res.data;
else if (res.type === "lvgl") result.lvglImg = res.data;
else if (res.type === "system") result.systemImg = res.data;
});
wsNotify.eventBus.$on("open", (message) => {
this.sendMsg();
this.$nextTick(() => {
console.log(message);
});
// 这里启动一个定时器,10秒钟后,如果没有消息进来,说明当前没有在线设备
});
wsNotify.eventBus.$on("close", (message) => {
this.$nextTick(() => {
console.log(message);
});
});
wsNotify.eventBus.$on("message", (message) => {
this.$nextTick(() => {
this.handleMessage(deepClone(message));
});
});
},
mounted() {},
destroyed() {
// 页面关闭则销毁该数据库
monitor.deleteDB();
......@@ -1009,6 +982,31 @@ export default {
.catch((err) => {
console.error(err);
});
this.socket = wsNotify;
wsNotify.eventBus.$on("exported", (res) => {
if (res.type === "evm") result.evmImg = res.data;
else if (res.type === "lvgl") result.lvglImg = res.data;
else if (res.type === "system") result.systemImg = res.data;
});
wsNotify.eventBus.$on("open", (message) => {
this.sendMsg();
this.$nextTick(() => {
console.log(message);
});
// 这里启动一个定时器,10秒钟后,如果没有消息进来,说明当前没有在线设备
});
wsNotify.eventBus.$on("close", (message) => {
this.$nextTick(() => {
console.log(message);
});
});
wsNotify.eventBus.$on("message", (message) => {
this.$nextTick(() => {
this.handleMessage(deepClone(message));
});
});
},
};
</script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment