Commit d817a246 authored by wanli's avatar wanli

update

parents 6caf39ef f021344b
......@@ -70,6 +70,7 @@ release.*
npm-debug.log*
yarn-debug.log*
yarn-error.log*
evm_monitor/
# Editor directories and files
.idea
......
......@@ -21,4 +21,4 @@ backup_dir = backup
evueapps_dir = evueapps
launcher_dir = launcher
host = 127.0.0.1
port = 5000
\ No newline at end of file
port = 5000
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-06-29 19:55:00
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\controller\__init__.py
'''
#!/usr/bin/env python
# -*- coding: utf_8 -*-
import os
import json
import logging
from app import signalManager
from .api_manager import apiManager
from .user_manager import userManager
from .login_manager import loginManager
from .annex_manager import annexManager
from .upload_manager import uploadManager
from .apps_manager import appsManager
from .menu_manager import menuManager
from .device_manager import deviceManager
from .download_manager import downloadManager
from .login_logs_manager import loginLogsManager
......@@ -87,11 +92,4 @@ def initConnect():
signalManager.actionGetAppLogsList.connect(appLogsManager.getList)
signalManager.actionUpdateAppLogs.connect(appLogsManager.update)
# 系统菜单
signalManager.actionAddMenu.connect(menuManager.add)
signalManager.actionDeleteMenu.connect(menuManager.delete)
signalManager.actionGetMenu.connect(menuManager.get)
signalManager.actionGetMenuList.connect(menuManager.getList)
signalManager.actionUpdateMenu.connect(menuManager.update)
initConnect()
\ No newline at end of file
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-06-22 13:38:34
LastEditTime: 2021-06-29 20:21:46
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\controller\api_manager.py
......@@ -10,22 +10,15 @@ FilePath: \evm-store\backend\controller\api_manager.py
# -*- coding: utf_8 -*-
import os
import time
import json
import logging
import traceback
import subprocess
import shutil
import uuid
from datetime import datetime
from pony.orm import *
from app.setting import config
from model.user import User
from utils import md5_salt
from utils.ccode import convert_string
logger = logging.getLogger("ApiManager")
logger = logging.getLogger(__name__)
class ApiManager(object):
def __init__(self):
......@@ -82,8 +75,6 @@ class ApiManager(object):
def opqcp(self, params):
target_file = os.path.normpath(os.sep.join([config.get("UPLOAD_PATH"), params.get("filename")]))
print("--------->", params, target_file)
print(os.stat(target_file))
shutil.copy(target_file, os.getcwd())
......@@ -100,7 +91,7 @@ class ApiManager(object):
result = os.system("./opqcp {i} ./out".format(i=os.path.basename(target_file)))
print(result)
command = ["./opqcp", os.path.basename(target_file), "./"]
# command = ["./opqcp", os.path.basename(target_file), "./"]
fname = os.sep.join([os.getcwd(), "out", os.path.basename(target_file)])
shutil.copy(fname, output_path)
os.remove(fname)
......
'''
Author: your name
Date: 2021-06-29 19:24:32
LastEditTime: 2021-06-29 19:28:16
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\controller\monitor.py
'''
from model.monitor import session, System, Lvgl, Evm, Image, Watch, Request
class SystemResource(object):
def get(self):
result = session.query(System).all()
print(result)
return result
def post(self, params):
result = System(**params)
session.add(result)
return session.commit()
def put(self):
pass
def delete(self):
pass
class LvglResource(object):
def get(self):
result = session.query(Lvgl).all()
print(result)
return result
def post(self, params):
result = Lvgl(**params)
session.add(result)
return session.commit()
def put(self):
pass
def delete(self):
pass
class EvmResource(object):
def get(self):
result = session.query(Evm).all()
print(result)
return result
def post(self, params):
result = Evm(**params)
session.add(result)
return session.commit()
def put(self):
pass
def delete(self):
pass
class ImageResource(object):
def get(self):
result = session.query(Image).all()
print(result)
return result
def post(self, params):
result = Image(**params)
session.add(result)
return session.commit()
def post_array(self, array, watch):
t = []
for a in array:
a.update({ "watch": watch })
t.append(Image(**a))
session.add_all(t)
return session.commit()
def put(self):
pass
def delete(self):
pass
systemResource = SystemResource()
lvglResource = LvglResource()
evmResource = EvmResource()
imageResource = ImageResource()
def insert_data(msg):
# 先判断手表imei是否存在,不存在则先注册手表IMEI
watch_id = -1
if msg.get("imei"):
result = session.query(Watch).filter_by(imei=msg.get("imei")).first()
if result:
watch_id = result.id
else:
result = Watch(imei=msg.get("imei"))
session.add(result)
session.flush()
session.commit()
result = session.query(Watch).filter_by(imei=msg.get("imei")).first()
if result:
watch_id = result.id
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 })
res = systemResource.post(msg.get("system"))
print("!!!!!!", res)
if msg.get("lvgl"):
msg.get("lvgl").update({ "watch": watch_id })
res = lvglResource.post(msg.get("lvgl"))
print("@@@@@@", res)
if msg.get("evm"):
msg.get("evm").update({ "watch": watch_id })
res = evmResource.post(msg.get("evm"))
print("######", res)
if msg.get("image"):
res = imageResource.post_array(msg.get("image"), watch_id)
print("$$$$$$", res)
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf_8 -*-
import uuid
from datetime import datetime
from pony.orm import PrimaryKey, Required, Optional, Set, LongStr, Json
from app import config
from . import fullStackDB
db = fullStackDB.db
class Menu(db.Entity):
_table_ = "{}".format(config['TABLE_PREFIX']) + "menu"
id = PrimaryKey(int, auto=True)
uuid = Required(uuid.UUID, unique=True, default=uuid.uuid1, index=True)
name = Optional(str)
title = Required(str)
path = Required(str)
icon = Optional(str)
hidden = Optional(bool, default=False)
component = Required(str)
redirect = Optional(str)
parent_id = Optional(str, default="")
create_at = Required(datetime, default=datetime.now)
create_by = Required("User", reverse='menu_creator') # Menu与User一对一关系
update_at = Required(datetime, default=datetime.now)
update_by = Required("User", reverse='menu_updater') # Menu与User一对一关系
delete_at = Optional(datetime)
delete_by = Optional("User", reverse='menu_deleter') # Menu与User一对一关系
is_delete = Required(bool, default=False)
sort = Optional(int, size=32, default=0)
remarks = Optional(str, max_len=255, default="", nullable=True)
\ No newline at end of file
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-06-29 19:58:57
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\model\monitor.py
'''
#!/usr/bin/env python
# -*- coding: utf_8 -*-
from app.setting import config
from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///{}?check_same_thread=False'.format(config.get("DATABASE")), echo=True)
Base = declarative_base()
def get_current_datetime():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
class Watch(Base):
__tablename__ = 'monitor_watch'
id = Column(Integer, primary_key=True, autoincrement=True)
imei = Column(String)
create_at = Column(String, default=get_current_datetime)
class Request(Base):
__tablename__ = 'monitor_request'
id = Column(Integer, primary_key=True, autoincrement=True)
watch = Column(Integer) # 手表ID
host = Column(String)
path = Column(String)
protocol = Column(String)
create_at = Column(String, default=get_current_datetime)
class System(Base):
__tablename__ = 'monitor_system'
id = Column(Integer, primary_key=True, autoincrement=True)
watch = Column(Integer) # 手表ID
free_size = Column(Integer) # 单位:字节
timestamp = Column(String(50), default=get_current_datetime)
class Lvgl(Base):
__tablename__ = 'monitor_lvgl'
id = Column(Integer, primary_key=True, autoincrement=True)
watch = Column(Integer) # 手表ID
total_size = Column(Integer) # 单位:字节
free_cnt = Column(Integer)
free_size = Column(Integer)
free_biggest_size = Column(Integer)
used_cnt = Column(Integer)
used_pct = Column(Integer)
frag_pct = Column(Integer)
timestamp = Column(String(50), default=get_current_datetime)
class Evm(Base):
__tablename__ = 'monitor_evm'
id = Column(Integer, primary_key=True, autoincrement=True)
watch = Column(Integer) # 手表ID
# total_size = Column(Integer) # 单位:字节
# free_size = Column(Integer)
# gc_usage = Column(Integer)
heap_map_size = Column(Integer)
heap_total_size = Column(Integer)
heap_used_size = Column(Integer)
stack_total_size = Column(Integer)
stack_used_size = Column(Integer)
timestamp = Column(String(50), default=get_current_datetime)
class Image(Base):
__tablename__ = 'monitor_image'
id = Column(Integer, primary_key=True, autoincrement=True)
watch = Column(Integer) # 手表ID
uri = Column(String(50))
length = Column(Integer)
png_uncompressed_size = Column(Integer)
png_total_count = Column(Integer)
png_file_size = Column(Integer)
timestamp = Column(String(50), default=get_current_datetime)
Base.metadata.create_all(engine, checkfirst=True)
# engine是2.2中创建的连接
Session = sessionmaker(bind=engine)
# 创建Session类实例
session = Session()
......@@ -47,6 +47,3 @@ class User(db.Entity):
device_creator = Set('Device', reverse='create_by')
device_updater = Set('Device', reverse='update_by')
device_deleter = Set('Device', reverse='delete_by')
menu_creator = Set('Menu', reverse='create_by')
menu_updater = Set('Menu', reverse='update_by')
menu_deleter = Set('Menu', reverse='delete_by')
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-06-29 20:22:42
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\start.py
'''
#!/usr/bin/env python
# -*- coding: utf_8 -*-
import sys
......@@ -9,16 +17,24 @@ from tornado.web import Application, RequestHandler, FallbackHandler
from tornado.ioloop import IOLoop
from tornado.autoreload import watch
from fullstack.log import logger
from view import app, NotifyHandler, ThreadNotifyHandler
from fullstack.log import logger
from view import app
from view.monitor import DeviceMessageHandler, NotifyHandler
from app import config
class GracefulExit(SystemExit):
code = 1
class VueHandler(RequestHandler):
def get(self):
remote_ip = self.request.remote_ip
logger.info("remote_ip %s" % remote_ip)
self.render("index.html")
def raise_graceful_exit(*args):
IOLoop.current().stop()
print("Gracefully shutdown", args)
raise GracefulExit()
def start():
settings = {
'debug': config['DEBUG'],
......@@ -31,8 +47,8 @@ def start():
application = Application([
(r'/', VueHandler),
(r'/index', VueHandler),
(r'/ws/api/v1/notify', NotifyHandler),
(r'/ws/api/v1/threadnotify', ThreadNotifyHandler),
(r"/api/v1/evm_store/monitor", DeviceMessageHandler),
(r'/ws/v1/notify', NotifyHandler),
(r'.*', FallbackHandler, dict(fallback=wsgi_app))
], **settings)
......@@ -45,14 +61,10 @@ def start():
print(config['LOGO'])
print("server running at %s:%d" % (config['HOST'], port))
# if sys.platform == "linux":
# # 子进程退出后向父进程发送的信号
# signal.signal(signal.SIGCHLD, IOLoop.instance().stop)
# # 主进程退出信号
# signal.signal(signal.SIGINT, IOLoop.instance().stop)
# signal.signal(signal.SIGTERM, IOLoop.instance().stop)
# 主进程退出信号
signal.signal(signal.SIGINT, raise_graceful_exit)
signal.signal(signal.SIGTERM, raise_graceful_exit)
IOLoop.instance().start()
......
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-06-29 19:37:32
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\backend\view\__init__.py
'''
#!/usr/bin/env python
# -*- coding: utf_8 -*-
......@@ -15,7 +23,6 @@ from .apps import apps_api
from .device import device_api
from .download import download_api
from .app_logs import appLogs_api
from .ws import NotifyHandler, ThreadNotifyHandler
from model import fullStackDB
from fullstack.response import ResponseCode, response_result
from app import config
......@@ -27,7 +34,7 @@ class JsonResponse(Response):
def force_type(cls, response, environ=None):
if isinstance(response, (list, dict)):
response = jsonify(response)
return super(Response, cls).force_type(response, environ)
return super(cls, Response).force_type(response, environ)
class FlaskAPP(Flask):
response_class = JsonResponse
......@@ -53,6 +60,12 @@ def create_app():
traceback.print_exc()
return response_result(ResponseCode.SERVER_ERROR, msg=str(e))
@app.errorhandler(HTTPException)
def handle_http_exception(e):
logger.error(str(e))
traceback.print_exc()
return response_result(ResponseCode.SERVER_ERROR, msg=str(e))
@app.errorhandler(Exception)
def handle_exception(e):
logger.error(str(e))
......
......@@ -29,6 +29,7 @@ def stopApp():
f.write(json.dumps(ret, indent=4))
return ret
<<<<<<< HEAD
@api.route("/opqcp", methods=['POST'])
def action_opqcp():
params = request.json
......@@ -38,6 +39,26 @@ def action_opqcp():
result, message = signalManager.actionOpqcp.emit(params)
return response_result(ResponseCode.OK, msg=message)
=======
@api.route("/monitor", methods=['GET', 'POST'])
def action_monitor():
print(request.json)
print(request.data)
print(request.form)
print(type(request.json))
return response_result(ResponseCode.OK)
@api.route("/opqcp", methods=['POST'])
def action_opqcp():
params = request.json
print(params)
signalManager.actionOpqcp.emit(params)
return response_result(ResponseCode.OK)
>>>>>>> master
@api.route("/updatePassword", methods=['POST'])
@validate_schema(UpdatePasswordSchema)
......
'''
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()
\ No newline at end of file
'''
Author: your name
Date: 2021-04-14 14:12:18
LastEditTime: 2021-06-29 19:39:04
LastEditors: your name
Description: In User Settings Edit
FilePath: \evm-store\backend\view\ws.py
'''
#!/usr/bin/env python
# -*- coding: utf_8 -*-
......@@ -5,9 +13,8 @@ import logging
from flask import json
from tornado.websocket import WebSocketHandler, WebSocketClosedError
from utils import ObjectDict
from app import config
logger = logging.getLogger("websocketApi")
logger = logging.getLogger(__name__)
class WebsocketResponse(ObjectDict):
def __init__(self, type="Response", api_code=-1, message='fail', data=None, traceback=""):
......@@ -80,8 +87,7 @@ class NotifyHandler(BaseWebsocket):
super(NotifyHandler, self).open()
def on_message(self, message):
pass
print(message)
class ThreadNotifyHandler(BaseWebsocket):
"""
......@@ -92,25 +98,4 @@ class ThreadNotifyHandler(BaseWebsocket):
super(ThreadNotifyHandler, self).open()
def on_message(self, message):
NotifyHandler.boardcastMessage(message)
# class Wsclient(object):
# """
# 用于和ThreadNotifyHandler建立websocket连接的客户端
# 使用方式:在子线程中建立到达threadnotify路由的websocket客户端如
# wsclient = Wsclient()
# wsclient.send(WebsocketResponse(
# "dashboard", 0, "success", data=cache))
# """
# def __init__(self):
# super(Wsclient, self).__init__()
# self.wsclient = websocket.WebSocket()
# self.wsclient.connect(
# "ws://localhost:%s/ws/api/v1/threadnotify" % config['PORT'])
# def send(self, msg):
# if isinstance(msg, dict):
# msg = json.dumps(msg)
# self.wsclient.send(msg)
NotifyHandler.boardcastMessage(message)
\ No newline at end of file
......@@ -239,6 +239,14 @@ export function getConvertString(params) {
});
}
export function actionOpqcp(params) {
return request({
url: "/api/v1/evm_store/opqcp",
method: "post",
data: params,
});
}
export function getTopicList(params) {
return request({
url: "/uowap/index",
......
......@@ -44,231 +44,242 @@ export const constantRoutes = [
hidden: true,
},
{
path: '/',
redirect: '/gallery',
path: '/gallery',
redirect: '/gallery/index',
component: StoreLayout,
children: [{
path: 'gallery',
path: 'index',
name: 'Gallery',
component: () => import('@/views/app-store/gallery'),
meta: { title: '商店首页', icon: 'home' }
}]
},
{
path: '/',
redirect: '/application',
path: '/application',
redirect: '/application/index',
component: StoreLayout,
children: [{
path: 'application',
path: 'index',
name: 'Application',
component: () => import('@/views/app-store/app'),
meta: { title: '应用详情', icon: 'home' }
}]
},
{
path: '/',
redirect: '/list',
path: '/list',
redirect: '/list/index',
component: StoreLayout,
children: [{
path: 'list',
path: 'index',
name: 'AppList',
component: () => import('@/views/app-store/list'),
meta: { title: '游戏', icon: 'home' }
}]
},
{
path: '/',
redirect: '/category',
path: '/category',
redirect: '/category/index',
component: StoreLayout,
children: [{
path: 'category',
path: 'index',
name: 'AppCategory',
component: () => import('@/views/app-store/category'),
meta: { title: '应用分类', icon: 'home' }
}]
},
{
path: '/',
redirect: '/rank',
path: '/rank',
redirect: '/rank/index',
component: StoreLayout,
children: [{
path: 'rank',
path: 'index',
name: 'AppRank',
component: () => import('@/views/app-store/rank'),
meta: { title: '应用排行', icon: 'home' }
}]
},
{
path: '/',
redirect: '/topic',
path: '/topic',
redirect: '/topic/index',
component: StoreLayout,
children: [{
path: 'topic',
path: 'index',
name: 'AppTopic',
component: () => import('@/views/app-store/topic'),
meta: { title: '应用排行', icon: 'home' }
}]
},
{
path: '/',
redirect: '/search',
path: '/search',
redirect: '/search/index',
component: StoreLayout,
children: [{
path: 'search',
path: 'index',
name: 'AppSearch',
component: () => import('@/views/app-store/search'),
meta: { title: '搜索应用', icon: 'home' }
}]
},
{
path: '/',
redirect: '/my',
path: '/my',
redirect: '/my/index',
component: StoreLayout,
children: [{
path: 'my',
path: 'index',
name: 'AppProfile',
component: () => import('@/views/app-store/profile'),
meta: { title: '个人中心', icon: 'shangcheng' }
}]
},
{
path: '/',
redirect: '/auth',
path: '/auth',
redirect: '/auth/index',
component: StoreLayout,
children: [{
path: 'auth',
path: 'index',
name: 'AppAuth',
component: () => import('@/views/app-store/auth'),
meta: { title: '账号认证', icon: 'shangcheng' }
}]
},
{
path: '/',
redirect: '/developer',
path: '/developer',
redirect: '/developer/index',
component: StoreLayout,
children: [{
path: 'developer',
path: 'index',
name: 'Developer',
component: () => import('@/views/app-store/developer'),
meta: { title: '开发者中心', icon: 'home' }
}]
},
{
path: '/',
redirect: '/docs',
path: '/docs',
redirect: '/docs/index',
component: Layout,
children: [{
path: 'docs',
path: 'index',
name: 'Document',
component: () => import('@/views/app-store/docs'),
meta: { title: '开发文档', icon: 'shangcheng' }
}]
},
{
path: '/',
redirect: '/home',
path: '/home',
redirect: '/home/index',
component: Layout,
children: [{
path: 'home',
path: 'index',
name: 'AppIndex',
component: () => import('@/views/system/apps'),
meta: { title: '应用管理', icon: 'home' }
}]
},
{
path: '/',
redirect: '/tool',
path: '/tool',
redirect: '/tool/index',
component: Layout,
children: [{
path: 'tool',
path: 'index',
name: 'AppTool',
component: () => import('@/views/system/tool'),
meta: { title: '工具', icon: 'home' }
}]
},
{
path: '/',
redirect: '/build',
path: '/build',
redirect: '/build/index',
component: Layout,
children: [{
path: 'build',
path: 'index',
name: 'AppBuild',
component: () => import('@/views/system/build'),
meta: { title: '打包日志', icon: 'home' }
}]
},
{
path: '/',
redirect: '/download',
path: '/opqcp',
redirect: '/opqcp/index',
component: Layout,
children: [{
path: 'download',
name: 'AppDownload',
component: () => import('@/views/system/download'),
meta: { title: '下载记录', icon: 'gongzuotai' }
path: 'index',
name: 'Opqcp',
component: () => import('@/views/system/opqcp'),
meta: { title: 'opqcp', icon: 'home' }
}]
},
{
path: '/',
redirect: '/device',
path: '/monitor',
redirect: '/monitor/index',
component: Layout,
children: [{
path: 'device',
path: 'index',
name: 'Monitor',
component: () => import('@/views/system/monitor'),
meta: { title: 'monitor', icon: 'home' }
}]
},
{
path: '/device',
redirect: '/device/index',
component: Layout,
children: [{
path: 'index',
name: 'Device',
component: () => import('@/views/system/device'),
meta: { title: '设备管理', icon: 'gongzuotai' }
}]
},
{
path: '/',
redirect: '/profile',
path: '/profile',
redirect: '/profile/index',
component: Layout,
children: [{
path: 'profile',
path: 'index',
name: 'Profile',
component: () => import('@/views/system/profile'),
meta: { title: '个人中心', icon: 'shangcheng' }
}]
},
{
path: '/',
redirect: '/user',
path: '/user',
redirect: '/user/index',
component: Layout,
children: [{
path: 'user',
path: 'index',
name: 'UserIndex',
component: () => import('@/views/system/users'),
meta: { title: '用户管理', icon: 'shangcheng' }
}]
},
{
path: '/',
redirect: '/404',
path: '/404',
redirect: '/404/index',
component: Layout,
children: [{
path: '404',
path: 'index',
name: 'Page404',
component: () => import('@/views/error-pages/404'),
meta: { title: '404', icon: 'home' }
}]
},
{
path: '/',
redirect: '/403',
path: '/403',
redirect: '/403/index',
component: Layout,
children: [{
path: '403',
path: 'index',
name: 'Page403',
component: () => import('@/views/error-pages/403'),
meta: { title: '403', icon: 'home' }
}]
},
{
path: '/',
redirect: '/not-found',
path: '/not-found',
redirect: '/not-found/index',
component: StoreLayout,
children: [{
path: 'not-found',
path: 'index',
name: 'NotFound',
component: () => import('@/views/error-pages/not-found'),
meta: { title: 'not-found', icon: 'home' }
......
/*
* @Author: your name
* @Date: 2021-04-14 14:12:19
* @LastEditTime: 2021-06-29 19:49:09
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \evm-store\frontend\src\settings.js
*/
export default {
name: {
zh: "EVM应用商店",
......@@ -33,42 +41,49 @@ export default {
title: "应用管理",
name: "AppIndex",
icon: "gongzuotai",
path: "home",
path: "home/index",
},
{
vue: "app-store/build.vue",
title: "打包日志",
name: "AppBuild",
icon: "gongzuotai",
path: "build",
path: "build/index",
},
{
vue: "app-store/device.vue",
title: "设备管理",
name: "Device",
icon: "gongzuotai",
path: "device",
path: "device/index",
},
{
vue: "profile/docs.vue",
title: "个人中心",
name: "Profile",
icon: "gongzuotai",
path: "profile",
path: "profile/index",
},
{
vue: "app-store/docs.vue",
title: "开发文档",
name: "Document",
icon: "gongzuotai",
path: "docs",
path: "docs/index",
},
{
vue: "system/monitor.vue",
title: "资源监视",
name: "Monitor",
icon: "gongzuotai",
path: "monitor/index",
},
{
vue: "system/tool.vue",
title: "工具",
name: "AppTool",
icon: "gongzuotai",
path: "tool",
path: "tool/index",
},
],
};
<template>
<div class="app-container">
<el-form :inline="true" :model="form" size="mini">
<el-form-item><el-button type="primary" @click="onSubmit">查询</el-button></el-form-item>
<el-form-item><el-button @click="onReset">重置</el-button></el-form-item>
</el-form>
<el-table v-loading="isLoading" element-loading-text="Loading" :data="list" size="mini" border stripe fit highlight-current-row>
<el-table-column prop="app.app_name" label="应用" align="center" min-width="150"></el-table-column>
<el-table-column prop="imei" label="IMEI" align="center" min-width="150"></el-table-column>
<el-table-column prop="download_at" label="下载时间" min-width="150"></el-table-column>
</el-table>
<div class="page-wrapper">
<el-pagination @current-change="handleCurrentChange" :current-page.sync="form.pagenum" background small :page-size="form.pagesize" :pager-count="5" layout="pager, prev, next, total" :total="total"></el-pagination>
</div>
</div>
</template>
<script>
import checkPermission from '@/utils/permission'
import { getDownloadList, deleteDownload } from '@/api/app-store'
import { mapTrim } from '@/utils/index'
import { formatUTCDateTime } from '@/utils/utils'
export default {
name: "AppDownload",
data() {
return {
total: 0,
list: [],
isLoading: false,
form: {
uuid: null,
imei: null,
pagesize: 15,
pagenum: 1
},
}
},
methods: {
checkPermission,
fetchData(params) {
this.isLoading = true
getDownloadList(params).then(res => {
if (res.code == 200) {
this.total = res.count
this.list = res.data.map(item => {
item.create_at = formatUTCDateTime(item.create_at)
item.update_at = formatUTCDateTime(item.update_at)
return item
})
}
}).catch(err => {
// this.$message.error(err.message)
console.log(err.message)
}).finally(() => {
this.isLoading = false
})
},
handleSizeChange(e) {
this.form.pagesize = e
this.fetchData(mapTrim(this.form))
},
handleCurrentChange(e) {
this.form.pagenum = e
this.fetchData(mapTrim(this.form))
},
handleDelete(index, row) {
this.$alert('您确定要删除么?删除操作将不可恢复。如需取消操作,请点击右上角关闭按钮。', '删除提醒', {
confirmButtonText: '确定',
callback: action => {
if (action == 'confirm') deleteDownload(row.id).then(res => {
console.log(res)
this.total -= 1
this.$delete(this.list, index)
this.$message({ type: 'success', message: `成功删除第${ index }行` })
}).catch(err => {
this.$message.error(err.message)
})
}
})
},
onSubmit() {
this.form.pagenum = 1
this.form.pagesize = 15
this.fetchData(mapTrim(this.form))
},
onReset(formName) {
this.form = {
account: null,
username: null,
pagesize: 15,
pagenum: 1
}
this.$refs[formName].resetFields()
this.fetchData(mapTrim(this.form))
}
},
mounted() {},
created() {
if (this.$store.getters.role !== "ADMIN") this.$router.push({ path: "/403" })
this.fetchData(mapTrim(this.form))
}
}
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
<template>
<div class="app-container">
<div>
<el-select size="mini" v-model="device" @change="onSelectChange" placeholder="请选择设备">
<el-option v-for="(item, index) in deviceList" :key="index" :label="item" :value="item"></el-option>
</el-select>
</div>
<h2>REQUEST</h2>
<el-table
element-loading-text="Loading"
:data="request"
size="mini"
border
stripe
fit
highlight-current-row
>
<el-table-column
prop="host"
label="host"
min-width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="path"
label="path"
min-width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="timestamp"
label="timestamp"
min-width="180"
show-overflow-tooltip
></el-table-column>
</el-table>
<h2>SYSTEM</h2>
<el-table
element-loading-text="Loading"
:data="system"
size="mini"
border
stripe
fit
highlight-current-row
>
<el-table-column
label="imei"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.imei }}</template>
</el-table-column>
<el-table-column
label="free_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.free_size }}(KB)</template>
</el-table-column>
</el-table>
<h2>LVGL</h2>
<el-table
element-loading-text="Loading"
:data="lvgl"
size="mini"
border
stripe
fit
highlight-current-row
>
<el-table-column
label="total_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.total_size }}(KB)</template>
</el-table-column>
<el-table-column
prop="free_cnt"
label="free_cnt"
min-width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="free_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.free_size }}(KB)</template>
</el-table-column>
<el-table-column
label="free_biggest_size"
min-width="180"
>
<template slot-scope="scope">{{ scope.row.free_biggest_size }}(KB)</template>
</el-table-column>
<el-table-column
label="used_cnt"
min-width="180"
>
<template slot-scope="scope">{{ scope.row.used_cnt }}</template>
</el-table-column>
<el-table-column
label="used_pct"
min-width="180"
>
<template slot-scope="scope">{{ scope.row.used_pct }}(%)</template>
</el-table-column>
<el-table-column
label="frag_pct"
min-width="180"
>
<template slot-scope="scope">{{ scope.row.frag_pct }}(%)</template>
</el-table-column>
</el-table>
<h2>EVM</h2>
<el-table
element-loading-text="Loading"
:data="evm"
size="mini"
border
stripe
fit
highlight-current-row
>
<!-- <el-table-column
label="total_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.total_size }}(KB)</template>
</el-table-column>
<el-table-column
label="free_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.free_size }}(KB)</template>
</el-table-column> -->
<el-table-column
label="heap_map_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.heap_map_size }}(KB)</template>
</el-table-column>
<el-table-column
label="heap_total_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.heap_total_size }}(KB)</template>
</el-table-column>
<el-table-column
label="heap_used_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.heap_used_size }}(KB)</template>
</el-table-column>
<el-table-column
label="stack_total_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.stack_total_size }}(KB)</template>
</el-table-column>
<el-table-column
label="stack_used_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.stack_used_size }}(KB)</template>
</el-table-column>
</el-table>
<h2>APP</h2>
<el-table
element-loading-text="Loading"
:data="image"
size="mini"
border
stripe
fit
highlight-current-row
>
<el-table-column
prop="uri"
label="uri"
min-width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="length"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.length }}(KB)</template>
</el-table-column>
<el-table-column
label="png_file_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.png_file_size }}(KB)</template>
</el-table-column>
<el-table-column
prop="png_total_count"
label="png_total_count"
min-width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="png_uncompressed_size"
min-width="180"
show-overflow-tooltip
>
<template slot-scope="scope">{{ scope.row.png_uncompressed_size }}(KB)</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "Monitor",
data() {
return {
device: null,
devices: {},
deviceList: [],
system: [],
lvgl: [],
evm: [],
image: [],
request: [],
socket: null,
form: {
system: ['free_size'],
lvgl: ['total_size', 'free_size', 'free_biggest_size'],
evm: ['total_size', 'free_size', 'heap_map_size', 'heap_total_size', 'heap_used_size', 'stack_total_size', 'stack_used_size'],
image: ['png_uncompressed_size', 'png_file_size', 'length']
},
};
},
filters: {
kb(value) {
return Math.ceil(value / 1024);
},
},
methods: {
initWebSocket() {
if ("WebSocket" in window) {
this.socket = new WebSocket(`ws://${window.location.host}/ws/v1/notify`);
// this.socket = new WebSocket("ws://localhost:5001/ws/v1/notify");
this.socket.onopen = () => {
console.log("连接成功");
this.sendMsg();
};
this.socket.onmessage = (evt) => {
var message = evt.data;
message = JSON.parse(message);
console.log(message);
this.handleMessage(message);
};
this.socket.onclose = function (res) {
console.log("断开了连接", res);
};
this.socket.onerror = function (err) {
console.log(err);
};
} else {
console.log("浏览器不支持WebSocket");
}
},
sendMsg() {
var message = "hello,world";
this.socket.send(message);
},
handleMessage(msg) {
if (!this.deviceList.includes(msg.imei)) {
this.deviceList.push(msg.imei)
}
if (!this.device) {
this.device = this.deviceList[0]
}
this.devices[msg.imei] = msg
this.processData(this.devices[this.device])
},
processData(msg) {
Object.keys(msg).forEach(item => {
if (this.form[item]) {
var keys = this.form[item]
for(var i = 0; i < keys.length; i++) {
var k = keys[i]
if (item == "image") {
for(var j = 0; j < msg[item].length; j++) {
msg[item][j][k] = Math.ceil(msg[item][j][k] / 1024)
}
} else {
msg[item][k] = Math.ceil(msg[item][k] / 1024)
}
}
}
})
this.system = [{ imei: msg.imei, ...msg.system }];
this.lvgl = [{ ...msg.lvgl }];
this.evm = [{ ...msg.evm }];
this.request = [{ ...msg.request }];
this.image = msg.image;
},
onSelectChange(res) {
this.device = res
this.processData(this.devices[this.device])
console.log(res)
},
},
mounted() {},
created() {
this.initWebSocket();
},
};
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
<template>
<div class="app-container">
<el-alert title="代码混淆工具" type="success"></el-alert>
<div style="margin: 10px 0px">
<el-form>
<el-form-item>
<el-upload
class="upload-demo"
action="/api/v1/evm_store/upload"
name="binfile"
:on-success="handleUploaded"
:file-list="fileList"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">
上传C源文件,转换完成后会自动下载
</div>
</el-upload>
</el-form-item>
<el-form-item>
<el-button type="success" @click="getConvertString">转换</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { actionOpqcp } from "@/api/app-store";
export default {
name: "Opqcp",
data() {
return {
fileList: [],
inputString: null,
outputString: null,
filename: "app.js",
};
},
methods: {
createFile(content, filename) {
const a = document.createElement("a");
const blob = new Blob([content]);
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
},
handleUploaded(response) {
if (response.code == 200) {
this.filename = response.data.filename
actionOpqcp({ filename: response.data.filepath })
.then((res) => {
this.$message.success(res.message);
// const a = document.createElement("a");
// a.href = url;
// a.download = filename;
// a.click();
})
.catch((err) => {
this.$message.error(err.message);
});
}
console.log(response)
},
downloadFile() {
this.$prompt("请输入文件名", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
inputValue: this.filename,
inputErrorMessage: "文件名格式不正确",
})
.then(({ value }) => {
if (value) this.filename = value;
this.createFile(this.outputString, this.filename);
})
.catch(() => {
this.$message({
type: "info",
message: "取消输入",
});
});
},
getConvertString() {
},
},
mounted() {},
created() {},
};
</script>
<style lang="scss" scoped>
.app-container {
& > div.page-wrapper {
margin: 10px 0px;
}
}
</style>
File added
This diff is collapsed.
'''
Author: your name
Date: 2021-06-21 14:52:24
LastEditTime: 2021-06-29 16:33:06
LastEditors: Please set LastEditors
Description: In User Settings Edit
FilePath: \evm-store\tools\modules\file-manager\main.py
'''
import os
import shutil
import pprint
from pathlib import Path, PurePosixPath, PureWindowsPath
import platform
import json
from fs.osfs import OSFS
from fs import open_fs
from fs.walk import Walker
disk_root = "D:\\projects\\scriptiot\\evm_app_store_files"
class FileManager(object):
def __init__(self) -> None:
pass
'''
@description: 根据前端传递的路径参数,获取该路径的目录以及文件信息,文件类别,可以看做是一个盘符
@param {*} self
@return {*}
'''
def initialize(self):
'''
disks: {
files: {driver: "local"},
images: {driver: "local"}
}
lang: "en"
leftDisk: null
rightDisk: null
windowsConfig: 2
'''
result = {
"disks": {},
"lang": "zh",
"leftDisk": None,
"rightDisk": None,
"windowsConfig": 1
}
# 这里需要过滤,有些目录只能管理员才能查看
for d in os.listdir(disk_root):
if os.path.isdir(os.sep.join([disk_root, d])):
result["disks"].update({
d: { "driver": "local" }
})
return result
'''
@description: 获取当前类别的目录信息
@param {*} self
@return {*}
'''
def content(self, disk, target_path='/'):
'''
目录信息结构体:
{
basename: "docs"
dirname: ""
path: "docs"
timestamp: 1556821372
type: "dir"
},
{
basename: "cars"
dirname: "wallpapers"
path: "wallpapers/cars"
timestamp: 1544277291
type: "dir"
}
文件信息结构体:
{
basename: "alfa.sql"
dirname: "code"
extension: "sql"
filename: "alfa"
path: "code/alfa.sql"
size: 3208
timestamp: 1544277274
type: "file"
}
'''
sys_str = platform.system()
# disk = "uploads" # disk就是文件根目录,只能以某个目录为根目录,浏览这个目录下面的所有文件
# target_path = None # 就是以disk为根目录的路径,判断是否以**/**或者**\\**开头
if not target_path.startswith("/"):
target_path = "/" + target_path
result = {
"directories": [],
"files": []
}
disk_path = os.sep.join([disk_root, disk])
if not os.path.exists(disk_path):
return result
if not os.path.exists(os.path.normpath(os.sep.join([disk_path, target_path]))):
return result
os.chdir(disk_path)
home_fs = open_fs('.')
for file in home_fs.scandir(target_path, namespaces=['details']):
if file.is_dir:
tmp = {
"basename": file.name,
"dirname": os.path.basename(target_path),
"path": os.path.normpath(os.sep.join([target_path, file.name])),
"timestamp": int(file.raw.get("details").get("modified")),
"type": "dir"
}
if (sys_str == "Windows"):
p = PureWindowsPath(tmp.get("path"))
tmp["path"] = str(p.relative_to("\\"))
else:
p = PurePosixPath(tmp.get("path"))
tmp["path"] = str(p.relative_to('/'))
result["directories"].append(tmp)
else:
fn, ex = os.path.splitext(file.name)
tmp = {
"basename": file.name,
"dirname": os.path.basename(target_path),
"extension": ex[1:],
"filename": fn,
"path": os.path.normpath(os.sep.join([target_path, file.name])),
"size": file.size,
"timestamp": int(file.raw.get("details").get("modified")),
"type": "file"
}
if (sys_str == "Windows"):
p = PureWindowsPath(tmp.get("path"))
tmp["path"] = str(p.relative_to("\\"))
else:
p = PurePosixPath(tmp.get("path"))
tmp["path"] = str(p.relative_to('/'))
result["files"].append(tmp)
home_fs.close()
with open("result.json", "w") as f:
json.dump(result, f)
f.write(json.dumps(result, ensure_ascii=True))
pprint.pprint(result)
return result
'''
@description: 获取目录结构树
@param {*} self
@return {*}
'''
def tree(self, disk, target_path="/"):
'''
{
basename: "trees"
dirname: "wallpapers/nature"
path: "wallpapers/nature/trees"
props: {
hasSubdirectories: false
}
timestamp: 1544277291
type: "dir"
}
'''
if not target_path.startswith("/"):
target_path = "/" + target_path
result = []
disk_path = os.sep.join([disk_root, disk])
if not os.path.exists(disk_path):
return result
if not os.path.exists(os.path.normpath(os.sep.join([disk_path, target_path]))):
return result
os.chdir(disk_path)
home_fs = OSFS(os.getcwd())
rp = Path(disk_root)
print("%%%%", rp)
p = Path(disk_path)
for child in p.iterdir():
print("//////////", child.is_dir(), child.resolve(), child.name, child.parent, child.root, child.drive, child.relative_to(rp))
print("------------------->", p)
# 获取当前目录下所有目录、文件、子目录以及子文件的信息。递归获取
for step in home_fs.walk():
result.append({
"basename": os.path.basename(step.path),
"dirname": os.path.dirname(step.path),
"path": step.path,
"props": {
"hasSubdirectories": True if len(step.files) else False
},
# "timestamp": int(os.path.getatime(os.sep.join([target_path, step.path]))),
"type": "dir"
})
home_fs.close()
pprint.pprint(result)
return result
fileManager = FileManager()
if __name__ == "__main__":
'''
python -m memory_profiler example.py
'''
# from memory_profiler import profile
# @profile
# def test():
# pass
# result = fileManager.initialize()
# print(result)
# result = fileManager.content("uploads", "evueapps/evm")
# print(result)
result = fileManager.tree("uploads", "evueapps/evm")
print(result)
\ No newline at end of file
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