Compare commits

...
177 Commits
Author SHA1 Message Date
Mr Chen 63e427b488 Merge pull request #445 from midoks/dev
0.16.0
2023-08-30 23:26:30 +08:00
midoks c688c692f9 0.16.0
yum install -y libargon2-devel
apt install -y libargon2-dev

OP防火墙 - 重载即可

* 增加PHP83。
* 面板日志单独为一页并加入日志审计功能。
* 修复webssh服务器读取问题。
* 站点批量删除修复。
* OP防火墙-修复`自动强制验证`关闭不生效。
* 新增OneDrive备份插件。
* FTP备份优化。
2023-08-30 23:24:49 +08:00
midoks c9f074b319 FTP备份优化 2023-08-30 20:48:54 +08:00
midoks 38b4042c5a Update msonedrive.js 2023-08-30 19:51:52 +08:00
midoks bf32390f0e Update README.md 2023-08-30 18:40:21 +08:00
midoks 91a9be4cc0 Update mw.py 2023-08-30 18:26:08 +08:00
midoks be5f438f84 Delete config.conf 2023-08-30 17:47:38 +08:00
midoks 2705fd7ba2 Update config_api.py 2023-08-30 17:45:21 +08:00
midoks 4de7e72f0a Update test.py 2023-08-30 17:37:49 +08:00
midoks da668c723c onedrive插件OK 2023-08-30 17:35:41 +08:00
midoks 20624217bf Update backup.py 2023-08-30 15:11:17 +08:00
midoks 2403af08c6 Update crontab.js 2023-08-30 13:35:52 +08:00
midoks 2350b73896 Update layout.html 2023-08-28 23:50:14 +08:00
midoks 464fa9cc0f Update cert_api.py 2023-08-28 23:06:16 +08:00
midoks 9a79f0b728 Update README.md 2023-08-28 22:57:47 +08:00
midoks 52cfff7038 OP防火墙-修复自动强制验证关闭不生效。 2023-08-28 22:50:03 +08:00
midoks 8d42f8137c Update .gitignore 2023-08-28 11:45:37 +08:00
midoks 41fb9759a3 Create readme.md 2023-08-28 11:38:44 +08:00
midoks 7d3833b2ef Update index.py 2023-08-27 19:56:17 +08:00
midoks 0badb053e0 站点批量删除修复。 2023-08-27 19:46:56 +08:00
midoks 80b9e7cbf7 Update index.py 2023-08-27 19:00:13 +08:00
midoks 94df21192f Update dynamic-tracking.js 2023-08-27 18:50:25 +08:00
midoks 346d687368 Update simple_trace.sh 2023-08-27 18:34:47 +08:00
midoks 46ec655365 Update simple_trace.sh 2023-08-27 18:28:52 +08:00
midoks e852020c38 Update simple_trace.sh 2023-08-27 17:51:18 +08:00
midoks d06e83676b Update simple_trace.sh 2023-08-27 17:50:32 +08:00
midoks 7a511f8217 Update dynamic-tracking.js 2023-08-27 17:09:49 +08:00
midoks 8c5021b9dc Update simple_trace.sh 2023-08-27 16:48:05 +08:00
midoks b7d50540ac Create ubuntu.sh 2023-08-27 16:45:06 +08:00
midoks 2a95fcc59a Update install.sh 2023-08-27 16:29:52 +08:00
midoks 2b04cb3947 Update dynamic-tracking.js 2023-08-27 16:17:15 +08:00
midoks 7f0ad25342 Update simple_macosx_trace.sh 2023-08-27 15:51:42 +08:00
midoks 09f7e6f5b5 update 2023-08-27 15:50:52 +08:00
midoks 17a7ffa0b4 update 2023-08-27 15:38:00 +08:00
midoks ba6dcabd04 Update simple_trace.sh 2023-08-27 14:29:17 +08:00
midoks 0ff5c170d3 update 2023-08-27 14:28:26 +08:00
midoks b78e020993 Update index.py 2023-08-26 23:14:06 +08:00
midoks 9586eeda07 up 2023-08-26 23:02:17 +08:00
midoks ea462aa51d update 2023-08-26 22:43:13 +08:00
midoks aaac8b5239 文件管理-svg预览优化 2023-08-26 22:38:27 +08:00
midoks 2b86c375b0 动态追踪- svg查看功能 2023-08-26 22:23:13 +08:00
midoks 600e2688f9 update 2023-08-26 21:11:34 +08:00
midoks 3537bc520f Update dynamic-tracking.js 2023-08-26 17:47:06 +08:00
midoks 9ffdffadd6 Update README.md 2023-08-26 17:42:59 +08:00
midoks 3942f2fbf5 Update index.py 2023-08-26 17:35:48 +08:00
midoks 8ff2f217b3 Update index.py 2023-08-26 17:23:34 +08:00
midoks 480bd154c6 Update index.py 2023-08-26 17:21:20 +08:00
midoks 5eb3ed4524 Update README.md 2023-08-26 16:49:19 +08:00
midoks 50e78ae6f6 Update logs.html 2023-08-26 16:22:08 +08:00
midoks 0ec9b31c2f update 2023-08-26 16:17:54 +08:00
midoks 191b54821e Update logs_api.py 2023-08-26 16:07:19 +08:00
midoks c2188a2c7e update 2023-08-26 16:04:35 +08:00
midoks d23b64a92c Update update_dev.sh 2023-08-26 16:03:29 +08:00
midoks 3ae97e1c75 Update config_api.py 2023-08-26 15:59:04 +08:00
midoks f0e7361436 Update logs_api.py 2023-08-26 15:57:54 +08:00
midoks 5f85d41352 日志审计转移完成 2023-08-26 15:55:09 +08:00
midoks 6fc8803446 update 2023-08-26 00:29:44 +08:00
midoks b3120f3435 日志功能从防火墙提出来 2023-08-26 00:24:04 +08:00
midoks f9f1b1a113 update 2023-08-25 21:21:58 +08:00
midoks 2645297cee update 2023-08-25 21:20:56 +08:00
midoks 7f171f5986 update 2023-08-25 20:56:53 +08:00
midoks c3b3e3b01c update 2023-08-25 16:55:44 +08:00
midoks 3824b394ad php argon2 2023-08-25 16:55:32 +08:00
midoks 270660fb53 update 2023-08-25 15:26:23 +08:00
midoks c4171a9506 Update install.sh 2023-08-25 15:09:54 +08:00
midoks 222943e312 Update index.py 2023-08-24 22:35:44 +08:00
midoks 92f8a4e949 Update mw.tpl 2023-08-24 22:12:02 +08:00
midoks eff1f55a21 Update cli.sh 2023-08-24 22:10:43 +08:00
midoks 0b54da9747 Update freebsd.sh 2023-08-24 21:39:29 +08:00
midoks 0bec57937f Update index.py 2023-08-24 21:31:35 +08:00
midoks 6c64f8ee5e Update install.sh 2023-08-24 21:25:15 +08:00
midoks b65ad9de80 Update install.sh 2023-08-24 21:18:49 +08:00
midoks 07be263d81 Update install.sh 2023-08-24 21:12:53 +08:00
midoks bf9cb52fec Update index.py 2023-08-24 21:07:42 +08:00
midoks f7135a6ded Update index.py 2023-08-24 21:02:36 +08:00
midoks 7b98dde1aa Update index.py 2023-08-24 21:02:26 +08:00
midoks b51f3fdd68 update 2023-08-24 21:00:47 +08:00
midoks e02c52df49 Update freebsd.sh 2023-08-24 20:58:26 +08:00
midoks 730bc7171b Update index.py 2023-08-24 20:55:57 +08:00
midoks c065eabb48 Update index.py 2023-08-24 20:47:49 +08:00
midoks 1ad1e3326d php扩展库读取优化 2023-08-24 20:45:25 +08:00
midoks d4346a51bc Update crontab_api.py 2023-08-24 20:22:53 +08:00
midoks 8260cc5f4a Update crontab_api.py 2023-08-24 20:12:50 +08:00
midoks 021b299b7d Update mw.tpl 2023-08-24 20:09:53 +08:00
midoks a767e7e578 Update index.py 2023-08-24 20:05:08 +08:00
midoks 57da2aef27 Update freebsd.sh 2023-08-24 19:48:06 +08:00
midoks 5b43438cb1 Update index.py 2023-08-24 19:46:02 +08:00
midoks 7ab88a1bea Update index.py 2023-08-24 19:05:11 +08:00
midoks 31291a13c7 Update index.py 2023-08-24 18:58:59 +08:00
midoks 43d0b75d98 Update index.py 2023-08-24 18:58:35 +08:00
midoks 5490197b8a Update index.py 2023-08-24 18:58:16 +08:00
midoks 8f03574bce update 2023-08-24 18:56:19 +08:00
midoks 94487e0b3d Update index.py 2023-08-24 18:54:09 +08:00
midoks 45cc0159af Update index.py 2023-08-24 18:48:07 +08:00
midoks 504a618eb1 Update index.py 2023-08-24 18:33:48 +08:00
midoks 5e25849464 Update index.py 2023-08-24 18:33:22 +08:00
midoks 9bb59a1559 Update index.py 2023-08-24 18:10:07 +08:00
midoks 6883316efc Update index.py 2023-08-24 18:09:16 +08:00
midoks de7ea503e5 update 2023-08-24 18:03:23 +08:00
midoks 4fcad95c79 Update index.py 2023-08-24 15:28:10 +08:00
midoks 75dc1bd70d Update freebsd.sh 2023-08-24 15:18:38 +08:00
midoks 44758e3e55 Update index.py 2023-08-24 15:02:20 +08:00
midoks 140624e62f Update index.py 2023-08-24 14:47:01 +08:00
midoks 65f90b473c Update index.py 2023-08-24 14:44:59 +08:00
midoks 0a089fcedf Update index.py 2023-08-24 14:41:58 +08:00
midoks 010624023f update 2023-08-24 14:39:32 +08:00
midoks 9399a14a92 update 2023-08-24 12:52:10 +08:00
midoks 2875b40e62 Update README.md 2023-08-23 20:15:28 +08:00
midoks 78c3686091 Update freebsd.sh 2023-08-23 13:12:29 +08:00
midoks d7447197ec Update freebsd.sh 2023-08-22 19:58:23 +08:00
midoks 9b64ec5c6d Update freebsd.sh 2023-08-22 18:48:18 +08:00
midoks dad51dad77 Update files_api.py 2023-08-22 18:48:07 +08:00
midoks d89751f733 update 2023-08-22 18:25:46 +08:00
midoks 1dc486711b Update install.sh 2023-08-22 17:42:34 +08:00
midoks 60a2f85f02 Update install.sh 2023-08-22 17:41:57 +08:00
midoks 830d387ddb up 2023-08-22 17:37:53 +08:00
midoks ae225780f9 Update system_api.py 2023-08-22 17:27:21 +08:00
midoks e0a0a82d68 update 2023-08-22 17:25:54 +08:00
midoks 0b23c5f330 update 2023-08-22 17:18:32 +08:00
midoks fb01c68f5a Update mw.py 2023-08-22 17:09:26 +08:00
midoks 5755121fa5 Update mw.py 2023-08-22 17:05:23 +08:00
midoks 3d1c613864 Update mw.py 2023-08-22 17:02:39 +08:00
midoks 9590c4bb7d Update mw.py 2023-08-22 17:01:45 +08:00
midoks 32c0bdf093 Update system_api.py 2023-08-22 16:52:15 +08:00
midoks 4f5424a746 Update freebsd.sh 2023-08-22 16:36:56 +08:00
midoks 81ba3bce9d Update freebsd.sh 2023-08-22 16:21:24 +08:00
midoks 22b3a1bc42 Update op_waf.js 2023-08-21 23:15:10 +08:00
midoks df9a34aa31 Update index.py 2023-08-21 22:33:33 +08:00
midoks 2400213533 up 2023-08-21 22:20:51 +08:00
midoks 465eb118a9 0.16.0
改版为【老子面板】
2023-08-21 20:28:06 +08:00
midoks 7e81aa109f Update all_test.sh 2023-08-21 19:49:47 +08:00
midoks b23b41c7a7 Update phplib.conf 2023-08-21 19:22:19 +08:00
midoks 724a77ae81 Update install.sh 2023-08-21 19:17:37 +08:00
midoks 3499ed74ee Update info.json 2023-08-21 19:13:36 +08:00
midoks 52997049e2 Update layout.html 2023-08-21 19:11:28 +08:00
midoks a96a36b087 Create install.sh 2023-08-21 19:02:52 +08:00
midoks 5926f688a6 Update macos.sh 2023-08-21 00:41:26 +08:00
midoks 1b754f5c43 Update push_notice_msg.py 2023-08-21 00:12:30 +08:00
midoks c4c20de520 Update install.sh 2023-08-20 22:37:42 +08:00
midoks 616895785f Update init_cmd.py 2023-08-20 20:37:30 +08:00
midoks 29d6c8740a Update receive_music163_search.py 2023-08-20 20:35:33 +08:00
midoks 64aa9a9d01 Update receive_music163_search.py 2023-08-20 19:46:30 +08:00
midoks ffbe8ba6d4 Update receive_music163_search.py 2023-08-20 19:41:04 +08:00
midoks ed39c5d243 Update receive_music163_search.py 2023-08-20 16:56:48 +08:00
midoks 4bb2115040 Update receive_music163_search.py 2023-08-20 15:32:16 +08:00
midoks 6b0cf8129d Update receive_music163_search.py 2023-08-20 15:11:19 +08:00
midoks ab7bbe942b Update receive_music163_search.py 2023-08-20 15:11:01 +08:00
midoks a8a3fa1754 update 2023-08-20 15:10:58 +08:00
midoks e343f33b47 Update receive_faq.py 2023-08-20 14:58:48 +08:00
midoks f55367ab5e Update index.py 2023-08-20 00:26:17 +08:00
midoks 050bd158c1 update 2023-08-20 00:25:46 +08:00
midoks d35a680fec update 2023-08-19 20:11:08 +08:00
midoks 4a4ddeaabe Update system_api.py 2023-08-19 00:17:23 +08:00
midoks 0e74b0cccf Update system_api.py 2023-08-19 00:15:39 +08:00
midoks 806e29577e Update system_api.py 2023-08-19 00:14:47 +08:00
midoks 75923f5363 Update system_api.py 2023-08-19 00:13:19 +08:00
midoks 834196883c Update index.py 2023-08-18 00:53:15 +08:00
midoks 341826c641 Update index.py 2023-08-18 00:52:28 +08:00
midoks 1bd1ce5b31 Update index.py 2023-08-18 00:42:20 +08:00
Mr Chen eef504e172 Merge pull request #442 from midoks/dev
OP防火墙测试功能修复
2023-08-18 00:20:06 +08:00
midoks a0434ef7d6 Update index.py 2023-08-18 00:13:17 +08:00
midoks 893bbb8ea7 Update install.sh 2023-08-17 22:49:01 +08:00
midoks 92e3e277cc Update info.json 2023-08-17 21:38:44 +08:00
midoks 58e48bf013 Update info.json 2023-08-17 21:36:41 +08:00
midoks 644760d5b0 update 2023-08-17 21:35:37 +08:00
midoks d6ccd81def 动态追踪 - 专业人员使用 2023-08-17 21:29:54 +08:00
Mr Chen d32e71b2d9 Merge pull request #441 from midoks/dev
centos9 mysql8安装需要patchelf
2023-08-17 18:43:28 +08:00
midoks ae9e56c56c Update rhel.sh 2023-08-17 18:41:42 +08:00
midoks d7c0285bbf Update rhel.sh 2023-08-17 18:38:43 +08:00
midoks 5cc0957ffd Update rhel.sh 2023-08-17 18:38:18 +08:00
Mr Chen 1e44d64ace Merge pull request #440 from midoks/dev
mysql安装优化
2023-08-17 17:55:46 +08:00
midoks 907851c413 update 2023-08-17 17:29:04 +08:00
midoks 0faafc654b Update install.sh 2023-08-17 16:58:36 +08:00
Mr Chen 4cdc399b77 Merge pull request #439 from midoks/dev
mongodb脚本升级和检查openresty状态优化
2023-08-17 16:25:46 +08:00
midoks a085e5b1ea Update mw.py 2023-08-17 16:20:07 +08:00
midoks bdbf4dddc6 Update mongodb.tpl 2023-08-17 15:39:45 +08:00
midoks 5cee2f2b6d mongodb centos 2023-08-17 15:36:13 +08:00
98 changed files with 4891 additions and 468 deletions
+2 -2
View File
@@ -177,5 +177,5 @@ debug.out
mdioks.session-journal
*.session
mdioks.session-journal
*.session
+13 -5
View File
@@ -100,12 +100,20 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
```
### 版本更新 0.15.4
### 版本更新 0.16.0
* OP防火墙-验证优化[cf缓存问题解决]。
* OP防火墙-加入地区限制(最好卸载重装)。
* 在aarch64架构下低于PHP70的版本[安装/扩展安装]优化。
* Mongodb安装优化。
yum install -y libargon2-devel
apt install -y libargon2-dev
OP防火墙 - 重载即可
* 增加PHP83。
* 面板日志单独为一页并加入日志审计功能。
* 修复webssh服务器读取问题。
* 站点批量删除修复。
* OP防火墙-修复`自动强制验证`关闭不生效。
* 新增OneDrive备份插件。
* FTP备份优化。
### JSDelivr安装地址
+12 -8
View File
@@ -1496,8 +1496,9 @@ fullchain.pem 粘贴到证书输入框
'cert_timeout'] = int(time.time())
if self.__config['orders'][i]['cert_timeout'] > start_time:
writeLog(
"|-本次跳过域名: {},未过期!".format(self.__config['orders'][i]['domains'][0]))
msg = "|-本次跳过域名: {},未过期!".format(
self.__config['orders'][i]['domains'][0])
writeLog(msg)
continue
# 已删除的网站直接跳过续签
@@ -1514,8 +1515,9 @@ fullchain.pem 粘贴到证书输入框
break
if not mw.M('domain').where("name=?", (domain,)).count() and not mw.M('binding').where("domain=?", domain).count():
auth_to = None
writeLog(
"|-跳过被删除的域名: {}".format(self.__config['orders'][i]['domains']))
msg = "|-跳过被删除的域名: {}".format(
self.__config['orders'][i]['domains'])
writeLog(msg)
if not auth_to:
continue
@@ -1526,15 +1528,17 @@ fullchain.pem 粘贴到证书输入框
timeout = self.__config['orders'][i][
'next_retry_time'] - int(time.time())
if timeout > 0:
writeLog('|-本次跳过域名:{},因第上次续签失败,还需要等待{}小时后再重试'.format(
self.__config['orders'][i]['domains'], int(timeout / 60 / 60)))
msg = '|-本次跳过域名:{},因第上次续签失败,还需要等待{}小时后再重试'.format(
self.__config['orders'][i]['domains'], int(timeout / 60 / 60))
writeLog(msg)
continue
# 是否到了最大重试次数
if 'retry_count' in self.__config['orders'][i]:
if self.__config['orders'][i]['retry_count'] >= 5:
writeLog('|-本次跳过域名:{},因连续5次续签失败,不再续签此证书(可尝试手动续签此证书,成功后错误次数将被重置)'.format(
self.__config['orders'][i]['domains']))
msg = '|-本次跳过域名:{},因连续5次续签失败,不再续签此证书(可尝试手动续签此证书,成功后错误次数将被重置)'.format(
self.__config['orders'][i]['domains'])
writeLog(msg)
continue
# 加入到续签订单
+1 -1
View File
@@ -27,7 +27,7 @@ from flask import request
class config_api:
__version = '0.15.4'
__version = '0.16.0'
__api_addr = 'data/api.json'
def __init__(self):
+9 -7
View File
@@ -602,20 +602,22 @@ echo "--------------------------------------------------------------------------
# 将Shell脚本写到文件
def writeShell(self, config):
u_file = '/var/spool/cron/crontabs/root'
if not os.path.exists(u_file):
file = '/var/spool/cron/crontabs/root'
current_os = mw.getOs()
if current_os == 'darwin':
file = '/etc/crontab'
elif current_os.startswith("freebsd"):
file = '/var/cron/tabs/root'
if not os.path.exists(file):
file = '/var/spool/cron/root'
if mw.isAppleSystem():
file = '/etc/crontab'
else:
file = u_file
if not os.path.exists(file):
mw.writeFile(file, '')
conf = mw.readFile(file)
conf += str(config) + "\n"
if mw.writeFile(file, conf):
if not os.path.exists(u_file):
if not os.path.exists(file):
mw.execShell("chmod 600 '" + file +
"' && chown root.root " + file)
else:
+7 -5
View File
@@ -64,8 +64,13 @@ class files_api:
filename = request.args.get('filename', '')
if not os.path.exists(filename):
return ''
is_attachment = True
if filename.endswith(".svg"):
is_attachment = False
response = make_response(send_from_directory(
os.path.dirname(filename), os.path.basename(filename), as_attachment=True))
os.path.dirname(filename), os.path.basename(filename), as_attachment=is_attachment))
return response
def zipApi(self):
@@ -708,10 +713,7 @@ class files_api:
return not path in nDirs
def getDirSize(self, path):
if mw.isAppleSystem():
tmp = mw.execShell('du -sh ' + path)
else:
tmp = mw.execShell('du -sbh ' + path)
tmp = mw.execShell('du -sh ' + path)
return tmp
def checkFileName(self, filename):
-33
View File
@@ -178,12 +178,6 @@ class firewall_api:
limit = request.form.get('limit', '10').strip()
return self.getList(int(p), int(limit))
def getLogListApi(self):
p = request.form.get('p', '1').strip()
limit = request.form.get('limit', '10').strip()
search = request.form.get('search', '').strip()
return self.getLogList(int(p), int(limit), search)
def getSshInfoApi(self):
data = {}
@@ -389,11 +383,6 @@ class firewall_api:
return mw.returnData(True, '设置成功!')
def delPanelLogsApi(self):
mw.M('logs').where('id>?', (0,)).delete()
mw.writeLog('面板设置', '面板操作日志已清空!')
return mw.returnJson(True, '面板操作日志已清空!')
##### ----- start ----- ###
def getList(self, page, limit):
@@ -414,28 +403,6 @@ class firewall_api:
data['page'] = mw.getPage(_page)
return mw.getJson(data)
def getLogList(self, page, limit, search=''):
find_search = ''
if search != '':
find_search = "type like '%" + search + "%' or log like '%" + \
search + "%' or addtime like '%" + search + "%'"
start = (page - 1) * limit
_list = mw.M('logs').where(find_search, ()).field(
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
data = {}
data['data'] = _list
count = mw.M('logs').where(find_search, ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'getLogs'
_page['p'] = page
data['page'] = mw.getPage(_page)
return mw.getJson(data)
def addAcceptPort(self, port):
if self.__isUfw:
mw.execShell('ufw allow ' + port + '/tcp')
+352
View File
@@ -0,0 +1,352 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 日志类操作
# ---------------------------------------------------------------------------------
import psutil
import time
import os
import sys
import mw
import re
import json
import pwd
from datetime import datetime
from flask import request
class logs_api:
__months = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',
'Jul': '07', 'Aug': '08', 'Sep': '09', 'Sept': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'}
def __init__(self):
pass
def delPanelLogsApi(self):
mw.M('logs').where('id>?', (0,)).delete()
mw.writeLog('面板设置', '面板操作日志已清空!')
return mw.returnJson(True, '面板操作日志已清空!')
def getLogListApi(self):
p = request.form.get('p', '1').strip()
limit = request.form.get('limit', '10').strip()
search = request.form.get('search', '').strip()
return self.getLogList(int(p), int(limit), search)
def getLogList(self, page, limit, search=''):
find_search = ''
if search != '':
find_search = "type like '%" + search + "%' or log like '%" + \
search + "%' or addtime like '%" + search + "%'"
start = (page - 1) * limit
_list = mw.M('logs').where(find_search, ()).field(
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
data = {}
data['data'] = _list
count = mw.M('logs').where(find_search, ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'getLogs'
_page['p'] = page
data['page'] = mw.getPage(_page)
return mw.getJson(data)
def getLogsTitle(self, log_name):
log_name = log_name.replace('.1', '')
if log_name in ['mw-update.log']:
return '面板更新日志'
if log_name in ['mw-install.log']:
return '面板安装日志'
if log_name in ['auth.log', 'secure'] or log_name.find('auth.') == 0:
return '授权日志'
if log_name in ['dmesg'] or log_name.find('dmesg') == 0:
return '内核缓冲区日志'
if log_name in ['syslog'] or log_name.find('syslog') == 0:
return '系统警告/错误日志'
if log_name in ['btmp']:
return '失败的登录记录'
if log_name in ['utmp', 'wtmp']:
return '登录和重启记录'
if log_name in ['lastlog']:
return '用户最后登录'
if log_name in ['yum.log']:
return 'yum包管理器日志'
if log_name in ['anaconda.log']:
return 'Anaconda日志'
if log_name in ['dpkg.log']:
return 'dpkg日志'
if log_name in ['daemon.log']:
return '系统后台守护进程日志'
if log_name in ['boot.log']:
return '启动日志'
if log_name in ['kern.log']:
return '内核日志'
if log_name in ['maillog', 'mail.log']:
return '邮件日志'
if log_name.find('Xorg') == 0:
return 'Xorg日志'
if log_name in ['cron.log']:
return '定时任务日志'
if log_name in ['alternatives.log']:
return '更新替代信息'
if log_name in ['debug']:
return '调试信息'
if log_name.find('apt') == 0:
return 'apt-get相关日志'
if log_name.find('installer') == 0:
return '系统安装相关日志'
if log_name in ['messages']:
return '综合日志'
return '{}日志'.format(log_name.split('.')[0])
def getAuditLogsFilesApi(self):
log_dir = '/var/log'
log_files = []
for log_file in os.listdir(log_dir):
log_suffix = log_file.split('.')[-1:]
if log_suffix[0] in ['gz', 'xz', 'bz2', 'asl']:
continue
if log_file in ['.', '..', 'faillog', 'fontconfig.log', 'unattended-upgrades', 'tallylog']:
continue
filename = os.path.join(log_dir, log_file)
if os.path.isfile(filename):
file_size = os.path.getsize(filename)
if not file_size:
continue
tmp = {
'name': log_file,
'size': file_size,
'log_file': filename,
'title': self.getLogsTitle(log_file),
'uptime': os.path.getmtime(filename)
}
log_files.append(tmp)
else:
for next_name in os.listdir(filename):
if next_name[-3:] in ['.gz', '.xz']:
continue
next_file = os.path.join(filename, next_name)
if not os.path.isfile(next_file):
continue
file_size = os.path.getsize(next_file)
if not file_size:
continue
log_name = '{}/{}'.format(log_file, next_name)
tmp = {
'name': log_name,
'size': file_size,
'log_file': next_file,
'title': self.getLogsTitle(log_name),
'uptime': os.path.getmtime(next_file)
}
log_files.append(tmp)
log_files = sorted(log_files, key=lambda x: x['name'], reverse=True)
return mw.getJson(log_files)
def getAuditFileApi(self):
log_name = request.form.get('log_name', '').strip()
return self.getAuditLogsName(log_name)
def __to_date2(self, date_str):
tmp = date_str.split()
s_date = str(tmp[-1]) + '-' + self.__months.get(tmp[1],
tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
return s_date
def __to_date3(self, date_str):
tmp = date_str.split()
s_date = str(datetime.now().year) + '-' + \
self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
return s_date
def __to_date4(self, date_str):
tmp = date_str.split()
s_date = str(datetime.now().year) + '-' + \
self.__months.get(tmp[0], tmp[0]) + '-' + tmp[1] + ' ' + tmp[2]
return s_date
def getAuditLast(self, log_name):
# 获取日志
cmd = '''LANG=en_US.UTF-8 last -n 200 -x -f {} |grep -v 127.0.0.1|grep -v " begins"'''.format(
'/var/log/' + log_name)
result = mw.execShell(cmd)
lastlog_list = []
for _line in result[0].split("\n"):
if not _line:
continue
tmp = {}
sp_arr = _line.split()
tmp['用户'] = sp_arr[0]
if sp_arr[0] == 'runlevel':
tmp['来源'] = sp_arr[4]
tmp['端口'] = ' '.join(sp_arr[1:4])
tmp['时间'] = self.__to_date3(
' '.join(sp_arr[5:])) + ' ' + ' '.join(sp_arr[-2:])
elif sp_arr[0] in ['reboot', 'shutdown']:
tmp['来源'] = sp_arr[3]
tmp['端口'] = ' '.join(sp_arr[1:3])
if sp_arr[-3] == '-':
tmp['时间'] = self.__to_date3(
' '.join(sp_arr[4:])) + ' ' + ' '.join(sp_arr[-3:])
else:
tmp['时间'] = self.__to_date3(
' '.join(sp_arr[4:])) + ' ' + ' '.join(sp_arr[-2:])
elif sp_arr[1] in ['tty1', 'tty', 'tty2', 'tty3', 'hvc0', 'hvc1', 'hvc2'] or len(sp_arr) == 9:
tmp['来源'] = ''
tmp['端口'] = sp_arr[1]
tmp['时间'] = self.__to_date3(
' '.join(sp_arr[2:])) + ' ' + ' '.join(sp_arr[-3:])
else:
tmp['来源'] = sp_arr[2]
tmp['端口'] = sp_arr[1]
tmp['时间'] = self.__to_date3(
' '.join(sp_arr[3:])) + ' ' + ' '.join(sp_arr[-3:])
# tmp['_line'] = _line
lastlog_list.append(tmp)
# lastlog_list = sorted(lastlog_list,key=lambda x:x['时间'],reverse=True)
return mw.returnData(True, 'ok!', lastlog_list)
def getAuditLastLog(self):
cmd = '''LANG=en_US.UTF-8 lastlog|grep -v Username'''
result = mw.execShell(cmd)
lastlog_list = []
for _line in result[0].split("\n"):
if not _line:
continue
tmp = {}
sp_arr = _line.split()
tmp['用户'] = sp_arr[0]
# tmp['_line'] = _line
if _line.find('Never logged in') != -1:
tmp['最后登录时间'] = '0'
tmp['最后登录来源'] = '-'
tmp['最后登录端口'] = '-'
lastlog_list.append(tmp)
continue
tmp['最后登录来源'] = sp_arr[2]
tmp['最后登录端口'] = sp_arr[1]
tmp['最后登录时间'] = self.__to_date2(' '.join(sp_arr[3:]))
lastlog_list.append(tmp)
lastlog_list = sorted(lastlog_list, key=lambda x: x[
'最后登录时间'], reverse=True)
for i in range(len(lastlog_list)):
if lastlog_list[i]['最后登录时间'] == '0':
lastlog_list[i]['最后登录时间'] = '从未登录过'
return mw.returnData(True, 'ok!', lastlog_list)
def parseAuditFile(self, log_name, result):
log_list = []
is_string = True
for _line in result.split("\n"):
if not _line.strip():
continue
if log_name.find('sa/sa') == -1:
if _line[:3] in self.__months:
_msg = _line[16:]
_tmp = _msg.split(": ")
_act = ''
if len(_tmp) > 1:
_act = _tmp[0]
_msg = _tmp[1]
else:
_msg = _tmp[0]
_line = {
"时间": self.__to_date4(_line[:16].strip()),
"角色": _act,
"事件": _msg
}
is_string = False
elif _line[:2] in ['19', '20', '21', '22', '23', '24']:
_msg = _line[19:]
_tmp = _msg.split(" ")
_act = _tmp[1]
_msg = ' '.join(_tmp[2:])
_line = {
"时间": _line[:19].strip(),
"角色": _act,
"事件": _msg
}
is_string = False
elif log_name.find('alternatives') == 0:
_tmp = _line.split(": ")
_last = _tmp[0].split(" ")
_act = _last[0]
_msg = ' '.join(_tmp[1:])
_line = {
"时间": ' '.join(_last[1:]).strip(),
"角色": _act,
"事件": _msg
}
is_string = False
else:
if not is_string:
if type(_line) != dict:
continue
log_list.append(_line)
return log_list
def getAuditLogsName(self, log_name):
# print(log_name)
if log_name in ['wtmp', 'btmp', 'utmp'] or log_name.find('wtmp') == 0 or log_name.find('btmp') == 0 or log_name.find('utmp') == 0:
return self.getAuditLast(log_name)
if log_name.find('lastlog') == 0:
return self.getAuditLastLog()
if log_name.find('sa/sa') == 0:
if log_name.find('sa/sar') == -1:
return mw.execShell("sar -f /var/log/{}".format(log_name))[0]
log_dir = '/var/log'
log_file = log_dir + '/' + log_name
if not os.path.exists(log_file):
return mw.returnData(False, '日志文件不存在!')
result = mw.getLastLine(log_file, 100)
try:
log_list = self.parseAuditFile(log_name, result)
_string = []
_dict = []
_list = []
for _line in log_list:
if isinstance(_line, str):
_string.append(_line.strip())
elif isinstance(_line, dict):
_dict.append(_line)
elif isinstance(_line, list):
_list.append(_line)
else:
continue
_str_len = len(_string)
_dict_len = len(_dict)
_list_len = len(_list)
if _str_len > _dict_len + _list_len:
return "\n".join(_string)
elif _dict_len > _str_len + _list_len:
return mw.returnData(True, 'ok!', _dict)
else:
return mw.returnData(True, 'ok!', _list)
except:
return mw.returnData(True, 'ok!', result)
+13 -6
View File
@@ -349,7 +349,8 @@ def restartMw():
def checkWebConfig():
op_dir = getServerDir() + '/openresty/nginx'
cmd = "ulimit -n 10240 && " + op_dir + \
# "ulimit -n 10240 && " +
cmd = op_dir + \
"/sbin/nginx -t -c " + op_dir + "/conf/nginx.conf"
result = execShell(cmd)
searchStr = 'test is successful'
@@ -1355,6 +1356,12 @@ def getCpuType():
cpuinfo = execShell(cmd)
return cpuinfo[0].strip()
current_os = getOs()
if current_os.startswith('freebsd'):
cmd = "sysctl -a | egrep -i 'hw.model' | awk -F ':' '{print $2}'"
cpuinfo = execShell(cmd)
return cpuinfo[0].strip()
# 取CPU类型
cpuinfo = open('/proc/cpuinfo', 'r').read()
rep = "model\s+name\s+:\s+(.+)"
@@ -1411,7 +1418,7 @@ def makeConf():
file = getRunDir() + '/data/json/config.json'
if not os.path.exists(file):
c = {}
c['title'] = '金灵面板'
c['title'] = '老子面板'
c['home'] = 'http://github/midoks/mdserver-web'
c['recycle_bin'] = True
c['template'] = 'default'
@@ -2099,15 +2106,15 @@ done
def echoStart(tag):
print("=" * 90)
print("=" * 89)
print("★开始{}[{}]".format(tag, formatDate()))
print("=" * 90)
print("=" * 89)
def echoEnd(tag):
print("=" * 90)
print("=" * 89)
print("☆{}完成[{}]".format(tag, formatDate()))
print("=" * 90)
print("=" * 89)
print("\n")
+22 -5
View File
@@ -274,26 +274,43 @@ class system_api:
return title
def getSystemVersion(self):
#
# 取操作系统版本
if mw.getOs() == 'darwin':
current_os = mw.getOs()
# mac
if current_os == 'darwin':
data = mw.execShell('sw_vers')[0]
data_list = data.strip().split("\n")
mac_version = ''
for x in data_list:
mac_version += x.split("\t")[1] + ' '
return mac_version
arch_ver = mw.execShell("arch")
return mac_version + " (" + arch_ver[0].strip() + ")"
# freebsd
if current_os.startswith('freebsd'):
version = mw.execShell(
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
arch_ver = mw.execShell(
"sysctl -a | egrep -i 'hw.machine_arch' | awk -F ':' '{print $2}'")
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
redhat_series = '/etc/redhat-release'
if os.path.exists(redhat_series):
version = mw.readFile('/etc/redhat-release')
version = version.replace('release ', '').strip()
return version
arch_ver = mw.execShell("arch")
return version + " (" + arch_ver[0].strip() + ")"
os_series = '/etc/os-release'
if os.path.exists(os_series):
version = mw.execShell(
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
return version[0].strip()
arch_ver = mw.execShell("arch")
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
return '未识别系统信息'
@@ -318,7 +335,7 @@ class system_api:
cpuCount = psutil.cpu_count()
cpuLogicalNum = psutil.cpu_count(logical=False)
used = psutil.cpu_percent(interval=interval)
cpuLogicalNum = 0
if os.path.exists('/proc/cpuinfo'):
c_tmp = mw.readFile('/proc/cpuinfo')
d_tmp = re.findall("physical id.+", c_tmp)
+4
View File
@@ -7,6 +7,10 @@ MDIR=$(dirname "$DIR")
PATH=$PATH:$DIR/bin
if [ -f bin/activate ];then
source bin/activate
if [ "$?" != "0" ];then
echo "load local python env fail!"
fi
fi
export LC_ALL="en_US.UTF-8"
+48 -6
View File
@@ -14,6 +14,7 @@ if sys.platform != "darwin":
sys.path.append(os.getcwd() + "/class/core")
import mw
import db
_ver = sys.version_info
is_py2 = (_ver[0] == 2)
@@ -185,6 +186,35 @@ def backupAllFunc(stype):
"path": "path",
}
backups = []
sql = db.Sql()
# print("stype:", stype)
# 提前获取-清理多余备份
if stype == 'site':
pid = sql.table('sites').where('name=?', (name,)).getField('id')
backups = sql.table('backup').where(
'type=? and pid=?', ('0', pid)).field('id,filename').select()
if stype == 'database':
db_path = mw.getServerDir() + '/mysql'
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
'name=?', (name,)).getField('id')
backups = sql.table('backup').where(
'type=? and pid=?', ('1', pid)).field('id,filename').select()
if stype == 'path':
backup_path = backup_dir + '/path'
_name = 'path_{}'.format(os.path.basename(name))
backups = findPathName(backup_path, _name)
# 其他类型关系性数据库(mysql类的)
if stype.find('database_') > -1:
plugin_name = stype.replace('database_', '')
db_path = mw.getServerDir() + '/' + plugin_name
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
'name=?', (name,)).getField('id')
backups = sql.table('backup').where(
'type=? and pid=?', ('1', pid)).field('id,filename').select()
args = stype + " " + name + " " + num
cmd = 'python3 ' + mw.getRunDir() + '/scripts/backup.py ' + args
if stype.find('database_') > -1:
@@ -213,19 +243,31 @@ def backupAllFunc(stype):
filename = mw.execShell(find_new_file)[0].strip()
if filename == "":
mw.echoInfo("not find upload file!")
return False
return ''
print("|-准备上传文件 {}".format(filename))
ftp = FtpPSClient()
ftp.uploadFile(filename, stype)
# print(backups)
backups = sorted(backups, key=lambda x: x['filename'], reverse=False)
mw.echoStart('开始删除远程备份')
num = int(num)
sep = len(backups) - num
if sep > -1:
for backup in backups:
fn = os.path.basename(backup['filename'])
object_name = ftp.buildDirName(stype, fn)
ftp.deleteFile(object_name)
mw.echoInfo("---已清理远程过期备份文件:" + object_name)
sep -= 1
if sep < 0:
break
mw.echoEnd('结束删除远程备份')
return ''
def backupSite():
# 备份站点
pass
def in_array(name, arr=[]):
for x in arr:
if name == x:
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

+19
View File
@@ -0,0 +1,19 @@
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('dynamic-tracking');">服务</p>
<p onclick="pluginInitD('dynamic-tracking');">自启动</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinHeight(300);
resetPluginWinWidth(500);
$.getScript( "/plugins/file?name=dynamic-tracking&f=static/js/dynamic-tracking.js", function(){
pluginService('dynamic-tracking', $('.plugin_version').attr('version'));
});
</script>
+228
View File
@@ -0,0 +1,228 @@
# coding:utf-8
import sys
import io
import os
import time
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'dynamic-tracking'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def status():
dir_path = getServerDir() + '/trace'
if not os.path.exists(dir_path):
os.mkdir(dir_path)
return 'start'
def dtOp(method):
return 'ok'
def start():
return dtOp('start')
def stop():
return dtOp('stop')
def restart():
status = dtOp('restart')
return status
def reload():
return dtOp('reload')
def initdStatus():
return 'ok'
def initdInstall():
return 'ok'
def initdUinstall():
return 'ok'
def get_file(args):
dir_path = getServerDir() + '/trace'
path = dir_path + '/' + args['file'] + '/main.svg'
if os.path.exists(path):
d = mw.readFile(path)
return mw.returnData(True, 'ok', d)
else:
return mw.returnData(False, '无效目录')
def get_file_path(args):
dir_path = getServerDir() + '/trace'
path = dir_path + '/' + args['file'] + '/main.svg'
if os.path.exists(path):
return mw.returnData(True, 'ok', path)
else:
return mw.returnData(False, '无效目录')
def dtGetFilePath():
args = getArgs()
data = checkArgs(args, ['file'])
if not data[0]:
return data[1]
dir_path = getServerDir() + '/trace'
path = dir_path + '/' + args['file'] + '/main.svg'
if os.path.exists(path):
return mw.returnJson(True, 'ok', path)
else:
return mw.returnJson(False, '无效目录')
def dtRemoveFilePath():
args = getArgs()
data = checkArgs(args, ['file'])
if not data[0]:
return data[1]
dir_path = getServerDir() + '/trace'
path = dir_path + '/' + args['file']
if os.path.exists(path):
mw.execShell('rm -rf ' + path)
return mw.returnJson(True, '删除成功!')
def dtFileList():
dir_path = getServerDir() + '/trace'
if not os.path.exists(dir_path):
os.mkdir(dir_path)
file_info = []
for name in os.listdir(dir_path):
if name == ".DS_Store":
continue
# print(name)
info = {}
try:
info['name'] = name
info['abs_path'] = dir_path + '/' + name + '/main.svg'
except Exception as e:
return mw.returnJson(False, str(e))
file_info.append(info)
file_info = sorted(file_info, key=lambda x: x['name'], reverse=False)
return mw.returnJson(True, 'ok!', file_info)
def dtSimpleTrace():
if mw.isAppleSystem():
return mw.returnJson(False, 'macosx只能手动执行!')
args = getArgs()
data = checkArgs(args, ['pid'])
if not data[0]:
return data[1]
plugins_shell = getPluginDir() + '/shell/simple_trace.sh'
cmd = plugins_shell + ' "' + args['pid'] + '"'
data = mw.execShell("bash " + cmd + " &")
return mw.returnJson(True, '执行成功!')
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'run_info':
print(runInfo())
elif func == 'conf':
print(getConf())
elif func == 'run_log':
print(runLog())
elif func == 'file_list':
print(dtFileList())
elif func == 'get_file_path':
print(dtGetFilePath())
elif func == 'remove_file_path':
print(dtRemoveFilePath())
elif func == 'simple_trace':
print(dtSimpleTrace())
else:
print('error')
+36
View File
@@ -0,0 +1,36 @@
{
"hook":[
{
"tag":"menu",
"menu": {
"title":"动态追踪",
"name":"dynamic-tracking",
"path":"static/html/index.html",
"css_path":"static/css/dynamic-tracking.css",
"js_path":"static/js/dynamic-tracking.js"
}
},
{
"tag":"global_static",
"global_static": {
"title":"动态追踪",
"name":"dynamic-tracking",
"css_path":"static/css/ico.css"
}
}
],
"sort": 7,
"ps": "专业使用,动态追踪调试程序<无侵入>![<span style='color:red;'>潜龙勿用|实验</span>]",
"name": "dynamic-tracking",
"title": "动态追踪",
"shell": "install.sh",
"versions":["0.1"],
"tip": "soft",
"checks": "server/dynamic-tracking",
"path": "server/dynamic-tracking",
"display": 1,
"author": "midoks",
"date": "2023-08-17",
"type": 0,
"pid": "4"
}
+88
View File
@@ -0,0 +1,88 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
# cd /www/server/mdserver-web/plugins/dynamic-tracking && /bin/bash install.sh uninstall 1.0
# cd /www/server/mdserver-web/plugins/dynamic-tracking && /bin/bash install.sh install 1.0
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
OSNAME=`bash ${rootPath}/scripts/getos.sh`
if [ "" == "$OSNAME" ];then
OSNAME=`cat ${rootPath}/data/osname.pl`
fi
if [ "macos" != "$OSNAME" ];then
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
fi
Install_App()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/source
mkdir -p $serverPath/dynamic-tracking
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
HTTP_PREFIX="https://"
if [ ! -z "$cn" ];then
HTTP_PREFIX="https://ghproxy.com/"
fi
# FlameGraph start
if [ ! -d $serverPath/dynamic-tracking/FlameGraph ];then
if [ ! -f $serverPath/source/FlameGraph.zip ]; then
wget --no-check-certificate -O $serverPath/source/FlameGraph.zip ${HTTP_PREFIX}github.com/brendangregg/FlameGraph/archive/refs/heads/master.zip
fi
cd $serverPath/source && unzip $serverPath/source/FlameGraph.zip
mv $serverPath/source/FlameGraph-master $serverPath/dynamic-tracking/FlameGraph
fi
# FlameGraph end
shell_file=${curPath}/versions/${OSNAME}.sh
echo $shell_file
if [ ! -f $shell_file ];then
echo '不支持...' > $install_tmp
exit 1
fi
bash -x $shell_file
echo "cp -rf ${curPath}/shell $serverPath/dynamic-tracking"
cp -rf ${curPath}/shell $serverPath/dynamic-tracking
echo "${VERSION}" > $serverPath/dynamic-tracking/version.pl
echo '安装完成' > $install_tmp
cd ${rootPath} && python3 ${rootPath}/plugins/dynamic-tracking/index.py start
# cd ${rootPath} && python3 ${rootPath}/plugins/dynamic-tracking/index.py initd_install
}
Uninstall_App()
{
rm -rf $serverPath/dynamic-tracking
echo "Uninstall_App" > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
@@ -0,0 +1,39 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# debug
# cd /www/server/mdserver-web
# bash /www/server/mdserver-web/plugins/dynamic-tracking/shell/simple_macosx_trace.sh "22431"
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web
# bash /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/dynamic-tracking/shell/simple_macosx_trace.sh "22431"
# dtrace -x ustackframes=100 -n 'pid$target::mach_msg_trap:entry { @[ustack()] = count(); } tick-30s { exit(0); }' -p 18572 -o out.SystemUIServer_stacks
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/stackcollapse.pl out.SystemUIServer_stacks > kernel.cbt
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/flamegraph.pl kernel.cbt > kernel.svg
curPath=`pwd`
rootPath=$(dirname "$curPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
PID=$1
echo $rootPath # /Users/midoks/Desktop/mwdev/server
echo $curPath # /Users/midoks/Desktop/mwdev/server/mdserver-web
APP_DIR=${rootPath}/dynamic-tracking
DST_FILE_DIR=${APP_DIR}/trace/PID_${PID}
mkdir -p $DST_FILE_DIR
DST_FILE=${DST_FILE_DIR}/out.SystemUIServer_stacks
if [ ! -f $DST_FILE ];then
sudo dtrace -x ustackframes=100 -n 'pid$target::mach_msg_trap:entry { @[ustack()] = count(); } tick-30s { exit(0); }' -p "$PID" -o $DST_FILE
fi
${APP_DIR}/FlameGraph/stackcollapse.pl $DST_FILE > ${DST_FILE_DIR}/kernel.cbt
${APP_DIR}/FlameGraph/flamegraph.pl ${DST_FILE_DIR}/kernel.cbt > ${DST_FILE_DIR}/main.svg
@@ -0,0 +1,43 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# debug
# cd /www/server/mdserver-web
# bash /www/server/mdserver-web/plugins/dynamic-tracking/shell/simple_trace.sh "2401699"
curPath=`pwd`
rootPath=$(dirname "$curPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
PID=$1
echo $rootPath # /Users/midoks/Desktop/mwdev/server
echo $curPath # /Users/midoks/Desktop/mwdev/server/mdserver-web
APP_DIR=/www/server/dynamic-tracking
DST_FILE_DIR=${APP_DIR}/trace/PID_${PID}
mkdir -p $DST_FILE_DIR
# DST_FILE=${DST_FILE_DIR}/main.strace
# perf record -F 99 -p 335584 -g -- sleep 30
cd ${DST_FILE_DIR}
perf record -F 99 -p ${PID} -g -- sleep 30
perf script > out.perf
${APP_DIR}/FlameGraph/stackcollapse-perf.pl ${DST_FILE_DIR}/out.perf > ${DST_FILE_DIR}/out.folded
${APP_DIR}/FlameGraph/flamegraph.pl ${DST_FILE_DIR}/out.folded > ${DST_FILE_DIR}/main.svg
# perf record -F 99 -p 2401699 -g -- sleep 30
# perf script > out.perf
# /www/server/dynamic-tracking/FlameGraph/stackcollapse-perf.pl out.perf > out.folded
# /www/server/dynamic-tracking/FlameGraph/flamegraph.pl out.folded > php-zend-flame-graph.svg
# ${APP_DIR}/FlameGraph/stackcollapse.pl $DST_FILE > ${DST_FILE_DIR}/kernel.cbt
# ${APP_DIR}/FlameGraph/flamegraph.pl ${DST_FILE_DIR}/kernel.cbt > ${DST_FILE_DIR}/main.svg
@@ -0,0 +1,75 @@
.screen-all {
padding: 5px;
}
.s-right .panel-default{
margin-bottom: 10px;
}
.s-left .panel-default{
margin-bottom: 10px;
}
.data-collect {
width: 45px;
height: 30px;
border: 0;
cursor: pointer;
margin-right: 2px;
margin-top: 10px;
color: #fff;
background-color: #20a53a;
border-color: #20a53a;
}
#file_list .list {
list-style: none;
border-top: none;
border: 1px solid #ececec;
overflow-y: auto;
}
#file_list .list li.active {
background-color: #f2f2f2;
}
#file_list .tab-con{
padding: 0px;
margin-top: 10px;
}
#file_list .list li>span {
vertical-align: top;
display: inline-block;
}
#file_list .list li {
display: inline-block;
height: 38px;
line-height: 38px;
color: #444;
border-bottom: 1px solid #ececec;
font-size: 13px;
cursor: pointer;
position: relative;
width: 100%;
}
#file_list .file {
padding-left: 10px;
}
#file_list .list li .tootls{
width: 70px;
text-align: right;
padding-right: 10px;
/* display: none; */
position: absolute;
right: 5px;
}
/*.tab-con .tab-block.on {
display: inline-block;
}*/
@@ -0,0 +1,11 @@
/* menu start */
.menu .current .menu_dynamic-tracking:hover {
background-image: url("/plugins/file?name=dynamic-tracking&f=ico.png");
}
.menu .menu_plugin_dynamic-tracking {
background-image: url("/plugins/file?name=dynamic-tracking&f=ico.png");
}
/* menu end */
@@ -0,0 +1,81 @@
<style>
.weblog{
font-size: 12px;
display:inline-block;
line-height:30px;
}
.weblog em{
font-style:normal;
color:#666;
margin: 0 30px;
}
.weblog span{
margin-right:5px;
}
.weblog a{
color:#20a53a;
}
.firewall-port-box{
margin-bottom:15px;
}
</style>
<div class="main-content">
<div class="container-fluid">
<div class="pos-box bgw mtb15">
<div class="position f14 c9 pull-left">
<a class="plr10 c4" href="/">首页</a>/<span class="plr10 c4">动态追踪</span>
</div>
<div class="search pull-right">
<form target="hid" onsubmit='return false;'>
<input type="text" id="searchValue" class="ser-text pull-left" placeholder="进程ID" />
<button type="button" class="data-collect pull-left">采样</button>
</form>
</div>
</div>
<!-- //// -->
<div class="safe bgw pd15 mtb15" id="ff_box">
<div id="file_list" style="float:left;width:300px;">
<div class="tab-nav">
<span class="on">文件列表</span>
</div>
<div class="tab-con">
<div class="tab-block on">
<ul class="list" style="display: block; height: 94px;"></ul>
</div>
</div>
</div>
<div id="flame_graph" style="float:left;">
<div class="tab-nav">
<span class="on">火焰图</span>
</div>
<div class="tab-con">
<iframe class="tab-block on" width="100%" height="100%"
src=""
frameborder="0"
border="0"
marginwidth="0"
marginheight="0"
scrolling="yes"
noresize=""
allowfullscreen="allowfullscreen"
mozallowfullscreen="mozallowfullscreen"
msallowfullscreen="msallowfullscreen"
oallowfullscreen="oallowfullscreen"
webkitallowfullscreen="webkitallowfullscreen"
allowfullscreen="true"></iframe>
</div>
</div>
</div>
<!-- //// -->
</div>
</div>
+178
View File
@@ -0,0 +1,178 @@
function changeDivH(){
var l = $(window).height();
var w = $(window).width();
$('#ff_box').css('height',l-80-60);
$('#file_list').css('height',l-80-60);
$('#file_list .tab-con .list').css('height', l-80-60-70);
$('#flame_graph').css('height',l-80-60).css('width',w-300-200-40);
$('#flame_graph iframe').css('height',l-80-60-70);
}
$(document).ready(function(){
var tag = $.getUrlParam('tag');
if(tag == 'dynamic-tracking'){
dynamicTrackingLoad();
}
});
function dynamicTrackingLoad(){
changeDivH();
$(window).resize(function(){
changeDivH();
});
//加载采样数据列表
dtFileList();
}
$('.data-collect').click(function(){
layer.msg('开始采样',{icon:0,time:2000});
var pid = $('#searchValue').val();
dtPost('simple_trace', '', {pid:pid}, function(rdata){
// console.log(rdata);
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata['msg'],{icon:rdata['status']?1:2,time:2000,shade: [0.3, '#000']});
});
});
function dtPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'dynamic-tracking';
req_data['func'] = method;
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
if (!data.status){
//错误展示10S
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function dtPostCb(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var pdata = {};
pdata['name'] = 'dynamic-tracking';
pdata['func'] = method;
args['version'] = version;
if (typeof(args) == 'string'){
pdata['args'] = JSON.stringify(toArrayObject(args));
} else {
pdata['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', pdata, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function dtFileList(){
dtPost('file_list', '', {}, function(data){
var rdata = $.parseJSON(data.data);
var alist = rdata.data;
if (alist.length == 0){
var em ='<li class="data-file-list" style="text-align: center;">无数据</li>';
$('#file_list .list').html(em);
return;
}
var tli = '';
for (var i = 0; i < alist.length; i++) {
if (i==0){
tli +='<li title="双击打开浏览" class="data-file-list active" data-index="'+i+'" data-file="'+alist[i]['name']+'">\
<span class="file">'+alist[i]['name']+'</span>\
<span class="tootls">\
<span class="glyphicon glyphicon-link" aria-hidden="true" title="外部连接"></span>\
<span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除"></span>\
</span>\
</li>';
} else{
tli +='<li class="data-file-list" data-index="'+i+'" data-file="'+alist[i]['name']+'">\
<span class="file">'+alist[i]['name']+'</span>\
<span class="tootls">\
<span class="glyphicon glyphicon-link" aria-hidden="true" title="外部连接"></span>\
<span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除"></span>\
</span>\
</li>';
}
}
$('#file_list .list').html(tli);
dtGetFile(alist[0]['name']);
$('#file_list li .file').click(function(){
$('#file_list li').removeClass('active');
$(this).parent().addClass('active');
var i = $(this).parent().data('index');
dtGetFile(alist[i]['name']);
});
$('#file_list li .glyphicon-link').click(function(){
var i = $(this).parent().parent().data('index');
var abs_p = alist[i]['abs_path'];
var durl = '/files/download?filename='+abs_p;
window.open(durl);
});
$('#file_list li .glyphicon-trash').click(function(){
var i = $(this).parent().parent().data('index');
var f = alist[i]['name'];
dtPost('remove_file_path', '',{file:f}, function(rdata){
var rdata = $.parseJSON(rdata.data);
layer.msg(rdata['msg'],{icon:rdata['status']?1:2,time:2000});
if (rdata.status){
dtFileList();
}
});
});
});
}
function dtGetFile(file){
dtPost('get_file_path', '', {file:file}, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
if (!rdata.status){
layer.msg(rdata.msg,{icon:0,time:2000,shade: [2, '#000']});
return;
}
var durl = '/files/download?filename='+rdata.data;
$('#flame_graph .tab-con .tab-block').attr('src',durl);
});
}
@@ -0,0 +1,11 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
SYS_ARCH=`arch`
@@ -0,0 +1,26 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
SYS_ARCH=`arch`
# apt-get install linux-perf
# apt-get update -y
# strace -p $(ps -ef|grep "pool www" | awk '{print $2}' | grep -v grep | tr '\n' ',' )
# perf record -F 99 -p 2401699 -g -- sleep 30
# perf script > out.perf
# /www/server/dynamic-tracking/FlameGraph/stackcollapse-perf.pl out.perf > out.folded
# /www/server/dynamic-tracking/FlameGraph/flamegraph.pl out.folded > php-zend-flame-graph.svg
# WWW_PID=$(ps -ef|grep "pool www" | awk '{print $2}' | grep -v grep | tr '\n' ',')
# WWW_PID=${WWW_PID//,/}
# WWW_PID=${var%,}
# perf record -F 99 -p "1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1127,1128,1129,1130,1131,1473,1768,2848,2962,21582,35891" \
# -g -- sleep 30
@@ -0,0 +1,21 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
SYS_ARCH=`arch`
# 关于macosx使用dtrace
# https://groups.google.com/g/openresty/c/MswlH_8DDHA
# http://dtrace.org/blogs/brendan/2012/11/14/dtracing-in-anger/
# dtrace -x ustackframes=100 -n 'pid$target::mach_msg_trap:entry { @[ustack()] = count(); } tick-30s { exit(0); }' -p 18572 -o out.SystemUIServer_stacks
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/stackcollapse.pl out.SystemUIServer_stacks > kernel.cbt
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/flamegraph.pl kernel.cbt > kernel.svg
@@ -0,0 +1,11 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
SYS_ARCH=`arch`
+2 -2
View File
@@ -87,7 +87,7 @@ class backupTools:
pid = mw.M('databases').dbPos(db_path, db_name).where(
'name=?', (name,)).getField('id')
mw.M('backup').add('type,name,pid,filename,addtime,size', (1, os.path.basename(
mw.M('backup').add('type,name,pid,filename,addtime,size', (3, os.path.basename(
filename), pid, filename, endDate, os.path.getsize(filename)))
log = "数据库[" + name + "]备份成功,用时[" + str(round(outTime, 2)) + "]秒"
mw.writeLog('计划任务', log)
@@ -97,7 +97,7 @@ class backupTools:
# 清理多余备份
backups = mw.M('backup').where(
'type=? and pid=?', ('1', pid)).field('id,filename').select()
'type=? and pid=?', ('3', pid)).field('id,filename').select()
num = len(backups) - int(count)
if num > 0:
+46 -11
View File
@@ -31,8 +31,13 @@ def getServerDir():
def getInitDFile():
if app_debug:
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
@@ -88,7 +93,7 @@ def checkArgs(data, ck=[]):
def status():
data = mw.execShell(
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
"ps aux|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
@@ -113,8 +118,8 @@ def initDreplace():
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/memcached.service'
systemServiceTpl = getPluginDir() + '/init.d/memcached.service.tpl'
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/memcached.service.tpl'
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$SERVER_PATH}', service_path)
@@ -137,13 +142,20 @@ def initDreplace():
def memOp(method):
file = initDreplace()
if not mw.isAppleSystem():
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell(file + ' ' + method)
if current_os.startswith("freebsd"):
data = mw.execShell('service ' + getPluginName() + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
if data[1] == '':
return 'ok'
return data[1]
@@ -226,9 +238,15 @@ def saveConf():
def initdStatus():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
@@ -238,17 +256,34 @@ def initdStatus():
def initdInstall():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
# freebsd initd install
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
return 'ok'
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
def initdUinstall():
if not app_debug:
if mw.isAppleSystem():
return "Apple Computer does not support"
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
return 'ok'
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
+1 -1
View File
@@ -30,7 +30,7 @@ app_start(){
echo "Starting mongodb server..."
echo $EXEC -f $CONF
$EXEC -f $CONF >> {$SERVER_PATH}/mongodb/logs.pl 2>&1 &
$EXEC -f $CONF >> {$SERVER_PATH}/mongodb/logs.pl 1>&1 2>&1 &
}
app_stop(){
+19 -5
View File
@@ -19,17 +19,31 @@ if [ "$SYS_NAME_LEN" == "1" ];then
SYS_NAME=${SYS_NAME}0
fi
if [ "$SYS_NAME" -gt "82" ];then
SYS_NAME="82"
if [ "$SYS_ARCH" == "aarch64" ];then
if [ "$SYS_NAME" -gt "82" ];then
SYS_NAME="82"
fi
if [ "$SYS_NAME" -lt "62" ];then
SYS_NAME="62"
fi
else
if [ "$SYS_NAME" -gt "80" ];then
SYS_NAME="80"
fi
if [ "$SYS_NAME" -lt "70" ];then
SYS_NAME="70"
fi
fi
if [ "$SYS_NAME" -lt "62" ];then
SYS_NAME="62"
fi
# https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-rhel82-4.4.23.tgz
# https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.23.tgz
# https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-4.4.23.tgz
# https://fastdl.mongodb.org/linux/mongodb-linux-aarch64-rhel82-4.4.23.tgz
# https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-4.4.23.tgz
MG_DIR=$serverPath/source/mongodb
mkdir -p $MG_DIR
+9 -4
View File
@@ -19,12 +19,17 @@ if [ "$SYS_NAME_LEN" == "1" ];then
SYS_NAME=${SYS_NAME}0
fi
if [ "$SYS_NAME" -gt "82" ];then
if [ "$SYS_ARCH" == "aarch64" ];then
SYS_NAME="82"
fi
else
if [ "$SYS_NAME" -lt "70" ];then
SYS_NAME="70"
if [ "$SYS_NAME" -gt "80" ];then
SYS_NAME="80"
fi
if [ "$SYS_NAME" -lt "70" ];then
SYS_NAME="70"
fi
fi
MG_DIR=$serverPath/source/mongodb
+16 -5
View File
@@ -19,12 +19,23 @@ if [ "$SYS_NAME_LEN" == "1" ];then
SYS_NAME=${SYS_NAME}0
fi
if [ "$SYS_NAME" -gt "90" ];then
SYS_NAME="82"
fi
if [ "$SYS_ARCH" == "aarch64" ];then
if [ "$SYS_NAME" -gt "90" ];then
SYS_NAME="90"
fi
if [ "$SYS_NAME" -lt "70" ];then
SYS_NAME="70"
if [ "$SYS_NAME" -lt "82" ];then
SYS_NAME="82"
fi
else
if [ "$SYS_NAME" -gt "90" ];then
SYS_NAME="90"
fi
if [ "$SYS_NAME" -lt "70" ];then
SYS_NAME="70"
fi
fi
MG_DIR=$serverPath/source/mongodb
+16 -5
View File
@@ -19,12 +19,23 @@ if [ "$SYS_NAME_LEN" == "1" ];then
SYS_NAME=${SYS_NAME}0
fi
if [ "$SYS_NAME" -gt "90" ];then
SYS_NAME="82"
fi
if [ "$SYS_ARCH" == "aarch64" ];then
if [ "$SYS_NAME" -gt "90" ];then
SYS_NAME="90"
fi
if [ "$SYS_NAME" -lt "70" ];then
SYS_NAME="70"
if [ "$SYS_NAME" -lt "82" ];then
SYS_NAME="82"
fi
else
if [ "$SYS_NAME" -gt "90" ];then
SYS_NAME="90"
fi
if [ "$SYS_NAME" -lt "70" ];then
SYS_NAME="70"
fi
fi
MG_DIR=$serverPath/source/mongodb
+820
View File
@@ -0,0 +1,820 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import io
sys.path.append(os.getcwd() + "/class/core")
import mw
import oauthlib
import requests
import datetime
from requests_oauthlib import OAuth2Session
DEBUG = False
def setDebug(d=False):
DEBUG = d
class UnauthorizedError(Exception):
pass
class ObjectNotFoundError(Exception):
pass
class msodclient:
plugin_dir = ''
server_dir = ''
credential_file = 'credentials.json'
user_conf = "user.conf"
token_file = 'token.pickle'
def __init__(self, plugin_dir, server_dir):
self.plugin_dir = plugin_dir
self.server_dir = server_dir
self.load()
def setDebug(self, d=False):
DEBUG = d
def load(self):
credential_path = os.path.join(self.plugin_dir, self.credential_file)
credential = json.loads(mw.readFile(credential_path))
# print(credential)
self.credential = credential["onedrive-international"]
self.authorize_url = '{0}{1}'.format(
self.credential['authority'],
self.credential['authorize_endpoint'])
self.token_url = '{0}{1}'.format(
self.credential['authority'],
self.credential['token_endpoint'])
self.token_path = os.path.join(self.server_dir, self.token_file)
self.root_uri = self.credential["api_uri"] + "/me/drive/root"
self.backup_path = 'backup'
def store_token(self, token):
"""存储token"""
enstr = mw.enDoubleCrypt('msodc', json.dumps(token))
mw.writeFile(self.token_path, enstr)
return True
def get_store_token(self):
rdata = mw.readFile(self.token_path)
destr = mw.deDoubleCrypt('msodc', rdata)
return json.loads(destr)
def clear_token(self):
"""清除token记录"""
try:
if os.path.isfile(self.token_path):
os.remove(self.token_path)
except:
if DEBUG:
print("清除token失败。")
def refresh_token(self, origin_token):
"""刷新token"""
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
os.environ['OAUTHLIB_IGNORE_SCOPE_CHANGE'] = '1'
refresh_token = origin_token["refresh_token"]
aad_auth = OAuth2Session(
self.credential["client_id"],
scope=self.credential["scopes"],
redirect_uri=self.credential["redirect_uri"])
new_token = aad_auth.refresh_token(
self.token_url,
refresh_token=refresh_token,
client_id=self.credential["client_id"],
client_secret=self.credential["client_secret"])
return new_token
def get_token_from_authorized_url(self, authorized_url, expected_state=None):
"""通过授权编码获取访问token"""
# 忽略token scope与已请求的scope不一致
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
os.environ['OAUTHLIB_IGNORE_SCOPE_CHANGE'] = '1'
aad_auth = OAuth2Session(self.credential["client_id"],
state=expected_state,
scope=self.credential['scopes'],
redirect_uri=self.credential['redirect_uri'])
token = aad_auth.fetch_token(
self.token_url,
client_secret=self.credential["client_secret"],
authorization_response=authorized_url)
return token
def get_token(self):
token = self.get_store_token()
now = time.time()
expire_time = token["expires_at"] - 300
if now >= expire_time:
new_token = self.refresh_token(token)
self.store_token(new_token)
return new_token
return token
def get_sign_in_url(self):
"""生成签名地址"""
# Initialize the OAuth client
aad_auth = OAuth2Session(self.credential["client_id"],
scope=self.credential['scopes'],
redirect_uri=self.credential['redirect_uri'])
sign_in_url, state = aad_auth.authorization_url(self.authorize_url,
prompt='login')
return sign_in_url, state
def get_authorized_header(self):
token_obj = self.get_token()
token = token_obj["access_token"]
header = {
"Authorization": "Bearer " + token,
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/67.0.3396.99 Safari/537.36'
}
return header
def get_user_from_ms(self):
"""查询用户信息"""
try:
headers = self.get_authorized_header()
user_api_base = self.credential["api_uri"] + "/me"
# select_user_info_uri = self.build_uri(base=user_api_base)
response = requests.get(user_api_base, headers=headers)
if DEBUG:
print("Debug get user:")
print(response.status_code)
print(response.text)
if response.status_code == 200:
response_data = response.json()
user_principal_name = response_data["userPrincipalName"]
return user_principal_name
except oauthlib.oauth2.rfc6749.errors.InvalidGrantError:
self.clear_auth()
if DEBUG:
print("用户授权已过期。")
return None
def clear_auth(self):
self.clear_token()
self.clear_user()
def clear_user(self):
try:
# 清空user
path = os.path.join(self.server_dir, self.user_conf)
if os.path.isfile(path):
os.remove(path)
except:
if DEBUG:
print("清除user失败。")
def store_user(self):
"""更新并存储用户信息"""
user = self.get_user_from_ms()
if user:
path = os.path.join(self.server_dir, self.user_conf)
mw.writeFile(path, user)
else:
raise RuntimeError("无法获取用户信息。")
# --------------------- 文件操作功能 ----------------------
# 取目录路径
def get_path(self, path):
sep = ":"
if path == '/':
path = ''
if path[-1:] == '/':
path = path[:-1]
if path[:1] != "/" and path[:1] != sep:
path = "/" + path
if path == '/':
path = ''
# if path[:1] != sep:
# path = sep + path
try:
from urllib.parse import quote
except:
from urllib import quote
# path = quote(path)
return path.replace('//', '/')
def build_uri(self, path="", operate=None, base=None):
"""构建请求URL
API请求URI格式参考:
https://graph.microsoft.com/v1.0/me/drive/root:/bt_backup/:content
--------------------------------------------- ---------- --------
base path operate
各部分之间用“:”连接。
:param path 子资源路径
:param operate 对文件进行的操作,比如content,children
:return 请求url
"""
if base is None:
base = self.root_uri
path = self.get_path(path)
sep = ":"
if operate:
if operate[:1] != "/":
operate = "/" + operate
if path:
uri = base + sep + path
if operate:
uri += sep + operate
else:
uri = base
if operate:
uri += operate
return uri
def get_list(self, path="/"):
"""获取存储空间中的所有文件对象"""
list_uri = self.build_uri(path, operate="/children")
if DEBUG:
print("List uri:")
print(list_uri)
data = []
response = requests.get(list_uri, headers=self.get_authorized_header())
status_code = response.status_code
if status_code == 200:
if DEBUG:
print("DEBUG:")
print(response.json())
response_data = response.json()
drive_items = response_data["value"]
for item in drive_items:
tmp = {}
tmp['name'] = item["name"]
tmp['size'] = item["size"]
if "folder" in item:
# print("{} is folder:".format(item["name"]))
# print(item["folder"])
tmp["type"] = None
tmp['download'] = ""
if "file" in item:
tmp["type"] = "File"
tmp['download'] = item["@microsoft.graph.downloadUrl"]
# print("{} is file:".format(item["name"]))
# print(item["file"])
formats = ["%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%SZ"]
t = None
for time_format in formats:
try:
t = datetime.datetime.strptime(
item["lastModifiedDateTime"], time_format)
break
except:
continue
t += datetime.timedelta(hours=8)
ts = int(
(time.mktime(t.timetuple()) + t.microsecond / 1000000.0))
tmp['time'] = ts
data.append(tmp)
mlist = {'path': path, 'list': data}
return mlist
def get_object(self, object_name):
"""查询对象信息"""
try:
get_uri = self.build_uri(path=object_name)
if DEBUG:
print("Get uri:")
print(get_uri)
response = requests.get(get_uri,
headers=self.get_authorized_header())
if response.status_code in [200]:
response_data = response.json()
if DEBUG:
print("Object info:")
print(response_data)
return response_data
if response.status_code == 404:
if DEBUG:
print("对象不存在。")
if DEBUG:
print("Get Object debug:")
print(response.status_code)
print(response.text)
except Exception as e:
if DEBUG:
print("Get object has excepiton:")
print(e)
return None
def is_folder(self, obj):
if "folder" in obj:
return True
return False
def delete_object_by_os(self, object_name):
"""删除对象
:param object_name:
:return: True 删除成功
其他 删除失败
"""
obj = self.get_object(object_name)
if obj is None:
if DEBUG:
print("对象不存在,删除操作未执行。")
return True
if self.is_folder(obj):
child_count = obj["folder"]["childCount"]
if child_count > 0:
if DEBUG:
print("文件夹不是空文件夹无法删除。")
return False
headers = self.get_authorized_header()
delete_uri = self.build_uri(object_name)
response = requests.delete(delete_uri, headers=headers)
if response.status_code == 204:
if DEBUG:
print("对象: {} 已被删除。".format(object_name))
return True
return False
def delete_object(self, object_name, retries=2):
"""删除对象
:param object_name:
:param retries: 重试次数,默认2次
:return: True 删除成功
其他 删除失败
"""
try:
return self.delete_object_by_os(object_name)
except Exception as e:
print("删除文件异常:")
print(e)
# 重试
if retries > 0:
print("重新尝试删除文件{}...".format(object_name))
return self.delete_object(
object_name,
retries=retries - 1)
return False
def build_object_name(self, data_type, file_name):
"""根据数据类型构建对象存储名称
:param data_type:
:param file_name:
:return:
"""
import re
prefix_dict = {
"site": "web",
"database": "db",
"path": "path",
}
file_regx = prefix_dict.get(data_type) + "_(.+)_20\d+_\d+(?:\.|_)"
sub_search = re.search(file_regx, file_name)
sub_path_name = ""
if sub_search:
sub_path_name = sub_search.groups()[0]
sub_path_name += '/'
# 构建OS存储路径
object_name = self.backup_path + '/' + \
data_type + '/' + \
sub_path_name + \
file_name
if object_name[:1] == "/":
object_name = object_name[1:]
return object_name
def delete_file(self, file_name, data_type=None):
"""删除文件
根据传入的文件名称和文件数据类型构建对象名称,再删除
:param file_name:
:param data_type: 数据类型 site/database/path
:return: True 删除成功
其他 删除失败
"""
object_name = self.build_object_name(data_type, file_name)
return self.delete_object(object_name)
def create_dir_by_step(self, parent_folder, sub_folder):
create_uri = self.build_uri(path=parent_folder, operate="/children")
if DEBUG:
print("Create dir uri:")
print(create_uri)
post_data = {
"name": sub_folder,
"folder": {"@odata.type": "microsoft.graph.folder"},
"@microsoft.graph.conflictBehavior": "fail"
}
headers = self.get_authorized_header()
headers.update({"Content-type": "application/json"})
response = requests.post(create_uri, headers=headers, json=post_data)
if response.status_code in [201, 409]:
if DEBUG:
if response.status_code == 409:
print("目录:{} 已经存在。".format(sub_folder))
return True
else:
if DEBUG:
print("目录:{} 创建失败:".format(sub_folder))
print(response.status_code)
print(response.text)
return False
def create_dir(self, dir_name):
"""创建远程目录
# API 请求结构
# POST /me/drive/root/children
# or
# POST /me/drive/root:/bt_backup/:/children
# Content - Type: application / json
# {
# "name": "New Folder",
# "folder": {},
# "@microsoft.graph.conflictBehavior": "rename"
# }
# Response: status code == 201 新创建/ 409 已存在
# @microsoft.graph.conflictBehavior: fail/rename/replace
:param dir_name: 目录名称
:param parent_id: 父目录ID
:return: True/False
"""
dir_name = self.get_path(dir_name.strip())
onedrive_business_reserved = r"[\*<>?:|#%]"
if re.search(onedrive_business_reserved, dir_name) \
or dir_name[-1] == "." or dir_name[:1] == "~":
if DEBUG:
print("文件夹名称包含非法字符。")
return False
parent_folder = self.get_path(os.path.split(dir_name)[0])
sub_folder = os.path.split(dir_name)[1]
# print("create_dir:", dir_name)
obj = self.get_object(dir_name)
# 判断对象是否存在
if obj is None:
if not self.create_dir_by_step(parent_folder, sub_folder):
# 兼容OneDrive 商业版文件夹创建
folder_array = dir_name.split("/")
parent_folder = self.get_path(folder_array[0])
for i in range(1, len(folder_array)):
sub_folder = folder_array[i]
if DEBUG:
print("Parent folder: {}".format(parent_folder))
print("Sub folder: {}".format(sub_folder))
if self.create_dir_by_step(parent_folder, sub_folder):
parent_folder += "/" + folder_array[i]
else:
return False
return True
else:
if self.is_folder(obj):
if DEBUG:
print("文件夹已存在。")
return True
def resumable_upload(self,
local_file_name,
object_name=None,
progress_callback=None,
progress_file_name=None,
multipart_threshold=1024 * 1024 * 2,
part_size=1024 * 1024 * 5,
store_dir="/tmp",
auto_cancel=True,
retries=5,
):
"""断点续传
:param local_file_name: 本地文件名称
:param object_name: 指定OS中存储的对象名称
:param part_size: 指定分片上传的每个分片的大小。必须是320*1024的整数倍。
:param multipart_threshold: 文件长度大于该值时,则用分片上传。
:param progress_callback: 进度回调函数,默认是把进度信息输出到标准输出。
:param progress_file_name: 进度信息保存文件,进度格式参见[report_progress]
:param store_dir: 上传分片存储目录, 默认/tmp。
:param auto_cancel: 当备份失败是否自动取消上传记录
:param retries: 上传重试次数
:return: True上传成功/False or None上传失败
"""
try:
file_size_separation_value = 4 * 1024 * 1024
if part_size % 320 != 0:
if DEBUG:
print("Part size 必须是320的整数倍。")
return False
if object_name is None:
temp_file_name = os.path.split(local_file_name)[1]
object_name = os.path.join(self.backup_path, temp_file_name)
# if progress_file_name:
# os.environ[PROGRESS_FILE_NAME] = progress_file_name
# progress_callback = report_progress
print("|-正在上传到 {}...".format(object_name))
dir_name = os.path.split(object_name)[0]
if not self.create_dir(dir_name):
if DEBUG:
print("目录创建失败!")
return False
local_file_size = os.path.getsize(local_file_name)
# if local_file_size < file_size_separation_value:
if False:
# 小文件上传
upload_uri = self.build_uri(path=object_name,
operate="/content")
if DEBUG:
print("Upload uri:")
print(upload_uri)
headers = self.get_authorized_header()
# headers.update({
# "Content-Type": "application/octet-stream"
# })
# files = {"file": (object_name, open(local_file_name, "rb"))}
file_data = open(local_file_name, "rb")
response = requests.put(upload_uri,
headers=headers,
data=file_data)
if DEBUG:
print("status code:")
print(response.status_code)
# print(response.text)
if response.status_code in [201, 200]:
if DEBUG:
print("文件上传成功!")
return True
else:
# 大文件上传
# 1. 创建上传session
create_session_uri = self.build_uri(
path=object_name,
operate="createUploadSession")
headers = self.get_authorized_header()
response = requests.post(create_session_uri, headers=headers)
if response.status_code == 200:
response_data = response.json()
upload_url = response_data["uploadUrl"]
expiration_date_time = response_data["expirationDateTime"]
if DEBUG:
print("上传session已建立。")
print("Upload url: {}".format(upload_url))
print("Expiration datetime: {}".format(
expiration_date_time))
# 2. 分片上传文件
requests.adapters.DEFAULT_RETRIES = 1
session = requests.session()
session.keep_alive = False
# 开始分片上传
import math
parts = int(math.ceil(local_file_size / part_size))
for i in range(parts):
if DEBUG:
if i == parts - 1:
num = "最后"
else:
num = "第{}".format(i + 1)
print("正在上传{}部分...".format(num))
upload_range_start = i * part_size
upload_range_end = min(upload_range_start + part_size,
local_file_size)
content_length = upload_range_end - upload_range_start
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/67.0.3396.99 Safari/537.36'
}
# 开发记录
# Content-Range和标准的http请求头中的Range作用有所不同
# Content-Range是OneDrive自定义的分片上传标识,格式也不一样
headers.update({
"Content-Length": repr(content_length),
"Content-Range": "bytes {}-{}/{}".format(
upload_range_start,
upload_range_end - 1,
local_file_size),
"Content-Type": "application/octet-stream"
})
if DEBUG:
print("Headers:")
print(headers)
'''# TODO 优化read的读取占用内存'''
f = io.open(local_file_name, "rb")
f.seek(upload_range_start)
upload_data = f.read(content_length)
sub_response = session.put(upload_url,
headers=headers,
data=upload_data)
expected_status_code = [200, 201, 202]
if sub_response.status_code in expected_status_code:
if DEBUG:
print("Response status code: {}, "
"bytes {}-{} 已上传成功。".format(
sub_response.status_code,
upload_range_start,
upload_range_end - 1)
)
print(sub_response.text)
if sub_response.status_code in [200, 201]:
if DEBUG:
print("文件 {} 上传成功。".format(object_name))
return True
else:
print(sub_response.status_code)
print(sub_response.text)
_error_msg = "Bytes {}-{} 分片上传失败。".format(
upload_range_start,
upload_range_end
)
if self.error_msg:
self.error_msg += r"\n"
self.error_msg += _error_msg
raise RuntimeError(_error_msg)
time.sleep(0.5)
else:
raise RuntimeError("session创建失败。")
except UnauthorizedError as e:
_error_msg = str(e)
if self.error_msg:
self.error_msg += r"\n"
self.error_msg += _error_msg
print(_error_msg)
return False
except Exception as e:
print("文件上传出现错误:")
print(e)
if self.error_msg:
self.error_msg += r"\n"
self.error_msg += "文件{}上传出现错误:{}".format(object_name, str(e))
try:
if upload_url:
if DEBUG:
print("正在清理上传session.")
session.delete(upload_url)
except:
pass
finally:
try:
f.close()
except:
pass
try:
session.close()
except:
pass
# 重试断点续传
if retries > 0:
print("重试上传文件....")
return self.resumable_upload(
local_file_name,
object_name=object_name,
store_dir=store_dir,
part_size=part_size,
multipart_threshold=multipart_threshold,
progress_callback=progress_callback,
progress_file_name=progress_file_name,
retries=retries - 1,
)
else:
if self.error_msg:
self.error_msg += r"\n"
self.error_msg += "文件{}上传失败。".format(object_name)
return False
def upload_abs_file(self, file_name, remote_dir, *args, **kwargs):
"""按照数据类型上传文件
:param file_name: 上传文件名称
:param data_type: 数据类型 site/database/path
:return: True/False
"""
try:
import re
# 根据数据类型提取子分类名称
# 比如data_type=database,子分类名称是数据库的名称。
# 提取方式是从file_name中利用正则规则去提取。
self.error_msg = ""
file_name = os.path.abspath(file_name)
temp_name = os.path.split(file_name)[1]
object_name = 'backup/' + temp_name
print(file_name)
print(object_name)
return self.resumable_upload(file_name,
object_name=object_name,
*args,
**kwargs)
except Exception as e:
if self.error_msg:
self.error_msg += r"\n"
self.error_msg += "文件上传出现错误:{}".format(str(e))
return False
def upload_file(self, file_name, data_type, *args, **kwargs):
"""按照数据类型上传文件
:param file_name: 上传文件名称
:param data_type: 数据类型 site/database/path
:return: True/False
"""
try:
import re
# 根据数据类型提取子分类名称
# 比如data_type=database,子分类名称是数据库的名称。
# 提取方式是从file_name中利用正则规则去提取。
self.error_msg = ""
if not file_name or not data_type:
_error_msg = "文件参数错误。"
print(_error_msg)
self.error_msg = _error_msg
return False
file_name = os.path.abspath(file_name)
temp_name = os.path.split(file_name)[1]
object_name = self.build_object_name(data_type, temp_name)
# dir_name = os.path.dirname(object_name)
# self.create_dir(dir_name)
if DEBUG:
print(file_name)
print(object_name)
print(dir_name)
return self.resumable_upload(file_name,
object_name=object_name,
*args,
**kwargs)
except Exception as e:
if self.error_msg:
self.error_msg += r"\n"
self.error_msg += "文件上传出现错误:{}".format(str(e))
return False
+12
View File
@@ -0,0 +1,12 @@
{
"onedrive-international": {
"client_id": "08125e6b-6502-4ac9-9548-ad682f00848d",
"client_secret": "0WA8Q~sZkZFZKv50ryP4ux~.fpVtbHw7BuTZmbQB",
"authority": "https://login.microsoftonline.com/common",
"token_endpoint": "/oauth2/v2.0/token",
"authorize_endpoint": "/oauth2/v2.0/authorize",
"scopes": "offline_access Files.ReadWrite.All User.Read",
"redirect_uri": "http://localhost",
"api_uri": "https://graph.microsoft.com/v1.0"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+311
View File
@@ -0,0 +1,311 @@
<style>
.upyunCon {
height: 428px;
}
.up-place {
height: 62px;
border-bottom: 1px solid #ddd;
}
.up-place .btn {
border-radius: 0;
}
.up-place .place-input {
background-color: #f3f3f3;
border: 1px solid #ccc;
height: 30px;
line-height: 28px;
overflow: hidden;
margin: 1px 0 0 -1px;
width: 340px;
}
.place-input ul {
display: inline-block;
position: relative;
width: auto;
}
.place-input ul li {
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
float: left;
padding-left: 10px;
padding-right: 18px;
}
.place-input ul li a {
height: 28px;
cursor: pointer;
display: inline-block;
}
.upyunlist {
height: 516px;
overflow: auto;
}
.up-bottom {
background-color: #fafafa;
border-top: 1px solid #eee;
bottom: 0;
position: absolute;
width: 100%;
}
.up-use {
line-height: 50px
}
.list-list .cursor span {
line-height: 30px;
}
.btn-title {
margin-top: 1px
}
.tip {
font-size: 10px;
font-style: oblique;
color: green;
}
</style>
<div class="upyunCon">
<div class="up-place pd15">
<button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退"></button>
<input id="myPath" style="display:none;" type="text" value="">
<div class="place-input pull-left">
<div style="width:1400px;height:28px"><ul></ul></div>
</div>
<button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" style="margin-left:-1px;"></button>
<button class="btn btn-default btn-sm pull-right btn-title" onclick="authApi()">授权</button>
<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="createDir()">新建文件夹</button>
</div>
<div class="upyunlist pd15">
<div class="divtable" style="margin-bottom:15px">
<table class="table table-hover">
<thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>
<tbody class="list-list"></tbody>
</table>
</div>
</div>
</div>
<style type="text/css">
.check_api {
padding: 20px;
}
.up-place {
height: 62px;
border-bottom: 1px solid #ddd;
}
.up-place .btn {
border-radius: 0;
}
.up-place .place-input {
background-color: #f3f3f3;
border: 1px solid #ccc;
height: 30px;
line-height: 28px;
overflow: hidden;
margin: 1px 0 0 -1px;
width: 340px;
}
.place-input ul {
display: inline-block;
position: relative;
width: auto;
}
.place-input ul li {
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
float: left;
padding-left: 10px;
padding-right: 18px;
}
.place-input ul li a {
height: 28px;
cursor: pointer;
display: inline-block;
}
.upyunlist {
height: 546px;
overflow: auto;
}
.up-bottom {
background-color: #fafafa;
border-top: 1px solid #eee;
bottom: 0;
position: absolute;
width: 100%;
}
.up-use {
line-height: 50px
}
.list-list .cursor span {
line-height: 30px;
}
.btn-title {
margin-top: 1px
}
.step_item{
clear: both;
}
.step_item .serial_box{
display: inline-block;
clear: both;
}
.step_item .serial{
width: 70px;
height: 30px;
line-height: 30px;
text-align: center;
display: inline-block;
float: left;
}
.step_item .serial span{
display: inline-block;
width: 30px;
height: 30px;
text-align: center;
line-height: 28px;
font-size: 11px;
border-radius: 50%;
color: #20a53a;
border: 2px solid #20a53a;
}
.step_item .serial_title{
margin-bottom: 10px;
font-size: 15px;
line-height: 30px;
color: #666;
}
.step_two_url{
display: inline-block;
overflow: hidden;
width: 380px;
/*text-overflow: ellipsis;*/
white-space: nowrap;
height: 35px;
line-height: 35px;
margin-right: 15px;
border-radius: 2px;
padding: 0 10px;
float: left;
width:360px;
padding-right: 35px;
}
.btn_btlink{
display: inline-block;
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid #20a53a;
color: #fff;
background-color: #20a53a;
margin-right:10px;
}
.btn_btlink:hover{
color: #fff;
background-color: #10952a;
border-color: #398439;
}
.btn_btlink a:visited{
color: #fff;
background-color: #10952a;
border-color: #398439;
}
.view_video{
margin-bottom: 10px;
}
.view_video ul li{
line-height: 20px;
font-size: 13px;
}
.setp_one i{
position: absolute;
top: 8px;
left: 25px;
width: 30px;
height: 30px;
}
.OneDrive{
width:465px;
height:100px;
margin-bottom:10px;
}
</style>
<script type="text/html" id="check_api">
<div class="check_api">
<div class="step_two">
<div class="step_item">
<div class="serial"><span>1</span></div>
<div class="serial_box">
<div class="serial_title">阅读简易操作教程:如何获取Microsoft OneDrive授权?</div>
<div class="serial_conter">
<div class="view_video">
<ul>
<li>1. 点击下面第<div class="serial" style="float: none;width: 45px;"><span>2</span></div>步中的 打开授权链接。<li>
<li>2. 在新窗口页面上登录Microsoft账号。阅读授权权限,并同意。<li>
<li>3. 页面跳转后,将浏览器的地址栏地址复制到第<div class="serial" style="float: none;width: 45px;"><span>3</span></div>步的文本框中。<li>
<li>4. 点击 获取授权,随即完成授权。<li>
</ul>
</div>
<hr/>
</div>
</div>
</div>
<div class="step_item pb15">
<div class="serial"><span>2</span></div>
<div class="serial_box">
<div class="serial_title">操作1:👇打开授权链接,根据网页提示对插件进行授权。</div>
<div class="serial_conter step_two" style="width: 500px;">
<input class="bt-input-text mr5 step_two_url" type="text" disabled>
<span class="ico-copy mr10" data-copy="" style="vertical-align: middle;cursor: pointer;margin-left: -37px;margin-right: 20px;"></span>
<a href="" class="btn_btlink open_btlink" target="_blank" style="padding: 7px 10px;">打开授权链接</a>
</div>
</div>
</div>
<div class="step_item">
<div class="serial"><span>3</span></div>
<div class="serial_box">
<div class="serial_title">操作2:复制回浏览器跳转后的地址:</div>
<div class="serial_conter">
<textarea row="3" placeholder="验证URL地址" class="bt-input-text OneDrive" style="resize: none;"/></br>
<button type="button" class="btn btn-success btn-sm set_auth_btn">获取授权</button>
</div>
</div>
</div>
</div>
</div>
</script>
<script type="text/javascript" src="/plugins/file?name=msonedrive&f=js/msonedrive.js"></script>
<script type="text/javascript">
$.getScript( "/plugins/file?name=msonedrive&f=js/msonedrive.js", function(){
odList('/');
});
</script>
+351
View File
@@ -0,0 +1,351 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
# print(sys.platform)
if sys.platform != "darwin":
os.chdir("/www/server/mdserver-web")
sys.path.append(os.getcwd() + "/class/core")
import mw
import db
_ver = sys.version_info
is_py2 = (_ver[0] == 2)
is_py3 = (_ver[0] == 3)
DEBUG = False
if is_py2:
reload(sys)
sys.setdefaultencoding('utf-8')
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'msonedrive'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def in_array(name, arr=[]):
for x in arr:
if name == x:
return True
return False
sys.path.append(getPluginDir() + "/class")
from msodclient import msodclient
msodc = msodclient(getPluginDir(), getServerDir())
msodc.setDebug(False)
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def status():
return 'start'
def isAuthApi():
cfg = getServerDir() + "/user.conf"
if os.path.exists(cfg):
return True
return False
def getConf():
if not isAuthApi():
sign_in_url, state = msodc.get_sign_in_url()
return mw.returnJson(False, "未授权!", {'auth_url': sign_in_url})
return mw.returnJson(True, "OK")
def setAuthUrl():
args = getArgs()
data = checkArgs(args, ['url'])
if not data[0]:
return data[1]
url = args['url']
try:
if url.startswith("http://"):
url = url.replace("http://", "https://")
token = msodc.get_token_from_authorized_url(authorized_url=url)
msodc.store_token(token)
msodc.store_user()
return mw.returnJson(True, "授权成功!")
except Exception as e:
return mw.returnJson(False, "授权失败2!:" + str(e))
return mw.returnJson(False, "授权失败!:" + str(e))
def clearAuth():
cfg = getServerDir() + "/user.conf"
if os.path.exists(cfg):
os.remove(cfg)
token = getServerDir() + "/token.pickle"
if os.path.exists(token):
os.remove(token)
return mw.returnJson(True, "清空授权成功!")
def getList():
cfg = getServerDir() + "/user.conf"
if not os.path.exists(cfg):
return mw.returnJson(False, "未配置,请点击`授权`", [])
args = getArgs()
data = checkArgs(args, ['path'])
if not data[0]:
return data[1]
try:
flist = msodc.get_list(args['path'])
return mw.returnJson(True, "ok", flist)
except Exception as e:
return mw.returnJson(False, str(e), [])
def createDir():
cfg = getServerDir() + "/user.conf"
if not os.path.exists(cfg):
return mw.returnJson(False, "未配置OneDrive,请点击`授权`", [])
args = getArgs()
data = checkArgs(args, ['path', 'name'])
if not data[0]:
return data[1]
file = args['path'] + "/" + args['name']
isok = msodc.create_dir(file)
if isok:
return mw.returnJson(True, "创建成功")
return mw.returnJson(False, "创建失败")
def deleteDir():
args = getArgs()
data = checkArgs(args, ['dir_name', 'path'])
if not data[0]:
return data[1]
file = args['path'] + "/" + args['dir_name']
file = file.strip('/')
isok = msodc.delete_object(file)
if isok:
return mw.returnJson(True, "删除成功")
return mw.returnJson(False, "文件不为空,删除失败!")
def deleteFile():
args = getArgs()
data = checkArgs(args, ['path', 'filename'])
if not data[0]:
return data[1]
file = args['path'] + "/" + args['filename']
file = file.strip('/')
isok = msodc.delete_object(file)
if isok:
return mw.returnJson(True, "删除成功")
return mw.returnJson(False, "删除失败")
def findPathName(path, filename):
f = os.scandir(path)
l = []
for ff in f:
t = {}
if ff.name.find(filename) > -1:
t['filename'] = path + '/' + ff.name
l.append(t)
return l
def backupAllFunc(stype):
if not isAuthApi():
mw.echoInfo("未授权API,无法使用!!!")
return ''
os.chdir(mw.getRunDir())
backup_dir = mw.getBackupDir()
run_dir = mw.getRunDir()
stype = sys.argv[1]
name = sys.argv[2]
num = sys.argv[3]
prefix_dict = {
"site": "web",
"database": "db",
"path": "path",
}
backups = []
sql = db.Sql()
# print("stype:", stype)
# 提前获取-清理多余备份
if stype == 'site':
pid = sql.table('sites').where('name=?', (name,)).getField('id')
backups = sql.table('backup').where(
'type=? and pid=?', ('0', pid)).field('id,filename').select()
if stype == 'database':
db_path = mw.getServerDir() + '/mysql'
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
'name=?', (name,)).getField('id')
backups = sql.table('backup').where(
'type=? and pid=?', ('1', pid)).field('id,filename').select()
if stype == 'path':
backup_path = backup_dir + '/path'
_name = 'path_{}'.format(os.path.basename(name))
backups = findPathName(backup_path, _name)
# 其他类型关系性数据库(mysql类的)
if stype.find('database_') > -1:
plugin_name = stype.replace('database_', '')
db_path = mw.getServerDir() + '/' + plugin_name
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
'name=?', (name,)).getField('id')
backups = sql.table('backup').where(
'type=? and pid=?', ('1', pid)).field('id,filename').select()
args = stype + " " + name + " " + num
cmd = 'python3 ' + run_dir + '/scripts/backup.py ' + args
if stype.find('database_') > -1:
plugin_name = stype.replace('database_', '')
args = "database " + name + " " + num
cmd = 'python3 ' + run_dir + '/plugins/' + \
plugin_name + '/scripts/backup.py ' + args
if stype == 'path':
name = os.path.basename(name)
# print("cmd:", cmd)
os.system(cmd)
# 开始执行上传信息.
if stype.find('database_') > -1:
bk_name = 'database'
plugin_name = stype.replace('database_', '')
bk_prefix = plugin_name + '/db'
stype = 'database'
else:
bk_prefix = prefix_dict[stype]
bk_name = stype
find_path = backup_dir + '/' + bk_name + '/' + bk_prefix + '_' + name
find_new_file = "ls " + find_path + \
"_* | grep '.gz' | cut -d \ -f 1 | awk 'END {print}'"
# print(find_new_file)
filename = mw.execShell(find_new_file)[0].strip()
if filename == "":
mw.echoInfo("not find upload file!")
return False
mw.echoInfo("准备上传文件 {}".format(filename))
mw.echoStart('开始上传')
msodc.upload_file(filename, stype)
mw.echoEnd('上传成功')
# print(backups)
backups = sorted(backups, key=lambda x: x['filename'], reverse=False)
mw.echoStart('开始删除远程备份')
num = int(num)
sep = len(backups) - num
if sep > -1:
for backup in backups:
fn = os.path.basename(backup['filename'])
msodc.delete_file(fn, stype)
mw.echoInfo("---已清理远程过期备份文件:" + fn)
sep -= 1
if sep < 0:
break
mw.echoEnd('结束删除远程备份')
return ''
def installPreInspection():
return 'ok'
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'install_pre_inspection':
print(installPreInspection())
elif func == 'conf':
print(getConf())
elif func == 'set_auth_url':
print(setAuthUrl())
elif func == 'clear_auth':
print(clearAuth())
elif func == "get_list":
print(getList())
elif func == "create_dir":
print(createDir())
elif func == "delete_dir":
print(deleteDir())
elif func == 'delete_file':
print(deleteFile())
elif in_array(func, ['site', 'database', 'path']) or func.find('database_') > -1:
print(backupAllFunc(func))
else:
print('error')
+14
View File
@@ -0,0 +1,14 @@
{
"hook":["backup"],
"title": "OneDrive",
"tip": "lib",
"name": "msonedrive",
"type": "sort",
"ps": "微软家的云网盘服务。",
"versions": "1.0",
"shell": "install.sh",
"checks": "server/msonedrive",
"author": "midoks",
"date": "2023-8-18",
"pid": "4"
}
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
PATH=/www/server/panel/pyenv/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
Install_App()
{
pip install requests-oauthlib==1.3.0
mkdir -p $serverPath/msonedrive
echo '正在安装脚本文件...' > $install_tmp
echo "${VERSION}" > $serverPath/msonedrive/version.pl
echo '安装完成' > $install_tmp
echo "Successify"
}
Uninstall_App()
{
rm -rf $serverPath/msonedrive
}
if [ "${1}" == 'install' ];then
Install_App
elif [ "${1}" == 'uninstall' ];then
Uninstall_App
else
echo 'Error!';
fi
+258
View File
@@ -0,0 +1,258 @@
function msodPost(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'msonedrive', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function createDir(){
layer.open({
type: 1,
area: "400px",
title: "创建目录",
closeBtn: 1,
shift: 5,
shadeClose: false,
btn: ['确定','取消'],
content:'<div class="bingfa bt-form c6" style="padding-bottom: 10px;">\
<p>\
<span class="span_tit">目录名称:</span>\
<input style="width: 200px;" type="text" name="newPath" value="">\
</p>\
</div>',
success:function(){
$("input[name='newPath']").focus().keyup(function(e){
if(e.keyCode == 13) $(".layui-layer-btn0").click();
});
},
yes:function(index,layero){
var name = $("input[name='newPath']").val();
if(name == ''){
layer.msg('目录名称不能为空!',{icon:2});
return;
}
var path = $("#myPath").val();
var dirname = name;
var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
msodPost('create_dir', {path:path,name:dirname}, function(data){
layer.close(loadT);
var rdata = $.parseJSON(data.data);
if(rdata.status) {
showMsg(rdata.msg, function(){
layer.close(index);
odList(path);
} ,{icon:1}, 2000);
} else{
layer.msg(rdata.msg,{icon:2});
}
});
}
});
}
//设置API
function authApi(){
msodPost('conf', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
// console.log(rdata);
// console.log(rdata.data.auth_url);
var apicon = '';
if (rdata.status){
var html = '';
html += '<button id="clear_auth" onclick="clearAuth();" class="btn btn-default btn-sm">清空配置</button>';
var loadOpen = layer.open({
type: 1,
title: '已授权',
area: '240px',
content:'<div class="change-default pd20">'+html+'</div>',
success: function(){
$('#clear_auth').click(function(){
msodPost('clear_auth', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
layer.close(loadOpen);
odList('/');
},{icon:rdata.status?1:2},2000);
});
});
}
});
return true;
} else{
apicon = '<div class="new_form">'+$("#check_api").html()+'</div>';
}
var layer_auth = layer.open({
type: 1,
area: "620px",
title: "OneDrive授权",
closeBtn: 1,
shift: 5,
shadeClose: false,
content:apicon,
success:function(layero,index){
// console.log(layero,index);
if (!rdata.status){
$('.check_api .step_two_url').val(rdata.data['auth_url']);
$('.check_api .open_btlink').attr('href',rdata.data['auth_url']);
$('.check_api .ico-copy').click(function(){
copyPass(rdata.data['auth_url']);
});
$('.check_api .set_auth_btn').click(function(){
var url = $('.check_api .OneDrive').val();
if ( url == ''){
layer.msg("验证URL不能为空",{icon:2});
return;
}
// console.log(url);
msodPost('set_auth_url', {url:url}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var show_time = 2000;
if (!rdata.status){
show_time = 10000;
}
showMsg(rdata.msg,function(){
if (rdata.status){
layer.close(layer_auth);
odList('/');
}
},{icon:rdata.status?1:2},show_time);
});
});
}
}
});
});
}
//计算当前目录偏移
function upPathLeft(){
var UlWidth = $(".place-input ul").width();
var SpanPathWidth = $(".place-input").width() - 20;
var Ml = UlWidth - SpanPathWidth;
if(UlWidth > SpanPathWidth ){
$(".place-input ul").css("left",-Ml)
}
else{
$(".place-input ul").css("left",0)
}
}
function odList(path){
msodPost('get_list', {path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
if(rdata.status === false){
showMsg(rdata.msg,function(){
authApi();
},{icon:2},2000);
return;
}
var mlist = rdata.data;
var listBody = ''
var listFiles = ''
for(var i=0;i<mlist.list.length;i++){
if(mlist.list[i].type == null){
listBody += '<tr><td class="cursor" onclick="odList(\''+(path+'/'+mlist.list[i].name).replace('//','/')+'\')"><span class="ico ico-folder"></span>\<span>'+mlist.list[i].name+'</span></td>\
<td>-</td>\
<td>-</td>\
<td class="text-right"><a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', true)">删除</a></td></tr>'
}else{
listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span>\<span>'+mlist.list[i].name+'</span></td>\
<td>'+toSize(mlist.list[i].size)+'</td>\
<td>'+getLocalTime(mlist.list[i].time)+'</td>\
<td class="text-right"><a target="_blank" href="'+mlist.list[i].download+'" class="btlink">下载</a> | <a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', false)">删除</a></td></tr>'
}
}
listBody += listFiles;
var pathLi='';
var tmp = path.split('/')
var pathname = '';
var n = 0;
for(var i=0;i<tmp.length;i++){
if(n > 0 && tmp[i] == '') continue;
var dirname = tmp[i];
if(dirname == '') {
dirname = '根目录';
n++;
}
pathname += '/' + tmp[i];
pathname = pathname.replace('//','/');
pathLi += '<li><a title="'+pathname+'" onclick="osList(\''+pathname+'\')">'+dirname+'</a></li>';
}
var um = 1;
if(tmp[tmp.length-1] == '') um = 2;
var backPath = tmp.slice(0,tmp.length-um).join('/') || '/';
$('#myPath').val(path);
$(".upyunCon .place-input ul").html(pathLi);
$(".upyunlist .list-list").html(listBody);
upPathLeft();
$('#backBtn').unbind().click(function() {
odList(backPath);
});
$('.upyunCon .refreshBtn').unbind().click(function(){
odList(path);
});
});
}
//删除文件
function deleteFile(name, is_dir){
if (is_dir === false){
safeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
var path = $("#myPath").val();
var filename = name;
msodPost('delete_file', {filename:filename,path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
odList(path);
},{icon:rdata.status?1:2},2000);
});
});
} else {
safeMessage('删除文件夹','删除后将无法恢复,真的要删除['+name+']吗?',function(){
var path = $("#myPath").val();
msodPost('delete_dir', {dir_name:name,path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
odList(path);
},{icon:rdata.status?1:2},2000);
});
});
}
}
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/python
# coding: utf-8
# python3 plugins/msonedrive/t/test.py
# https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/08125e6b-6502-4ac9-9548-ad682f00848d/objectId/62b1d655-9828-47ed-be99-65eb18c3a929/isMSAApp~/false/defaultBlade/Overview/appSignInAudience/AzureADandPersonalMicrosoftAccount/servicePrincipalCreated~/true
# 0WA8Q~sZkZFZKv50ryP4ux~.fpVtbHw7BuTZmbQB
# client_id:d9878fac-8526-4ff6-8036-e1c92dd9dd80
# 08125e6b-6502-4ac9-9548-ad682f00848d
# https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code&client_id=d9878fac-8526-4ff6-8036-e1c92dd9dd80&redirect_uri=http://localhost&scope=offline_access+Files.ReadWrite.All+User.Read&state=cwopMdHiPIkze4MvgFL6WfSl8LdYAl&prompt=login
# http://localhost/?code=M.C106_BAY.2.3e12c859-6107-0c5b-9ef4-14b3fb8269ba&state=JzHdzHXmA7x6zl7Be6cJ6uOlf9Bg69
# python3 /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/msonedrive/index.py site t1.cn 3
# python3 /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/msonedrive/index.py database t1 3
# python3
# /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/msonedrive/index.py
# path /Users/midoks/Desktop/dev/python 3
import sys
import io
import os
import time
import re
import json
from requests_oauthlib import OAuth2Session
sys.path.append(os.getcwd() + "/class/core")
import mw
def getPluginName():
return 'msonedrive'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
sys.path.append(getPluginDir() + "/class")
from msodclient import msodclient
msodclient.setDebug(True)
msodc = msodclient(getPluginDir(), getServerDir())
# sign_in_url, state = msodc.get_sign_in_url()
# print(sign_in_url)
def set_auth_url(url):
try:
if url.startswith("http://"):
url = url.replace("http://", "https://")
token = msodc.get_token_from_authorized_url(
authorized_url=url)
msodc.store_token(token)
msodc.store_user()
return mw.returnJson(True, "授权成功!")
except Exception as e:
print(e)
return mw.returnJson(False, "授权失败2!:" + str(e))
return mw.returnJson(False, "授权失败!:" + str(e))
# url = 'http://localhost/?code=M.C106_BAY.2.310112f3-a158-c400-9667-d158cbd1de6c&state=jEJz0ucR9bpZYD9PGxp2GgRDotrzO6'
# token = set_auth_url(url)
# print(token)
# token = msodc.get_token()
# print("token:", token)
# t = msodc.get_list('/backup')
# print(t)
# t = msodc.create_dir('backup')
# print(t)
# t = msodc.delete_object('backup')
# print(t)
t = msodc.upload_file('web_t1.cn_20230830_134549.tar.gz', 'site')
print(t)
# print(msodc.error_msg)
# /Users/midoks/Desktop/mwdev/server/mdserver-web/paramiko.log
# backup/site/paramiko.log
# |-正在上传到 backup/site/paramiko.log...
# True
# t = msodc.upload_abs_file(
# 'web_t1.cn_20230830_134549.tar.gz', 'site')
# print(t)
# print(msodc.error_msg)
+9 -38
View File
@@ -55,19 +55,20 @@ def is_number(s):
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
@@ -2195,40 +2196,10 @@ def updateSlaveSSH(version=''):
def getSlaveList(version=''):
db = pMysqlDb()
dlist = db.query('show slave status')
ret = []
for x in range(0, len(dlist)):
tmp = {}
tmp['Master_User'] = dlist[x]["Master_User"]
tmp['Master_Host'] = dlist[x]["Master_Host"]
tmp['Master_Port'] = dlist[x]["Master_Port"]
tmp['Master_Log_File'] = dlist[x]["Master_Log_File"]
tmp['Slave_IO_Running'] = dlist[x]["Slave_IO_Running"]
tmp['Slave_SQL_Running'] = dlist[x]["Slave_SQL_Running"]
tmp['Last_Error'] = dlist[x]["Last_Error"]
tmp['Last_IO_Error'] = dlist[x]["Last_IO_Error"]
tmp['Last_SQL_Error'] = dlist[x]["Last_SQL_Error"]
tmp['Slave_SQL_Running_State'] = dlist[x]["Slave_SQL_Running_State"]
tmp['Error'] = ''
if tmp['Last_Error'] != '':
tmp['Error'] = tmp['Last_Error']
if tmp['Last_IO_Error'] != '':
tmp['Error'] = tmp['Last_IO_Error']
if tmp['Last_SQL_Error'] != '':
tmp['Error'] = tmp['Last_SQL_Error']
if tmp['Error'] == '':
tmp['Error'] = tmp['Slave_SQL_Running_State']
ret.append(tmp)
data = {}
data['data'] = ret
data['data'] = dlist
return mw.getJson(data)
@@ -2751,8 +2722,8 @@ def installPreInspection(version):
if not sysName in ('debian', 'ubuntu'):
return '仅支持debian,ubuntu'
if (sysName == 'debian' and not sysId in('11', '10')):
return 'debian支持10,11'
if (sysName == 'debian' and not sysId in('12', '11', '10')):
return 'debian支持10,11,12'
if (sysName == 'ubuntu' and version == '5.7' and not sysId in ('18.04')):
return "Ubuntu Apt MySQL[" + version + "] 仅支持18.04"
+6 -5
View File
@@ -46,19 +46,20 @@ def getServerDir():
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
+56 -6
View File
@@ -45,8 +45,12 @@ def getServerDir():
def getInitDFile():
if app_debug:
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
@@ -524,12 +528,26 @@ def initMysql8Pwd():
def myOp(version, method):
# import commands
init_file = initDreplace(version)
current_os = mw.getOs()
try:
isInited = initMysqlData()
if not isInited:
mw.execShell('systemctl start mysql')
if current_os.startswith("freebsd"):
mw.execShell('service ' + getPluginName() + ' start')
else:
mw.execShell('systemctl start mysql')
initMysqlPwd()
mw.execShell('systemctl stop mysql')
if current_os.startswith("freebsd"):
mw.execShell('service ' + getPluginName() + ' stop')
else:
mw.execShell('systemctl stop mysql')
if current_os.startswith("freebsd"):
data = mw.execShell('service ' + getPluginName() + ' ' + method)
return 'ok'
mw.execShell('systemctl ' + method + ' mysql')
return 'ok'
@@ -610,9 +628,15 @@ def reload(version=''):
def initdStatus():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status mysql | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
@@ -621,17 +645,34 @@ def initdStatus():
def initdInstall():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
return 'ok'
mw.execShell('systemctl enable mysql')
return 'ok'
def initdUinstall():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
return 'ok'
mw.execShell('systemctl disable mysql')
return 'ok'
@@ -748,6 +789,9 @@ def runInfo(version):
def myDbStatus(version):
if status(version) == 'stop':
return mw.returnJson(False, 'MySQL未启动', [])
result = {}
db = pMysqlDb()
data = db.query('show variables')
@@ -2368,6 +2412,9 @@ def updateSlaveSSH(version=''):
def getSlaveList(version=''):
if status(version) == 'stop':
return mw.returnJson(False, 'MySQL未启动', [])
db = pMysqlDb()
dlist = db.query('show slave status')
data = {}
@@ -2383,6 +2430,9 @@ def getSlaveSyncCmd(version=''):
def initSlaveStatus(version=''):
if status(version) == 'stop':
return mw.returnJson(False, 'MySQL未启动', [])
mode_file = getSyncModeFile()
if not os.path.exists(mode_file):
return mw.returnJson(False, '需要先设置同步配置')
+11 -2
View File
@@ -66,6 +66,15 @@ Install_mysql()
cd ${mysqlDir} && tar -zxvf ${mysqlDir}/mysql-5.5.62.tar.gz
fi
WHERE_DIR_GCC=/usr/bin/gcc
WHERE_DIR_GPP=/usr/bin/g++
if [ ! -f $WHERE_DIR_GCC ];then
WHERE_DIR_GCC=`which gcc`
fi
if [ ! -f $WHERE_DIR_GPP ];then
WHERE_DIR_GPP=`which g++`
fi
if [ ! -d $serverPath/mysql ];then
cd ${mysqlDir}/mysql-5.5.62 && cmake \
@@ -81,8 +90,8 @@ Install_mysql()
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DCMAKE_C_COMPILER=/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/g++
-DCMAKE_C_COMPILER=$WHERE_DIR_GCC \
-DCMAKE_CXX_COMPILER=$WHERE_DIR_GPP
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mysql ];then
+3 -3
View File
@@ -76,9 +76,9 @@ Install_mysql()
OPENSSL_VERSION=`openssl version|awk '{print $2}'|awk -F '.' '{print $1}'`
if [ "${OPENSSL_VERSION}" -ge "3" ];then
#openssl version to high
cd ${rootPath}/plugins/php/lib && /bin/bash openssl.sh
export PKG_CONFIG_PATH=$serverPath/lib/openssl/lib/pkgconfig
OPTIONS="-DWITH_SSL=${serverPath}/lib/openssl"
cd ${rootPath}/plugins/php/lib && /bin/bash openssl10.sh
export PKG_CONFIG_PATH=$serverPath/lib/openssl10/lib/pkgconfig
OPTIONS="-DWITH_SSL=${serverPath}/lib/openssl10"
fi
if [ ! -d $serverPath/mysql ];then
+3 -3
View File
@@ -91,9 +91,9 @@ Install_mysql()
OPENSSL_VERSION=`openssl version|awk '{print $2}'|awk -F '.' '{print $1}'`
if [ "${OPENSSL_VERSION}" -ge "3" ];then
#openssl version to high
cd ${rootPath}/plugins/php/lib && /bin/bash openssl.sh
export PKG_CONFIG_PATH=$serverPath/lib/openssl/lib/pkgconfig
OPTIONS="-DWITH_SSL=${serverPath}/lib/openssl"
cd ${rootPath}/plugins/php/lib && /bin/bash openssl_11.sh
export PKG_CONFIG_PATH=$serverPath/lib/openssl11/lib/pkgconfig
OPTIONS="-DWITH_SSL=${serverPath}/lib/openssl11"
fi
if [ ! -d $serverPath/mysql ];then
+5 -5
View File
@@ -1434,13 +1434,13 @@ def testRun():
# if not data[0]:
# return data[1]
conf_json = getServerDir() + "/waf/default.json"
data = mw.readFile(conf_json)
pdata = json.loads(data)
default_site = pdata['default']
default_path = getServerDir() + "/waf/default.pl"
default_site = mw.readFile(default_path)
url = "http://" + default_site + '/?t=../etc/passwd'
returnData = mw.httpGet(url, 10)
# url = "https://" + default_site + '/?t=../etc/passwd'
# returnData = mw.httpGet(url, 3)
return mw.returnJson(True, '测试运行成功!', returnData)
+1 -1
View File
@@ -484,7 +484,7 @@ function scanRule() {
var tmp = $.parseJSON(data.data);
var rdata = $.parseJSON(tmp.data);
create_l = ({
create_l = layer.open({
type: 1,
title: "常用扫描器过滤规则",
area: '650px',
+8 -6
View File
@@ -309,14 +309,16 @@ local function is_open_waf_cc_increase()
end
-- C:D("waf config:"..json.encode(config))
if cpu_percent >= config['safe_verify']['cpu'] then
return true
end
if site_config[server_name] and site_config[server_name]['safe_verify']['open'] then
if cpu_percent >= site_config[server_name]['safe_verify']['cpu'] then
if config['safe_verify']['auto'] then
if cpu_percent >= config['safe_verify']['cpu'] then
return true
end
if site_config[server_name] and site_config[server_name]['safe_verify']['open'] then
if cpu_percent >= site_config[server_name]['safe_verify']['cpu'] then
return true
end
end
end
return false
+69 -18
View File
@@ -11,9 +11,7 @@ import re
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
@@ -31,8 +29,13 @@ def getServerDir():
def getInitDFile():
if app_debug:
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
@@ -95,6 +98,14 @@ def getInitDTpl():
return path
def getPidFile():
file = getConf()
content = mw.readFile(file)
rep = 'pid\s*(.*);'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getFileOwner(filename):
import pwd
stat = os.lstat(filename)
@@ -118,13 +129,16 @@ def confReplace():
user = 'www'
user_group = 'www'
if mw.getOs() == 'darwin':
current_os = mw.getOs()
if current_os == 'darwin':
# macosx do
user = mw.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
# user = 'root'
user_group = 'staff'
content = content.replace('{$EVENT_MODEL}', 'kqueue')
elif current_os.startswith('freebsd'):
content = content.replace('{$EVENT_MODEL}', 'kqueue')
else:
content = content.replace('{$EVENT_MODEL}', 'epoll')
@@ -222,8 +236,8 @@ def initDreplace():
# /usr/lib/systemd/system
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/openresty.service'
systemServiceTpl = getPluginDir() + '/init.d/openresty.service.tpl'
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/openresty.service.tpl'
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(systemService, se_content)
@@ -233,9 +247,8 @@ def initDreplace():
def status():
data = mw.execShell(
"ps -ef|grep openresty |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
pid_file = getPidFile()
if not os.path.exists(pid_file):
return 'stop'
return 'start'
@@ -249,20 +262,33 @@ def restyOp(method):
if not check_data[1].find('test is successful') > -1:
return check_data[1]
if not mw.isAppleSystem():
data = mw.execShell('systemctl ' + method + ' openresty')
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell(file + ' ' + method)
if current_os.startswith("freebsd"):
data = mw.execShell('service openresty ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell('systemctl ' + method + ' openresty')
if data[1] == '':
return 'ok'
return data[1]
def op_submit_systemctl_restart():
current_os = mw.getOs()
if current_os.startswith("freebsd"):
mw.execShell('service openresty restart')
return True
mw.execShell('systemctl restart openresty')
return True
def op_submit_init_restart(file):
@@ -280,11 +306,9 @@ def restyOp_restart():
if not mw.isAppleSystem():
threading.Timer(2, op_submit_systemctl_restart, args=()).start()
# submit_restart1()
return 'ok'
threading.Timer(2, op_submit_init_restart, args=(file,)).start()
# submit_restart2(file)
return 'ok'
@@ -293,7 +317,11 @@ def start():
def stop():
return restyOp('stop')
r = restyOp('stop')
pid_file = getPidFile()
if os.path.exists(pid_file):
os.remove(pid_file)
return r
def restart():
@@ -306,10 +334,15 @@ def reload():
def initdStatus():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status openresty | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
@@ -318,17 +351,35 @@ def initdStatus():
def initdInstall():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
# freebsd initd install
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
return 'ok'
mw.execShell('systemctl enable openresty')
return 'ok'
def initdUinstall():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
return 'ok'
mw.execShell('systemctl disable openresty')
return 'ok'
+7 -3
View File
@@ -2,7 +2,7 @@
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# cd /www/server/mdserver-web/plugins/openresty && bash install.sh install 1.21.4.1
# cd /www/server/mdserver-web/plugins/openresty && bash install.sh install 1.21.4.2
curPath=`pwd`
rootPath=$(dirname "$curPath")
@@ -77,10 +77,14 @@ Install_openresty()
cd ${openrestyDir} && tar -zxvf openresty-${VERSION}.tar.gz
OPTIONS=''
if [ "$VERSION" != "1.21.4.2" ];then
OPTIONS=" ${OPTIONS} --with-ipv6 "
fi
# --with-openssl=$serverPath/source/lib/openssl-1.0.2q
cd ${openrestyDir}/openresty-${VERSION} && ./configure \
--prefix=$serverPath/openresty \
--with-ipv6 \
$OPTIONS \
--with-stream \
--with-http_v2_module \
--with-http_ssl_module \
@@ -92,7 +96,7 @@ Install_openresty()
# --with-debug
# 用于调式
make -j${cpuCore} && make install && make clean
gmake -j${cpuCore} && gmake install && gmake clean
if [ -d $serverPath/openresty ];then
echo "${VERSION}" > $serverPath/openresty/version.pl
+4 -4
View File
@@ -62,10 +62,6 @@ cd ${curPath} && sh -x $curPath/versions/$2/install.sh $1
if [ "${action}" == "install" ] && [ -d ${serverPath}/php-yum/${type} ];then
#初始化
cd ${rootPath} && python3 ${rootPath}/plugins/php-yum/index.py start ${type}
cd ${rootPath} && python3 ${rootPath}/plugins/php-yum/index.py initd_install ${type}
# 安装通用扩展
echo "install PHP-YUM[${type}] extend start"
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install mysqlnd
@@ -82,6 +78,10 @@ if [ "${action}" == "install" ] && [ -d ${serverPath}/php-yum/${type} ];then
cd ${rootPath}/plugins/php-yum/versions && bash common.sh ${type} install mbstring
echo "install PHP-YUM[${type}] extend end"
#初始化
cd ${rootPath} && python3 ${rootPath}/plugins/php-yum/index.py start ${type}
cd ${rootPath} && python3 ${rootPath}/plugins/php-yum/index.py initd_install ${type}
if [ ! -f /usr/local/bin/composer ];then
cd /tmp
curl -sS https://getcomposer.org/installer | /opt/remi/php${type}/root/usr/bin/php
+64 -20
View File
@@ -12,8 +12,6 @@ import shutil
# sys.setdefaultencoding('utf8')
sys.path.append(os.getcwd() + "/class/core")
# sys.path.append("/usr/local/lib/python3.6/site-packages")
import mw
if mw.isAppleSystem():
@@ -40,8 +38,12 @@ def getServerDir():
def getInitDFile(version):
if app_debug:
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName() + version
@@ -52,13 +54,16 @@ def getArgs():
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
@@ -80,7 +85,7 @@ def getFpmConfFile(version):
def status_progress(version):
# ps -ef|grep 'php/81' |grep -v grep | grep -v python | awk '{print $2}
cmd = "ps -ef|grep 'php/" + version + \
cmd = "ps aux|grep 'php/" + version + \
"' |grep -v grep | grep -v python | awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
@@ -147,7 +152,7 @@ def contentReplace(content, version):
def makeOpenrestyConf():
phpversions = ['00', '52', '53', '54', '55', '56',
'70', '71', '72', '73', '74', '80', '81', '82']
'70', '71', '72', '73', '74', '80', '81', '82', '83']
sdir = mw.getServerDir()
@@ -277,11 +282,11 @@ def initReplace(version):
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/php' + version + '.service'
systemServiceTpl = getPluginDir() + '/init.d/php.service.tpl'
if version == '52':
systemServiceTpl = getPluginDir() + '/init.d/php.service.52.tpl'
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/php.service.tpl'
if version == '52':
systemServiceTpl = getPluginDir() + '/init.d/php.service.52.tpl'
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$VERSION}', version)
@@ -295,16 +300,23 @@ def initReplace(version):
def phpOp(version, method):
file = initReplace(version)
if not mw.isAppleSystem():
if method == 'stop' or method == 'restart':
mw.execShell(file + ' ' + 'stop')
data = mw.execShell('systemctl ' + method + ' php' + version)
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell(file + ' ' + method)
if current_os.startswith("freebsd"):
data = mw.execShell('service php' + version + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
if method == 'stop' or method == 'restart':
mw.execShell(file + ' ' + 'stop')
data = mw.execShell('systemctl ' + method + ' php' + version)
if data[1] == '':
return 'ok'
return data[1]
@@ -336,9 +348,15 @@ def reload(version):
def initdStatus(version):
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile(version)
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status php' + version + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
@@ -347,17 +365,32 @@ def initdStatus(version):
def initdInstall(version):
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
import shutil
source_bin = initReplace(version)
initd_bin = getInitDFile(version)
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
return 'ok'
mw.execShell('systemctl enable php' + version)
return 'ok'
def initdUinstall(version):
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile(version)
os.remove(initd_bin)
return 'ok'
mw.execShell('systemctl disable php' + version)
return 'ok'
@@ -857,7 +890,7 @@ def get_php_info(args):
return getPhpinfo(args['version'])
def getLibConf(version):
def libConfCommon(version):
fname = getConf(version)
if not os.path.exists(fname):
return mw.returnJson(False, '指定PHP版本不存在!')
@@ -886,6 +919,17 @@ def getLibConf(version):
else:
lib['status'] = True
libs.append(lib)
return libs
def get_lib_conf(data):
libs = libConfCommon(data['version'])
# print(libs)
return mw.returnData(True, 'OK!', libs)
def getLibConf(version):
libs = libConfCommon(version)
return mw.returnJson(True, 'OK!', libs)
+2 -2
View File
@@ -5,8 +5,8 @@
"name": "php",
"title": "PHP",
"coexist": true,
"versions": ["53","54","55","56","70","71","72","73","74","80","81","82"],
"updates": ["5.3.29","5.4.45","5.6.36","7.0.30","7.1.33","7.2.32","7.3.20","7.4.30","8.0.30","8.1.8","8.2.0"],
"versions": ["53","54","55","56","70","71","72","73","74","80","81","82","83"],
"updates": ["5.3.29","5.4.45","5.6.36","7.0.30","7.1.33","7.2.32","7.3.20","7.4.30","8.0.30","8.1.8","8.2.9","8.3.0"],
"tip": "soft",
"install_pre_inspection":true,
"checks": "server/php/VERSION/bin/php",
+7 -3
View File
@@ -34,7 +34,7 @@ function phpPostCallbak(method, version, args,callback){
req_data['func'] = method;
args['version'] = version;
if (typeof(args) == 'string'){
if (typeof(args) == 'string' && args == ''){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
@@ -582,9 +582,13 @@ function getPHPInfo(version) {
function phpLibConfig(version){
// phpPost('get_lib_conf', version, {}, function(rdata){
// var rdata = $.parseJSON(rdata.data);
// });
phpPost('get_lib_conf', version, '', function(data){
var rdata = $.parseJSON(data.data);
phpPostCallbak('get_lib_conf', version, {}, function(rdata){
var rdata = rdata.data;
if (!rdata.status){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+27
View File
@@ -0,0 +1,27 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
rootPath=$(dirname "$rootPath")
opensslVersion="1.1.1p"
# echo $rootPath
SERVER_ROOT=$rootPath/lib
SOURCE_ROOT=$rootPath/source/lib
mkdir -p $SOURCE_ROOT
if [ ! -d ${SERVER_ROOT}/openssl11 ];then
cd ${SOURCE_ROOT}
if [ ! -f ${SOURCE_ROOT}/openssl-${opensslVersion}.tar.gz ];then
wget --no-check-certificate -O ${SOURCE_ROOT}/openssl-${opensslVersion}.tar.gz https://www.openssl.org/source/openssl-${opensslVersion}.tar.gz
fi
tar -zxvf openssl-${opensslVersion}.tar.gz
cd openssl-${opensslVersion}
./config --prefix=${SERVER_ROOT}/openssl11 zlib-dynamic shared
make && make install
fi
+2 -1
View File
@@ -16,7 +16,7 @@ function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)"
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.0.29
version=8.0.30
PHP_VER=80
Install_php()
{
@@ -140,6 +140,7 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then
--enable-sysvshm \
--disable-intl \
--disable-fileinfo \
--with-password-argon2 \
$OPTIONS \
--enable-fpm
make clean && make -j${cpuCore} && make install && make clean
+2 -1
View File
@@ -16,7 +16,7 @@ function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)"
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.1.20
version=8.1.22
PHP_VER=81
Install_php()
{
@@ -133,6 +133,7 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then
--enable-sysvshm \
--disable-intl \
--disable-fileinfo \
--with-password-argon2 \
$OPTIONS \
--enable-fpm
make clean && make -j${cpuCore} && make install && make clean
+2 -1
View File
@@ -16,7 +16,7 @@ function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)"
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.2.8
version=8.2.9
PHP_VER=82
Install_php()
{
@@ -135,6 +135,7 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then
--enable-sysvshm \
--disable-intl \
--disable-fileinfo \
--with-password-argon2 \
$OPTIONS \
--enable-fpm
make clean && make -j${cpuCore} && make install && make clean
+157
View File
@@ -0,0 +1,157 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sourcePath=${serverPath}/source
sysName=`uname`
install_tmp=${rootPath}/tmp/mw_install.pl
function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; }
function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; }
function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; }
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
version=8.3.0alpha2
PHP_VER=83
Install_php()
{
#------------------------ install start ------------------------------------#
echo "安装php-${version} ..." > $install_tmp
mkdir -p $sourcePath/php
mkdir -p $serverPath/php
cd ${rootPath}/plugins/php/lib && /bin/bash freetype_new.sh
cd ${rootPath}/plugins/php/lib && /bin/bash zlib.sh
# redat ge 8
which yum
if [ "$?" == "0" ];then
cd ${rootPath}/plugins/php/lib && /bin/bash oniguruma.sh
fi
if [ ! -d $sourcePath/php/php${PHP_VER} ];then
# ----------------------------------------------------------------------- #
# 中国优化安装
# cn=$(curl -fsSL -m 10 -s http://ipinfo.io/json | grep "\"country\": \"CN\"")
# LOCAL_ADDR=common
# if [ ! -z "$cn" ];then
# LOCAL_ADDR=cn
# fi
# if [ "$LOCAL_ADDR" == "cn" ];then
# if [ ! -f $sourcePath/php/php-${version}.tar.xz ];then
# wget --no-check-certificate -O $sourcePath/php/php-${version}.tar.xz https://mirrors.sohu.com/php/php-${version}.tar.xz
# fi
# fi
# ----------------------------------------------------------------------- #
if [ ! -f $sourcePath/php/php-${version}.tar.xz ];then
wget --no-check-certificate -O $sourcePath/php/php-${version}.tar.xz https://downloads.php.net/~eric/php-${version}.tar.xz
fi
cd $sourcePath/php && tar -Jxf $sourcePath/php/php-${version}.tar.xz
mv $sourcePath/php/php-${version} $sourcePath/php/php${PHP_VER}
fi
cd $sourcePath/php/php${PHP_VER}
OPTIONS=''
if [ $sysName == 'Darwin' ]; then
OPTIONS='--without-iconv'
OPTIONS="${OPTIONS} --with-curl=${serverPath}/lib/curl"
else
OPTIONS='--without-iconv'
OPTIONS="${OPTIONS} --with-curl"
fi
IS_64BIT=`getconf LONG_BIT`
if [ "$IS_64BIT" == "64" ];then
OPTIONS="${OPTIONS} --with-libdir=lib64"
fi
# ----- cpu start ------
if [ -z "${cpuCore}" ]; then
cpuCore="1"
fi
if [ -f /proc/cpuinfo ];then
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
fi
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
cpuCore="${MEM_INFO}"
fi
else
cpuCore="1"
fi
if [ "$cpuCore" -gt "2" ];then
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
else
cpuCore="1"
fi
# ----- cpu end ------
ZIP_OPTION='--with-zip'
libzip_version=`pkg-config libzip --modversion`
if version_lt "$libzip_version" "0.11.0" ;then
cd ${rootPath}/plugins/php/lib && /bin/bash libzip.sh
export PKG_CONFIG_PATH=$serverPath/lib/libzip/lib/pkgconfig
ZIP_OPTION="--with-zip=$serverPath/lib/libzip"
fi
echo "$sourcePath/php/php${PHP_VER}"
if [ ! -d $serverPath/php/${PHP_VER} ];then
cd $sourcePath/php/php${PHP_VER}
./buildconf --force
./configure \
--prefix=$serverPath/php/${PHP_VER} \
--exec-prefix=$serverPath/php/${PHP_VER} \
--with-config-file-path=$serverPath/php/${PHP_VER}/etc \
--enable-mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-zlib-dir=$serverPath/lib/zlib \
$ZIP_OPTION \
--enable-mbstring \
--enable-ftp \
--enable-sockets \
--enable-simplexml \
--enable-soap \
--enable-posix \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--disable-intl \
--disable-fileinfo \
--with-password-argon2 \
$OPTIONS \
--enable-fpm
make clean && make -j${cpuCore} && make install && make clean
fi
#------------------------ install end ------------------------------------#
}
Uninstall_php()
{
$serverPath/php/init.d/php${PHP_VER} stop
rm -rf $serverPath/php/${PHP_VER}
echo "卸载php-${version}..." > $install_tmp
}
action=${1}
if [ "${1}" == 'install' ];then
Install_php
else
Uninstall_php
fi
+2 -2
View File
@@ -26,7 +26,7 @@ ROOT_DIR=$(cd "$(dirname "$0")"; pwd)
# echo "php${PHP_VER} -- end"
PHP_VER_LIST=(53 54 55 56 70 71 72 73 74 80 81 82)
PHP_VER_LIST=(53 54 55 56 70 71 72 73 74 80 81 82 83)
# PHP_VER_LIST=(81)
for PHP_VER in ${PHP_VER_LIST[@]}; do
echo "php${PHP_VER} -- start"
@@ -37,7 +37,7 @@ for PHP_VER in ${PHP_VER_LIST[@]}; do
done
cd $DIR
PHP_VER_LIST=(53 54 55 56 70 71 72 73 74 80 81 82)
PHP_VER_LIST=(53 54 55 56 70 71 72 73 74 80 81 82 83)
# yar
PHP_EXT_LIST=(ZendGuardLoader pdo mysqlnd sqlite3 openssl pcntl opcache mcrypt fileinfo \
exif gd intl memcache memcached redis imagemagick xdebug \
+59 -29
View File
@@ -36,7 +36,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "脚本解密",
"msg": "用于解密SG11加密脚本!",
@@ -71,7 +72,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "加密库",
"msg": "Sodium加密库的包装器",
@@ -88,7 +90,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "运算库",
"msg": "一个开源的数学运算库",
@@ -109,7 +112,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "用于加速PHP脚本!",
@@ -130,7 +134,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "SSL!",
@@ -146,7 +151,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "加密软件!",
@@ -167,7 +173,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "高精度计算!",
@@ -188,7 +195,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "用于信号控制!",
@@ -210,7 +218,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "编码转换!",
@@ -230,7 +239,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "用于FILE!",
@@ -250,7 +260,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "用于图像文件格式!",
@@ -267,7 +278,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "序列化扩展!",
@@ -289,7 +301,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "国际化与本地化!",
@@ -311,7 +324,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "通用GD库!",
@@ -333,7 +347,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "提供国际化支持",
@@ -355,7 +370,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "强大的内容缓存器,不支持集群",
@@ -376,7 +392,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "强大的内容缓存器,支持集群",
@@ -398,7 +415,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "更强大的内容缓存器,支持集群",
@@ -445,7 +463,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "比GD更强大的图形库",
@@ -466,7 +485,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "调试器",
"msg": "不多说,不了解的不要安装",
@@ -488,7 +508,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "性能分析",
"msg": "不多说,不了解的不要安装!",
@@ -509,7 +530,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "异步、并行、高性能网络通信引擎",
@@ -553,7 +575,9 @@
"73",
"74",
"80",
"81"
"81",
"82",
"83"
],
"type": "框架",
"msg": "Yaf是一个C语言编写的PHP框架",
@@ -605,7 +629,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "通用扩展",
"msg": "Mongodb数据库连接驱动",
@@ -622,7 +647,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "缓存器",
"msg": "高性能无锁共享内存Cache",
@@ -643,7 +669,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "大数据",
"msg": "SOLR全文搜索服务",
@@ -664,7 +691,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "日志",
"msg": "SeasLog高性能日志记录",
@@ -678,7 +706,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "压缩",
"msg": "压缩组件",
@@ -699,7 +728,8 @@
"74",
"80",
"81",
"82"
"82",
"83"
],
"type": "压缩",
"msg": "压缩组件",
+46 -10
View File
@@ -27,8 +27,13 @@ def getServerDir():
def getInitDFile():
if app_debug:
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
@@ -69,7 +74,7 @@ def getArgs():
def status():
data = mw.execShell(
"ps -ef|grep redis |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
"ps aux|grep redis |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
if data[0] == '':
return 'stop'
@@ -113,8 +118,8 @@ def initDreplace():
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/redis.service'
systemServiceTpl = getPluginDir() + '/init.d/redis.service.tpl'
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/redis.service.tpl'
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$SERVER_PATH}', service_path)
@@ -127,16 +132,23 @@ def initDreplace():
def redisOp(method):
file = initDreplace()
if not mw.isAppleSystem():
data = mw.execShell('systemctl ' + method + ' redis')
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell(file + ' start')
if current_os.startswith("freebsd"):
data = mw.execShell('service ' + getPluginName() + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell('systemctl ' + method + ' redis')
if data[1] == '':
return 'ok'
return 'fail'
return data[1]
def start():
@@ -211,9 +223,15 @@ def runInfo():
def initdStatus():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
@@ -223,17 +241,35 @@ def initdStatus():
def initdInstall():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
# freebsd initd install
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
return 'ok'
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
def initdUinstall():
if mw.isAppleSystem():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
return 'ok'
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
+1 -1
View File
@@ -25,7 +25,7 @@ Install_redis()
mkdir -p $serverPath/redis
mkdir -p $serverPath/redis/data
cd redis-${VERSION} && make PREFIX=$serverPath/redis install
cd redis-${VERSION} && gmake PREFIX=$serverPath/redis install
sed '/^ *#/d' redis.conf > $serverPath/redis/redis.conf
if [ -d $serverPath/redis ];then
+2 -1
View File
@@ -22,6 +22,7 @@ def init(bot):
bot.set_my_commands(
commands=[
telebot.types.BotCommand("start", "查看帮助信息"),
telebot.types.BotCommand("faq", "查看bbs帖子主题【?:】"),
telebot.types.BotCommand("faq", ""),
telebot.types.BotCommand("music", "搜索网易音乐"),
],
)
@@ -100,7 +100,7 @@ def send_msg(bot, tag='ad', trigger_time=300):
markup = types.InlineKeyboardMarkup(keyboard)
msg_notice = "由于在解决的问题的时候,不给信息,无法了解情况。以后不再群里回答技术问题。全部去论坛提问。在解决问题的过程中,可能需要面板信息,和SSH信息,如无法提供请不要提问。为了让群里都知晓。轮播一年!\n"
msg_notice += "为了不打扰双方,私聊解决问题先转100U,否则无视!\n"
msg_notice += "为了不打扰双方,私聊解决问题先转1000U,否则无视!\n"
msg = bot.send_message(chat_id, msg_notice, reply_markup=markup)
# print(msg.message_id)
+9 -12
View File
@@ -191,20 +191,17 @@ def run(bot, message):
# print(text_body)
if isThisCmd('/?:', text_body):
cmd_text = getReadCmd('/?:', text_body)
cmd_text = cmd_text.strip().strip(":")
if cmd_text == "":
return bot.send_message(message.chat.id, "搜索内容不能为空, 例如:/?: 数据库")
return searchFaq(bot, message, cmd_text)
# if text_body.find('?') > -1 or text_body.find('?') > -1:
# return_msg = "你似乎在寻找【" + text_body + "】答案:\n"
# return_msg += "/faq:开始寻找你的问题\n"
# keyboard = [
# [
# types.InlineKeyboardButton(
# text="如未找到,可以在论坛补充你的提问!", url='https://bbs.midoks.me'),
# ]
# ]
# markup = types.InlineKeyboardMarkup(keyboard)
# bot.reply_to(message, return_msg, reply_markup=markup)
if isThisCmd('/faq', text_body):
cmd_text = getReadCmd('/faq', text_body)
cmd_text = cmd_text.strip().strip(":")
if cmd_text == "":
return bot.send_message(message.chat.id, "搜索内容不能为空, 例如:/faq 数据库")
return searchFaq(bot, message, cmd_text)
return bot
@@ -0,0 +1,341 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
import base64
import threading
import telebot
from telebot import types
from telebot.util import quick_markup
# 网易音乐搜索
def isThisCmd(cmd, msg):
clen = len(cmd)
msg_len = len(msg)
if msg_len < clen:
return False
check_msg = msg[0:clen]
if cmd == check_msg:
return True
return False
def getReadCmd(cmd, msg):
clen = len(cmd)
msg_len = len(msg)
real_msg = msg[clen:]
return real_msg
def ip2long(ip):
import struct
import socket
return struct.unpack("!L", socket.inet_aton(ip))[0]
def long2ip(longip):
import struct
import socket
return socket.inet_ntoa(struct.pack('!L', longip))
def mt_rand(a, b):
import random
return random.randint(a, b)
def httpPost(url, data, timeout=10):
"""
发送POST请求
@url 被请求的URL地址(必需)
@data POST参数,可以是字符串或字典(必需)
@timeout 超时时间默认60秒
return string
"""
try:
import urllib.request
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
headers = {
'Referer': 'https://music.163.com/',
'Cookie': 'appver=8.2.30; os=iPhone OS; osver=15.0; EVNSM=1.0.0; buildver=2206; channel=distribution; machineid=iPhone13.3',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 CloudMusic/0.1.1 NeteaseMusic/8.2.30',
'X-Real-IP': long2ip(mt_rand(1884815360, 1884890111)),
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
}
data = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url, data, headers=headers)
response = urllib.request.urlopen(req, timeout=timeout)
result = response.read()
if type(result) == bytes:
result = result.decode('utf-8')
return result
except Exception as ex:
return str(ex)
def musicSearch(kw, page=1, page_size=5):
m_offset = (int(page) - 1) * int(page_size)
data = httpPost('http://music.163.com/api/cloudsearch/pc', {
's': kw,
'type': '1',
'total': 'true',
'limit': page_size,
'offset': m_offset,
})
# data_a = json.loads(data)
# print(data)
# exit()
return json.loads(data)
def musicSongD(mid):
data = httpPost('http://music.163.com/api/v3/song/detail/', {
'c': '[{"id":' + str(mid) + ',"v":0}]',
})
# print(data)
return json.loads(data)
def musicSongDataUrl(mid):
data = httpPost('http://music.163.com/api/song/enhance/player/url', {
'br': 320 * 1000,
'ids': [mid],
})
return json.loads(data)
def writeLog(log_str):
if __name__ == "__main__":
print(log_str)
now = mw.getDateFromNow()
log_file = mw.getServerDir() + '/tgbot/task.log'
mw.writeFileLog(now + ':' + log_str, log_file, limit_size=5 * 1024)
return True
def tgSearchMusic_t(cmd_text):
data = musicSearch(cmd_text, 1, 5)
if data['code'] == 200 and len(data['result']['songs']) > 0:
slist = data['result']['songs']
print(slist)
else:
keyboard = [
[
types.InlineKeyboardButton(
text="论坛", url='https://bbs.midoks.me'),
types.InlineKeyboardButton(
text="搜索", url='https://bbs.midoks.me/search.php')
],
[
types.InlineKeyboardButton(
text="关闭消息", callback_data='bbs_search_close')
]
]
markup = types.InlineKeyboardMarkup(keyboard)
bot.send_message(
message.chat.id, "未找到合适内容,请在官方论坛[bbs.midoks.me]提问!", reply_markup=markup)
return True
def tgSearchMusic(bot, message, cmd_text):
import math
data = musicSearch(cmd_text, 1, 5)
if data['code'] == 200 and len(data['result']['songs']) > 0:
keyboard = []
slist = data['result']['songs']
page_total = math.ceil(data['result']['songCount'] / 5)
for x in slist:
author = ''
if len(x['ar']) > 0:
author = ' - ' + x['ar'][0]['name']
keyboard.append([types.InlineKeyboardButton(
text=x['name'] + author, callback_data='m163_id:' + str(x['id']))])
keyboard.append([
types.InlineKeyboardButton(
text="下一页", callback_data='m163_next_page_2'),
types.InlineKeyboardButton(
text="第1页,共" + str(page_total) + "页", callback_data='m163_page_total')
])
keyboard.append([types.InlineKeyboardButton(
text="关闭消息", callback_data='m163_search_close')])
# print(keyboard)
markup = types.InlineKeyboardMarkup(keyboard)
bot.send_message(message.chat.id, "寻找【" +
cmd_text.strip() + "】歌曲如下:", reply_markup=markup)
else:
bot.send_message(message.chat.id, "未找到合适内容")
return True
def getFaqKw(cmd):
matchObj = re.match(r'寻找【(.*?)】歌曲如下', cmd, re.M | re.I)
data = matchObj.groups()
if len(data) > 0:
return True, data[0]
return False, ''
def cleanMusicFileExpire(dir):
pass
def downloadAndUpMusic(bot, chat_id, mid, title):
import requests
murl_data = musicSongDataUrl(int(mid))
murl = murl_data['data'][0]['url']
def_dir = '/tmp/tgbot_music'
if not os.path.exists(def_dir):
os.mkdir(def_dir)
def_abs_path = def_dir + '/' + title + '.mp3'
# print('downloadAndUpMusic' + ":" + str(murl))
if murl:
msg_t = bot.send_message(chat_id, "已经获取资源URL,本地下载中...")
response = requests.get(murl)
with open(def_abs_path, "wb") as f:
f.write(response.content)
bot.edit_message_text(
chat_id=chat_id, message_id=msg_t.message_id, text="本地下载完,正在上传中...")
audio = open(def_abs_path, 'rb')
bot.send_audio(chat_id, audio)
bot.edit_message_text(
chat_id=chat_id, message_id=msg_t.message_id, text="上传结束...1s自动删除")
time.sleep(1)
bot.delete_message(chat_id=chat_id, message_id=msg_t.message_id)
else:
bot.send_message(chat_id, "无效资源")
if os.path.exists(def_abs_path):
os.remove(def_abs_path)
# cleanMusicFileExpire(def_dir)
return True
def answer_callback_query(bot, call):
import math
keyword = call.data
# print(keyword)
if keyword == 'm163_search_close':
bot.delete_message(chat_id=call.message.chat.id,
message_id=call.message.message_id)
return
# 音乐下载
if keyword.startswith('m163_id:'):
t = keyword.split(":")
inline_keyboard = call.json['message'][
"reply_markup"]["inline_keyboard"]
def_file_name = 'demo'
for x in inline_keyboard:
# print(x)
if x[0]['callback_data'] == keyword:
def_file_name = x[0]['text']
# print(call.message)
downloadAndUpMusic(bot, call.message.chat.id, t[1], def_file_name)
bot.delete_message(chat_id=call.message.chat.id,
message_id=call.message.message_id)
return True
is_m163_page = False
p = 1
if keyword.startswith('m163_next_page'):
is_m163_page = True
p = keyword.replace('m163_next_page_', '')
if keyword.startswith('m163_pre_page'):
is_m163_page = True
p = keyword.replace('m163_pre_page_', '')
if is_m163_page:
is_match, cmd_text = getFaqKw(call.message.text)
if not is_match:
bot.edit_message_text(
chat_id=call.message.chat.id, message_id=call.message.message_id, text="出现错误!")
return
data = musicSearch(cmd_text, p, 5)
dlist = data['result']['songs']
page_total = math.ceil(data['result']['songCount'] / 5)
keyboard = []
for x in dlist:
author = ''
if len(x['ar']) > 0:
author = ' - ' + x['ar'][0]['name']
keyboard.append([types.InlineKeyboardButton(
text=x['name'] + author, callback_data='m163_id:' + str(x['id']))])
page_nav = []
if int(p) > 1:
page_nav.append(types.InlineKeyboardButton(
text="上一页", callback_data='m163_pre_page_' + str(int(p) - 1)))
if int(p) < page_total:
page_nav.append(types.InlineKeyboardButton(
text="下一页", callback_data='m163_next_page_' + str(int(p) + 1)))
page_nav.append(types.InlineKeyboardButton(
text="第" + str(p) + "页,共" + str(page_total) + "页", callback_data='m163_page_total'))
keyboard.append(page_nav)
keyboard.append([types.InlineKeyboardButton(
text="关闭消息", callback_data='m163_search_close')])
markup = types.InlineKeyboardMarkup(keyboard)
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id,
text=call.message.text, reply_markup=markup)
def run(bot, message):
text_body = message.text
if isThisCmd('/music', text_body):
cmd_text = getReadCmd('/music', text_body)
cmd_text = cmd_text.strip().strip(":")
if cmd_text == "":
return bot.send_message(message.chat.id, "搜索内容不能为空, 例如:/music 刀郎")
return tgSearchMusic(bot, message, cmd_text)
return bot
if __name__ == '__main__':
# cleanMusicFileExpire("/tmp/tgbot_music")
# tgSearchMusic_t("一夜泥工")
# print(long2ip(mt_rand(1884815360, 1884890111)))
t = musicSongDataUrl(2063487880)
print(t['data'])
print("111")
+7 -3
View File
@@ -113,7 +113,7 @@ class App():
def getSshInfo(self, file):
rdata = mw.readFile(file)
destr = mw.enDoubleCrypt('mdserver-web', rdata)
destr = mw.deDoubleCrypt('mdserver-web', rdata)
return json.loads(destr)
def get_server_by_host(self):
@@ -150,15 +150,19 @@ class App():
info_file = self.__host_dir + '/' + name + '/info.json'
if not os.path.exists(info_file):
continue
host_info = {}
try:
info_tmp = self.getSshInfo(info_file)
host_info = {}
host_info['host'] = name
host_info['port'] = info_tmp['port']
host_info['ps'] = info_tmp['ps']
# host_info['sort'] = int(info_tmp['sort'])
except Exception as e:
print(e)
# print(e)
return mw.returnJson(False, str(e))
# if os.path.exists(info_file):
# os.remove(info_file)
# continue
+2 -2
View File
@@ -513,7 +513,7 @@ def index(reqClass=None, reqAction=None, reqData=None):
if reqClass == None:
reqClass = 'index'
pageFile = ('config', 'control', 'crontab', 'files', 'firewall',
pageFile = ('config', 'control', 'crontab', 'files', 'logs', 'firewall',
'index', 'plugins', 'login', 'system', 'site', 'cert', 'ssl', 'task', 'soft')
if reqClass == 'login':
@@ -553,7 +553,7 @@ def index(reqClass=None, reqAction=None, reqData=None):
return 'error request!'
# API请求
classFile = ('config_api', 'crontab_api', 'files_api', 'firewall_api',
classFile = ('config_api', 'crontab_api', 'files_api', 'logs_api', 'firewall_api',
'plugins_api', 'system_api', 'site_api', 'task_api', 'vip_api')
className = reqClass + '_api'
if not className in classFile:
+1 -1
View File
@@ -33,7 +33,7 @@ function getLogs(id){
function getBackupName(hook_data, name){
for (var i = 0; i < hook_data.length; i++) {
if (hook_data[i]['name'] == 'backup_ftp'){
if (hook_data[i]['name'] == name){
return hook_data[i]['title'];
}
}
+23 -15
View File
@@ -298,21 +298,29 @@ function openFilename(obj){
}
if (inArray(ext,['svg'])){
$.post("/files/get_body", "path=" + encodeURIComponent(path), function(rdata) {
if (rdata.data.status){
layer.open({
type:1,
closeBtn: 1,
title:"SVG预览",
area: '400px',
shadeClose: true,
content: '<div class="showpicdiv">'+rdata.data.data+'</div>'
});
} else {
layer.msg("无法预览");
}
},'json');
var url = '/files/download?filename='+path;
layer.open({
type:1,
closeBtn: 1,
title:"SVG预览",
area: ['600px','500px'],
maxmin:true,
shadeClose: true,
content: '<iframe width="100%" height="100%"\
src="'+url+'"\
frameborder="0"\
border="0"\
marginwidth="0"\
marginheight="0"\
scrolling="yes"\
noresize=""\
allowfullscreen="allowfullscreen"\
mozallowfullscreen="mozallowfullscreen"\
msallowfullscreen="msallowfullscreen"\
oallowfullscreen="oallowfullscreen"\
webkitallowfullscreen="webkitallowfullscreen"\
allowfullscreen="true"></iframe>'
});
}
}
-41
View File
@@ -6,10 +6,6 @@ setTimeout(function(){
showAccept(1);
},1000);
setTimeout(function(){
getLogs(1);
},1500);
$(function(){
// start
@@ -124,7 +120,6 @@ function getSshInfo(){
$("#firewall_status").html(fStatus);
showAccept(1);
getLogs(1);
},'json');
}
@@ -371,39 +366,3 @@ function delAcceptPort(id, port) {
},'json');
});
}
/**
* 取回数据
* @param {Int} page 分页号
*/
function getLogs(page,search) {
search = search == undefined ? '':search;
var loadT = layer.load();
$.post('/firewall/get_log_list','limit=10&p=' + page+"&search="+search, function(data) {
layer.close(loadT);
var body = '';
for (var i = 0; i < data.data.length; i++) {
body += "<tr>\
<td><em class='dlt-num'>" + data.data[i].id + "</em></td>\
<td>" + data.data[i].type + "</td>\
<td>" + data.data[i].log + "</td>\
<td>" + data.data[i].addtime + "</td>\
</tr>";
}
$("#logsBody").html(body);
$("#logsPage").html(data.page);
},'json');
}
//清理面板日志
function delLogs(){
layer.confirm('即将清空面板日志,继续吗?',{title:'清空日志',closeBtn:2},function(){
var loadT = layer.msg('正在清理,请稍候...',{icon:16});
$.post('/firewall/del_panel_logs','',function(rdata){
layer.close(loadT);
layer.msg(rdata.msg,{icon:rdata.status?1:2});
getLogs(1);
},'json');
});
}
+205
View File
@@ -0,0 +1,205 @@
$(document).ready(function(){
logsLoad();
});
function changeLogsViewH(){
var l = $(window).height();
$('.container-fluid .tab-view-box').css('height',l-80-40);
$('#panelLogs').css('height',l-80-40-50);
$('#logAudit .logAuditTab').css('height',l-80-40-50);
$('#logAudit .logAuditContent').css('height',l-80-40-50);
}
function logsLoad(){
changeLogsViewH();
$(window).resize(function(){
changeLogsViewH();
});
getLogs(1);
}
$('#cutTab .tabs-item').click(function(){
var type = $(this).data('name');
$('#cutTab .tabs-item').removeClass('active');
$(this).addClass('active');
$('.tab-view-box .tab-con').addClass('hide').removeClass('show').removeClass('w-full');
$('#'+type).addClass('show').addClass('w-full');
switch(type){
case 'panelLogs':
getLogs(1);
break;
case 'logAudit':
getAuditLogsFiles();
break;
}
});
$('#panelLogs .refresh').click(function(){
getLogs(1);
});
$('#panelLogs .clear').click(function(){
delLogs(1);
});
function getAuditLogsFiles(){
var loadT = layer.msg('正在获取日志审计列表...', { icon: 16, time: 0, shade: 0.3 });
$.post('/logs/get_audit_logs_files',{}, function(data) {
layer.close(loadT);
var option = '';
for (var i = 0; i < data.length; i++) {
var tip = data[i]['name'] +' - '+data[i]['title'] + '(' + toSize(data[i]['size']) + ')';
if (i==0){
option += '<div class="logAuditItem active" title="'+tip+'" data-file="'+data[i]['name']+'">'+tip+'</div>';
} else {
option += '<div class="logAuditItem" title="'+tip+'" data-file="'+data[i]['name']+'">'+tip+'</div>';
}
}
$("#logAudit .logAuditTab").html(option);
getAuditFile(data[0]['name']);
$('#logAudit .logAuditItem').click(function(){
$('#logAudit .logAuditItem').removeClass('active');
$(this).addClass('active');
getAuditFile($(this).data('file'));
});
},'json');
}
function getAuditFile(log_name){
var loadT = layer.msg('正在获取日志审计内容...', { icon: 16, time: 0, shade: 0.3 });
$.post('/logs/get_audit_file',{log_name:log_name}, function(data) {
layer.close(loadT);
// console.log(data);
try{
if (typeof(data) == 'object'){
var plist = data.data;
var pre_html ='<div id="logAuditTable" style="position: relative;display: block;">\
<div class="tootls_group tootls_top">\
<div class="pull-left">\
<button type="button" title="刷新列表" class="refresh btn btn-success btn-sm mr5"><span>刷新列表</span></button>\
</div>\
<!-- <div class="pull-right">\
<div class="logs_search" style="position: relative;">\
<input type="text" class="search_input" style="" placeholder="请输入来源/端口/角色/事件">\
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>\
</div>\
</div> --> \
</div>\
<div class="divtable mtb10" style="max-height: 83px;">\
<table class="table table-hover">\
<thead style="position: relative;z-index: 1;">\
<tr>\
<th><span data-index="0"><span>用户</span></span></th>\
<th><span data-index="1"><span>来源</span></span></th>\
<th><span data-index="2"><span>端口</span></span></th>\
<th><span data-index="3"><span>时间</span></span></th>\
</tr>\
</thead>\
<tbody>\
<tr><td><span>root</span></td>\
<td><span>117.139.193.29</span></td>\
<td><span>pts/0</span></td>\
<td><span>2023-08-25 13:27 still logged in</span></td>\
</tr>\
</tbody>\
</table>\
</div>\
<div class="tootls_group tootls_bottom">\
<div class="pull-left"></div>\
<div class="pull-right">\
</div>\
</div>\
</div>'
// var pre_html = '<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">\
// <thead><tr><th>时间</th><th>角色</th><th>事件</th></tr></thead>\
// <tbody></tbody>\
// </table>';
$('#logAudit .logAuditContent').html(pre_html);
if (plist.length>0){
var tmp = plist[0];
var thead = '';
tbody += '<tr>'
for (var i in tmp) {
tbody+='<th>'+ i + '</th>';
}
tbody += '</tr>';
$('#logAudit .logAuditContent thead').html(tbody);
}
var tbody = '';
for (var i = 0; i < plist.length; i++) {
tbody += '<tr>';
for (var vv in plist[i]) {
tbody+= '<td>'+ plist[i][vv] + '</td>'
}
tbody += '</tr>';
}
$('#logAudit .logAuditContent tbody').html(tbody);
$('#logAudit .refresh').click(function(){
getAuditFile(log_name);
});
}
if (typeof(data) == 'string'){
var cc = '<div id="logAuditPre">\
<pre style="height: 100%; background-color: rgb(51, 51, 51); color: rgb(255, 255, 255); overflow-x: hidden; overflow-wrap: break-word; white-space: pre-wrap;"><code>'+data+'</code></pre>\
</div>';
$('#logAudit .logAuditContent').html(cc);
}
} catch (e) {
layer.msg(str(e),{icon:2,time:10000,shade: [0.3, '#000']});
}
});
}
function getLogs(page,search) {
search = search == undefined ? '':search;
var loadT = layer.load();
$.post('/logs/get_log_list','limit=10&p=' + page+"&search="+search, function(data) {
layer.close(loadT);
var body = '';
for (var i = 0; i < data.data.length; i++) {
body += "<tr>\
<td><em class='dlt-num'>" + data.data[i].id + "</em></td>\
<td>" + data.data[i].type + "</td>\
<td>" + data.data[i].log + "</td>\
<td>" + data.data[i].addtime + "</td>\
</tr>";
}
$("#operationLog tbody").html(body);
$("#panelLogs .page").html(data.page);
},'json');
}
function delLogs(){
layer.confirm('即将清空面板日志,继续吗?',{title:'清空日志',closeBtn:2},function(){
var loadT = layer.msg('正在清理,请稍候...',{icon:16});
$.post('/logs/del_panel_logs','',function(rdata){
layer.close(loadT);
layer.msg(rdata.msg,{icon:rdata.status?1:2});
getLogs(1);
},'json');
});
}
+17 -22
View File
@@ -575,38 +575,33 @@ function allDeleteSite(){
if($("#delpath").is(":checked")){
path='&path=1';
}
syncDeleteSite(dataList,0,'',path);
syncDeleteSite(dataList, 0,'',path);
},thtml);
}
//模拟同步开始批量删除
function syncDeleteSite(dataList,successCount,errorMsg,path){
if(dataList.length < 1) {
layer.msg(lan.get('del_all_site_ok',[successCount]),{icon:1});
showMsg(lan.get('del_all_site_ok',[successCount]), function(){
// location.reload();
},{icon:1});
return;
}
var loadT = layer.msg(lan.get('del_all_task_the',[dataList[0].name]),{icon:16,time:0,shade: [0.3, '#000']});
$.ajax({
type:'POST',
url:'/site?action=DeleteSite',
data:'id='+dataList[0].id+'&webname='+dataList[0].name+path,
async: true,
success:function(frdata){
layer.close(loadT);
if(frdata.status){
successCount++;
$("input[title='"+dataList[0].name+"']").parents("tr").remove();
}else{
if(!errorMsg){
errorMsg = '<br><p>'+lan.site.del_err+':</p>';
}
errorMsg += '<li>'+dataList[0].name+' -> '+frdata.msg+'</li>'
}
dataList.splice(0,1);
syncDeleteSite(dataList,successCount,errorMsg,path);
$.post('/site/delete', 'id='+dataList[0].id+'&webname='+dataList[0].name+path , function(rdata){
layer.close(loadT);
if(rdata.status){
successCount++;
$("input[title='"+dataList[0].name+"']").parents("tr").remove();
} else {
if(!errorMsg){
errorMsg = '<br><p>'+lan.site.del_err+':</p>';
}
});
errorMsg += '<li>'+dataList[0].name+' -> '+rdata.msg+'</li>'
}
dataList.splice(0,1);
syncDeleteSite(dataList,successCount,errorMsg,path);
},'json');
}
File diff suppressed because one or more lines are too long
+1 -30
View File
@@ -106,36 +106,7 @@
</div>
</div>
</div>
<div class="white-black-ip bgw mtb15">
<div class="black-ip">
<div class="def-log">
<div class="title c6 plr15">
<h3 class="f16">面板操作日志</h3>
<a class="btn btn-default btn-sm" onclick="delLogs();" style="margin-top: 1px;">清空</a>
</div>
<div class="divtable pd15">
<div class="tablescroll">
<table class="table table-hover" style="min-width: 640px;border: 0 none;">
<thead>
<tr>
<th>编号</th>
<th>操作类型</th>
<th>详情</th>
<th>操作时间</th>
</tr>
</thead>
<tbody id="logsBody"></tbody>
</table>
</div>
<div class="dataTables_paginate paging_bootstrap pagination">
<ul id="logsPage" class="page"></ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="/static/app/firewall.js?v={{config.version}}"></script>
+6 -1
View File
@@ -53,6 +53,7 @@
<li id="memuAcontrol"><a class="menu_control" href="/control">监控</a></li>
<li id="memuAfirewall"><a class="menu_firewall" href="/firewall">安全</a></li>
<li id="memuAfiles"><a class="menu_folder" href="/files">文件</a></li>
<li id="memuAlogs"><a class="menu_logs" href="/logs">日志</a></li>
<li id="memuAcrontab"><a class="menu_day" href="/crontab">计划任务</a></li>
<!-- 插件设置的菜单 -->
{% for menu in data['hook_menu'] %}
@@ -85,7 +86,11 @@
<script src="/static/js/term-websocketio.js"></script>
<script src="/static/app/upload.js?v={{config.version}}"></script>
<script src="/static/app/public.js?v={{config.version}}"></script>
<script src="/static/js/echarts.min.js"></script>
<!-- <script src="/static/js/echarts.min.js"></script> -->
<!-- <script src="//cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/js/echarts.min.js"></script> -->
<script src="//unpkg.com/echarts@5.4.3/dist/echarts.min.js"></script>
<script src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
<script src="/static/js/xm-select.js"></script>
+189
View File
@@ -0,0 +1,189 @@
{% extends "layout.html" %}
{% block content %}
<style type="text/css">
#operationLog thead th:nth-child(1),
#operationLog tbody tr td:nth-child(1){width:100px;}
#operationLog thead th:nth-child(2),
#operationLog tbody tr td:nth-child(2){width:130px;}
#operationLog thead th:nth-child(4),
#operationLog tbody tr td:nth-child(4){width:150px;}
.logAuditContent {
padding: 0 0 0 15px;
margin-left: 15px;
width: 100%;
flex: 1;
border-left: 1px solid #ececec;
}
.tootls_group .logs_search .search_input {
height: 30px;
line-height: 30px;
border-radius: 2px;
border: 1px solid #ccc;
outline: none;
padding-left: 8px;
vertical-align: top;
width: 230px;
}
.tootls_group .logs_search .glyphicon-search {
height: 28px;
line-height: 28px;
padding: 0 10px;
color: #888;
position: absolute;
right: 0;
font-size: 14px;
cursor: pointer;
}
#logAudit .tootls_group {
justify-content: space-between;
}
#logAudit .tootls_group, #panelRun .tootls_group.tools_bottom {
display: flex;
flex-wrap: wrap;
height: auto;
line-height: inherit;
}
.logAuditTabContent {
display: flex;
height: 100%;
}
.logAuditTabContent .logAuditTab {
border: 1px solid #ececec;
overflow: auto;
}
.logAuditTabContent .logAuditTab .logAuditItem {
height: 35px;
line-height: 35px;
padding: 0 10px;
border-bottom: 1px solid #ececec;
cursor: pointer;
overflow: hidden;
}
.logAuditTabContent .logAuditTab .logAuditItem:hover, .logAuditTabContent .logAuditTab .logAuditItem.active {
background-color: #f2f2f2;
}
#logAuditTable thead th:nth-child(1),
#logAuditTable tbody tr td:nth-child(1){width:;}
#logAuditTable thead th:nth-child(2),
#logAuditTable tbody tr td:nth-child(2){width:;}
#logAuditTable thead th:nth-child(3),
#logAuditTable tbody tr td:nth-child(3){width:;}
#logAuditTable thead th:nth-child(4),
#logAuditTable tbody tr td:nth-child(4){width:300px;}
</style>
<div class="main-content" style="min-height: 389px;">
<div class="container-fluid" style="padding-bottom: 50px;">
<div id="cutTab" class="pos-box bgw mtb15" style="height:45px">
<div class="tab-list">
<div class="tabs-item active" data-name="panelLogs">面板日志</div>
<div class="tabs-item" data-name="logAudit">日志审计</div>
</div>
</div>
<div class="bgw mtb15 pd15 tab-view-box firewall-tab-view" style="overflow: hidden;">
<!-- logs start -->
<div class="tab-con show w-full" id="panelLogs" style="padding: 0px;">
<div id="operationLog" style="position: relative;">
<div class="tootls_group tootls_top">
<div class="pull-left">
<button type="button" title="刷新日志" class="refresh btn btn-success btn-sm mr5">
<span>刷新日志</span>
</button>
<button type="button" title="清空日志" class="clear btn btn-default btn-sm mr5">
<span>清空日志</span>
</button>
</div>
</div>
<div class="divtable mtb10">
<table class="table table-hover">
<thead style="position: relative;z-index: 1;"><tr>
<th><span>编号</span></th>
<th><span>操作类型</span></th>
<th><span>详情</span></th>
<th><span>操作时间</span></th>
</tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="dataTables_paginate paging_bootstrap page operationLog">
<div><span class="Pcurrent">1</span><span class="Pcount">共1条</span></div>
</div>
</div>
<!-- logs end -->
<div class="tab-con hide" id="logAudit" style="height: auto;">
<div class="logAuditTabContent">
<div class="logAuditTab" style="width: 300px;overflow: hidden;overflow-y: auto;">
<!--
<div class="logAuditItem active" title="wtmp - 登录和重启记录" data-file="/wtmp">
wtmp - 登录和重启记录(4.88 KB)
</div>
-->
</div>
<div class="logAuditContent" style="overflow: hidden;overflow-y: auto;">
<div id="logAuditTable" class="bt_table" style="display: block;">
<div class="tootls_group tootls_top">
<div class="pull-left">
<button type="button" title="刷新列表" class="btn btn-success btn-sm mr5"><span>刷新列表</span></button>
</div>
<div class="pull-right">
<div class="logs_search" style="position: relative;">
<input type="text" class="search_input" style="" placeholder="请输入来源/端口/角色/事件">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</div>
</div>
</div>
<div class="divtable mtb10" style="max-height: 83px;">
<table class="table table-hover">
<thead style="position: relative;z-index: 1;">
<tr>
<th><span data-index="0"><span>用户</span></span></th>
<th><span data-index="1"><span>来源</span></span></th>
<th><span data-index="2"><span>端口</span></span></th>
<th><span data-index="3"><span>时间</span></span></th>
</tr>
</thead>
<tbody>
<!-- <tr><td><span>root</span></td>
<td><span>117.139.193.29</span></td>
<td><span>pts/0</span></td>
<td><span>2023-08-25 13:27 still logged in</span></td>
</tr> -->
</tbody>
</table>
</div>
<div class="tootls_group tootls_bottom">
<div class="pull-left"></div>
<div class="pull-right">
<div class="page"><span class="Pcount">第 1 页</span></div>
</div>
</div>
</div>
<div id="logAuditPages" class="page" style="display: flex; justify-content: flex-end;"></div>
<div id="logAuditPre" style="display: none;"><pre style="height: 188px; background-color: rgb(51, 51, 51); color: rgb(255, 255, 255); overflow-x: hidden; overflow-wrap: break-word; white-space: pre-wrap;"><code></code></pre></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="/static/app/logs.js?v={{config.version}}"></script>
{% endblock %}
+11 -4
View File
@@ -22,6 +22,9 @@ PATH=$PATH:$mw_path/bin
if [ -f $mw_path/bin/activate ];then
source $mw_path/bin/activate
if [ "$?" != "0" ];then
echo "load local python env fail!"
fi
fi
mw_start_panel()
@@ -106,16 +109,20 @@ mw_stop_task()
mw_stop_panel()
{
echo -e "stopping mw-panel... \c";
pidfile=${mw_path}/logs/mw.pid
if [ -f $pidfile ];then
pid=`cat $pidfile`
kill -9 $pid > /dev/null 2>&1
rm -f $pidfile
fi
arr=`ps aux|grep 'gunicorn -c setting.py app:app'|grep -v grep|awk '{print $2}'`
for p in ${arr[@]}
do
kill -9 $p > /dev/null 2>&1
done
pidfile=${mw_path}/logs/mw.pid
if [ -f $pidfile ];then
rm -f $pidfile
fi
echo -e "\033[32mdone\033[0m"
}
+1
View File
@@ -104,6 +104,7 @@ yum install -y graphviz libxml2 libxml2-devel
yum install -y sqlite-devel
yum install -y oniguruma oniguruma-devel
yum install -y ImageMagick ImageMagick-devel
yum install -y libargon2-devel
for yumPack in make cmake gcc gcc-c++ flex bison file libtool libtool-libs autoconf kernel-devel patch wget gd gd-devel libxml2 libxml2-devel zlib zlib-devel glib2 glib2-devel tar bzip2 bzip2-devel libevent libevent-devel ncurses ncurses-devel curl curl-devel libcurl libcurl-devel e2fsprogs e2fsprogs-devel libidn libidn-devel vim-minimal gettext gettext-devel ncurses-devel gmp-devel libcap diffutils ca-certificates net-tools psmisc libXpm-devel git-core c-ares-devel libicu-devel libxslt libxslt-devel zip unzip glibc.i686 libstdc++.so.6 cairo-devel bison-devel ncurses-devel libaio-devel perl perl-devel perl-Data-Dumper lsof crontabs expat-devel readline-devel;
+3
View File
@@ -97,7 +97,10 @@ yum install -y libzip libzip-devel
yum install -y pcre pcre-devel
yum install -y icu libicu-devel
yum install -y freetype freetype-devel
yum install -y openssl openssl-devel
yum install -y libargon2-devel
yum install -y graphviz libxml2 libxml2-devel
yum install -y sqlite-devel
yum install -y oniguruma oniguruma-devel
+1
View File
@@ -109,6 +109,7 @@ yum install -y libjpeg-devel libpng-devel libwebp libwebp-devel
yum install -y net-tools
yum install -y ncurses-devel
yum install -y libXpm-devel
yum install -y libargon2-devel
for yumPack in flex file libtool libtool-libs kernel-devel patch wget glib2 glib2-devel tar bzip2 bzip2-devel libevent libevent-devel ncurses ncurses-devel curl curl-devel libcurl libcurl-devel e2fsprogs e2fsprogs-devel libidn libidn-devel vim-minimal gettext gettext-devel ncurses-devel gmp-devel libcap diffutils ca-certificates net-tools psmisc git-core c-ares-devel libicu-devel libxslt libxslt-devel zip unzip glibc.i686 libstdc++.so.6 cairo-devel ncurses-devel libaio-devel perl perl-devel perl-Data-Dumper expat-devel readline-devel;
+1
View File
@@ -160,6 +160,7 @@ apt install -y libunwind-dev
apt install -y libpcre3 libpcre3-dev
apt install -y openssl
apt install -y libssl-dev
apt install -y libargon2-dev
apt install -y libmemcached-dev
apt install -y libsasl2-dev
+1
View File
@@ -88,6 +88,7 @@ yum install -y openldap openldap-devel
yum install -y bison re2c
yum install -y cmake cmake3
yum install -y autoconf
yum install -y libargon2-devel
yum install -y libmemcached libmemcached-devel
yum install -y curl curl-devel
+48 -49
View File
@@ -3,22 +3,40 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
LANG=en_US.UTF-8
# -- debug start --
# https://www.freebsd.org/where/
# 手动升级到,可解决库找不到的问题。
# freebsd-update -r 13.2-RELEASE upgrade
# freebsd-update -r 14-RELEASE upgrade
# pkg install -y python39
# python3 -m ensurepip
# pip3 install --upgrade setuptools
# python3 -m pip install --upgrade pip
# echo "y" | pkg upgrade
# -- debug end --
if grep -Eq "FreeBSD" /etc/*-release && [ ! -f /bin/bash ]; then
ln -sf /usr/local/bin/bash /bin/bash
fi
# freebsd-update -r 13.0-RELEASE upgrade
echo "y" | pkg update
# echo "y" | pkg upgrade
# echo "y" | freebsd-update fetch install
echo "y" | pkg bootstrap -f
echo "y" | freebsd-update install
pkg install -y python3
# python3 -m ensurepip
# pip3 install --upgrade setuptools
# python3 -m pip install --upgrade pip
pkg install -y py39-pip
pkg install -y lsof
pkg install -y vim
pkg install -y sqlite3
pkg install -y py38-sqlite3
pkg install -y py39-sqlite3
pkg install -y gcc
pkg install -y autoconf
@@ -31,60 +49,41 @@ pkg install -y influxpkg-config
pkg install -y expect
pkg install -y pcre
pkg install -y libmemcached
pkg install -y webp
pkg install -y freetype
pkg install -y oniguruma
pkg install -y brotli
pkg install -y harfbuzz
pkg install -y libevent
pkg install -y pidof
pkg install -y pstree
# curl https://sh.rustup.rs -sSf | sh
pkg install -y rust
pkg autoremove -y
SSH_PORT=`netstat -ntpl|grep sshd|grep -v grep | sed -n "1,1p" | awk '{print $4}' | awk -F : '{print $2}'`
if [ "$SSH_PORT" == "" ];then
SSH_PORT_LINE=`cat /etc/ssh/sshd_config | grep "Port \d*" | tail -1`
SSH_PORT=${SSH_PORT_LINE/"Port "/""}
fi
SSH_PORT_LINE=`cat /etc/ssh/sshd_config | grep -E "Port d*" | tail -1`
SSH_PORT=${SSH_PORT_LINE/"Port "/""}
echo "SSH PORT:${SSH_PORT}"
# if [ -f /usr/sbin/iptables ];then
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
# iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 888 -j ACCEPT
# service iptables save
# iptables_status=`service iptables status | grep 'not running'`
# if [ "${iptables_status}" == '' ];then
# service iptables restart
# fi
# #安装时不开启
# service iptables stop
# fi
if [ ! -f /usr/sbin/iptables ];then
pkg install -y firewalld
systemctl enable firewalld
systemctl start firewalld
if [ "$SSH_PORT" != "" ];then
firewall-cmd --permanent --zone=public --add-port=${SSH_PORT}/tcp
else
firewall-cmd --permanent --zone=public --add-port=22/tcp
fi
firewall-cmd --permanent --zone=public --add-port=80/tcp
firewall-cmd --permanent --zone=public --add-port=443/tcp
firewall-cmd --permanent --zone=public --add-port=888/tcp
sed -i 's#AllowZoneDrifting=yes#AllowZoneDrifting=no#g' /etc/firewalld/firewalld.conf
firewall-cmd --reload
#安装时不开启
systemctl stop firewalld
# 检测防火墙是否开启
FW_ENABLE=`cat /etc/rc.conf | grep firewall_enable`
if [ "$FW_ENABLE" == "" ];then
sysrc firewall_enable="YES"
sysrc firewall_type="open"
sysrc firewall_script="/etc/ipfw.rules"
sysrc firewall_logging="YES"
sysrc firewall_logif="YES"
fi
# ipfw list
service ipfw stop
cd /www/server/mdserver-web/scripts && bash lib.sh
chmod 755 /www/server/mdserver-web/data
+1
View File
@@ -49,6 +49,7 @@ zypper install -y libtomcrypt-devel
zypper install -y libXpm-devel
zypper install -y freetype2-devel
zypper install -y libargon2-devel
# zypper install -y php-config
+3 -4
View File
@@ -172,7 +172,6 @@ if [ "$VERSION_ID" -ge "8" ];then
# else
# REPOS='--enablerepo=remi,appstream,baseos,epel,extras,powertools'
# fi
for rpms in gcc gcc-c++ lsof autoconf bzip2 bzip2-devel c-ares-devel \
ca-certificates cairo-devel cmake crontabs curl curl-devel diffutils e2fsprogs e2fsprogs-devel \
expat-devel expect file flex gd gd-devel gettext gettext-devel glib2 glib2-devel glibc.i686 \
@@ -181,8 +180,8 @@ if [ "$VERSION_ID" -ge "8" ];then
libpng libpng-devel libstdc++.so.6 libtirpc libtirpc-devel libtool libtool-libs libwebp libwebp-devel \
libxml2 libxml2-devel libxslt libxslt-devel libarchive make mysql-devel ncurses ncurses-devel net-tools \
oniguruma oniguruma-devel patch pcre pcre-devel perl perl-Data-Dumper perl-devel procps psmisc python3-devel \
openssl openssl-devel \
readline-devel rpcgen sqlite-devel tar unzip vim-minimal wget zip zlib zlib-devel ;
openssl openssl-devel patchelf libargon2-dev\
readline-devel rpcgen sqlite-devel tar unzip vim-minimal wget zip zlib zlib-devel;
do
# dnf --enablerepo=remi,appstream,baseos,epel,extras,powertools install -y oniguruma5php-devel
dnf $REPOS install -y $rpms;
@@ -202,7 +201,7 @@ else
make mysql-devel ncurses ncurses-devel net-tools oniguruma oniguruma-devel openldap openldap-devel \
openssl openssl-devel patch pcre pcre-devel perl perl-Data-Dumper perl-devel psmisc python-devel \
python3-devel python3-pip re2c readline-devel rpcgen sqlite-devel tar unzip vim-minimal vixie-cron \
wget zip zlib zlib-devel ImageMagick ImageMagick-devel ;
wget zip zlib zlib-devel ImageMagick ImageMagick-devel patchelf libargon2-dev;
do
yum install -y $rpms;
done
+1
View File
@@ -71,6 +71,7 @@ yum install -y libpng libpng-devel libwebp libwebp-devel pcre pcre-devel gd gd-d
yum install -y net-tools
yum install -y ncurses ncurses-devel mysql-devel make cmake
yum install -y sqlite-devel
yum install -y libargon2-dev
# python-imaging
# yum install -y MySQL-python
+1
View File
@@ -92,6 +92,7 @@ apt install -y libunwind-dev
apt install -y libpcre3 libpcre3-dev
apt install -y openssl
apt install -y libssl-dev
apt install -y libargon2-dev
apt install -y libmemcached-dev
apt install -y libsasl2-dev
+2
View File
@@ -103,6 +103,8 @@ fi
pip3 install --upgrade pip -i $PIPSRC
pip3 install --upgrade setuptools -i $PIPSRC
# --no-cache-dir
cd /www/server/mdserver-web && pip3 install -r /www/server/mdserver-web/requirements.txt -i $PIPSRC
+1 -1
View File
@@ -108,4 +108,4 @@ endTime=`date +%s`
((outTime=($endTime-$startTime)/60))
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
} 1> >(tee /www/server/mdserver-web/logs/mw-update.log) 2>&1
} 1> >(tee mw-update.log) 2>&1
+1 -1
View File
@@ -14,7 +14,7 @@ fi
echo -e "start mw"
cd /www/server/mdserver-web && bash cli.sh start
isStart=`ps -ef|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
isStart=`ps -aux|grep 'gunicorn -c setting.py app:app' |grep -v grep|awk '{print $2}'`
n=0
while [[ ! -f /etc/rc.d/init.d/mw ]];
do
+1 -1
View File
@@ -119,4 +119,4 @@ endTime=`date +%s`
((outTime=($endTime-$startTime)/60))
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
} 1> >(tee /www/server/mdserver-web/logs/mw-update.log) 2>&1
} 1> >(tee mw-update.log) 2>&1