first commit
49
app/ext.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
|
||||||
|
def UiWindow(title, icon, content, cheight=10, cwidth=15):
|
||||||
|
return {
|
||||||
|
"widgettype":"PopupWindow",
|
||||||
|
"options":{
|
||||||
|
"author":"cc",
|
||||||
|
"cwidth":cwidth,
|
||||||
|
"cheight":cheight,
|
||||||
|
"title":title,
|
||||||
|
"content":content,
|
||||||
|
"icon":icon or entire_url('/bricks/imgs/app.png'),
|
||||||
|
"movable":True,
|
||||||
|
"auto_open":True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def UiError(title="出错", message="出错啦", timeout=5):
|
||||||
|
return {
|
||||||
|
"widgettype":"Error",
|
||||||
|
"options":{
|
||||||
|
"author":"tr",
|
||||||
|
"timeout":timeout,
|
||||||
|
"cwidth":15,
|
||||||
|
"cheight":10,
|
||||||
|
"title":title,
|
||||||
|
"message":message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def UiMessage(title="消息", message="后台消息", timeout=5):
|
||||||
|
return {
|
||||||
|
"widgettype":"Message",
|
||||||
|
"options":{
|
||||||
|
"author":"tr",
|
||||||
|
"timeout":timeout,
|
||||||
|
"cwidth":15,
|
||||||
|
"cheight":10,
|
||||||
|
"title":title,
|
||||||
|
"message":message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def load_bricksExt():
|
||||||
|
g = ServerEnv()
|
||||||
|
g.UiError = UiError
|
||||||
|
g.UiMessage = UiMessage
|
||||||
|
g.UiWindow = UiWindow
|
||||||
|
|
||||||
29
app/mspapp.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
from appPublic.worker import awaitify
|
||||||
|
from appPublic.registerfunction import RegisterFunction
|
||||||
|
from appPublic.jsonConfig import getConfig
|
||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
from ahserver.webapp import webapp
|
||||||
|
from rbac.init import load_rbac
|
||||||
|
from msp.init import load_msp
|
||||||
|
from ext import load_bricksExt
|
||||||
|
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
def get_module_dbname(mname):
|
||||||
|
return "msp"
|
||||||
|
|
||||||
|
def init_func():
|
||||||
|
g = ServerEnv()
|
||||||
|
g.get_module_dbname = get_module_dbname
|
||||||
|
rf = RegisterFunction()
|
||||||
|
rf.register('get_module_dbname', get_module_dbname)
|
||||||
|
load_msp()
|
||||||
|
load_rbac()
|
||||||
|
load_bricksExt()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
webapp(init_func)
|
||||||
|
|
||||||
71
conf/config.json
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"logger":{
|
||||||
|
"name":"msp",
|
||||||
|
"levelname":"info",
|
||||||
|
"logfile":"$[workdir]$/logs/msp.log"
|
||||||
|
},
|
||||||
|
"databases":{
|
||||||
|
"msp":{
|
||||||
|
"driver":"aiomysql",
|
||||||
|
"async_mode":true,
|
||||||
|
"coding":"utf8",
|
||||||
|
"maxconn":100,
|
||||||
|
"dbname":"msp",
|
||||||
|
"kwargs":{
|
||||||
|
"user":"test",
|
||||||
|
"db":"msp",
|
||||||
|
"password":"QUZVcXg5V1p1STMybG5Ia6mX9D0v7+g=",
|
||||||
|
"host":"localhost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filesroot":"$[workdir]$/files",
|
||||||
|
"website":{
|
||||||
|
"paths":[
|
||||||
|
["$[workdir]$/wwwroot",""]
|
||||||
|
],
|
||||||
|
"client_max_size":10000,
|
||||||
|
"host":"0.0.0.0",
|
||||||
|
"port":10100,
|
||||||
|
"coding":"utf-8",
|
||||||
|
"indexes":[
|
||||||
|
"index.html",
|
||||||
|
"index.tmpl",
|
||||||
|
"index.ui",
|
||||||
|
"index.dspy",
|
||||||
|
"index.md"
|
||||||
|
],
|
||||||
|
"startswiths":[
|
||||||
|
{
|
||||||
|
"leading":"/idfile",
|
||||||
|
"registerfunction":"idFileDownload"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"processors":[
|
||||||
|
[".ws","ws"],
|
||||||
|
[".xterm","xterm"],
|
||||||
|
[".proxy","proxy"],
|
||||||
|
[".llm", "llm"],
|
||||||
|
[".llms", "llms"],
|
||||||
|
[".llma", "llma"],
|
||||||
|
[".xlsxds","xlsxds"],
|
||||||
|
[".sqlds","sqlds"],
|
||||||
|
[".tmpl.js","tmpl"],
|
||||||
|
[".tmpl.css","tmpl"],
|
||||||
|
[".html.tmpl","tmpl"],
|
||||||
|
[".bcrud", "bricks_crud"],
|
||||||
|
[".tmpl","tmpl"],
|
||||||
|
[".app","app"],
|
||||||
|
[".bui","bui"],
|
||||||
|
[".ui","bui"],
|
||||||
|
[".dspy","dspy"],
|
||||||
|
[".md","md"]
|
||||||
|
],
|
||||||
|
"session_max_time":3000,
|
||||||
|
"session_issue_time":2500,
|
||||||
|
"session_redis":{
|
||||||
|
"url":"redis://127.0.0.1:6379"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
3
json/build.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
xls2ui -m ../models -o ../wwwroot msp *.json
|
||||||
22
json/devgroup.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"tblname": "devgroup",
|
||||||
|
"title":"设备组",
|
||||||
|
"params": {
|
||||||
|
"sortby":"name",
|
||||||
|
"logined_userid":"ownerid",
|
||||||
|
"browserfields": {
|
||||||
|
"exclouded": ["id", "ownerid"],
|
||||||
|
"alters": {}
|
||||||
|
},
|
||||||
|
"editexclouded": [
|
||||||
|
"id", "ownerid"
|
||||||
|
],
|
||||||
|
"subtables":[
|
||||||
|
{
|
||||||
|
"field":"devgroupid",
|
||||||
|
"title":"主机",
|
||||||
|
"subtable":"hostdev"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
38
json/hostdev.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"tblname": "hostdev",
|
||||||
|
"title":"主机",
|
||||||
|
"params": {
|
||||||
|
"sortby":"name",
|
||||||
|
"confidential_fields":["passwd"],
|
||||||
|
"logined_userid":"ownerid",
|
||||||
|
"confidential_fields":["passwd", "client_key", "passphrase"],
|
||||||
|
"toolbar":{
|
||||||
|
"tools":[
|
||||||
|
{
|
||||||
|
"name":"sshcon",
|
||||||
|
"label":"ssh连接",
|
||||||
|
"selected_row":true,
|
||||||
|
"tip":"ssh链接到主机"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"binds":[
|
||||||
|
{
|
||||||
|
"wid":"self",
|
||||||
|
"event":"sshcon",
|
||||||
|
"actiontype":"urlwidget",
|
||||||
|
"target":"self",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('../connecthost.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"browserfields": {
|
||||||
|
"exclouded": ["id", "ownerid", "passwd", "client_key", "passphrase", "devgroupid"],
|
||||||
|
"alters": {}
|
||||||
|
},
|
||||||
|
"editexclouded": [
|
||||||
|
"id", "ownerid", "devgroupid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
17
json/jumperhost.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"models_dir": "${HOME}$/py/msp/models",
|
||||||
|
"output_dir": "${HOME}$/py/sage/wwwroot/_a/jumperhost",
|
||||||
|
"dbname": "sage",
|
||||||
|
"tblname": "jumperhost",
|
||||||
|
"title":"跳板主机",
|
||||||
|
"params": {
|
||||||
|
"sortby":"stepno",
|
||||||
|
"browserfields": {
|
||||||
|
"exclouded": ["id", "jumperid"],
|
||||||
|
"cwidth": {}
|
||||||
|
},
|
||||||
|
"editexclouded": [
|
||||||
|
"id", "jumperid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
models/atomservice.xlsx
Normal file
BIN
models/devgroup.xlsx
Normal file
BIN
models/hostdev.xlsx
Normal file
BIN
models/mixservice.xlsx
Normal file
BIN
models/mixserviceitem.xlsx
Normal file
206
models/mysql.ddl.sql
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
|
||||||
|
-- ./atomservice.xlsx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop table if exists atomservice;
|
||||||
|
CREATE TABLE atomservice
|
||||||
|
(
|
||||||
|
|
||||||
|
`id` VARCHAR(32) comment 'id',
|
||||||
|
`name` VARCHAR(99) comment '服务名称',
|
||||||
|
`description` VARCHAR(500) comment '描述',
|
||||||
|
`ownerid` VARCHAR(32) comment '属主id',
|
||||||
|
`paramsdesc` longtext comment '参数描述',
|
||||||
|
`script` longtext comment '脚本'
|
||||||
|
|
||||||
|
|
||||||
|
,primary key(id)
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '原子服务'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
-- ./hostdev.xlsx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop table if exists hostdev;
|
||||||
|
CREATE TABLE hostdev
|
||||||
|
(
|
||||||
|
|
||||||
|
`id` VARCHAR(32) comment 'id',
|
||||||
|
`name` VARCHAR(99) comment '主机名称',
|
||||||
|
`description` VARCHAR(500) comment '描述',
|
||||||
|
`ownerid` VARCHAR(32) comment '属主id',
|
||||||
|
`host` VARCHAR(400) comment '域名或ip',
|
||||||
|
`port` int comment '端口',
|
||||||
|
`user` VARCHAR(400) comment '用户',
|
||||||
|
`ssh_method` VARCHAR(1) comment 'ssh方法',
|
||||||
|
`passwd` VARCHAR(400) comment '用户密码',
|
||||||
|
`client_key` longtext comment '私钥',
|
||||||
|
`passphrase` VARCHAR(100) comment '私钥密码',
|
||||||
|
`devgroupid` VARCHAR(32) comment '设备组id'
|
||||||
|
|
||||||
|
|
||||||
|
,primary key(id)
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '主机设备'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
-- ./service_log.xlsx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop table if exists service_log;
|
||||||
|
CREATE TABLE service_log
|
||||||
|
(
|
||||||
|
|
||||||
|
`id` VARCHAR(32) comment 'id',
|
||||||
|
`servname` VARCHAR(100) comment '服务名称',
|
||||||
|
`date` date comment '主机名称',
|
||||||
|
`timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP comment '描述',
|
||||||
|
`hostid` VARCHAR(32) comment '主机id',
|
||||||
|
`serviceid` VARCHAR(32) comment '服务id',
|
||||||
|
`params` longtext comment '参数',
|
||||||
|
`user_orgid` VARCHAR(32) comment '用户机构id',
|
||||||
|
`userid` VARCHAR(32) comment '用户id'
|
||||||
|
|
||||||
|
|
||||||
|
,primary key(id)
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '服务日志'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
-- ./techservice.xlsx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop table if exists techservice;
|
||||||
|
CREATE TABLE techservice
|
||||||
|
(
|
||||||
|
|
||||||
|
`id` VARCHAR(32) comment 'id',
|
||||||
|
`name` VARCHAR(100) comment '服务名称',
|
||||||
|
`description` longtext comment '描述',
|
||||||
|
`script` longtext comment '服务脚本',
|
||||||
|
`params_ui` longtext comment '参数',
|
||||||
|
`ownerid` VARCHAR(32) comment '属主机构',
|
||||||
|
`enable_date` date comment '启用日期',
|
||||||
|
`disable_date` date comment '禁用日期'
|
||||||
|
|
||||||
|
|
||||||
|
,primary key(id)
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '技术服务'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
-- ./mixservice.xlsx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop table if exists mixservice;
|
||||||
|
CREATE TABLE mixservice
|
||||||
|
(
|
||||||
|
|
||||||
|
`id` VARCHAR(32) comment 'id',
|
||||||
|
`name` VARCHAR(99) comment '服务名称',
|
||||||
|
`description` VARCHAR(500) comment '描述',
|
||||||
|
`ownerid` VARCHAR(32) comment '属主id',
|
||||||
|
`paramsdesc` longtext comment '参数描述',
|
||||||
|
`script` longtext comment '脚本'
|
||||||
|
|
||||||
|
|
||||||
|
,primary key(id)
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '混合服务'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
-- ./devgroup.xlsx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop table if exists devgroup;
|
||||||
|
CREATE TABLE devgroup
|
||||||
|
(
|
||||||
|
|
||||||
|
`id` VARCHAR(32) comment 'id',
|
||||||
|
`name` VARCHAR(99) comment '组名称',
|
||||||
|
`description` VARCHAR(500) comment '描述',
|
||||||
|
`ownerid` VARCHAR(32) comment '属主id',
|
||||||
|
`enterhostid` VARCHAR(32) comment '跳板机id'
|
||||||
|
|
||||||
|
|
||||||
|
,primary key(id)
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '设备组'
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE INDEX devgroup_idx1 ON devgroup(ownerid);
|
||||||
|
|
||||||
|
-- ./mixserviceitem.xlsx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop table if exists atomservice;
|
||||||
|
CREATE TABLE atomservice
|
||||||
|
(
|
||||||
|
|
||||||
|
`id` VARCHAR(32) comment 'id',
|
||||||
|
`mixid` VARCHAR(32) comment '混合服务id',
|
||||||
|
`serviceid` VARCHAR(32) comment '服务id',
|
||||||
|
`hostvar` VARCHAR(99) comment '主机变量名'
|
||||||
|
|
||||||
|
|
||||||
|
,primary key(id)
|
||||||
|
|
||||||
|
|
||||||
|
)
|
||||||
|
engine=innodb
|
||||||
|
default charset=utf8
|
||||||
|
comment '原子服务'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
BIN
models/service_log.xlsx
Normal file
BIN
models/techservice.xlsx
Normal file
9
msp/certbot.sh
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
sudo apt update
|
||||||
|
sudo apt install python3 python3-venv libaugeas0
|
||||||
|
sudo apt-get remove certbot
|
||||||
|
sudo python3 -m venv /opt/certbot/
|
||||||
|
sudo /opt/certbot/bin/pip install --upgrade pip
|
||||||
|
sudo /opt/certbot/bin/pip install certbot certbot-nginx
|
||||||
|
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
|
||||||
|
sudo certbot --nginx
|
||||||
|
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
|
||||||
3
msp/coturn/data.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"port":13478
|
||||||
|
}
|
||||||
7
msp/coturn/install.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
sudo apt install -y coturn
|
||||||
|
sed 's/#listening-port=.*/listening-port=i13478/' -i /etc/turnserver.conf
|
||||||
|
sudo systemctl enable coturn
|
||||||
|
sudo systemctl restart coturn
|
||||||
|
|
||||||
8
msp/getdbname.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from ahserver.serverenv import get_serverenv
|
||||||
|
|
||||||
|
def get_dbname():
|
||||||
|
f = get_serverenv('get_module_dbname')
|
||||||
|
if f:
|
||||||
|
return f('msp')
|
||||||
|
return None
|
||||||
|
|
||||||
88
msp/hostdev.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import codecs
|
||||||
|
from appPublic.log import debug, error, exception
|
||||||
|
from appPublic.folderUtils import temp_file
|
||||||
|
from appPublic.sshx import SSHNode
|
||||||
|
from sqlor.dbpools import DBPools
|
||||||
|
from .getdbname import get_dbname
|
||||||
|
|
||||||
|
async def write_client_key(prikey):
|
||||||
|
client_key = temp_file()
|
||||||
|
with codecs.open(client_key, 'w', 'utf-8') as f:
|
||||||
|
f.write(host.client_key)
|
||||||
|
return client_key
|
||||||
|
|
||||||
|
|
||||||
|
async def _gethostdev(sor, hostid):
|
||||||
|
sql1 = """select a.*, b.enterhostid from hostdev a, devgroup b
|
||||||
|
where a.id=${id}$
|
||||||
|
and a.devgroupid = b.id"""
|
||||||
|
sql = """
|
||||||
|
select x.*,
|
||||||
|
y.host as jhost,
|
||||||
|
y.port as jport,
|
||||||
|
y.user as juser,
|
||||||
|
y.ssh_method as jssh_method,
|
||||||
|
y.passwd as jpassword,
|
||||||
|
y.client_key as jclient_key,
|
||||||
|
y.passphrase as jpassphrase
|
||||||
|
from (""" + sql1 + """) a left join hostdev b
|
||||||
|
on a.enterhostid = b.id
|
||||||
|
"""
|
||||||
|
recs = await sor.sqlExe(sql, {'id':hostid})
|
||||||
|
if len(recs) == 0:
|
||||||
|
return None
|
||||||
|
return rec[0]
|
||||||
|
|
||||||
|
async def hostdev_node(hostid, sor=None):
|
||||||
|
host = None
|
||||||
|
if sor:
|
||||||
|
host = await _gethostdev(sor, hostid)
|
||||||
|
else:
|
||||||
|
db = DBPools()
|
||||||
|
dbname = get_dbname()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
host = await _gethostdev(sor, hostid)
|
||||||
|
jumpers = []
|
||||||
|
jclient_key = None
|
||||||
|
client_key = None
|
||||||
|
node = None
|
||||||
|
if host.jssh_method == '0':
|
||||||
|
jumper = {
|
||||||
|
'host':host.jhost,
|
||||||
|
'port':host.jport,
|
||||||
|
'username':host.juser,
|
||||||
|
'password':host.jpassword
|
||||||
|
}
|
||||||
|
jumpers.append(jumper)
|
||||||
|
else:
|
||||||
|
jclient_key = write_client_key(host.jclient_key)
|
||||||
|
jumper = {
|
||||||
|
'host':host.jhost,
|
||||||
|
'port':host.jport,
|
||||||
|
'client_keys': [ client_key ],
|
||||||
|
'passphrase': jhost.passphrase
|
||||||
|
}
|
||||||
|
jumpers.append(jumper)
|
||||||
|
|
||||||
|
if host.ssh_method == '0': # password
|
||||||
|
node = SSHNode(host.host,
|
||||||
|
username=host.user,
|
||||||
|
port=host.port or 22,
|
||||||
|
password=host.passwd,
|
||||||
|
jumpers=jumpers)
|
||||||
|
else:
|
||||||
|
client_key = write_client_key(host.client_key)
|
||||||
|
node = SSHNode(host.host,
|
||||||
|
username=host.user,
|
||||||
|
port=host.port or 22,
|
||||||
|
client_keys=[client_key],
|
||||||
|
passphrase=host.passphrase,
|
||||||
|
jumpers=jumpers)
|
||||||
|
if jclient_key:
|
||||||
|
node.jclient_key_file = jclient_key
|
||||||
|
if client_key:
|
||||||
|
node.client_key_file = client_key
|
||||||
|
return node
|
||||||
|
|
||||||
9
msp/init.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
from .hostdev import hostdev_node
|
||||||
|
from .service import service4host, get_service_params_form
|
||||||
|
def load_msp():
|
||||||
|
g = ServerEnv()
|
||||||
|
g.service4host = service4host
|
||||||
|
g.hostdev_node = hostdev_node
|
||||||
|
g.get_service_params_form = get_service_params_form
|
||||||
|
|
||||||
52
msp/service.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import os
|
||||||
|
import codecs
|
||||||
|
import json
|
||||||
|
from traceback import format_exc
|
||||||
|
from appPublic.log import debug, error, exception
|
||||||
|
from appPublic.myTE import MyTemplateEngine
|
||||||
|
from appPublic.folderUtils import temp_file
|
||||||
|
from sqlor.dbpools import DBPools
|
||||||
|
from ahserver.serverenv import get_serverenv
|
||||||
|
from .getdbname import get_dbname
|
||||||
|
from .hostdev import hostdev_node
|
||||||
|
|
||||||
|
async def get_service_params_form(serviceid):
|
||||||
|
dbname = get_dbname()
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
servs = await sor.R('techservice', {'id':serviceid})
|
||||||
|
if len(servs) == 0:
|
||||||
|
e = Exception(f'techservice has not service with {serviceid=}')
|
||||||
|
exception(f'{e},{format_exc()}')
|
||||||
|
serv = servs[0]
|
||||||
|
fui = json.loads(serv.params_ui)
|
||||||
|
fui.fields.append({
|
||||||
|
'name':'serviceid',
|
||||||
|
'uitype':'hide',
|
||||||
|
'value':service
|
||||||
|
})
|
||||||
|
return fui
|
||||||
|
|
||||||
|
async def service4host(serviceid, hostid, parmas):
|
||||||
|
userinfos = {k:v for k,v in params.items() if k in ['userid', 'userorgid']}
|
||||||
|
params = {k:v for k,v in params.items() if k not in ['userid', 'userorgid']}
|
||||||
|
te = MyTemplateEngine(['.'])
|
||||||
|
dbname = get_dbname()
|
||||||
|
db = DBPools()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
servs = await sor.R('techservice', {'id':serviceid})
|
||||||
|
if len(servs) == 0:
|
||||||
|
e = Exception(f'techservice has not service with {serviceid=}')
|
||||||
|
exception(f'{e},{format_exc()}')
|
||||||
|
serv = servs[0]
|
||||||
|
script = te.renders(serv.script, params)
|
||||||
|
tmpf = temp_file(subffix='.sh')
|
||||||
|
with codecs.open(tmpf, 'w', 'utf-8') as f:
|
||||||
|
f.write(script)
|
||||||
|
node = await hostdev_node(hostid)
|
||||||
|
async with node.get_connector() as conn:
|
||||||
|
cmd = f'/tmp/{os.path.basename(tmpf)}'
|
||||||
|
await conn.l2r(tmpf, cmd)
|
||||||
|
await conn.run(f'chmod +x {cmd}')
|
||||||
|
x = await conn.run(f'bash {cmd}')
|
||||||
|
debug(f'{x.output=}')
|
||||||
23
msp/stun/README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# stun server
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
开源stunserver, 从[stunserver](https://github.com/jselbie/stunserver.git)下载源代码,并按照说明安装依赖并编译完成
|
||||||
|
使用本目录的install.sh, 完成安装
|
||||||
|
|
||||||
|
## 启动
|
||||||
|
|
||||||
|
sudo systemctl restart stund
|
||||||
|
|
||||||
|
# turnserver
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
apt install coturn
|
||||||
|
|
||||||
|
## 修改配置
|
||||||
|
/etc/turnserver
|
||||||
|
将listening-port修改为13479
|
||||||
|
保存并重启coturn服务
|
||||||
|
|
||||||
|
## 启动
|
||||||
|
sudo systemctl restart coturn
|
||||||
|
|
||||||
19
msp/stun/install.sh
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
sudo cp stunserver /usr/local/bin
|
||||||
|
chmod + /usr/local/bin/stunserver
|
||||||
|
sudo cat > /etc/systemd/system/stund.service <<!!
|
||||||
|
[Unit]
|
||||||
|
Description=Gadget Webserver base on aiothhp
|
||||||
|
After=network.target mariadb.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/local/bin/stunserver --primaryport 13478
|
||||||
|
ExecStop=/usr/bin/killall stunserver
|
||||||
|
KillMode=process
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
Alias=gadget.service
|
||||||
|
!!
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable stund.service
|
||||||
|
sudo systemctl restart stund.service
|
||||||
BIN
msp/stun/stunserver
Executable file
1
msp/version.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
__version__ = '0.0.1'
|
||||||
0
requirements.txt
Normal file
56
script/msp.nginx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
server {
|
||||||
|
if ($host = kymoz.com) {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
} # managed by Certbot
|
||||||
|
listen 10080;
|
||||||
|
server_name msp.kymoz.com;
|
||||||
|
rewrite ^(.*)$ https://${server_name}$1 permanent;
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
listen 10443 ssl;
|
||||||
|
autoindex on;
|
||||||
|
client_max_body_size 20m;
|
||||||
|
server_name msp.kymoz.com;
|
||||||
|
ssl_certificate /etc/letsencrypt/live/kymoz.com/fullchain.pem; # managed by Certbot
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/kymoz.com/privkey.pem; # managed by Certbot
|
||||||
|
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-server $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Scheme $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
proxy_set_header X-Forwarded-Url "$scheme://$host:$server_port$request_uri";
|
||||||
|
|
||||||
|
index index.html index.htm;
|
||||||
|
proxy_buffering off;
|
||||||
|
location ~^/ip$ {
|
||||||
|
return 200 "$remote_addr";
|
||||||
|
}
|
||||||
|
|
||||||
|
location /wss/ {
|
||||||
|
proxy_pass http://localhost:10101/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Prepath 'wss';
|
||||||
|
}
|
||||||
|
location / {
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-server $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Scheme $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
proxy_set_header X-real-ip $remote_addr;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_pass http://localhost:10100/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
13
script/msp.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=maneged service platform service
|
||||||
|
Documention=msp service to control msp service start or stoop
|
||||||
|
After=mariadb.service
|
||||||
|
Wants=systemd-networkd.service
|
||||||
|
Requires=nginx.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
ExecStart=su - ymq -c "cd; py/msp/script/run.sh"
|
||||||
|
ExecStop=su - ymq "cd; bin/killname msp.py"
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
6
script/run.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
$HOME/bin/killname app/mspapp.py
|
||||||
|
|
||||||
|
$HOME/py3/bin/python $HOME/py/msp/app/mspapp.py -w $HOME/py/msp -p 10100 >> $HOME/py/msp/logs/msp.log 2>&1 &
|
||||||
|
$HOME/py3/bin/python $HOME/py/msp/app/mspapp.py -w $HOME/py/msp -p 10101 >> $HOME/py/msp/logs/msp.log 2>&1 &
|
||||||
52
setup.py
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from msp.version import __version__
|
||||||
|
try:
|
||||||
|
from setuptools import setup
|
||||||
|
except ImportError:
|
||||||
|
from distutils.core import setup
|
||||||
|
required = []
|
||||||
|
with open('requirements.txt', 'r') as f:
|
||||||
|
ls = f.read()
|
||||||
|
required = ls.split('\n')
|
||||||
|
|
||||||
|
with open('msp/version.py', 'r') as f:
|
||||||
|
x = f.read()
|
||||||
|
y = x[x.index("'")+1:]
|
||||||
|
z = y[:y.index("'")]
|
||||||
|
version = z
|
||||||
|
with open("README.md", "r") as fh:
|
||||||
|
long_description = fh.read()
|
||||||
|
|
||||||
|
name = "msp"
|
||||||
|
description = "msp"
|
||||||
|
author = "yumoqing"
|
||||||
|
email = "yumoqing@gmail.com"
|
||||||
|
|
||||||
|
package_data = {}
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="msp",
|
||||||
|
version=version,
|
||||||
|
|
||||||
|
# uncomment the following lines if you fill them out in release.py
|
||||||
|
description=description,
|
||||||
|
author=author,
|
||||||
|
author_email=email,
|
||||||
|
platforms='any',
|
||||||
|
install_requires=required ,
|
||||||
|
packages=[
|
||||||
|
"msp"
|
||||||
|
],
|
||||||
|
package_data=package_data,
|
||||||
|
keywords = [
|
||||||
|
],
|
||||||
|
url="https://github.com/yumoqing/msp",
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
classifiers = [
|
||||||
|
'Operating System :: OS Independent',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
|
],
|
||||||
|
)
|
||||||
81
wwwroot/accordion.ui
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"Accordion",
|
||||||
|
"options":{
|
||||||
|
"width":"300px",
|
||||||
|
"flexShrink": 0,
|
||||||
|
"height":"100%",
|
||||||
|
"keyselectable":true,
|
||||||
|
"bgcolor":"#888888",
|
||||||
|
"item_size":"28px",
|
||||||
|
"items":[
|
||||||
|
{
|
||||||
|
"name":"models",
|
||||||
|
"refresh":true,
|
||||||
|
"label":"单模型对话",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"refresh":true,
|
||||||
|
"url":"{{entire_url('models/modeltypemenu.dspy')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"models_comp",
|
||||||
|
"refresh":true,
|
||||||
|
"label":"多模型对话",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"refresh":true,
|
||||||
|
"url":"{{entire_url('models/modelcomp.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"agents",
|
||||||
|
"refresh":true,
|
||||||
|
"label":"智能体",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('agents/index.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"apps",
|
||||||
|
"refresh":true,
|
||||||
|
"label":"应用",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('apps/index.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"tunes",
|
||||||
|
"refresh":true,
|
||||||
|
"label":"模型调优",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('tunes/index.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"feelog",
|
||||||
|
"refresh":true,
|
||||||
|
"label":"费用记录",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('fee/menu.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
38
wwwroot/app_panel.ui
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"HBox",
|
||||||
|
"options":{
|
||||||
|
"css":"filler"
|
||||||
|
},
|
||||||
|
"subwidgets":[
|
||||||
|
{
|
||||||
|
"widgettype":"Image",
|
||||||
|
"options":{
|
||||||
|
"height":"100%",
|
||||||
|
"css":"clickable",
|
||||||
|
"popup":{
|
||||||
|
"options":{
|
||||||
|
"auto_dismiss":true
|
||||||
|
},
|
||||||
|
"popup_event":"click",
|
||||||
|
"popup_desc":{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('menu.ui')}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"popupwindow":false
|
||||||
|
},
|
||||||
|
"url":"{{entire_url('/imgs/msp.png')}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype":"Title4",
|
||||||
|
"options":{
|
||||||
|
"i18n":true,
|
||||||
|
"otext":"服务平台",
|
||||||
|
"wrap":true,
|
||||||
|
"halign":"left"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
17
wwwroot/bottom.ui
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"HBox",
|
||||||
|
"options":{
|
||||||
|
"cheight":2,
|
||||||
|
"bgcolor":"#e5e5e5"
|
||||||
|
},
|
||||||
|
"subwidgets":[
|
||||||
|
{
|
||||||
|
"widgettype":"Text",
|
||||||
|
"options":{
|
||||||
|
"otext":"© 2024 版权所有 慢龟终至",
|
||||||
|
"i18n":true,
|
||||||
|
"wrap":true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
15
wwwroot/center.ui
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"VBox",
|
||||||
|
"id":"page_center",
|
||||||
|
"options":{
|
||||||
|
"css":"filler"
|
||||||
|
},
|
||||||
|
"subwidgets":[
|
||||||
|
{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('msp_profile.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
25
wwwroot/connecthost.ui
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"PopupWindow",
|
||||||
|
"options":{
|
||||||
|
"auto_open":true,
|
||||||
|
"auto_destroy":true,
|
||||||
|
"archor":"cc",
|
||||||
|
"cwidth":45,
|
||||||
|
"cheight":40,
|
||||||
|
"movable":true,
|
||||||
|
"icon":"{{entire_url('/imgs/terminal.png')}}",
|
||||||
|
"title":"{{params_kw.name}}",
|
||||||
|
"content":{
|
||||||
|
"widgettype":"Wterm",
|
||||||
|
"options":{
|
||||||
|
"height":"100%",
|
||||||
|
"width":"100%",
|
||||||
|
"term_options":{
|
||||||
|
"fontSize":24
|
||||||
|
},
|
||||||
|
"ws_url":"{{entire_url('https://msp.kymoz.com:10443/wss/ws/connecthost.xterm')}}?hostid={{params_kw.id}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
15
wwwroot/get_code.dspy
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
debug(f'{params_kw=}')
|
||||||
|
ns = params_kw.copy()
|
||||||
|
db = DBPools()
|
||||||
|
sql = f"""select {params_kw.tblvalue} as {params_kw.valueField},
|
||||||
|
{params_kw.tbltext} as {params_kw.textField}
|
||||||
|
from {params_kw.table} where 1=1 """
|
||||||
|
if params_kw.cond:
|
||||||
|
sql += f"and {params_kw.cond}"
|
||||||
|
print('sql=', sql)
|
||||||
|
dbname = await rfexe('get_module_dbname', 'msp')
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
rs = await sor.sqlExe(sql, ns)
|
||||||
|
return rs
|
||||||
|
return []
|
||||||
|
|
||||||
BIN
wwwroot/imgs/baichuan.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
wwwroot/imgs/bc_black.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/bc_empty.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
wwwroot/imgs/bc_white.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/bl_black.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/bl_empty.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
wwwroot/imgs/bl_white.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/br_black.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/br_empty.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
wwwroot/imgs/br_white.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/chatgpt.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
wwwroot/imgs/cl_black.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
wwwroot/imgs/cl_empty.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
wwwroot/imgs/cl_white.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
wwwroot/imgs/cr_black.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
wwwroot/imgs/cr_empty.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
wwwroot/imgs/cr_white.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
wwwroot/imgs/deepseek.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
wwwroot/imgs/dot_empty.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
wwwroot/imgs/doubao.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
wwwroot/imgs/download.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
wwwroot/imgs/ii_black.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
wwwroot/imgs/ii_empty.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
wwwroot/imgs/ii_white.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
wwwroot/imgs/key.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
wwwroot/imgs/like.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
wwwroot/imgs/login.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
wwwroot/imgs/logout.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
wwwroot/imgs/minimax.jpeg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
wwwroot/imgs/minimax.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
wwwroot/imgs/moonshot.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
BIN
wwwroot/imgs/msp.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
wwwroot/imgs/ollama.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
wwwroot/imgs/people.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
wwwroot/imgs/play.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
wwwroot/imgs/qianfan.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
wwwroot/imgs/qianwen.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
wwwroot/imgs/register.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
wwwroot/imgs/sage.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
wwwroot/imgs/search.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
wwwroot/imgs/sensetime.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
wwwroot/imgs/submit.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
wwwroot/imgs/tc_black.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/tc_empty.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
wwwroot/imgs/tc_white.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/terminal.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
wwwroot/imgs/tl_black.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/tl_empty.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
wwwroot/imgs/tl_white.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/tr_black.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/tr_empty.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
wwwroot/imgs/tr_white.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
wwwroot/imgs/unlike.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
wwwroot/imgs/upload.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
wwwroot/imgs/user.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
1
wwwroot/imgs/wechat.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg width="128" height="110" xmlns="http://www.w3.org/2000/svg"><path d="M86.635 33.334c1.467 0 2.917.113 4.358.283C87.078 14.392 67.58.111 45.321.111 20.44.111.055 17.987.055 40.687c0 13.104 6.781 23.863 18.115 32.209l-4.527 14.352 15.82-8.364c5.666 1.182 10.207 2.395 15.858 2.395 1.42 0 2.829-.073 4.227-.189-.886-3.19-1.398-6.53-1.398-9.996 0-20.845 16.98-37.76 38.485-37.76zm-24.34-12.936c3.407 0 5.665 2.363 5.665 5.954 0 3.576-2.258 5.97-5.666 5.97-3.392 0-6.795-2.395-6.795-5.97 0-3.591 3.403-5.954 6.795-5.954zM30.616 32.323c-3.393 0-6.818-2.395-6.818-5.971 0-3.591 3.425-5.954 6.818-5.954 3.392 0 5.65 2.363 5.65 5.954 0 3.576-2.258 5.97-5.65 5.97z"/><path d="M127.945 70.52c0-19.075-18.108-34.623-38.448-34.623-21.537 0-38.5 15.548-38.5 34.623 0 19.108 16.963 34.622 38.5 34.622 4.508 0 9.058-1.2 13.584-2.395l12.414 7.167-3.404-11.923c9.087-7.184 15.854-16.712 15.854-27.471zm-50.928-5.97c-2.254 0-4.53-2.362-4.53-4.773 0-2.378 2.276-4.771 4.53-4.771 3.422 0 5.665 2.393 5.665 4.771 0 2.41-2.243 4.773-5.665 4.773zm24.897 0c-2.24 0-4.498-2.362-4.498-4.773 0-2.378 2.258-4.771 4.498-4.771 3.392 0 5.665 2.393 5.665 4.771 0 2.41-2.273 4.773-5.665 4.773z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
wwwroot/imgs/weixinzhifu.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
wwwroot/imgs/zhifubao.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
wwwroot/imgs/zhipu.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
27
wwwroot/index.ui
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"VBox",
|
||||||
|
"options":{
|
||||||
|
"width":"100%",
|
||||||
|
"height":"100%"
|
||||||
|
},
|
||||||
|
"subwidgets":[
|
||||||
|
{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('top.ui')}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('center.ui')}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('bottom.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
6
wwwroot/keypress.ui
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"KeyPress",
|
||||||
|
"options":{
|
||||||
|
"height":"100%"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
wwwroot/menu.ui
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"Menu",
|
||||||
|
"options":{
|
||||||
|
"cwidth":10,
|
||||||
|
"target":"page_center",
|
||||||
|
"items":[
|
||||||
|
{
|
||||||
|
"name":"home",
|
||||||
|
"label":"主页",
|
||||||
|
"url":"{{entire_url('msp_profile.ui')}}"
|
||||||
|
}
|
||||||
|
{% if get_user() %}
|
||||||
|
,{
|
||||||
|
"name":"group",
|
||||||
|
"label":"设备组",
|
||||||
|
"url":"{{entire_url('devgroup')}}"
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||