commit c22035c5c429761d69766d425316389e5a64f30f Author: yumoqing Date: Wed Jul 16 15:06:49 2025 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..1d6ec14 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# msp + +managed service platform \ No newline at end of file diff --git a/app/ext.py b/app/ext.py new file mode 100644 index 0000000..b6119cf --- /dev/null +++ b/app/ext.py @@ -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 + diff --git a/app/mspapp.py b/app/mspapp.py new file mode 100644 index 0000000..55ff9dc --- /dev/null +++ b/app/mspapp.py @@ -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) + diff --git a/conf/config.json b/conf/config.json new file mode 100644 index 0000000..626e3f5 --- /dev/null +++ b/conf/config.json @@ -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" + } + } +} + diff --git a/json/build.sh b/json/build.sh new file mode 100755 index 0000000..ba74263 --- /dev/null +++ b/json/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash + +xls2ui -m ../models -o ../wwwroot msp *.json diff --git a/json/devgroup.json b/json/devgroup.json new file mode 100644 index 0000000..299ce58 --- /dev/null +++ b/json/devgroup.json @@ -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" + } + ] + } +} diff --git a/json/hostdev.json b/json/hostdev.json new file mode 100644 index 0000000..9b6054b --- /dev/null +++ b/json/hostdev.json @@ -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" + ] + } +} diff --git a/json/jumperhost.json b/json/jumperhost.json new file mode 100644 index 0000000..c1d7e5a --- /dev/null +++ b/json/jumperhost.json @@ -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" + ] + } +} diff --git a/models/atomservice.xlsx b/models/atomservice.xlsx new file mode 100644 index 0000000..811badf Binary files /dev/null and b/models/atomservice.xlsx differ diff --git a/models/devgroup.xlsx b/models/devgroup.xlsx new file mode 100644 index 0000000..9ecf134 Binary files /dev/null and b/models/devgroup.xlsx differ diff --git a/models/hostdev.xlsx b/models/hostdev.xlsx new file mode 100644 index 0000000..9bae171 Binary files /dev/null and b/models/hostdev.xlsx differ diff --git a/models/mixservice.xlsx b/models/mixservice.xlsx new file mode 100644 index 0000000..046b55a Binary files /dev/null and b/models/mixservice.xlsx differ diff --git a/models/mixserviceitem.xlsx b/models/mixserviceitem.xlsx new file mode 100644 index 0000000..2884603 Binary files /dev/null and b/models/mixserviceitem.xlsx differ diff --git a/models/mysql.ddl.sql b/models/mysql.ddl.sql new file mode 100644 index 0000000..9188074 --- /dev/null +++ b/models/mysql.ddl.sql @@ -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 '原子服务' +; + + diff --git a/models/service_log.xlsx b/models/service_log.xlsx new file mode 100644 index 0000000..0ce8d79 Binary files /dev/null and b/models/service_log.xlsx differ diff --git a/models/techservice.xlsx b/models/techservice.xlsx new file mode 100644 index 0000000..23e9c9d Binary files /dev/null and b/models/techservice.xlsx differ diff --git a/msp/certbot.sh b/msp/certbot.sh new file mode 100644 index 0000000..ad3d7d5 --- /dev/null +++ b/msp/certbot.sh @@ -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 diff --git a/msp/coturn/data.json b/msp/coturn/data.json new file mode 100644 index 0000000..d276604 --- /dev/null +++ b/msp/coturn/data.json @@ -0,0 +1,3 @@ +{ + "port":13478 +} diff --git a/msp/coturn/install.sh b/msp/coturn/install.sh new file mode 100755 index 0000000..3dad875 --- /dev/null +++ b/msp/coturn/install.sh @@ -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 + diff --git a/msp/getdbname.py b/msp/getdbname.py new file mode 100644 index 0000000..fb47fd1 --- /dev/null +++ b/msp/getdbname.py @@ -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 + diff --git a/msp/hostdev.py b/msp/hostdev.py new file mode 100644 index 0000000..488c2b8 --- /dev/null +++ b/msp/hostdev.py @@ -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 + diff --git a/msp/init.py b/msp/init.py new file mode 100644 index 0000000..5f9e3e9 --- /dev/null +++ b/msp/init.py @@ -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 + diff --git a/msp/service.py b/msp/service.py new file mode 100644 index 0000000..c2059fe --- /dev/null +++ b/msp/service.py @@ -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=}') diff --git a/msp/stun/README.md b/msp/stun/README.md new file mode 100644 index 0000000..874cd5c --- /dev/null +++ b/msp/stun/README.md @@ -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 + diff --git a/msp/stun/install.sh b/msp/stun/install.sh new file mode 100755 index 0000000..dbbcc2b --- /dev/null +++ b/msp/stun/install.sh @@ -0,0 +1,19 @@ +sudo cp stunserver /usr/local/bin +chmod + /usr/local/bin/stunserver +sudo cat > /etc/systemd/system/stund.service <> $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 & diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..4fb6054 --- /dev/null +++ b/setup.py @@ -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', + ], +) diff --git a/wwwroot/accordion.ui b/wwwroot/accordion.ui new file mode 100644 index 0000000..8f27a86 --- /dev/null +++ b/wwwroot/accordion.ui @@ -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')}}" + } + } + } + ] + } +} diff --git a/wwwroot/app_panel.ui b/wwwroot/app_panel.ui new file mode 100644 index 0000000..6f1933c --- /dev/null +++ b/wwwroot/app_panel.ui @@ -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" + } + } + ] +} diff --git a/wwwroot/bottom.ui b/wwwroot/bottom.ui new file mode 100644 index 0000000..dc8e13c --- /dev/null +++ b/wwwroot/bottom.ui @@ -0,0 +1,17 @@ +{ + "widgettype":"HBox", + "options":{ + "cheight":2, + "bgcolor":"#e5e5e5" + }, + "subwidgets":[ + { + "widgettype":"Text", + "options":{ + "otext":"© 2024 版权所有 慢龟终至", + "i18n":true, + "wrap":true + } + } + ] +} diff --git a/wwwroot/center.ui b/wwwroot/center.ui new file mode 100644 index 0000000..4b21d5f --- /dev/null +++ b/wwwroot/center.ui @@ -0,0 +1,15 @@ +{ + "widgettype":"VBox", + "id":"page_center", + "options":{ + "css":"filler" + }, + "subwidgets":[ + { + "widgettype":"urlwidget", + "options":{ + "url":"{{entire_url('msp_profile.ui')}}" + } + } + ] +} diff --git a/wwwroot/connecthost.ui b/wwwroot/connecthost.ui new file mode 100644 index 0000000..965c7c6 --- /dev/null +++ b/wwwroot/connecthost.ui @@ -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}}" + } + } + } +} + diff --git a/wwwroot/get_code.dspy b/wwwroot/get_code.dspy new file mode 100644 index 0000000..0a90bf4 --- /dev/null +++ b/wwwroot/get_code.dspy @@ -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 [] + diff --git a/wwwroot/imgs/baichuan.png b/wwwroot/imgs/baichuan.png new file mode 100644 index 0000000..7f8e3f0 Binary files /dev/null and b/wwwroot/imgs/baichuan.png differ diff --git a/wwwroot/imgs/bc_black.png b/wwwroot/imgs/bc_black.png new file mode 100644 index 0000000..7f396b3 Binary files /dev/null and b/wwwroot/imgs/bc_black.png differ diff --git a/wwwroot/imgs/bc_empty.png b/wwwroot/imgs/bc_empty.png new file mode 100644 index 0000000..fe4d97a Binary files /dev/null and b/wwwroot/imgs/bc_empty.png differ diff --git a/wwwroot/imgs/bc_white.png b/wwwroot/imgs/bc_white.png new file mode 100644 index 0000000..2c011f8 Binary files /dev/null and b/wwwroot/imgs/bc_white.png differ diff --git a/wwwroot/imgs/bl_black.png b/wwwroot/imgs/bl_black.png new file mode 100644 index 0000000..0331556 Binary files /dev/null and b/wwwroot/imgs/bl_black.png differ diff --git a/wwwroot/imgs/bl_empty.png b/wwwroot/imgs/bl_empty.png new file mode 100644 index 0000000..8bf28e0 Binary files /dev/null and b/wwwroot/imgs/bl_empty.png differ diff --git a/wwwroot/imgs/bl_white.png b/wwwroot/imgs/bl_white.png new file mode 100644 index 0000000..39b86ee Binary files /dev/null and b/wwwroot/imgs/bl_white.png differ diff --git a/wwwroot/imgs/br_black.png b/wwwroot/imgs/br_black.png new file mode 100644 index 0000000..1e2cf37 Binary files /dev/null and b/wwwroot/imgs/br_black.png differ diff --git a/wwwroot/imgs/br_empty.png b/wwwroot/imgs/br_empty.png new file mode 100644 index 0000000..afb65cb Binary files /dev/null and b/wwwroot/imgs/br_empty.png differ diff --git a/wwwroot/imgs/br_white.png b/wwwroot/imgs/br_white.png new file mode 100644 index 0000000..ba35c19 Binary files /dev/null and b/wwwroot/imgs/br_white.png differ diff --git a/wwwroot/imgs/chatgpt.png b/wwwroot/imgs/chatgpt.png new file mode 100644 index 0000000..1a7dd84 Binary files /dev/null and b/wwwroot/imgs/chatgpt.png differ diff --git a/wwwroot/imgs/cl_black.png b/wwwroot/imgs/cl_black.png new file mode 100644 index 0000000..1afed96 Binary files /dev/null and b/wwwroot/imgs/cl_black.png differ diff --git a/wwwroot/imgs/cl_empty.png b/wwwroot/imgs/cl_empty.png new file mode 100644 index 0000000..efd4f02 Binary files /dev/null and b/wwwroot/imgs/cl_empty.png differ diff --git a/wwwroot/imgs/cl_white.png b/wwwroot/imgs/cl_white.png new file mode 100644 index 0000000..bc533f3 Binary files /dev/null and b/wwwroot/imgs/cl_white.png differ diff --git a/wwwroot/imgs/cr_black.png b/wwwroot/imgs/cr_black.png new file mode 100644 index 0000000..33d4737 Binary files /dev/null and b/wwwroot/imgs/cr_black.png differ diff --git a/wwwroot/imgs/cr_empty.png b/wwwroot/imgs/cr_empty.png new file mode 100644 index 0000000..2b9ce1b Binary files /dev/null and b/wwwroot/imgs/cr_empty.png differ diff --git a/wwwroot/imgs/cr_white.png b/wwwroot/imgs/cr_white.png new file mode 100644 index 0000000..ca99405 Binary files /dev/null and b/wwwroot/imgs/cr_white.png differ diff --git a/wwwroot/imgs/deepseek.png b/wwwroot/imgs/deepseek.png new file mode 100644 index 0000000..9c98e40 Binary files /dev/null and b/wwwroot/imgs/deepseek.png differ diff --git a/wwwroot/imgs/dot_empty.png b/wwwroot/imgs/dot_empty.png new file mode 100644 index 0000000..41257a3 Binary files /dev/null and b/wwwroot/imgs/dot_empty.png differ diff --git a/wwwroot/imgs/doubao.png b/wwwroot/imgs/doubao.png new file mode 100644 index 0000000..dc514e1 Binary files /dev/null and b/wwwroot/imgs/doubao.png differ diff --git a/wwwroot/imgs/download.png b/wwwroot/imgs/download.png new file mode 100644 index 0000000..d3042d8 Binary files /dev/null and b/wwwroot/imgs/download.png differ diff --git a/wwwroot/imgs/ii_black.png b/wwwroot/imgs/ii_black.png new file mode 100644 index 0000000..99fc9fa Binary files /dev/null and b/wwwroot/imgs/ii_black.png differ diff --git a/wwwroot/imgs/ii_empty.png b/wwwroot/imgs/ii_empty.png new file mode 100644 index 0000000..0ae6207 Binary files /dev/null and b/wwwroot/imgs/ii_empty.png differ diff --git a/wwwroot/imgs/ii_white.png b/wwwroot/imgs/ii_white.png new file mode 100644 index 0000000..99fc9fa Binary files /dev/null and b/wwwroot/imgs/ii_white.png differ diff --git a/wwwroot/imgs/key.png b/wwwroot/imgs/key.png new file mode 100644 index 0000000..ceb598a Binary files /dev/null and b/wwwroot/imgs/key.png differ diff --git a/wwwroot/imgs/like.png b/wwwroot/imgs/like.png new file mode 100644 index 0000000..6441c9d Binary files /dev/null and b/wwwroot/imgs/like.png differ diff --git a/wwwroot/imgs/login.png b/wwwroot/imgs/login.png new file mode 100644 index 0000000..eb40e6a Binary files /dev/null and b/wwwroot/imgs/login.png differ diff --git a/wwwroot/imgs/logout.png b/wwwroot/imgs/logout.png new file mode 100644 index 0000000..eafcf76 Binary files /dev/null and b/wwwroot/imgs/logout.png differ diff --git a/wwwroot/imgs/minimax.jpeg b/wwwroot/imgs/minimax.jpeg new file mode 100644 index 0000000..93b4016 Binary files /dev/null and b/wwwroot/imgs/minimax.jpeg differ diff --git a/wwwroot/imgs/minimax.png b/wwwroot/imgs/minimax.png new file mode 100644 index 0000000..142514a Binary files /dev/null and b/wwwroot/imgs/minimax.png differ diff --git a/wwwroot/imgs/moonshot.png b/wwwroot/imgs/moonshot.png new file mode 100644 index 0000000..6f9ae5a Binary files /dev/null and b/wwwroot/imgs/moonshot.png differ diff --git a/wwwroot/imgs/msp.png b/wwwroot/imgs/msp.png new file mode 100644 index 0000000..114c87e Binary files /dev/null and b/wwwroot/imgs/msp.png differ diff --git a/wwwroot/imgs/ollama.png b/wwwroot/imgs/ollama.png new file mode 100644 index 0000000..38182d2 Binary files /dev/null and b/wwwroot/imgs/ollama.png differ diff --git a/wwwroot/imgs/people.png b/wwwroot/imgs/people.png new file mode 100644 index 0000000..6a3bc34 Binary files /dev/null and b/wwwroot/imgs/people.png differ diff --git a/wwwroot/imgs/play.png b/wwwroot/imgs/play.png new file mode 100644 index 0000000..dd0d089 Binary files /dev/null and b/wwwroot/imgs/play.png differ diff --git a/wwwroot/imgs/qianfan.png b/wwwroot/imgs/qianfan.png new file mode 100644 index 0000000..013abc9 Binary files /dev/null and b/wwwroot/imgs/qianfan.png differ diff --git a/wwwroot/imgs/qianwen.png b/wwwroot/imgs/qianwen.png new file mode 100644 index 0000000..3d8760e Binary files /dev/null and b/wwwroot/imgs/qianwen.png differ diff --git a/wwwroot/imgs/register.png b/wwwroot/imgs/register.png new file mode 100644 index 0000000..64636cc Binary files /dev/null and b/wwwroot/imgs/register.png differ diff --git a/wwwroot/imgs/sage.png b/wwwroot/imgs/sage.png new file mode 100644 index 0000000..e6a4bd3 Binary files /dev/null and b/wwwroot/imgs/sage.png differ diff --git a/wwwroot/imgs/search.png b/wwwroot/imgs/search.png new file mode 100644 index 0000000..da92fb3 Binary files /dev/null and b/wwwroot/imgs/search.png differ diff --git a/wwwroot/imgs/sensetime.png b/wwwroot/imgs/sensetime.png new file mode 100644 index 0000000..8d82e6f Binary files /dev/null and b/wwwroot/imgs/sensetime.png differ diff --git a/wwwroot/imgs/submit.png b/wwwroot/imgs/submit.png new file mode 100644 index 0000000..bda9bdc Binary files /dev/null and b/wwwroot/imgs/submit.png differ diff --git a/wwwroot/imgs/tc_black.png b/wwwroot/imgs/tc_black.png new file mode 100644 index 0000000..5aca0bb Binary files /dev/null and b/wwwroot/imgs/tc_black.png differ diff --git a/wwwroot/imgs/tc_empty.png b/wwwroot/imgs/tc_empty.png new file mode 100644 index 0000000..ddba8e7 Binary files /dev/null and b/wwwroot/imgs/tc_empty.png differ diff --git a/wwwroot/imgs/tc_white.png b/wwwroot/imgs/tc_white.png new file mode 100644 index 0000000..f931ab2 Binary files /dev/null and b/wwwroot/imgs/tc_white.png differ diff --git a/wwwroot/imgs/terminal.png b/wwwroot/imgs/terminal.png new file mode 100644 index 0000000..c98cd76 Binary files /dev/null and b/wwwroot/imgs/terminal.png differ diff --git a/wwwroot/imgs/tl_black.png b/wwwroot/imgs/tl_black.png new file mode 100644 index 0000000..6fa0768 Binary files /dev/null and b/wwwroot/imgs/tl_black.png differ diff --git a/wwwroot/imgs/tl_empty.png b/wwwroot/imgs/tl_empty.png new file mode 100644 index 0000000..605d91f Binary files /dev/null and b/wwwroot/imgs/tl_empty.png differ diff --git a/wwwroot/imgs/tl_white.png b/wwwroot/imgs/tl_white.png new file mode 100644 index 0000000..07be7eb Binary files /dev/null and b/wwwroot/imgs/tl_white.png differ diff --git a/wwwroot/imgs/tr_black.png b/wwwroot/imgs/tr_black.png new file mode 100644 index 0000000..a960be8 Binary files /dev/null and b/wwwroot/imgs/tr_black.png differ diff --git a/wwwroot/imgs/tr_empty.png b/wwwroot/imgs/tr_empty.png new file mode 100644 index 0000000..6e10ea7 Binary files /dev/null and b/wwwroot/imgs/tr_empty.png differ diff --git a/wwwroot/imgs/tr_white.png b/wwwroot/imgs/tr_white.png new file mode 100644 index 0000000..b5c3cb0 Binary files /dev/null and b/wwwroot/imgs/tr_white.png differ diff --git a/wwwroot/imgs/unlike.png b/wwwroot/imgs/unlike.png new file mode 100644 index 0000000..334f825 Binary files /dev/null and b/wwwroot/imgs/unlike.png differ diff --git a/wwwroot/imgs/upload.png b/wwwroot/imgs/upload.png new file mode 100644 index 0000000..4da3056 Binary files /dev/null and b/wwwroot/imgs/upload.png differ diff --git a/wwwroot/imgs/user.png b/wwwroot/imgs/user.png new file mode 100644 index 0000000..7ef4b96 Binary files /dev/null and b/wwwroot/imgs/user.png differ diff --git a/wwwroot/imgs/wechat.svg b/wwwroot/imgs/wechat.svg new file mode 100644 index 0000000..c586e55 --- /dev/null +++ b/wwwroot/imgs/wechat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wwwroot/imgs/weixinzhifu.png b/wwwroot/imgs/weixinzhifu.png new file mode 100644 index 0000000..7bb0735 Binary files /dev/null and b/wwwroot/imgs/weixinzhifu.png differ diff --git a/wwwroot/imgs/zhifubao.png b/wwwroot/imgs/zhifubao.png new file mode 100644 index 0000000..8bd1ad1 Binary files /dev/null and b/wwwroot/imgs/zhifubao.png differ diff --git a/wwwroot/imgs/zhipu.png b/wwwroot/imgs/zhipu.png new file mode 100644 index 0000000..5b5d7cf Binary files /dev/null and b/wwwroot/imgs/zhipu.png differ diff --git a/wwwroot/index.ui b/wwwroot/index.ui new file mode 100644 index 0000000..2cbe938 --- /dev/null +++ b/wwwroot/index.ui @@ -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')}}" + } + } + ] +} diff --git a/wwwroot/keypress.ui b/wwwroot/keypress.ui new file mode 100644 index 0000000..c444fe4 --- /dev/null +++ b/wwwroot/keypress.ui @@ -0,0 +1,6 @@ +{ + "widgettype":"KeyPress", + "options":{ + "height":"100%" + } +} diff --git a/wwwroot/menu.ui b/wwwroot/menu.ui new file mode 100644 index 0000000..3b75a8c --- /dev/null +++ b/wwwroot/menu.ui @@ -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 %} + ] + } +} diff --git a/wwwroot/msp_profile.md b/wwwroot/msp_profile.md new file mode 100644 index 0000000..11e7c33 --- /dev/null +++ b/wwwroot/msp_profile.md @@ -0,0 +1,14 @@ +# 服务平台 + +服务平台为注册客户提供在线技术服务,包括但不限于: + +* 系统监控 + +* 营运维护 + +* 一键安装 + +Slow and steady wins the race + + + diff --git a/wwwroot/msp_profile.ui b/wwwroot/msp_profile.ui new file mode 100644 index 0000000..9ebffee --- /dev/null +++ b/wwwroot/msp_profile.ui @@ -0,0 +1,7 @@ +{ + "widgettype":"MdWidget", + "options":{ + "md_url":"msp_profile.md" + } +} + diff --git a/wwwroot/test.ui b/wwwroot/test.ui new file mode 100644 index 0000000..703c593 --- /dev/null +++ b/wwwroot/test.ui @@ -0,0 +1,71 @@ +{ + "widgettyp": "Menu", + "options": { + "width": "100%", + "target": "main", + "items": [ + { + "name": "text2image", + "label": "\u6587\u751f\u56fe", + "items": [ + { + "name": "cogview", + "lable": "\u667a\u666e\u6587\u751f\u56fe", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=zXNnSdo2NmlFy_URIDQc7&modetypeid=text2image" + } + ] + }, + { + "name": "text2text", + "label": "\u6587\u751f\u6587", + "items": [ + { + "name": "\u5343\u5e06\u5927\u6a21\u578b", + "lable": "\u5343\u5e06\u5927\u6a21\u578b", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=-H1l7-eCRBD3pYZ-G2aIw&modetypeid=text2text" + }, + { + "name": "phi3:3.8b", + "lable": "phi3:3.8b", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=bmmjVUFgbLxvlD0M-raed&modetypeid=text2text" + }, + { + "name": "llama3:8b", + "lable": "8b\u53c2\u6570llama3", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=dm5-cLUWsB0vF12BwYfR6&modetypeid=text2text" + }, + { + "name": "codestral:22b", + "lable": "codestral:22b", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=E5_mRi0eI_pExMCwW0wvM&modetypeid=text2text" + }, + { + "name": "wizardlm2:7b", + "lable": "wizardlm2:7b", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=eYaTeUXEXKLqd6ruu9_VP&modetypeid=text2text" + }, + { + "name": "mistral:7b", + "lable": "mistral:7b", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=NdB3nq3SF9qfg5Kvnm2h0&modetypeid=text2text" + }, + { + "name": "moonshot-v1-8k", + "lable": "", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=puxRX9FT1pk4YnaT30oR9&modetypeid=text2text" + }, + { + "name": "codellama:13b", + "lable": "code llama:13b", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=wo5Q6ID-H6yx-3nDjdEt5&modetypeid=text2text" + }, + { + "name": "sqlcoder:15b", + "lable": "sqlcoder:15b", + "url": "http://localhost:9080/dialog/model_dialog.dspy?modelinstanceid=XtjmxxDPDdvfeCC2IVrDc&modetypeid=text2text" + } + ] + } + ] + } +} diff --git a/wwwroot/top.ui b/wwwroot/top.ui new file mode 100644 index 0000000..a334c67 --- /dev/null +++ b/wwwroot/top.ui @@ -0,0 +1,23 @@ +{ + "id":"top_panel", + "widgettype":"HBox", + "options":{ + "bgcolor":"#444444", + "cheight":2.5, + "color":"#eeeeee" + }, + "subwidgets":[ + { + "widgettype":"urlwidget", + "options":{ + "url":"app_panel.ui" + } + }, + { + "widgettype":"urlwidget", + "options":{ + "url":"{{entire_url('/rbac/user/user_panel.ui')}}" + } + } + ] +} diff --git a/wwwroot/ws/connecthost.xterm b/wwwroot/ws/connecthost.xterm new file mode 100644 index 0000000..dd0c7b4 --- /dev/null +++ b/wwwroot/ws/connecthost.xterm @@ -0,0 +1,34 @@ +debug(f'{params_kw=},') +def gethostinfo(hostdev): + r = hostdev + return DictObject(**{ + "host":r.host, + "port":r.port, + "username":r.user, + "password":password_decode(r.passwd), + }) + +db = DBPools() +userid = await get_user() +async with db.sqlorContext('msp') as sor: + ns = { + # "ownerid":userid, + "id":params_kw.hostid + } + sql="""select a.*, b.enterhostid +from hostdev a, devgroup b +where a.id= ${id}$ and a.devgroupid = b.id +""" + recs = await sor.sqlExe(sql,ns.copy()) + if len(recs) > 0: + r = recs[0] + hostinfo = gethostinfo(r) + if hostinfo.enterhostid: + recs = await sor.sqlExe(sql, {'id':r.enterhostid}) + if len(recs) > 0: + hostinfo.jumpers = [gethostinfo(recs[0])] + # hostinfo['commandlien'] = 'tail -f /var/log/syslog' + return hostinfo + else: + debug(f'{ns=} get hostdev error') +return None