mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 16:59:25 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cbca9232c | ||
|
|
742bb6d86d | ||
|
|
b14accd83e | ||
|
|
8ae01d8d36 | ||
|
|
5db1e58e6a | ||
|
|
a2e6d2f280 | ||
|
|
83f3d224ed | ||
|
|
73693620df | ||
|
|
72eb67dfda | ||
|
|
c55b4a02c8 | ||
|
|
721efd6a16 | ||
|
|
61c8ce4b6f | ||
|
|
ce95ca6905 | ||
|
|
01dee5fe1f | ||
|
|
1a72edee9a | ||
|
|
27b6ad0280 | ||
|
|
ae9e6921c3 | ||
|
|
b51eb99027 | ||
|
|
2e584c540d | ||
|
|
bbf258e1a7 | ||
|
|
53d57716aa | ||
|
|
e9a6e5477d | ||
|
|
46ca8a6b44 | ||
|
|
d6f88caf3d | ||
|
|
abc85902a2 | ||
|
|
9edc8bbea2 | ||
|
|
443d3efd37 | ||
|
|
948bcde358 | ||
|
|
83aa3cfca6 | ||
|
|
976c88ed44 | ||
|
|
0db16797b5 | ||
|
|
b7802fc898 | ||
|
|
741dffd5db | ||
|
|
2c9f11bcfe | ||
|
|
16893e51e6 | ||
|
|
34a43a6af9 | ||
|
|
4dd5d946d9 | ||
|
|
7e63f686b9 | ||
|
|
7b57972179 | ||
|
|
a758a36bdc | ||
|
|
84123c603d | ||
|
|
33f9c09a07 |
@@ -1,30 +0,0 @@
|
||||
---
|
||||
name: BUG提交
|
||||
about: 问题描述
|
||||
---
|
||||
|
||||
## 什么系统 ?
|
||||
|
||||
Debian x, Centos x, Centos x stream, Ubuntu x?
|
||||
|
||||
## 错误信息 ?
|
||||
|
||||
Ex:
|
||||
```bash
|
||||
................start mw success
|
||||
bash: line 149: ./scripts/init.d/mw: No such file or directory
|
||||
```
|
||||
|
||||
## 错误截图 ?
|
||||
|
||||
...
|
||||
|
||||
|
||||
## 浏览器版本 ?
|
||||
|
||||
...
|
||||
|
||||
|
||||
## 软件版本(插件/面板) ?
|
||||
|
||||
...
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
name: 需求提交
|
||||
about: 需求描述
|
||||
---
|
||||
|
||||
## 需求
|
||||
|
||||
想开发一个什么插件?
|
||||
想有什么功能?
|
||||
|
||||
|
||||
## 提供参考
|
||||
|
||||
给开发者提供参考!
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Bug提交
|
||||
description: 提交错误报告以帮助我们改进
|
||||
labels: ["\U0001F48A bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
感谢您花时间填写此错误报告!
|
||||
|
||||
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
|
||||
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
|
||||
- type: input
|
||||
attributes:
|
||||
label: 操作系统
|
||||
description: |
|
||||
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 描述错误
|
||||
description: 对bug的清晰而简洁的描述。
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 提出问题
|
||||
url: https://github.com/midoks/mdserver-web/discussions
|
||||
about: 请在讨论中提出问题。
|
||||
- name: 提出建议
|
||||
url: https://github.com/midoks/mdserver-web/discussions/categories/proposal
|
||||
about: 请在讨论中提出建议。
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Bug提交
|
||||
description: 提交错误报告以帮助我们改进
|
||||
labels: ["\U0001F48A bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
感谢您花时间填写此错误报告!
|
||||
|
||||
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
|
||||
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
|
||||
- type: input
|
||||
attributes:
|
||||
label: 操作系统
|
||||
description: |
|
||||
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 描述错误
|
||||
description: 对bug的清晰而简洁的描述。
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Bug提交
|
||||
description: 提交错误报告以帮助我们改进
|
||||
labels: ["\U0001F48A bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
感谢您花时间填写此错误报告!
|
||||
|
||||
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
|
||||
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
|
||||
- type: input
|
||||
attributes:
|
||||
label: 操作系统
|
||||
description: |
|
||||
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 描述错误
|
||||
description: 对bug的清晰而简洁的描述。
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,9 +0,0 @@
|
||||
### 合并描述
|
||||
|
||||
对pull请求的内容进行清晰、简洁的描述,即应该解决什么问题?
|
||||
|
||||
问题链接:<!--将问题链接粘贴到此处,如果不适用,请填写“不适用”->
|
||||
|
||||
### 清单
|
||||
|
||||
- [ ] 我添加了测试用例来覆盖新代码。
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL55
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL55
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.5
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL56
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL56
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.6
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL57
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL57
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.7
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP MySQL80
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install MySQL80
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 8.0
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP OpenResty
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "dev" ]
|
||||
pull_request:
|
||||
branches: [ "master", "dev" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install OpenResty
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/openresty && sudo bash install.sh install 1.21.4.1
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
@@ -1,68 +0,0 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: MW APP PHP
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "run_test" ]
|
||||
pull_request:
|
||||
branches: [ "run_test" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
#runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install MW
|
||||
run: |
|
||||
sudo bash scripts/install_dev.sh
|
||||
- name: Install PHP53
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 53
|
||||
- name: Install PHP54
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 54
|
||||
- name: Install PHP55
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 55
|
||||
- name: Install PHP56
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 56
|
||||
- name: Install PHP70
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 70
|
||||
- name: Install PHP71
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 71
|
||||
- name: Install PHP72
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 72
|
||||
- name: Install PHP73
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 73
|
||||
- name: Install PHP74
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 74
|
||||
- name: Install PHP80
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 80
|
||||
- name: Install PHP81
|
||||
run: |
|
||||
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 81
|
||||
- name: Start DEBUG
|
||||
run: |
|
||||
gunicorn -c setting.py app:app
|
||||
python3 task.py &
|
||||
+2
-51
@@ -8,11 +8,13 @@ __pycache__/
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
@@ -104,54 +106,3 @@ venv.bak/
|
||||
.DS_Store
|
||||
.idea/*.xml
|
||||
.idea/*.iml
|
||||
tmp/*
|
||||
*.swp
|
||||
*.zip
|
||||
scripts/init.d/mw
|
||||
logs/*
|
||||
data/*.db
|
||||
data/control.conf
|
||||
data/iplist.txt
|
||||
data/json/index.json
|
||||
data/json/config.json
|
||||
data/site.pl
|
||||
data/admin_path.pl
|
||||
data/close.pl
|
||||
ssl/input.pl
|
||||
data/datadir.pl
|
||||
data/502Task.pl
|
||||
data/default.pl
|
||||
data/backup.pl
|
||||
data/default_site.pl
|
||||
lib/python*
|
||||
|
||||
bin
|
||||
pyvenv.cfg
|
||||
include
|
||||
share
|
||||
pip-selfcheck.json
|
||||
|
||||
scripts/mdserver-web
|
||||
data/api_login.txt
|
||||
data/sessions
|
||||
data/ssl.pl
|
||||
data/port.pl
|
||||
data/ipv6.pl
|
||||
data/restart.pl
|
||||
data/ssl.pl
|
||||
data/edate.pl
|
||||
data/osname.pl
|
||||
data/only_netio_counters.pl
|
||||
data/system.db-journal
|
||||
data/hook_*.json
|
||||
|
||||
plugins/l2tp
|
||||
plugins/openlitespeed
|
||||
plugins/gdrive
|
||||
plugins/mtproxy
|
||||
plugins/zimg
|
||||
plugins/bk_demo
|
||||
debug.out
|
||||
|
||||
|
||||
|
||||
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [midoks] [midoks of copyright owner]
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,180 +1,14 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/logo.png" height="140" />
|
||||
<h3 align="center">mdserver-web</h3>
|
||||
<p align="center">一款简单Linux面板服务</p>
|
||||
</p>
|
||||
|
||||
### 简介
|
||||
|
||||
简单的Linux面板,感谢BT.CN写出如此好的web管理软件。我一看到,就知道这是我一直想要的页面化管理方式。
|
||||
复制了后台管理界面,按照自己想要的方式写了一版。
|
||||
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
[](https://github.com/midoks/mdserver-web/wiki)
|
||||
[](https://www.jsdelivr.com/package/gh/midoks/mdserver-web)
|
||||
|
||||
* SSH终端工具
|
||||
* 面板收藏功能
|
||||
* 网站子目录绑定
|
||||
* 网站备份功能
|
||||
* 插件方式管理
|
||||
|
||||
基本上可以使用,后续会继续优化!欢迎提供意见!
|
||||
|
||||
- 吹水组 - https://t.me/mdserver_web
|
||||
- [兼容性测试报告](/compatibility.md)
|
||||
- [常用命令说明](/cmd.md)
|
||||
|
||||
### 主要插件介绍
|
||||
|
||||
* OpenResty - 轻量级,占有内存少,并发能力强。
|
||||
* PHP[52-81] - PHP是世界上最好的编程语言。
|
||||
* MySQL - 一种关系数据库管理系统。
|
||||
* MariaDB - 是MySQL的一个重要分支。
|
||||
* MongoDB - 一种非关系NOSQL数据库管理系统。
|
||||
* phpMyAdmin - 著名Web端MySQL管理工具。
|
||||
* Memcached - 一个高性能的分布式内存对象缓存系统。
|
||||
* Redis - 一个高性能的KV数据库。
|
||||
* PureFtpd - 一款专注于程序健壮和软件安全的免费FTP服务器软件。
|
||||
* Gogs - 一款极易搭建的自助Git服务。
|
||||
* Rsyncd - 通用同步服务。
|
||||
|
||||
|
||||
### 插件开发相关
|
||||
# mdweb
|
||||
简单的Linux面板
|
||||
|
||||
### 自动安装
|
||||
```
|
||||
插件文档还不完善,如果有不明白的地方提Issue! 我会尽力完善。
|
||||
如果你自己写了插件,想分享出来,也可以提Issue。
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdweb/master/install/install.sh | sh
|
||||
```
|
||||
|
||||
- 简单例子 - https://github.com/mw-plugin/simple-plugin
|
||||
- 插件地址 - https://github.com/mw-plugin
|
||||
- 开发文档 - https://github.com/midoks/mdserver-web/wiki/插件开发
|
||||
|
||||
|
||||
# Note
|
||||
|
||||
```
|
||||
phpMyAdmin[4.4.15]支持MySQL[5.5-5.7]
|
||||
phpMyAdmin[5.2.0]支持MySQL[8.0]
|
||||
|
||||
PHP[53-72]支持phpMyAdmin[4.4.15]
|
||||
PHP[72-81]支持phpMyAdmin[5.2.0]
|
||||
```
|
||||
|
||||
# AD - VPS推荐 - 🙏
|
||||
|
||||
- [ZZZ评测](https://www.zzzvps.com/)
|
||||
|
||||
| 服务商 | LOGO | 推广地址 | 优惠码 |
|
||||
| ------------- |----------|-----------|-------|
|
||||
| digitalvirt |[](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | 9SYDY7UH0U |
|
||||
| 搬瓦工 |[](https://bandwagonhost.com/aff.php?aff=54161) | https://bandwagonhost.com/aff.php?aff=54161 | BWH3HYATVBJW |
|
||||
|
||||
# Docker
|
||||
|
||||
- 由[DDSRem](https://github.com/DDSRem)开发维护。
|
||||
- https://hub.docker.com/r/ddsderek/mw-server
|
||||
|
||||
```
|
||||
docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:443 -p 888:888 ddsderek/mw-server:latest
|
||||
```
|
||||
|
||||
|
||||
### 版本更新 0.9.9
|
||||
|
||||
* 更换Logo。
|
||||
* 增加amazon linux系统支持。
|
||||
* 修复rsyncd在debian或ubuntu下安装失败问题。
|
||||
* Readme加入一AD。
|
||||
* PHP-YUM|PHP-APT优化[性能调整]。
|
||||
* 优化Gogs使用MySQL的方式。
|
||||
* 配置模板添加一个whmcs。
|
||||
* MySQL和MariaDB无法直接卸载。
|
||||
* OpenResty加入http_realip_module模块。
|
||||
* PHP加入igbinary扩展。
|
||||
|
||||
|
||||
### JSDelivr安装地址
|
||||
|
||||
- 初始安装
|
||||
|
||||
```
|
||||
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
|
||||
```
|
||||
|
||||
- 直接更新
|
||||
|
||||
```
|
||||
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
|
||||
```
|
||||
|
||||
### 备用地址
|
||||
|
||||
- 初始安装
|
||||
|
||||
```
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
|
||||
|
||||
```
|
||||
|
||||
- 直接更新
|
||||
|
||||
```
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
|
||||
```
|
||||
|
||||
|
||||
### 通用软件安装[命令行安装]
|
||||
|
||||
- 需已经安装mdserver-web
|
||||
|
||||
```
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
|
||||
```
|
||||
|
||||
|
||||
### DEV使用
|
||||
|
||||
```
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
|
||||
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
|
||||
|
||||
|
||||
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/master/scripts/install_dev.sh | bash
|
||||
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/master/scripts/update_dev.sh | bash
|
||||
```
|
||||
|
||||
### 捐赠地址 USDT(TRC20)
|
||||
|
||||
TVbNgrpeGBGZVm5gTLa21ADP7RpnPFhjya
|
||||
|
||||
|
||||
### 微信赞助
|
||||
|
||||
[](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/weixin_zz.jpg)
|
||||
|
||||
|
||||
### 无图不真相
|
||||
|
||||
[](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/mdw.jpg)
|
||||
|
||||
|
||||
### Stargazers over time
|
||||
|
||||
[](https://starchart.cc/midoks/mdserver-web)
|
||||
|
||||
|
||||
### 感谢开发赞助
|
||||
|
||||
[](https://digitalvirt.com/aff.php?aff=154)
|
||||
|
||||
### 授权许可
|
||||
|
||||
本项目采用 Apache 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/midoks/mdserver-web/blob/master/LICENSE) 文件中。
|
||||
|
||||
### 手动操作
|
||||
- pip install pip==9.0.3
|
||||
- pip install flask
|
||||
- pip install gunicorn
|
||||
- pip install psutil
|
||||
- pip install -r requirements.txt
|
||||
|
||||
@@ -1,37 +1,36 @@
|
||||
# coding:utf-8
|
||||
|
||||
# pip install profiler_online
|
||||
# 性能测试
|
||||
# from profiler_online import run_profiler
|
||||
# run_profiler()
|
||||
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
|
||||
from flask import Flask
|
||||
import views
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
from route import app, socketio
|
||||
|
||||
sys.path.append("class/")
|
||||
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
DEFAULT_MODULES = (
|
||||
(views.dashboard, "/"),
|
||||
(views.site, "/site"),
|
||||
(views.files, "/files"),
|
||||
(views.soft, "/soft"),
|
||||
(views.config, "/config"),
|
||||
(views.plugins, "/plugins"),
|
||||
(views.task, "/task"),
|
||||
)
|
||||
|
||||
try:
|
||||
if __name__ == "__main__":
|
||||
import time
|
||||
# print "time.time(): %f " % time.time()
|
||||
app.config.version = "0.0.1" + str(time.time())
|
||||
|
||||
PORT = 7200
|
||||
if os.path.exists('data/port.pl'):
|
||||
f = open('data/port.pl')
|
||||
PORT = int(f.read())
|
||||
f.close()
|
||||
|
||||
HOST = '0.0.0.0'
|
||||
http_server = WSGIServer(
|
||||
(HOST, PORT), app, handler_class=WebSocketHandler)
|
||||
def setting_modules(app, modules):
|
||||
for module, url_prefix in modules:
|
||||
app.register_blueprint(module, url_prefix=url_prefix)
|
||||
|
||||
http_server.serve_forever()
|
||||
setting_modules(app, DEFAULT_MODULES)
|
||||
|
||||
socketio.run(app, host=HOST, port=PORT)
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import string
|
||||
import json
|
||||
import hashlib
|
||||
import shlex
|
||||
import datetime
|
||||
import subprocess
|
||||
import re
|
||||
import hashlib
|
||||
from random import Random
|
||||
|
||||
import mw
|
||||
import db
|
||||
|
||||
from flask import redirect
|
||||
|
||||
|
||||
def init():
|
||||
initDB()
|
||||
initUserInfo()
|
||||
initInitD()
|
||||
|
||||
|
||||
def local():
|
||||
result = checkClose()
|
||||
if result:
|
||||
return result
|
||||
|
||||
|
||||
# 检查面板是否关闭
|
||||
def checkClose():
|
||||
if os.path.exists('data/close.pl'):
|
||||
return redirect('/close')
|
||||
|
||||
|
||||
def initDB():
|
||||
try:
|
||||
sql = db.Sql().dbfile('default')
|
||||
csql = mw.readFile('data/sql/default.sql')
|
||||
csql_list = csql.split(';')
|
||||
for index in range(len(csql_list)):
|
||||
sql.execute(csql_list[index], ())
|
||||
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
|
||||
|
||||
def doContentReplace(src, dst):
|
||||
content = mw.readFile(src)
|
||||
content = content.replace("{$SERVER_PATH}", mw.getRunDir())
|
||||
mw.writeFile(dst, content)
|
||||
|
||||
|
||||
def initInitD():
|
||||
|
||||
# systemctl
|
||||
# 有问题
|
||||
# if os.path.exists('/lib/systemd/system'):
|
||||
# systemd_mw = '/lib/systemd/system/mw.service'
|
||||
# systemd_mw_task = '/lib/systemd/system/mw-task.service'
|
||||
|
||||
# systemd_mw_tpl = mw.getRunDir() + '/scripts/init.d/mw.service.tpl'
|
||||
# systemd_mw_task_tpl = mw.getRunDir() + '/scripts/init.d/mw-task.service.tpl'
|
||||
|
||||
# os.remove(systemd_mw)
|
||||
# os.remove(systemd_mw_task)
|
||||
# doContentReplace(systemd_mw_tpl, systemd_mw)
|
||||
# doContentReplace(systemd_mw_task_tpl, systemd_mw_task)
|
||||
|
||||
# mw.execShell('systemctl enable mw')
|
||||
# mw.execShell('systemctl enable mw-task')
|
||||
# mw.execShell('systemctl daemon-reload')
|
||||
|
||||
script = mw.getRunDir() + '/scripts/init.d/mw.tpl'
|
||||
script_bin = mw.getRunDir() + '/scripts/init.d/mw'
|
||||
doContentReplace(script, script_bin)
|
||||
mw.execShell('chmod +x ' + script_bin)
|
||||
|
||||
# 在linux系统中,确保/etc/init.d存在
|
||||
if not mw.isAppleSystem() and not os.path.exists("/etc/init.d"):
|
||||
mw.execShell('mkdir -p /etc/init.d')
|
||||
|
||||
# initd
|
||||
if os.path.exists("/etc/init.d"):
|
||||
initd_bin = '/etc/init.d/mw'
|
||||
if not os.path.exists(initd_bin):
|
||||
import shutil
|
||||
shutil.copyfile(script_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
# 加入自启动
|
||||
mw.execShell('which chkconfig && chkconfig --add mw')
|
||||
mw.execShell('which update-rc.d && update-rc.d -f mw defaults')
|
||||
|
||||
# 获取系统IPV4
|
||||
mw.setHostAddr(mw.getLocalIp())
|
||||
|
||||
|
||||
def initUserInfo():
|
||||
|
||||
data = mw.M('users').where('id=?', (1,)).getField('password')
|
||||
if data == '21232f297a57a5a743894a0e4a801fc3':
|
||||
pwd = mw.getRandomString(8).lower()
|
||||
file_pw = mw.getRunDir() + '/data/default.pl'
|
||||
mw.writeFile(file_pw, pwd)
|
||||
mw.M('users').where('id=?', (1,)).setField(
|
||||
'password', mw.md5(pwd))
|
||||
@@ -1,335 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
from flask import session
|
||||
from flask import request
|
||||
|
||||
|
||||
class config_api:
|
||||
|
||||
__version = '0.9.9'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
##### ----- start ----- ###
|
||||
|
||||
# 取面板列表
|
||||
def getPanelListApi(self):
|
||||
data = mw.M('panel').field(
|
||||
'id,title,url,username,password,click,addtime').order('click desc').select()
|
||||
return mw.getJson(data)
|
||||
|
||||
def addPanelInfoApi(self):
|
||||
title = request.form.get('title', '')
|
||||
url = request.form.get('url', '')
|
||||
username = request.form.get('username', '')
|
||||
password = request.form.get('password', '')
|
||||
# 校验是还是重复
|
||||
isAdd = mw.M('panel').where(
|
||||
'title=? OR url=?', (title, url)).count()
|
||||
if isAdd:
|
||||
return mw.returnJson(False, '备注或面板地址重复!')
|
||||
isRe = mw.M('panel').add('title,url,username,password,click,addtime',
|
||||
(title, url, username, password, 0, int(time.time())))
|
||||
if isRe:
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
return mw.returnJson(False, '添加失败!')
|
||||
|
||||
# 删除面板资料
|
||||
def delPanelInfoApi(self):
|
||||
mid = request.form.get('id', '')
|
||||
isExists = mw.M('panel').where('id=?', (mid,)).count()
|
||||
if not isExists:
|
||||
return mw.returnJson(False, '指定面板资料不存在!')
|
||||
mw.M('panel').where('id=?', (mid,)).delete()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
# 修改面板资料
|
||||
def setPanelInfoApi(self):
|
||||
title = request.form.get('title', '')
|
||||
url = request.form.get('url', '')
|
||||
username = request.form.get('username', '')
|
||||
password = request.form.get('password', '')
|
||||
mid = request.form.get('id', '')
|
||||
# 校验是还是重复
|
||||
isSave = mw.M('panel').where(
|
||||
'(title=? OR url=?) AND id!=?', (title, url, mid)).count()
|
||||
if isSave:
|
||||
return mw.returnJson(False, '备注或面板地址重复!')
|
||||
|
||||
# 更新到数据库
|
||||
isRe = mw.M('panel').where('id=?', (mid,)).save(
|
||||
'title,url,username,password', (title, url, username, password))
|
||||
if isRe:
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
return mw.returnJson(False, '修改失败!')
|
||||
|
||||
def syncDateApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发系统不必同步时间!')
|
||||
|
||||
data = mw.execShell('ntpdate -s time.nist.gov')
|
||||
if data[0] == '':
|
||||
return mw.returnJson(True, '同步成功!')
|
||||
return mw.returnJson(False, '同步失败:' + data[0])
|
||||
|
||||
def setPasswordApi(self):
|
||||
password1 = request.form.get('password1', '')
|
||||
password2 = request.form.get('password2', '')
|
||||
if password1 != password2:
|
||||
return mw.returnJson(False, '两次输入的密码不一致,请重新输入!')
|
||||
if len(password1) < 5:
|
||||
return mw.returnJson(False, '用户密码不能小于5位!')
|
||||
mw.M('users').where("username=?", (session['username'],)).setField(
|
||||
'password', mw.md5(password1.strip()))
|
||||
return mw.returnJson(True, '密码修改成功!')
|
||||
|
||||
def setNameApi(self):
|
||||
name1 = request.form.get('name1', '')
|
||||
name2 = request.form.get('name2', '')
|
||||
if name1 != name2:
|
||||
return mw.returnJson(False, '两次输入的用户名不一致,请重新输入!')
|
||||
if len(name1) < 3:
|
||||
return mw.returnJson(False, '用户名长度不能少于3位')
|
||||
|
||||
mw.M('users').where("username=?", (session['username'],)).setField(
|
||||
'username', name1.strip())
|
||||
|
||||
session['username'] = name1
|
||||
return mw.returnJson(True, '用户修改成功!')
|
||||
|
||||
def setApi(self):
|
||||
webname = request.form.get('webname', '')
|
||||
port = request.form.get('port', '')
|
||||
host_ip = request.form.get('host_ip', '')
|
||||
domain = request.form.get('domain', '')
|
||||
sites_path = request.form.get('sites_path', '')
|
||||
backup_path = request.form.get('backup_path', '')
|
||||
|
||||
if domain != '':
|
||||
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
|
||||
if not re.match(reg, domain):
|
||||
return mw.returnJson(False, '主域名格式不正确')
|
||||
|
||||
if int(port) >= 65535 or int(port) < 100:
|
||||
return mw.returnJson(False, '端口范围不正确!')
|
||||
|
||||
if webname != mw.getConfig('title'):
|
||||
mw.setConfig('title', webname)
|
||||
|
||||
if sites_path != mw.getWwwDir():
|
||||
mw.setWwwDir(sites_path)
|
||||
|
||||
if backup_path != mw.getWwwDir():
|
||||
mw.setBackupDir(backup_path)
|
||||
|
||||
if port != mw.getHostPort():
|
||||
import system_api
|
||||
import firewall_api
|
||||
|
||||
if os.path.exists("/lib/systemd/system/firewalld.service"):
|
||||
if not firewall_api.firewall_api().getFwStatus():
|
||||
return mw.returnJson(False, 'firewalld必须先启动!')
|
||||
|
||||
mw.setHostPort(port)
|
||||
|
||||
msg = mw.getInfo('放行端口[{1}]成功', (port,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
mw.M('firewall').add('port,ps,addtime', (port, "配置修改", addtime))
|
||||
|
||||
firewall_api.firewall_api().addAcceptPort(port)
|
||||
firewall_api.firewall_api().firewallReload()
|
||||
|
||||
system_api.system_api().restartMw()
|
||||
|
||||
if host_ip != mw.getHostAddr():
|
||||
mw.setHostAddr(host_ip)
|
||||
|
||||
mhost = mw.getHostAddr()
|
||||
info = {
|
||||
'uri': '/config',
|
||||
'host': mhost + ':' + port
|
||||
}
|
||||
return mw.returnJson(True, '保存成功!', info)
|
||||
|
||||
def setAdminPathApi(self):
|
||||
admin_path = request.form.get('admin_path', '').strip()
|
||||
admin_path_checks = ['/', '/close', '/login', '/do_login', '/site',
|
||||
'/sites', '/download_file', '/control', '/crontab',
|
||||
'/firewall', '/files', 'config', '/soft', '/system',
|
||||
'/code', '/ssl', '/plugins']
|
||||
if admin_path == '':
|
||||
admin_path = '/'
|
||||
if admin_path != '/':
|
||||
if len(admin_path) < 6:
|
||||
return mw.returnJson(False, '安全入口地址长度不能小于6位!')
|
||||
if admin_path in admin_path_checks:
|
||||
return mw.returnJson(False, '该入口已被面板占用,请使用其它入口!')
|
||||
if not re.match("^/[\w\./-_]+$", admin_path):
|
||||
return mw.returnJson(False, '入口地址格式不正确,示例: /my_panel')
|
||||
else:
|
||||
domain = mw.readFile('data/domain.conf')
|
||||
if not domain:
|
||||
domain = ''
|
||||
limitip = mw.readFile('data/limitip.conf')
|
||||
if not limitip:
|
||||
limitip = ''
|
||||
if not domain.strip() and not limitip.strip():
|
||||
return mw.returnJson(False, '警告,关闭安全入口等于直接暴露你的后台地址在外网,十分危险,至少开启以下一种安全方式才能关闭:<a style="color:red;"><br>1、绑定访问域名<br>2、绑定授权IP</a>')
|
||||
|
||||
admin_path_file = 'data/admin_path.pl'
|
||||
admin_path_old = '/'
|
||||
if os.path.exists(admin_path_file):
|
||||
admin_path_old = mw.readFile(admin_path_file).strip()
|
||||
|
||||
if admin_path_old != admin_path:
|
||||
mw.writeFile(admin_path_file, admin_path)
|
||||
mw.restartMw()
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
def closePanelApi(self):
|
||||
filename = 'data/close.pl'
|
||||
if os.path.exists(filename):
|
||||
os.remove(filename)
|
||||
return mw.returnJson(True, '开启成功')
|
||||
mw.writeFile(filename, 'True')
|
||||
mw.execShell("chmod 600 " + filename)
|
||||
mw.execShell("chown root.root " + filename)
|
||||
return mw.returnJson(True, '面板已关闭!')
|
||||
|
||||
def setIpv6StatusApi(self):
|
||||
ipv6_file = 'data/ipv6.pl'
|
||||
if os.path.exists('data/ipv6.pl'):
|
||||
os.remove(ipv6_file)
|
||||
mw.writeLog('面板设置', '关闭面板IPv6兼容!')
|
||||
else:
|
||||
mw.writeFile(ipv6_file, 'True')
|
||||
mw.writeLog('面板设置', '开启面板IPv6兼容!')
|
||||
mw.restartMw()
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
# 获取面板证书
|
||||
def getPanelSslApi(self):
|
||||
cert = {}
|
||||
cert['privateKey'] = mw.readFile('ssl/privateKey.pem')
|
||||
cert['certPem'] = mw.readFile('ssl/certificate.pem')
|
||||
cert['rep'] = os.path.exists('ssl/input.pl')
|
||||
return mw.getJson(cert)
|
||||
|
||||
# 保存面板证书
|
||||
def savePanelSslApi(self):
|
||||
keyPath = 'ssl/privateKey.pem'
|
||||
certPath = 'ssl/certificate.pem'
|
||||
checkCert = '/tmp/cert.pl'
|
||||
|
||||
certPem = request.form.get('certPem', '').strip()
|
||||
privateKey = request.form.get('privateKey', '').strip()
|
||||
|
||||
mw.writeFile(checkCert, certPem)
|
||||
if privateKey:
|
||||
mw.writeFile(keyPath, privateKey)
|
||||
if certPem:
|
||||
mw.writeFile(certPath, certPem)
|
||||
if not mw.checkCert(checkCert):
|
||||
return mw.returnJson(False, '证书错误,请检查!')
|
||||
mw.writeFile('ssl/input.pl', 'True')
|
||||
return mw.returnJson(True, '证书已保存!')
|
||||
|
||||
# 设置面板SSL
|
||||
def setPanelSslApi(self):
|
||||
sslConf = mw.getRunDir() + '/data/ssl.pl'
|
||||
if os.path.exists(sslConf):
|
||||
os.system('rm -f ' + sslConf)
|
||||
return mw.returnJson(True, 'SSL已关闭,请使用http协议访问面板!')
|
||||
else:
|
||||
os.system('pip install cffi==1.10')
|
||||
os.system('pip install cryptography==2.1')
|
||||
os.system('pip install pyOpenSSL==16.2')
|
||||
try:
|
||||
if not self.createSSL():
|
||||
return mw.returnJson(False, '开启失败,无法自动安装pyOpenSSL组件!<p>请尝试手动安装: pip install pyOpenSSL</p>')
|
||||
mw.writeFile(sslConf, 'True')
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '开启失败,无法自动安装pyOpenSSL组件!<p>请尝试手动安装: pip install pyOpenSSL</p>')
|
||||
return mw.returnJson(True, '开启成功,请使用https协议访问面板!')
|
||||
|
||||
def getApi(self):
|
||||
data = {}
|
||||
return mw.getJson(data)
|
||||
##### ----- end ----- ###
|
||||
|
||||
# 自签证书
|
||||
def createSSL(self):
|
||||
if os.path.exists('ssl/input.pl'):
|
||||
return True
|
||||
import OpenSSL
|
||||
key = OpenSSL.crypto.PKey()
|
||||
key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
|
||||
cert = OpenSSL.crypto.X509()
|
||||
cert.set_serial_number(0)
|
||||
cert.get_subject().CN = mw.getLocalIp()
|
||||
cert.set_issuer(cert.get_subject())
|
||||
cert.gmtime_adj_notBefore(0)
|
||||
cert.gmtime_adj_notAfter(86400 * 3650)
|
||||
cert.set_pubkey(key)
|
||||
cert.sign(key, 'md5')
|
||||
cert_ca = OpenSSL.crypto.dump_certificate(
|
||||
OpenSSL.crypto.FILETYPE_PEM, cert)
|
||||
private_key = OpenSSL.crypto.dump_privatekey(
|
||||
OpenSSL.crypto.FILETYPE_PEM, key)
|
||||
if len(cert_ca) > 100 and len(private_key) > 100:
|
||||
mw.writeFile('ssl/certificate.pem', cert_ca)
|
||||
mw.writeFile('ssl/privateKey.pem', private_key)
|
||||
print(cert_ca, private_key)
|
||||
return True
|
||||
return False
|
||||
|
||||
def getVersion(self):
|
||||
return self.__version
|
||||
|
||||
def get(self):
|
||||
|
||||
data = {}
|
||||
data['title'] = mw.getConfig('title')
|
||||
data['site_path'] = mw.getWwwDir()
|
||||
data['backup_path'] = mw.getBackupDir()
|
||||
sformat = 'date +"%Y-%m-%d %H:%M:%S %Z %z"'
|
||||
data['systemdate'] = mw.execShell(sformat)[0].strip()
|
||||
|
||||
data['port'] = mw.getHostPort()
|
||||
data['ip'] = mw.getHostAddr()
|
||||
|
||||
admin_path_file = 'data/admin_path.pl'
|
||||
if not os.path.exists(admin_path_file):
|
||||
data['admin_path'] = '/'
|
||||
else:
|
||||
data['admin_path'] = mw.readFile(admin_path_file)
|
||||
|
||||
ipv6_file = 'data/ipv6.pl'
|
||||
if os.path.exists('data/ipv6.pl'):
|
||||
data['ipv6'] = 'checked'
|
||||
else:
|
||||
data['ipv6'] = ''
|
||||
|
||||
ssl_file = 'data/ssl.pl'
|
||||
if os.path.exists('data/ssl.pl'):
|
||||
data['ssl'] = 'checked'
|
||||
else:
|
||||
data['ssl'] = ''
|
||||
|
||||
data['site_count'] = mw.M('sites').count()
|
||||
|
||||
data['username'] = mw.M('users').where(
|
||||
"id=?", (1,)).getField('username')
|
||||
|
||||
return data
|
||||
@@ -1,549 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
from flask import request
|
||||
|
||||
|
||||
class crontab_api:
|
||||
|
||||
field = 'id,name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
##### ----- start ----- ###
|
||||
def listApi(self):
|
||||
p = request.args.get('p', 1)
|
||||
psize = 10
|
||||
|
||||
startPage = (int(p) - 1) * psize
|
||||
pageInfo = str(startPage) + ',' + str(psize)
|
||||
|
||||
_list = mw.M('crontab').where('', ()).field(
|
||||
self.field).limit(pageInfo).order('id desc').select()
|
||||
|
||||
data = []
|
||||
for i in range(len(_list)):
|
||||
tmp = _list[i]
|
||||
if _list[i]['type'] == "day":
|
||||
tmp['type'] = '每天'
|
||||
tmp['cycle'] = mw.getInfo('每天, {1}点{2}分 执行', (str(
|
||||
_list[i]['where_hour']), str(_list[i]['where_minute'])))
|
||||
elif _list[i]['type'] == "day-n":
|
||||
tmp['type'] = mw.getInfo(
|
||||
'每{1}天', (str(_list[i]['where1']),))
|
||||
tmp['cycle'] = mw.getInfo('每隔{1}天, {2}点{3}分 执行', (str(
|
||||
_list[i]['where1']), str(_list[i]['where_hour']), str(_list[i]['where_minute'])))
|
||||
elif _list[i]['type'] == "hour":
|
||||
tmp['type'] = '每小时'
|
||||
tmp['cycle'] = mw.getInfo(
|
||||
'每小时, 第{1}分钟 执行', (str(_list[i]['where_minute']),))
|
||||
elif _list[i]['type'] == "hour-n":
|
||||
tmp['type'] = mw.getInfo(
|
||||
'每{1}小时', (str(_list[i]['where1']),))
|
||||
tmp['cycle'] = mw.getInfo('每{1}小时, 第{2}分钟 执行', (str(
|
||||
_list[i]['where1']), str(_list[i]['where_minute'])))
|
||||
elif _list[i]['type'] == "minute-n":
|
||||
tmp['type'] = mw.getInfo(
|
||||
'每{1}分钟', (str(_list[i]['where1']),))
|
||||
tmp['cycle'] = mw.getInfo(
|
||||
'每隔{1}分钟执行', (str(_list[i]['where1']),))
|
||||
elif _list[i]['type'] == "week":
|
||||
tmp['type'] = '每周'
|
||||
if not _list[i]['where1']:
|
||||
_list[i]['where1'] = '0'
|
||||
tmp['cycle'] = mw.getInfo('每周{1}, {2}点{3}分执行', (self.toWeek(int(
|
||||
_list[i]['where1'])), str(_list[i]['where_hour']), str(_list[i]['where_minute'])))
|
||||
elif _list[i]['type'] == "month":
|
||||
tmp['type'] = '每月'
|
||||
tmp['cycle'] = mw.getInfo('每月, {1}日 {2}点{3}分执行', (str(_list[i]['where1']), str(
|
||||
_list[i]['where_hour']), str(_list[i]['where_minute'])))
|
||||
data.append(tmp)
|
||||
|
||||
_ret = {}
|
||||
_ret['data'] = data
|
||||
|
||||
count = mw.M('crontab').where('', ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['p'] = p
|
||||
_page['row'] = psize
|
||||
_page['tojs'] = "getCronData"
|
||||
|
||||
_ret['list'] = mw.getPage(_page)
|
||||
_ret['p'] = p
|
||||
return mw.getJson(_ret)
|
||||
|
||||
# 设置计划任务状态
|
||||
def setCronStatusApi(self):
|
||||
mid = request.form.get('id', '')
|
||||
cronInfo = mw.M('crontab').where(
|
||||
'id=?', (mid,)).field(self.field).find()
|
||||
status = 1
|
||||
if cronInfo['status'] == status:
|
||||
status = 0
|
||||
self.removeForCrond(cronInfo['echo'])
|
||||
else:
|
||||
cronInfo['status'] = 1
|
||||
self.syncToCrond(cronInfo)
|
||||
|
||||
mw.M('crontab').where('id=?', (mid,)).setField('status', status)
|
||||
mw.writeLog(
|
||||
'计划任务', '修改计划任务[' + cronInfo['name'] + ']状态为[' + str(status) + ']')
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
# 获取指定任务数据
|
||||
def getCrondFindApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
data = mw.M('crontab').where(
|
||||
'id=?', (sid,)).field(self.field).find()
|
||||
return mw.getJson(data)
|
||||
|
||||
def modifyCrondApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
iname = request.form.get('name', '')
|
||||
field_type = request.form.get('type', '')
|
||||
week = request.form.get('week', '')
|
||||
where1 = request.form.get('where1', '')
|
||||
hour = request.form.get('hour', '')
|
||||
minute = request.form.get('minute', '')
|
||||
save = request.form.get('save', '')
|
||||
backup_to = request.form.get('backup_to', '')
|
||||
stype = request.form.get('stype', '')
|
||||
sname = request.form.get('sname', '')
|
||||
sbody = request.form.get('sbody', '')
|
||||
urladdress = request.form.get('urladdress', '')
|
||||
|
||||
if len(iname) < 1:
|
||||
return mw.returnJson(False, '任务名称不能为空!')
|
||||
|
||||
params = {
|
||||
'name': iname,
|
||||
'type': field_type,
|
||||
'week': week,
|
||||
'where1': where1,
|
||||
'hour': hour,
|
||||
'minute': minute,
|
||||
'save': save,
|
||||
'backup_to': backup_to,
|
||||
'stype': stype,
|
||||
'sname': sname,
|
||||
'sbody': sbody,
|
||||
'urladdress': urladdress,
|
||||
}
|
||||
cuonConfig, get, name = self.getCrondCycle(params)
|
||||
cronInfo = mw.M('crontab').where(
|
||||
'id=?', (sid,)).field(self.field).find()
|
||||
del(cronInfo['id'])
|
||||
del(cronInfo['addtime'])
|
||||
cronInfo['name'] = get['name']
|
||||
cronInfo['type'] = get['type']
|
||||
cronInfo['where1'] = get['where1']
|
||||
cronInfo['where_hour'] = get['hour']
|
||||
cronInfo['where_minute'] = get['minute']
|
||||
cronInfo['save'] = get['save']
|
||||
cronInfo['backup_to'] = get['backup_to']
|
||||
cronInfo['sbody'] = get['sbody']
|
||||
cronInfo['urladdress'] = get['urladdress']
|
||||
|
||||
addData = mw.M('crontab').where('id=?', (sid,)).save('name,type,where1,where_hour,where_minute,save,backup_to,sbody,urladdress', (get[
|
||||
'name'], field_type, get['where1'], get['hour'], get['minute'], get['save'], get['backup_to'], get['sbody'], get['urladdress']))
|
||||
self.removeForCrond(cronInfo['echo'])
|
||||
self.syncToCrond(cronInfo)
|
||||
mw.writeLog('计划任务', '修改计划任务[' + cronInfo['name'] + ']成功')
|
||||
return mw.returnJson(True, '修改成功')
|
||||
|
||||
def logsApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
echo = mw.M('crontab').where("id=?", (sid,)).field('echo').find()
|
||||
logFile = mw.getServerDir() + '/cron/' + echo['echo'] + '.log'
|
||||
if not os.path.exists(logFile):
|
||||
return mw.returnJson(False, '当前日志为空!')
|
||||
log = mw.getNumLines(logFile, 500)
|
||||
return mw.returnJson(True, log)
|
||||
|
||||
def addApi(self):
|
||||
iname = request.form.get('name', '')
|
||||
field_type = request.form.get('type', '')
|
||||
week = request.form.get('week', '')
|
||||
where1 = request.form.get('where1', '')
|
||||
hour = request.form.get('hour', '')
|
||||
minute = request.form.get('minute', '')
|
||||
save = request.form.get('save', '')
|
||||
backup_to = request.form.get('backupTo', '')
|
||||
stype = request.form.get('sType', '')
|
||||
sname = request.form.get('sName', '')
|
||||
sbody = request.form.get('sBody', '')
|
||||
urladdress = request.form.get('urladdress', '')
|
||||
|
||||
if len(iname) < 1:
|
||||
return mw.returnJson(False, '任务名称不能为空!')
|
||||
|
||||
params = {
|
||||
'name': iname,
|
||||
'type': field_type,
|
||||
'week': week,
|
||||
'where1': where1,
|
||||
'hour': hour,
|
||||
'minute': minute,
|
||||
'save': save,
|
||||
'backup_to': backup_to,
|
||||
'stype': stype,
|
||||
'sname': sname,
|
||||
'sbody': sbody,
|
||||
'urladdress': urladdress,
|
||||
}
|
||||
|
||||
addData = self.add(params)
|
||||
if addData > 0:
|
||||
return mw.returnJson(True, '添加成功')
|
||||
return mw.returnJson(False, '添加失败')
|
||||
|
||||
def add(self, params):
|
||||
|
||||
iname = params["name"]
|
||||
field_type = params["type"]
|
||||
week = params["week"]
|
||||
where1 = params["where1"]
|
||||
hour = params["hour"]
|
||||
minute = params["minute"]
|
||||
save = params["save"]
|
||||
backup_to = params["backup_to"]
|
||||
stype = params["stype"]
|
||||
sname = params["sname"]
|
||||
sbody = params["sbody"]
|
||||
urladdress = params["urladdress"]
|
||||
|
||||
# print params
|
||||
cronConfig, get, name = self.getCrondCycle(params)
|
||||
cronPath = mw.getServerDir() + '/cron'
|
||||
cronName = self.getShell(params)
|
||||
|
||||
if type(cronName) == dict:
|
||||
return cronName
|
||||
|
||||
cronConfig += ' ' + cronPath + '/' + cronName + \
|
||||
' >> ' + cronPath + '/' + cronName + '.log 2>&1'
|
||||
|
||||
# print(cronConfig)
|
||||
if not mw.isAppleSystem():
|
||||
wRes = self.writeShell(cronConfig)
|
||||
if type(wRes) != bool:
|
||||
return wRes
|
||||
self.crondReload()
|
||||
|
||||
add_time = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
task_id = mw.M('crontab').add('name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress',
|
||||
(iname, field_type, where1, hour, minute, cronName, add_time, 1, save, backup_to, stype, sname, sbody, urladdress,))
|
||||
return task_id
|
||||
|
||||
def startTaskApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
echo = mw.M('crontab').where('id=?', (sid,)).getField('echo')
|
||||
execstr = mw.getServerDir() + '/cron/' + echo
|
||||
os.system('chmod +x ' + execstr)
|
||||
os.system('nohup ' + execstr + ' >> ' + execstr + '.log 2>&1 &')
|
||||
return mw.returnJson(True, '任务已执行!')
|
||||
|
||||
def delApi(self):
|
||||
task_id = request.form.get('id', '')
|
||||
try:
|
||||
data = self.delete(task_id)
|
||||
if not data[0]:
|
||||
return mw.returnJson(False, data[1])
|
||||
return mw.returnJson(True, '删除成功')
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '删除失败:' + str(e))
|
||||
|
||||
def delete(self, tid):
|
||||
|
||||
find = mw.M('crontab').where("id=?", (tid,)).field('name,echo').find()
|
||||
if not self.removeForCrond(find['echo']):
|
||||
return (False, '无法写入文件,请检查是否开启了系统加固功能!')
|
||||
|
||||
cronPath = mw.getServerDir() + '/cron'
|
||||
sfile = cronPath + '/' + find['echo']
|
||||
|
||||
if os.path.exists(sfile):
|
||||
os.remove(sfile)
|
||||
sfile = cronPath + '/' + find['echo'] + '.log'
|
||||
if os.path.exists(sfile):
|
||||
os.remove(sfile)
|
||||
|
||||
mw.M('crontab').where("id=?", (tid,)).delete()
|
||||
mw.writeLog('计划任务', mw.getInfo('删除计划任务[{1}]成功!', (find['name'],)))
|
||||
return (True, "OK")
|
||||
|
||||
def delLogsApi(self):
|
||||
sid = request.form.get('id', '')
|
||||
try:
|
||||
echo = mw.M('crontab').where("id=?", (sid,)).getField('echo')
|
||||
logFile = mw.getServerDir() + '/cron/' + echo + '.log'
|
||||
os.remove(logFile)
|
||||
return mw.returnJson(True, '任务日志已清空!')
|
||||
except:
|
||||
return mw.returnJson(False, '任务日志清空失败!')
|
||||
|
||||
# 取数据列表
|
||||
def getDataListApi(self):
|
||||
stype = request.form.get('type', '')
|
||||
|
||||
bak_data = []
|
||||
|
||||
if stype == 'sites' or stype == 'databases':
|
||||
hookPath = mw.getPanelDataDir() + "/hook_backup.json"
|
||||
if os.path.exists(hookPath):
|
||||
t = mw.readFile(hookPath)
|
||||
bak_data = json.loads(t)
|
||||
|
||||
if stype == 'databases':
|
||||
db_list = {}
|
||||
db_list['orderOpt'] = bak_data
|
||||
path = mw.getServerDir() + '/mysql'
|
||||
if not os.path.exists(path + '/mysql.db'):
|
||||
db_list['data'] = []
|
||||
else:
|
||||
db_list['data'] = mw.M('databases').dbPos(
|
||||
path, 'mysql').field('name,ps').select()
|
||||
return mw.getJson(db_list)
|
||||
|
||||
data = {}
|
||||
data['orderOpt'] = bak_data
|
||||
|
||||
data['data'] = mw.M(stype).field('name,ps').select()
|
||||
return mw.getJson(data)
|
||||
##### ----- start ----- ###
|
||||
|
||||
# 转换大写星期
|
||||
def toWeek(self, num):
|
||||
wheres = {
|
||||
0: '日',
|
||||
1: '一',
|
||||
2: '二',
|
||||
3: '三',
|
||||
4: '四',
|
||||
5: '五',
|
||||
6: '六'
|
||||
}
|
||||
try:
|
||||
return wheres[num]
|
||||
except:
|
||||
return ''
|
||||
|
||||
def getCrondCycle(self, params):
|
||||
cuonConfig = ''
|
||||
name = ''
|
||||
if params['type'] == "day":
|
||||
cuonConfig = self.getDay(params)
|
||||
name = '每天'
|
||||
elif params['type'] == "day-n":
|
||||
cuonConfig = self.getDay_N(params)
|
||||
name = mw.getInfo('每{1}天', (params['where1'],))
|
||||
elif params['type'] == "hour":
|
||||
cuonConfig = self.getHour(params)
|
||||
name = '每小时'
|
||||
elif params['type'] == "hour-n":
|
||||
cuonConfig = self.getHour_N(params)
|
||||
name = '每小时'
|
||||
elif params['type'] == "minute-n":
|
||||
cuonConfig = self.minute_N(params)
|
||||
elif params['type'] == "week":
|
||||
params['where1'] = params['week']
|
||||
cuonConfig = self.week(params)
|
||||
elif params['type'] == "month":
|
||||
cuonConfig = self.month(params)
|
||||
return cuonConfig, params, name
|
||||
|
||||
# 取任务构造Day
|
||||
def getDay(self, param):
|
||||
cuonConfig = "{0} {1} * * * ".format(param['minute'], param['hour'])
|
||||
return cuonConfig
|
||||
# 取任务构造Day_n
|
||||
|
||||
def getDay_N(self, param):
|
||||
cuonConfig = "{0} {1} */{2} * * ".format(
|
||||
param['minute'], param['hour'], param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
# 取任务构造Hour
|
||||
def getHour(self, param):
|
||||
cuonConfig = "{0} * * * * ".format(param['minute'])
|
||||
return cuonConfig
|
||||
|
||||
# 取任务构造Hour-N
|
||||
def getHour_N(self, param):
|
||||
cuonConfig = "{0} */{1} * * * ".format(
|
||||
param['minute'], param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
# 取任务构造Minute-N
|
||||
def minute_N(self, param):
|
||||
cuonConfig = "*/{0} * * * * ".format(param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
# 取任务构造week
|
||||
def week(self, param):
|
||||
cuonConfig = "{0} {1} * * {2}".format(
|
||||
param['minute'], param['hour'], param['week'])
|
||||
return cuonConfig
|
||||
|
||||
# 取任务构造Month
|
||||
def month(self, param):
|
||||
cuonConfig = "{0} {1} {2} * * ".format(
|
||||
param['minute'], param['hour'], param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
# 取执行脚本
|
||||
def getShell(self, param):
|
||||
# try:
|
||||
stype = param['stype']
|
||||
if stype == 'toFile':
|
||||
shell = param.sFile
|
||||
else:
|
||||
head = "#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n"
|
||||
log = '.log'
|
||||
|
||||
script_dir = mw.getServerDir() + "/mdserver-web/scripts"
|
||||
|
||||
wheres = {
|
||||
'path': head + "python " + script_dir + "/backup.py path " + param['sname'] + " " + str(param['save']),
|
||||
'site': head + "python " + script_dir + "/backup.py site " + param['sname'] + " " + str(param['save']),
|
||||
'database': head + "python " + script_dir + "/backup.py database " + param['sname'] + " " + str(param['save']),
|
||||
'logs': head + "python " + script_dir + "/logs_backup.py " + param['sname'] + log + " " + str(param['save']),
|
||||
'rememory': head + "/bin/bash " + script_dir + '/rememory.sh'
|
||||
}
|
||||
if param['backup_to'] != 'localhost':
|
||||
cfile = mw.getPluginDir() + "/" + \
|
||||
param['backup_to'] + "/index.py"
|
||||
wheres = {
|
||||
'path': head + "python3 " + cfile + " path " + param['sname'] + " " + str(param['save']),
|
||||
'site': head + "python3 " + cfile + " site " + param['sname'] + " " + str(param['save']),
|
||||
'database': head + "python3 " + cfile + " database " + param['sname'] + " " + str(param['save']),
|
||||
'logs': head + "python3 " + script_dir + "/logs_backup.py " + param['sname'] + log + " " + str(param['save']),
|
||||
'rememory': head + "/bin/bash " + script_dir + '/rememory.sh'
|
||||
}
|
||||
try:
|
||||
shell = wheres[stype]
|
||||
except:
|
||||
if stype == 'toUrl':
|
||||
shell = head + "curl -sS --connect-timeout 10 -m 60 '" + \
|
||||
param['urladdress'] + "'"
|
||||
else:
|
||||
shell = head + param['sbody'].replace("\r\n", "\n")
|
||||
|
||||
shell += '''
|
||||
echo "----------------------------------------------------------------------------"
|
||||
endDate=`date +"%Y-%m-%d %H:%M:%S"`
|
||||
echo "★[$endDate] Successful"
|
||||
echo "----------------------------------------------------------------------------"
|
||||
'''
|
||||
cronPath = mw.getServerDir() + '/cron'
|
||||
if not os.path.exists(cronPath):
|
||||
mw.execShell('mkdir -p ' + cronPath)
|
||||
|
||||
if not 'echo' in param:
|
||||
cronName = mw.md5(mw.md5(str(time.time()) + '_mw'))
|
||||
else:
|
||||
cronName = param['echo']
|
||||
file = cronPath + '/' + cronName
|
||||
mw.writeFile(file, self.checkScript(shell))
|
||||
mw.execShell('chmod 750 ' + file)
|
||||
return cronName
|
||||
|
||||
# 检查脚本
|
||||
def checkScript(self, shell):
|
||||
keys = ['shutdown', 'init 0', 'mkfs', 'passwd',
|
||||
'chpasswd', '--stdin', 'mkfs.ext', 'mke2fs']
|
||||
for key in keys:
|
||||
shell = shell.replace(key, '[***]')
|
||||
return shell
|
||||
|
||||
# 将Shell脚本写到文件
|
||||
def writeShell(self, config):
|
||||
u_file = '/var/spool/cron/crontabs/root'
|
||||
if not os.path.exists(u_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):
|
||||
mw.execShell("chmod 600 '" + file +
|
||||
"' && chown root.root " + file)
|
||||
else:
|
||||
mw.execShell("chmod 600 '" + file +
|
||||
"' && chown root.crontab " + file)
|
||||
return True
|
||||
return mw.returnJson(False, '文件写入失败,请检查是否开启系统加固功能!')
|
||||
|
||||
# 重载配置
|
||||
def crondReload(self):
|
||||
if mw.isAppleSystem():
|
||||
if os.path.exists('/etc/crontab'):
|
||||
pass
|
||||
# mw.execShell('/usr/sbin/cron restart')
|
||||
else:
|
||||
if os.path.exists('/etc/init.d/crond'):
|
||||
mw.execShell('/etc/init.d/crond reload')
|
||||
elif os.path.exists('/etc/init.d/cron'):
|
||||
mw.execShell('service cron restart')
|
||||
else:
|
||||
mw.execShell("systemctl reload crond")
|
||||
|
||||
# 从crond删除
|
||||
def removeForCrond(self, echo):
|
||||
u_file = '/var/spool/cron/crontabs/root'
|
||||
if not os.path.exists(u_file):
|
||||
file = '/var/spool/cron/root'
|
||||
if mw.isAppleSystem():
|
||||
file = '/etc/crontab'
|
||||
|
||||
if not os.path.exists(file):
|
||||
return False
|
||||
else:
|
||||
file = u_file
|
||||
|
||||
if mw.isAppleSystem():
|
||||
return True
|
||||
|
||||
conf = mw.readFile(file)
|
||||
rep = ".+" + str(echo) + ".+\n"
|
||||
conf = re.sub(rep, "", conf)
|
||||
if not mw.writeFile(file, conf):
|
||||
return False
|
||||
self.crondReload()
|
||||
return True
|
||||
|
||||
def syncToCrond(self, cronInfo):
|
||||
if 'status' in cronInfo:
|
||||
if cronInfo['status'] == 0:
|
||||
return False
|
||||
if 'where_hour' in cronInfo:
|
||||
cronInfo['hour'] = cronInfo['where_hour']
|
||||
cronInfo['minute'] = cronInfo['where_minute']
|
||||
cronInfo['week'] = cronInfo['where1']
|
||||
cuonConfig, cronInfo, name = self.getCrondCycle(cronInfo)
|
||||
cronPath = mw.getServerDir() + '/cron'
|
||||
cronName = self.getShell(cronInfo)
|
||||
if type(cronName) == dict:
|
||||
return cronName
|
||||
cuonConfig += ' ' + cronPath + '/' + cronName + \
|
||||
' >> ' + cronPath + '/' + cronName + '.log 2>&1'
|
||||
wRes = self.writeShell(cuonConfig)
|
||||
if type(wRes) != bool:
|
||||
return False
|
||||
self.crondReload()
|
||||
@@ -1,356 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
|
||||
import sqlite3
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
class Sql():
|
||||
#------------------------------
|
||||
# 数据库操作类 For sqlite3
|
||||
#------------------------------
|
||||
__DB_FILE = None # 数据库文件
|
||||
__DB_CONN = None # 数据库连接对象
|
||||
__DB_TABLE = "" # 被操作的表名称
|
||||
__OPT_WHERE = "" # where条件
|
||||
__OPT_LIMIT = "" # limit条件
|
||||
__OPT_GROUP = "" # group条件
|
||||
__OPT_ORDER = "" # order条件
|
||||
__OPT_FIELD = "*" # field条件
|
||||
__OPT_PARAM = () # where值
|
||||
|
||||
def __init__(self):
|
||||
self.__DB_FILE = 'data/default.db'
|
||||
|
||||
def __GetConn(self):
|
||||
# 取数据库对象
|
||||
try:
|
||||
if self.__DB_CONN == None:
|
||||
self.__DB_CONN = sqlite3.connect(self.__DB_FILE)
|
||||
self.__DB_CONN.text_factory = str
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def autoTextFactory(self):
|
||||
if sys.version_info[0] == 3:
|
||||
self.__DB_CONN.text_factory = lambda x: str(
|
||||
x, encoding="utf-8", errors='ignore')
|
||||
else:
|
||||
self.__DB_CONN.text_factory = lambda x: unicode(
|
||||
x, "utf-8", "ignore")
|
||||
|
||||
def dbfile(self, name):
|
||||
self.__DB_FILE = 'data/' + name + '.db'
|
||||
return self
|
||||
|
||||
def dbPos(self, path, name):
|
||||
self.__DB_FILE = path + '/' + name + '.db'
|
||||
return self
|
||||
|
||||
def table(self, table):
|
||||
# 设置表名
|
||||
self.__DB_TABLE = table
|
||||
return self
|
||||
|
||||
def where(self, where, param):
|
||||
# WHERE条件
|
||||
if where:
|
||||
self.__OPT_WHERE = " WHERE " + where
|
||||
self.__OPT_PARAM = param
|
||||
return self
|
||||
|
||||
def andWhere(self, where, param):
|
||||
# WHERE条件
|
||||
if where:
|
||||
self.__OPT_WHERE = self.__OPT_WHERE + " and " + where
|
||||
# print(param)
|
||||
# print(self.__OPT_PARAM)
|
||||
self.__OPT_PARAM = self.__OPT_PARAM + param
|
||||
return self
|
||||
|
||||
def order(self, order):
|
||||
# ORDER条件
|
||||
if len(order):
|
||||
self.__OPT_ORDER = " ORDER BY " + order
|
||||
else:
|
||||
self.__OPT_ORDER = ""
|
||||
return self
|
||||
|
||||
def group(self, group):
|
||||
if len(group):
|
||||
self.__OPT_GROUP = " GROUP BY " + group
|
||||
else:
|
||||
self.__OPT_GROUP = ""
|
||||
return self
|
||||
|
||||
def limit(self, limit):
|
||||
# LIMIT条件
|
||||
if len(limit):
|
||||
self.__OPT_LIMIT = " LIMIT " + limit
|
||||
else:
|
||||
self.__OPT_LIMIT = ""
|
||||
return self
|
||||
|
||||
def field(self, field):
|
||||
# FIELD条件
|
||||
if len(field):
|
||||
self.__OPT_FIELD = field
|
||||
return self
|
||||
|
||||
def select(self):
|
||||
# 查询数据集
|
||||
self.__GetConn()
|
||||
try:
|
||||
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
|
||||
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
|
||||
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
|
||||
data = result.fetchall()
|
||||
# 构造字曲系列
|
||||
if self.__OPT_FIELD != "*":
|
||||
field = self.__OPT_FIELD.split(',')
|
||||
tmp = []
|
||||
for row in data:
|
||||
i = 0
|
||||
tmp1 = {}
|
||||
for key in field:
|
||||
tmp1[key] = row[i]
|
||||
i += 1
|
||||
tmp.append(tmp1)
|
||||
del(tmp1)
|
||||
data = tmp
|
||||
del(tmp)
|
||||
else:
|
||||
# 将元组转换成列表
|
||||
tmp = map(list, data)
|
||||
data = tmp
|
||||
del(tmp)
|
||||
self.__close()
|
||||
return data
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def inquiry(self, input_field=''):
|
||||
# 查询数据集
|
||||
# 不清空查询参数
|
||||
self.__GetConn()
|
||||
try:
|
||||
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
|
||||
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
|
||||
# print(sql, self.__OPT_PARAM)
|
||||
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
|
||||
data = result.fetchall()
|
||||
# 构造字曲系列
|
||||
if self.__OPT_FIELD != "*":
|
||||
|
||||
if input_field != "":
|
||||
field = input_field.split(',')
|
||||
else:
|
||||
field = self.__OPT_FIELD.split(',')
|
||||
|
||||
tmp = []
|
||||
for row in data:
|
||||
i = 0
|
||||
tmp1 = {}
|
||||
for key in field:
|
||||
tmp1[key] = row[i]
|
||||
i += 1
|
||||
tmp.append(tmp1)
|
||||
del(tmp1)
|
||||
data = tmp
|
||||
del(tmp)
|
||||
else:
|
||||
# 将元组转换成列表
|
||||
tmp = map(list, data)
|
||||
data = tmp
|
||||
del(tmp)
|
||||
return data
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def getField(self, keyName):
|
||||
# 取回指定字段
|
||||
result = self.field(keyName).select()
|
||||
if len(result) == 1:
|
||||
return result[0][keyName]
|
||||
return result
|
||||
|
||||
def setField(self, keyName, keyValue):
|
||||
# 更新指定字段
|
||||
return self.save(keyName, (keyValue,))
|
||||
|
||||
def find(self):
|
||||
# 取一行数据
|
||||
result = self.limit("1").select()
|
||||
if len(result) == 1:
|
||||
return result[0]
|
||||
return result
|
||||
|
||||
def count(self):
|
||||
# 取行数
|
||||
key = "COUNT(*)"
|
||||
data = self.field(key).select()
|
||||
try:
|
||||
return int(data[0][key])
|
||||
except:
|
||||
return 0
|
||||
|
||||
def add(self, keys, param):
|
||||
# 插入数据
|
||||
self.__GetConn()
|
||||
try:
|
||||
values = ""
|
||||
for key in keys.split(','):
|
||||
values += "?,"
|
||||
values = self.checkInput(values[0:len(values) - 1])
|
||||
sql = "INSERT INTO " + self.__DB_TABLE + \
|
||||
"(" + keys + ") " + "VALUES(" + values + ")"
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
last_id = result.lastrowid
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
return last_id
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def checkInput(self, data):
|
||||
if not data:
|
||||
return data
|
||||
if type(data) != str:
|
||||
return data
|
||||
checkList = [
|
||||
{'d': '<', 'r': '<'},
|
||||
{'d': '>', 'r': '>'},
|
||||
{'d': '\'', 'r': '‘'},
|
||||
{'d': '"', 'r': '“'},
|
||||
{'d': '&', 'r': '&'},
|
||||
{'d': '#', 'r': '#'},
|
||||
{'d': '<', 'r': '<'}
|
||||
]
|
||||
for v in checkList:
|
||||
data = data.replace(v['d'], v['r'])
|
||||
return data
|
||||
|
||||
def addAll(self, keys, param):
|
||||
# 插入数据
|
||||
self.__GetConn()
|
||||
try:
|
||||
values = ""
|
||||
for key in keys.split(','):
|
||||
values += "?,"
|
||||
values = values[0:len(values) - 1]
|
||||
sql = "INSERT INTO " + self.__DB_TABLE + \
|
||||
"(" + keys + ") " + "VALUES(" + values + ")"
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
return True
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def commit(self):
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
|
||||
def save(self, keys, param):
|
||||
# 更新数据
|
||||
self.__GetConn()
|
||||
try:
|
||||
opt = ""
|
||||
for key in keys.split(','):
|
||||
opt += key + "=?,"
|
||||
opt = opt[0:len(opt) - 1]
|
||||
sql = "UPDATE " + self.__DB_TABLE + " SET " + opt + self.__OPT_WHERE
|
||||
|
||||
# import mw
|
||||
# mw.writeFile('/tmp/test.pl', sql)
|
||||
|
||||
# 处理拼接WHERE与UPDATE参数
|
||||
tmp = list(param)
|
||||
for arg in self.__OPT_PARAM:
|
||||
tmp.append(arg)
|
||||
self.__OPT_PARAM = tuple(tmp)
|
||||
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def delete(self, id=None):
|
||||
# 删除数据
|
||||
self.__GetConn()
|
||||
try:
|
||||
if id:
|
||||
self.__OPT_WHERE = " WHERE id=?"
|
||||
self.__OPT_PARAM = (id,)
|
||||
sql = "DELETE FROM " + self.__DB_TABLE + self.__OPT_WHERE
|
||||
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def originExecute(self, sql, param=()):
|
||||
self.__GetConn()
|
||||
try:
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
self.__DB_CONN.commit()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def execute(self, sql, param=()):
|
||||
# 执行SQL语句返回受影响行
|
||||
self.__GetConn()
|
||||
# print sql, param
|
||||
try:
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def query(self, sql, param):
|
||||
# 执行SQL语句返回数据集
|
||||
self.__GetConn()
|
||||
try:
|
||||
result = self.__DB_CONN.execute(sql, param)
|
||||
# 将元组转换成列表
|
||||
# data = map(list, result)
|
||||
return result
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def create(self, name):
|
||||
# 创建数据表
|
||||
self.__GetConn()
|
||||
import mw
|
||||
script = mw.readFile('data/' + name + '.sql')
|
||||
result = self.__DB_CONN.executescript(script)
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
|
||||
def fofile(self, filename):
|
||||
# 执行脚本
|
||||
self.__GetConn()
|
||||
import mw
|
||||
script = mw.readFile(filename)
|
||||
result = self.__DB_CONN.executescript(script)
|
||||
self.__DB_CONN.commit()
|
||||
return result.rowcount
|
||||
|
||||
def __close(self):
|
||||
# 清理条件属性
|
||||
self.__OPT_WHERE = ""
|
||||
self.__OPT_FIELD = "*"
|
||||
self.__OPT_ORDER = ""
|
||||
self.__OPT_LIMIT = ""
|
||||
self.__OPT_PARAM = ()
|
||||
|
||||
def close(self):
|
||||
# 释放资源
|
||||
try:
|
||||
self.__DB_CONN.close()
|
||||
self.__DB_CONN = None
|
||||
except:
|
||||
pass
|
||||
@@ -1,878 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
import shutil
|
||||
|
||||
from flask import request
|
||||
from flask import send_file, send_from_directory
|
||||
from flask import make_response
|
||||
from flask import session
|
||||
|
||||
|
||||
class files_api:
|
||||
|
||||
rPath = None
|
||||
|
||||
def __init__(self):
|
||||
self.rPath = mw.getRootDir() + '/recycle_bin/'
|
||||
|
||||
##### ----- start ----- ###
|
||||
def getBodyApi(self):
|
||||
path = request.form.get('path', '')
|
||||
return self.getBody(path)
|
||||
|
||||
def getLastBodyApi(self):
|
||||
path = request.form.get('path', '')
|
||||
line = request.form.get('line', '100')
|
||||
|
||||
if not os.path.exists(path):
|
||||
return mw.returnJson(False, '文件不存在', (path,))
|
||||
|
||||
try:
|
||||
data = mw.getNumLines(path, int(line))
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, u'无法正确读取文件!' + str(ex))
|
||||
|
||||
def saveBodyApi(self):
|
||||
path = request.form.get('path', '')
|
||||
data = request.form.get('data', '')
|
||||
encoding = request.form.get('encoding', '')
|
||||
return self.saveBody(path, data, encoding)
|
||||
|
||||
def downloadApi(self):
|
||||
filename = request.args.get('filename', '')
|
||||
if not os.path.exists(filename):
|
||||
return ''
|
||||
response = make_response(send_from_directory(
|
||||
os.path.dirname(filename), os.path.basename(filename), as_attachment=True))
|
||||
return response
|
||||
|
||||
def zipApi(self):
|
||||
sfile = request.form.get('sfile', '')
|
||||
dfile = request.form.get('dfile', '')
|
||||
stype = request.form.get('type', '')
|
||||
path = request.form.get('path', '')
|
||||
return self.zip(sfile, dfile, stype, path)
|
||||
|
||||
def unzipApi(self):
|
||||
sfile = request.form.get('sfile', '')
|
||||
dfile = request.form.get('dfile', '')
|
||||
stype = request.form.get('type', '')
|
||||
path = request.form.get('path', '')
|
||||
return self.unzip(sfile, dfile, stype, path)
|
||||
|
||||
# 移动文件或目录
|
||||
def mvFileApi(self):
|
||||
sfile = request.form.get('sfile', '')
|
||||
dfile = request.form.get('dfile', '')
|
||||
if not self.checkFileName(dfile):
|
||||
return mw.returnJson(False, '文件名中不能包含特殊字符!')
|
||||
if not os.path.exists(sfile):
|
||||
return mw.returnJson(False, '指定文件不存在!')
|
||||
|
||||
if not self.checkDir(sfile):
|
||||
return mw.returnJson(False, 'FILE_DANGER')
|
||||
|
||||
import shutil
|
||||
try:
|
||||
shutil.move(sfile, dfile)
|
||||
msg = mw.getInfo('移动文件或目录[{1}]到[{2}]成功!', (sfile, dfile,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(True, '移动文件或目录成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '移动文件或目录失败!')
|
||||
|
||||
def deleteApi(self):
|
||||
path = request.form.get('path', '')
|
||||
return self.delete(path)
|
||||
|
||||
def fileAccessApi(self):
|
||||
filename = request.form.get('filename', '')
|
||||
data = self.getAccess(filename)
|
||||
return mw.getJson(data)
|
||||
|
||||
def setFileAccessApi(self):
|
||||
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不设置!')
|
||||
|
||||
filename = request.form.get('filename', '')
|
||||
user = request.form.get('user', '')
|
||||
access = request.form.get('access', '755')
|
||||
sall = '-R'
|
||||
try:
|
||||
if not self.checkDir(filename):
|
||||
return mw.returnJson(False, '请不要花样作死')
|
||||
|
||||
if not os.path.exists(filename):
|
||||
return mw.returnJson(False, '指定文件不存在!')
|
||||
|
||||
os.system('chmod ' + sall + ' ' + access + " '" + filename + "'")
|
||||
os.system('chown ' + sall + ' ' + user +
|
||||
':' + user + " '" + filename + "'")
|
||||
msg = mw.getInfo(
|
||||
'设置[{1}]权限为[{2}]所有者为[{3}]', (filename, access, user,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '设置失败!')
|
||||
|
||||
def getDirSizeApi(self):
|
||||
path = request.form.get('path', '')
|
||||
tmp = self.getDirSize(path)
|
||||
return mw.returnJson(True, tmp[0].split()[0])
|
||||
|
||||
def getDirApi(self):
|
||||
path = request.form.get('path', '')
|
||||
if not os.path.exists(path):
|
||||
path = mw.getRootDir() + "/wwwroot"
|
||||
search = request.args.get('search', '').strip().lower()
|
||||
page = request.args.get('p', '1').strip().lower()
|
||||
row = request.args.get('showRow', '10')
|
||||
disk = request.form.get('disk', '')
|
||||
if disk == 'True':
|
||||
row = 1000
|
||||
|
||||
return self.getDir(path, int(page), int(row), search)
|
||||
|
||||
def createFileApi(self):
|
||||
file = request.form.get('path', '')
|
||||
try:
|
||||
if not self.checkFileName(file):
|
||||
return mw.returnJson(False, '文件名中不能包含特殊字符!')
|
||||
if os.path.exists(file):
|
||||
return mw.returnJson(False, '指定文件已存在!')
|
||||
_path = os.path.dirname(file)
|
||||
if not os.path.exists(_path):
|
||||
os.makedirs(_path)
|
||||
open(file, 'w+').close()
|
||||
self.setFileAccept(file)
|
||||
msg = mw.getInfo('创建文件[{1}]成功!', (file,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(True, '文件创建成功!')
|
||||
except Exception as e:
|
||||
return mw.returnJson(True, '文件创建失败!')
|
||||
|
||||
def createDirApi(self):
|
||||
path = request.form.get('path', '')
|
||||
try:
|
||||
if not self.checkFileName(path):
|
||||
return mw.returnJson(False, '目录名中不能包含特殊字符!')
|
||||
if os.path.exists(path):
|
||||
return mw.returnJson(False, '指定目录已存在!')
|
||||
os.makedirs(path)
|
||||
self.setFileAccept(path)
|
||||
msg = mw.getInfo('创建目录[{1}]成功!', (path,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(True, '目录创建成功!')
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '目录创建失败!')
|
||||
|
||||
def downloadFileApi(self):
|
||||
import db
|
||||
import time
|
||||
url = request.form.get('url', '')
|
||||
path = request.form.get('path', '')
|
||||
filename = request.form.get('filename', '')
|
||||
execstr = url + '|mw|' + path + '/' + filename
|
||||
execstr = execstr.strip()
|
||||
mw.M('tasks').add('name,type,status,addtime,execstr',
|
||||
('下载文件[' + filename + ']', 'download', '-1', time.strftime('%Y-%m-%d %H:%M:%S'), execstr))
|
||||
|
||||
# self.setFileAccept(path + '/' + filename)
|
||||
mw.triggerTask()
|
||||
return mw.returnJson(True, '已将下载任务添加到队列!')
|
||||
|
||||
# 删除进程下的所有进程
|
||||
def removeTaskRecursion(self, pid):
|
||||
cmd = "ps -ef|grep " + pid + \
|
||||
" | grep -v grep |sed -n '2,1p' | awk '{print $2}'"
|
||||
sub_pid = mw.execShell(cmd)
|
||||
|
||||
if sub_pid[0].strip() == '':
|
||||
return 'ok'
|
||||
|
||||
self.removeTaskRecursion(sub_pid[0].strip())
|
||||
mw.execShell('kill -9 ' + sub_pid[0].strip())
|
||||
return sub_pid[0].strip()
|
||||
|
||||
def removeTaskApi(self):
|
||||
import system_api
|
||||
mid = request.form.get('id', '')
|
||||
try:
|
||||
name = mw.M('tasks').where('id=?', (mid,)).getField('name')
|
||||
status = mw.M('tasks').where('id=?', (mid,)).getField('status')
|
||||
mw.M('tasks').delete(mid)
|
||||
if status == '-1':
|
||||
task_pid = mw.execShell(
|
||||
"ps aux | grep 'task.py' | grep -v grep |awk '{print $2}'")
|
||||
|
||||
task_list = task_pid[0].strip().split("\n")
|
||||
for i in range(len(task_list)):
|
||||
self.removeTaskRecursion(task_list[i])
|
||||
|
||||
mw.triggerTask()
|
||||
system_api.system_api().restartTask()
|
||||
except:
|
||||
system_api.system_api().restartTask()
|
||||
return mw.returnJson(True, '任务已删除!')
|
||||
|
||||
# 上传文件
|
||||
def uploadFileApi(self):
|
||||
from werkzeug.utils import secure_filename
|
||||
from flask import request
|
||||
|
||||
path = request.args.get('path', '')
|
||||
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
f = request.files['zunfile']
|
||||
filename = os.path.join(path, f.filename)
|
||||
|
||||
s_path = path
|
||||
if os.path.exists(filename):
|
||||
s_path = filename
|
||||
p_stat = os.stat(s_path)
|
||||
f.save(filename)
|
||||
os.chown(filename, p_stat.st_uid, p_stat.st_gid)
|
||||
os.chmod(filename, p_stat.st_mode)
|
||||
|
||||
msg = mw.getInfo('上传文件[{1}] 到 [{2}]成功!', (filename, path))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnMsg(True, '上传成功!')
|
||||
|
||||
def getRecycleBinApi(self):
|
||||
rPath = self.rPath
|
||||
if not os.path.exists(rPath):
|
||||
os.system('mkdir -p ' + rPath)
|
||||
data = {}
|
||||
data['dirs'] = []
|
||||
data['files'] = []
|
||||
data['status'] = os.path.exists('data/recycle_bin.pl')
|
||||
data['status_db'] = os.path.exists('data/recycle_bin_db.pl')
|
||||
for file in os.listdir(rPath):
|
||||
try:
|
||||
tmp = {}
|
||||
fname = rPath + file
|
||||
tmp1 = file.split('_mw_')
|
||||
tmp2 = tmp1[len(tmp1) - 1].split('_t_')
|
||||
tmp['rname'] = file
|
||||
tmp['dname'] = file.replace('_mw_', '/').split('_t_')[0]
|
||||
tmp['name'] = tmp2[0]
|
||||
tmp['time'] = int(float(tmp2[1]))
|
||||
if os.path.islink(fname):
|
||||
filePath = os.readlink(fname)
|
||||
link = ' -> ' + filePath
|
||||
if os.path.exists(filePath):
|
||||
tmp['size'] = os.path.getsize(filePath)
|
||||
else:
|
||||
tmp['size'] = 0
|
||||
else:
|
||||
tmp['size'] = os.path.getsize(fname)
|
||||
if os.path.isdir(fname):
|
||||
data['dirs'].append(tmp)
|
||||
else:
|
||||
data['files'].append(tmp)
|
||||
except Exception as e:
|
||||
continue
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
# 回收站开关
|
||||
def recycleBinApi(self):
|
||||
c = 'data/recycle_bin.pl'
|
||||
db = request.form.get('db', '')
|
||||
if db != '':
|
||||
c = 'data/recycle_bin_db.pl'
|
||||
if os.path.exists(c):
|
||||
os.remove(c)
|
||||
mw.writeLog('文件管理', '已关闭回收站功能!')
|
||||
return mw.returnJson(True, '已关闭回收站功能!')
|
||||
else:
|
||||
mw.writeFile(c, 'True')
|
||||
mw.writeLog('文件管理', '已开启回收站功能!')
|
||||
return mw.returnJson(True, '已开启回收站功能!')
|
||||
|
||||
def reRecycleBinApi(self):
|
||||
rPath = self.rPath
|
||||
path = request.form.get('path', '')
|
||||
dFile = path.replace('_mw_', '/').split('_t_')[0]
|
||||
try:
|
||||
import shutil
|
||||
shutil.move(rPath + path, dFile)
|
||||
msg = mw.getInfo('移动文件[{1}]到回收站成功!', (dFile,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(True, '恢复成功!')
|
||||
except Exception as e:
|
||||
msg = mw.getInfo('从回收站恢复[{1}]失败!', (dFile,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(False, '恢复失败!')
|
||||
|
||||
def delRecycleBinApi(self):
|
||||
rPath = self.rPath
|
||||
path = request.form.get('path', '')
|
||||
empty = request.form.get('empty', '')
|
||||
dFile = path.split('_t_')[0]
|
||||
|
||||
if not self.checkDir(path):
|
||||
return mw.returnJson(False, '敏感目录,请不要花样作死!')
|
||||
|
||||
os.system('which chattr && chattr -R -i ' + rPath + path)
|
||||
if os.path.isdir(rPath + path):
|
||||
import shutil
|
||||
shutil.rmtree(rPath + path)
|
||||
else:
|
||||
os.remove(rPath + path)
|
||||
|
||||
tfile = path.replace('_mw_', '/').split('_t_')[0]
|
||||
msg = mw.getInfo('已彻底从回收站删除{1}!', (tfile,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(True, msg)
|
||||
|
||||
# 获取进度
|
||||
def getSpeedApi(self):
|
||||
data = mw.getSpeed()
|
||||
return mw.returnJson(True, '已清空回收站!', data)
|
||||
|
||||
def closeRecycleBinApi(self):
|
||||
rPath = self.rPath
|
||||
os.system('which chattr && chattr -R -i ' + rPath)
|
||||
rlist = os.listdir(rPath)
|
||||
i = 0
|
||||
l = len(rlist)
|
||||
for name in rlist:
|
||||
i += 1
|
||||
path = rPath + name
|
||||
mw.writeSpeed(name, i, l)
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.remove(path)
|
||||
mw.writeSpeed(None, 0, 0)
|
||||
mw.writeLog('文件管理', '已清空回收站!')
|
||||
return mw.returnJson(True, '已清空回收站!')
|
||||
|
||||
def deleteDirApi(self):
|
||||
path = request.form.get('path', '')
|
||||
if not os.path.exists(path):
|
||||
return mw.returnJson(False, '指定文件不存在!')
|
||||
|
||||
# 检查是否为.user.ini
|
||||
if path.find('.user.ini'):
|
||||
os.system("which chattr && chattr -i '" + path + "'")
|
||||
try:
|
||||
if os.path.exists('data/recycle_bin.pl'):
|
||||
if self.mvRecycleBin(path):
|
||||
return mw.returnJson(True, '已将文件移动到回收站!')
|
||||
mw.execShell('rm -rf ' + path)
|
||||
mw.writeLog('文件管理', '删除文件成功!', (path,))
|
||||
return mw.returnJson(True, '删除文件成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '删除文件失败!')
|
||||
|
||||
def closeLogsApi(self):
|
||||
logPath = mw.getLogsDir()
|
||||
os.system('rm -f ' + logPath + '/*')
|
||||
os.system('kill -USR1 `cat ' + mw.getServerDir() +
|
||||
'openresty/nginx/logs/nginx.pid`')
|
||||
mw.writeLog('文件管理', '网站日志已被清空!')
|
||||
tmp = self.getDirSize(logPath)
|
||||
return mw.returnJson(True, tmp[0].split()[0])
|
||||
|
||||
def setBatchDataApi(self):
|
||||
path = request.form.get('path', '')
|
||||
stype = request.form.get('type', '')
|
||||
access = request.form.get('access', '')
|
||||
user = request.form.get('user', '')
|
||||
data = request.form.get('data')
|
||||
if stype == '1' or stype == '2':
|
||||
session['selected'] = {
|
||||
'path': path,
|
||||
'type': stype,
|
||||
'access': access,
|
||||
'user': user,
|
||||
'data': data
|
||||
}
|
||||
return mw.returnJson(True, '标记成功,请在目标目录点击粘贴所有按钮!')
|
||||
elif stype == '3':
|
||||
for key in json.loads(data):
|
||||
try:
|
||||
filename = path + '/' + key
|
||||
if not self.checkDir(filename):
|
||||
return mw.returnJson(False, 'FILE_DANGER')
|
||||
os.system('chmod -R ' + access + " '" + filename + "'")
|
||||
os.system('chown -R ' + user + ':' +
|
||||
user + " '" + filename + "'")
|
||||
except:
|
||||
continue
|
||||
mw.writeLog('文件管理', '批量设置权限成功!')
|
||||
return mw.returnJson(True, '批量设置权限成功!')
|
||||
else:
|
||||
import shutil
|
||||
isRecyle = os.path.exists('data/recycle_bin.pl')
|
||||
data = json.loads(data)
|
||||
l = len(data)
|
||||
i = 0
|
||||
for key in data:
|
||||
try:
|
||||
filename = path + '/' + key
|
||||
topath = filename
|
||||
if not os.path.exists(filename):
|
||||
continue
|
||||
|
||||
i += 1
|
||||
mw.writeSpeed(key, i, l)
|
||||
if os.path.isdir(filename):
|
||||
if not self.checkDir(filename):
|
||||
return mw.returnJson(False, '请不要花样作死!')
|
||||
if isRecyle:
|
||||
self.mvRecycleBin(topath)
|
||||
else:
|
||||
shutil.rmtree(filename)
|
||||
else:
|
||||
if key == '.user.ini':
|
||||
os.system('which chattr && chattr -i ' + filename)
|
||||
if isRecyle:
|
||||
self.mvRecycleBin(topath)
|
||||
else:
|
||||
os.remove(filename)
|
||||
except:
|
||||
continue
|
||||
mw.writeSpeed(None, 0, 0)
|
||||
mw.writeLog('文件管理', '批量删除成功!')
|
||||
return mw.returnJson(True, '批量删除成功!')
|
||||
|
||||
def checkExistsFilesApi(self):
|
||||
dfile = request.form.get('dfile', '')
|
||||
filename = request.form.get('filename', '')
|
||||
data = []
|
||||
filesx = []
|
||||
if filename == '':
|
||||
filesx = json.loads(session['selected']['data'])
|
||||
else:
|
||||
filesx.append(filename)
|
||||
|
||||
for fn in filesx:
|
||||
if fn == '.':
|
||||
continue
|
||||
filename = dfile + '/' + fn
|
||||
if os.path.exists(filename):
|
||||
tmp = {}
|
||||
stat = os.stat(filename)
|
||||
tmp['filename'] = fn
|
||||
tmp['size'] = os.path.getsize(filename)
|
||||
tmp['mtime'] = str(int(stat.st_mtime))
|
||||
data.append(tmp)
|
||||
return mw.returnJson(True, 'ok', data)
|
||||
|
||||
def batchPasteApi(self):
|
||||
path = request.form.get('path', '')
|
||||
stype = request.form.get('type', '')
|
||||
# filename = request.form.get('filename', '')
|
||||
import shutil
|
||||
if not self.checkDir(path):
|
||||
return mw.returnJson(False, '请不要花样作死!')
|
||||
i = 0
|
||||
myfiles = json.loads(session['selected']['data'])
|
||||
l = len(myfiles)
|
||||
if stype == '1':
|
||||
for key in myfiles:
|
||||
i += 1
|
||||
mw.writeSpeed(key, i, l)
|
||||
try:
|
||||
|
||||
sfile = session['selected'][
|
||||
'path'] + '/' + key
|
||||
dfile = path + '/' + key
|
||||
|
||||
if os.path.isdir(sfile):
|
||||
shutil.copytree(sfile, dfile)
|
||||
else:
|
||||
shutil.copyfile(sfile, dfile)
|
||||
stat = os.stat(sfile)
|
||||
os.chown(dfile, stat.st_uid, stat.st_gid)
|
||||
except:
|
||||
continue
|
||||
msg = mw.getInfo('从[{1}]批量复制到[{2}]成功',
|
||||
(session['selected']['path'], path,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
else:
|
||||
for key in myfiles:
|
||||
try:
|
||||
i += 1
|
||||
mw.writeSpeed(key, i, l)
|
||||
|
||||
sfile = session['selected'][
|
||||
'path'] + '/' + key
|
||||
dfile = path + '/' + key
|
||||
|
||||
shutil.move(sfile, dfile)
|
||||
except:
|
||||
continue
|
||||
msg = mw.getInfo('从[{1}]批量移动到[{2}]成功',
|
||||
(session['selected']['path'], path,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
mw.writeSpeed(None, 0, 0)
|
||||
errorCount = len(myfiles) - i
|
||||
del(session['selected'])
|
||||
msg = mw.getInfo('批量操作成功[{1}],失败[{2}]', (str(i), str(errorCount)))
|
||||
return mw.returnJson(True, msg)
|
||||
|
||||
def copyFileApi(self):
|
||||
sfile = request.form.get('sfile', '')
|
||||
dfile = request.form.get('dfile', '')
|
||||
|
||||
if sfile == dfile:
|
||||
return mw.returnJson(False, '源与目的一致!')
|
||||
|
||||
if not os.path.exists(sfile):
|
||||
return mw.returnJson(False, '指定文件不存在!')
|
||||
|
||||
if os.path.isdir(sfile):
|
||||
return self.copyDir(sfile, dfile)
|
||||
|
||||
try:
|
||||
import shutil
|
||||
shutil.copyfile(sfile, dfile)
|
||||
msg = mw.getInfo('复制文件[{1}]到[{2}]成功!', (sfile, dfile,))
|
||||
mw.writeLog('文件管理', msg)
|
||||
stat = os.stat(sfile)
|
||||
os.chown(dfile, stat.st_uid, stat.st_gid)
|
||||
return mw.returnJson(True, '文件复制成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '文件复制失败!')
|
||||
|
||||
##### ----- end ----- ###
|
||||
|
||||
def copyDir(self, sfile, dfile):
|
||||
|
||||
if not os.path.exists(sfile):
|
||||
return mw.returnJson(False, '指定目录不存在!')
|
||||
|
||||
if os.path.exists(dfile):
|
||||
return mw.returnJson(False, '指定目录已存在!')
|
||||
import shutil
|
||||
try:
|
||||
shutil.copytree(sfile, dfile)
|
||||
stat = os.stat(sfile)
|
||||
os.chown(dfile, stat.st_uid, stat.st_gid)
|
||||
msg = mw.getInfo('复制目录[{1}]到[{2}]成功!', (sfile, dfile))
|
||||
mw.writeLog('文件管理', msg)
|
||||
return mw.returnJson(True, '目录复制成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '目录复制失败!')
|
||||
|
||||
# 检查敏感目录
|
||||
def checkDir(self, path):
|
||||
# path = str(path, encoding='utf-8')
|
||||
path = path.replace('//', '/')
|
||||
if path[-1:] == '/':
|
||||
path = path[:-1]
|
||||
|
||||
nDirs = ('',
|
||||
'/',
|
||||
'/*',
|
||||
'/www',
|
||||
'/root',
|
||||
'/boot',
|
||||
'/bin',
|
||||
'/etc',
|
||||
'/home',
|
||||
'/dev',
|
||||
'/sbin',
|
||||
'/var',
|
||||
'/usr',
|
||||
'/tmp',
|
||||
'/sys',
|
||||
'/proc',
|
||||
'/media',
|
||||
'/mnt',
|
||||
'/opt',
|
||||
'/lib',
|
||||
'/srv',
|
||||
'/selinux',
|
||||
'/www/server',
|
||||
mw.getRootDir())
|
||||
|
||||
return not path in nDirs
|
||||
|
||||
def getDirSize(self, path):
|
||||
if mw.getOs() == 'darwin':
|
||||
tmp = mw.execShell('du -sh ' + path)
|
||||
else:
|
||||
tmp = mw.execShell('du -sbh ' + path)
|
||||
return tmp
|
||||
|
||||
def checkFileName(self, filename):
|
||||
# 检测文件名
|
||||
nots = ['\\', '&', '*', '|', ';']
|
||||
if filename.find('/') != -1:
|
||||
filename = filename.split('/')[-1]
|
||||
for n in nots:
|
||||
if n in filename:
|
||||
return False
|
||||
return True
|
||||
|
||||
def setFileAccept(self, filename):
|
||||
auth = 'www:www'
|
||||
if mw.getOs() == 'darwin':
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
auth = user + ':staff'
|
||||
os.system('chown -R ' + auth + ' ' + filename)
|
||||
os.system('chmod -R 755 ' + filename)
|
||||
|
||||
# 移动到回收站
|
||||
def mvRecycleBin(self, path):
|
||||
rPath = self.rPath
|
||||
if not os.path.exists(rPath):
|
||||
os.system('mkdir -p ' + rPath)
|
||||
|
||||
rFile = rPath + path.replace('/', '_mw_') + '_t_' + str(time.time())
|
||||
try:
|
||||
import shutil
|
||||
shutil.move(path, rFile)
|
||||
mw.writeLog('文件管理', mw.getInfo(
|
||||
'移动文件[{1}]到回收站成功!', (path)))
|
||||
return True
|
||||
except:
|
||||
mw.writeLog('文件管理', mw.getInfo(
|
||||
'移动文件[{1}]到回收站失败!', (path)))
|
||||
return False
|
||||
|
||||
def getBody(self, path):
|
||||
if not os.path.exists(path):
|
||||
return mw.returnJson(False, '文件不存在', (path,))
|
||||
|
||||
if os.path.getsize(path) > 2097152:
|
||||
return mw.returnJson(False, u'不能在线编辑大于2MB的文件!')
|
||||
|
||||
fp = open(path, 'rb')
|
||||
data = {}
|
||||
data['status'] = True
|
||||
try:
|
||||
if fp:
|
||||
from chardet.universaldetector import UniversalDetector
|
||||
detector = UniversalDetector()
|
||||
srcBody = b""
|
||||
for line in fp.readlines():
|
||||
detector.feed(line)
|
||||
srcBody += line
|
||||
detector.close()
|
||||
char = detector.result
|
||||
data['encoding'] = char['encoding']
|
||||
if char['encoding'] == 'GB2312' or not char['encoding'] or char[
|
||||
'encoding'] == 'TIS-620' or char['encoding'] == 'ISO-8859-9':
|
||||
data['encoding'] = 'GBK'
|
||||
if char['encoding'] == 'ascii' or char[
|
||||
'encoding'] == 'ISO-8859-1':
|
||||
data['encoding'] = 'utf-8'
|
||||
if char['encoding'] == 'Big5':
|
||||
data['encoding'] = 'BIG5'
|
||||
if not char['encoding'] in ['GBK', 'utf-8', 'BIG5']:
|
||||
data['encoding'] = 'utf-8'
|
||||
try:
|
||||
if sys.version_info[0] == 2:
|
||||
data['data'] = srcBody.decode(
|
||||
data['encoding']).encode('utf-8', errors='ignore')
|
||||
else:
|
||||
data['data'] = srcBody.decode(data['encoding'])
|
||||
except:
|
||||
data['encoding'] = char['encoding']
|
||||
if sys.version_info[0] == 2:
|
||||
data['data'] = srcBody.decode(
|
||||
data['encoding']).encode('utf-8', errors='ignore')
|
||||
else:
|
||||
data['data'] = srcBody.decode(data['encoding'])
|
||||
else:
|
||||
if sys.version_info[0] == 2:
|
||||
data['data'] = srcBody.decode('utf-8').encode('utf-8')
|
||||
else:
|
||||
data['data'] = srcBody.decode('utf-8')
|
||||
data['encoding'] = u'utf-8'
|
||||
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, u'文件编码不被兼容,无法正确读取文件!' + str(ex))
|
||||
|
||||
def saveBody(self, path, data, encoding='utf-8'):
|
||||
if not os.path.exists(path):
|
||||
return mw.returnJson(False, '文件不存在')
|
||||
try:
|
||||
if encoding == 'ascii':
|
||||
encoding = 'utf-8'
|
||||
if sys.version_info[0] == 2:
|
||||
data = data.encode(encoding, errors='ignore')
|
||||
fp = open(path, 'w+')
|
||||
else:
|
||||
data = data.encode(
|
||||
encoding, errors='ignore').decode(encoding)
|
||||
fp = open(path, 'w+', encoding=encoding)
|
||||
fp.write(data)
|
||||
fp.close()
|
||||
|
||||
if path.find("web_conf") > 0:
|
||||
mw.restartWeb()
|
||||
|
||||
mw.writeLog('文件管理', '文件保存成功', (path,))
|
||||
return mw.returnJson(True, '文件保存成功')
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, 'FILE_SAVE_ERR:' + str(ex))
|
||||
|
||||
def zip(self, sfile, dfile, stype, path):
|
||||
if sfile.find(',') == -1:
|
||||
if not os.path.exists(path + '/' + sfile):
|
||||
return mw.returnMsg(False, '指定文件不存在!')
|
||||
|
||||
try:
|
||||
tmps = mw.getRunDir() + '/tmp/panelExec.log'
|
||||
if stype == 'zip':
|
||||
os.system("cd '" + path + "' && zip '" + dfile +
|
||||
"' -r '" + sfile + "' > " + tmps + " 2>&1")
|
||||
else:
|
||||
sfiles = ''
|
||||
for sfile in sfile.split(','):
|
||||
if not sfile:
|
||||
continue
|
||||
sfiles += " '" + sfile + "'"
|
||||
os.system("cd '" + path + "' && tar -zcvf '" +
|
||||
dfile + "' " + sfiles + " > " + tmps + " 2>&1")
|
||||
self.setFileAccept(dfile)
|
||||
mw.writeLog("文件管理", '文件压缩成功!', (sfile, dfile))
|
||||
return mw.returnJson(True, '文件压缩成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '文件压缩失败!')
|
||||
|
||||
def unzip(self, sfile, dfile, stype, path):
|
||||
|
||||
if not os.path.exists(sfile):
|
||||
return mw.returnMsg(False, '指定文件不存在!')
|
||||
|
||||
try:
|
||||
tmps = mw.getRunDir() + '/tmp/panelExec.log'
|
||||
if stype == 'zip':
|
||||
os.system("cd " + path + " && unzip -d '" + dfile +
|
||||
"' '" + sfile + "' > " + tmps + " 2>&1")
|
||||
else:
|
||||
sfiles = ''
|
||||
for sfile in sfile.split(','):
|
||||
if not sfile:
|
||||
continue
|
||||
sfiles += " '" + sfile + "'"
|
||||
os.system("cd " + path + " && tar -zxvf " + sfiles +
|
||||
" -C " + dfile + " > " + tmps + " 2>&1")
|
||||
self.setFileAccept(dfile)
|
||||
mw.writeLog("文件管理", '文件解压成功!', (sfile, dfile))
|
||||
return mw.returnJson(True, '文件解压成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '文件解压失败!')
|
||||
|
||||
def delete(self, path):
|
||||
|
||||
if not os.path.exists(path):
|
||||
return mw.returnJson(False, '指定文件不存在!')
|
||||
|
||||
# 检查是否为.user.ini
|
||||
if path.find('.user.ini') >= 0:
|
||||
os.system("which chattr && chattr -i '" + path + "'")
|
||||
|
||||
try:
|
||||
if os.path.exists('data/recycle_bin.pl'):
|
||||
if self.mvRecycleBin(path):
|
||||
return mw.returnJson(True, '已将文件移动到回收站!')
|
||||
os.remove(path)
|
||||
mw.writeLog('文件管理', mw.getInfo(
|
||||
'删除文件[{1}]成功!', (path)))
|
||||
return mw.returnJson(True, '删除文件成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '删除文件失败!')
|
||||
|
||||
def getAccess(self, filename):
|
||||
data = {}
|
||||
try:
|
||||
stat = os.stat(filename)
|
||||
data['chmod'] = str(oct(stat.st_mode)[-3:])
|
||||
data['chown'] = pwd.getpwuid(stat.st_uid).pw_name
|
||||
except:
|
||||
data['chmod'] = 755
|
||||
data['chown'] = 'www'
|
||||
return data
|
||||
|
||||
# 计算文件数量
|
||||
def getCount(self, path, search):
|
||||
i = 0
|
||||
for name in os.listdir(path):
|
||||
if search:
|
||||
if name.lower().find(search) == -1:
|
||||
continue
|
||||
# if name[0:1] == '.':
|
||||
# continue
|
||||
i += 1
|
||||
return i
|
||||
|
||||
def getDir(self, path, page=1, page_size=10, search=None):
|
||||
data = {}
|
||||
dirnames = []
|
||||
filenames = []
|
||||
|
||||
info = {}
|
||||
info['count'] = self.getCount(path, search)
|
||||
info['row'] = page_size
|
||||
info['p'] = page
|
||||
info['tojs'] = 'getFiles'
|
||||
pageObj = mw.getPageObject(info, '1,2,3,4,5,6,7,8')
|
||||
data['PAGE'] = pageObj[0]
|
||||
|
||||
i = 0
|
||||
n = 0
|
||||
for filename in os.listdir(path):
|
||||
if search:
|
||||
if filename.lower().find(search) == -1:
|
||||
continue
|
||||
i += 1
|
||||
if n >= pageObj[1].ROW:
|
||||
break
|
||||
if i < pageObj[1].SHIFT:
|
||||
continue
|
||||
try:
|
||||
filePath = path + '/' + filename
|
||||
link = ''
|
||||
if os.path.islink(filePath):
|
||||
filePath = os.readlink(filePath)
|
||||
link = ' -> ' + filePath
|
||||
if not os.path.exists(filePath):
|
||||
filePath = path + '/' + filePath
|
||||
if not os.path.exists(filePath):
|
||||
continue
|
||||
|
||||
stat = os.stat(filePath)
|
||||
accept = str(oct(stat.st_mode)[-3:])
|
||||
mtime = str(int(stat.st_mtime))
|
||||
user = ''
|
||||
try:
|
||||
user = pwd.getpwuid(stat.st_uid).pw_name
|
||||
except Exception as ee:
|
||||
user = str(stat.st_uid)
|
||||
|
||||
size = str(stat.st_size)
|
||||
if os.path.isdir(filePath):
|
||||
dirnames.append(filename + ';' + size + ';' +
|
||||
mtime + ';' + accept + ';' + user + ';' + link)
|
||||
else:
|
||||
filenames.append(filename + ';' + size + ';' +
|
||||
mtime + ';' + accept + ';' + user + ';' + link)
|
||||
n += 1
|
||||
except Exception as e:
|
||||
continue
|
||||
data['DIR'] = sorted(dirnames)
|
||||
data['FILES'] = sorted(filenames)
|
||||
data['PATH'] = path.replace('//', '/')
|
||||
|
||||
return mw.getJson(data)
|
||||
@@ -1,410 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
from flask import request
|
||||
|
||||
|
||||
class firewall_api:
|
||||
|
||||
__isFirewalld = False
|
||||
__isUfw = False
|
||||
__isMac = False
|
||||
|
||||
def __init__(self):
|
||||
if os.path.exists('/usr/sbin/firewalld'):
|
||||
self.__isFirewalld = True
|
||||
if os.path.exists('/usr/sbin/ufw'):
|
||||
self.__isUfw = True
|
||||
if mw.isAppleSystem():
|
||||
self.__isMac = True
|
||||
|
||||
##### ----- start ----- ###
|
||||
# 添加屏蔽IP
|
||||
def addDropAddressApi(self):
|
||||
import re
|
||||
port = request.form.get('port', '').strip()
|
||||
ps = request.form.get('ps', '').strip()
|
||||
|
||||
rep = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
|
||||
if not re.search(rep, port):
|
||||
return mw.returnJson(False, '您输入的IP地址不合法!')
|
||||
address = port
|
||||
if mw.M('firewall').where("port=?", (address,)).count() > 0:
|
||||
return mw.returnJson(False, '您要放屏蔽的IP已存在屏蔽列表,无需重复处理!')
|
||||
if self.__isUfw:
|
||||
mw.execShell('ufw deny from ' + address + ' to any')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
cmd = 'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="' + \
|
||||
address + '" drop\''
|
||||
mw.execShell(cmd)
|
||||
else:
|
||||
cmd = 'iptables -I INPUT -s ' + address + ' -j DROP'
|
||||
mw.execShell(cmd)
|
||||
|
||||
msg = mw.getInfo('屏蔽IP[{1}]成功!', (address,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
mw.M('firewall').add('port,ps,addtime', (address, ps, addtime))
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
# 添加放行端口
|
||||
def addAcceptPortApi(self):
|
||||
|
||||
if not self.getFwStatus():
|
||||
return mw.returnJson(False, '防火墙启动时,才能添加规则!')
|
||||
|
||||
import re
|
||||
import time
|
||||
port = request.form.get('port', '').strip()
|
||||
ps = request.form.get('ps', '').strip()
|
||||
stype = request.form.get('type', '').strip()
|
||||
|
||||
rep = "^\d{1,5}(:\d{1,5})?$"
|
||||
if not re.search(rep, port):
|
||||
return mw.returnJson(False, '端口范围不正确!')
|
||||
|
||||
if mw.M('firewall').where("port=?", (port,)).count() > 0:
|
||||
return mw.returnJson(False, '您要放行的端口已存在,无需重复放行!')
|
||||
|
||||
msg = mw.getInfo('放行端口[{1}]成功', (port,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
mw.M('firewall').add('port,ps,addtime', (port, ps, addtime))
|
||||
|
||||
self.addAcceptPort(port)
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '添加放行(' + port + ')端口成功!')
|
||||
|
||||
# 删除IP屏蔽
|
||||
def delDropAddressApi(self):
|
||||
if not self.getFwStatus():
|
||||
return mw.returnJson(False, '防火墙启动时,才能删除规则!')
|
||||
|
||||
port = request.form.get('port', '').strip()
|
||||
ps = request.form.get('ps', '').strip()
|
||||
sid = request.form.get('id', '').strip()
|
||||
address = port
|
||||
if self.__isUfw:
|
||||
mw.execShell('ufw delete deny from ' + address + ' to any')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
|
||||
elif self.__isMac:
|
||||
pass
|
||||
else:
|
||||
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
|
||||
mw.execShell(cmd)
|
||||
|
||||
msg = mw.getInfo('解除IP[{1}]的屏蔽!', (address,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
mw.M('firewall').where("id=?", (sid,)).delete()
|
||||
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
# 删除放行端口
|
||||
def delAcceptPortApi(self):
|
||||
port = request.form.get('port', '').strip()
|
||||
sid = request.form.get('id', '').strip()
|
||||
mw_port = mw.readFile('data/port.pl')
|
||||
try:
|
||||
if(port == mw_port):
|
||||
return mw.returnJson(False, '失败,不能删除当前面板端口!')
|
||||
if self.__isUfw:
|
||||
mw.execShell('ufw delete allow ' + port + '/tcp')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
|
||||
else:
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
|
||||
msg = mw.getInfo('删除防火墙放行端口[{1}]成功!', (port,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
mw.M('firewall').where("id=?", (sid,)).delete()
|
||||
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '删除失败!:' + str(e))
|
||||
|
||||
def getWwwPathApi(self):
|
||||
path = mw.getLogsDir()
|
||||
return mw.getJson({'path': path})
|
||||
|
||||
def getListApi(self):
|
||||
p = request.form.get('p', '1').strip()
|
||||
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):
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = mw.readFile(file)
|
||||
rep = "#*Port\s+([0-9]+)\s*\n"
|
||||
port = re.search(rep, conf).groups(0)[0]
|
||||
|
||||
isPing = True
|
||||
try:
|
||||
if mw.isAppleSystem():
|
||||
isPing = True
|
||||
else:
|
||||
file = '/etc/sysctl.conf'
|
||||
conf = mw.readFile(file)
|
||||
rep = "#*net\.ipv4\.icmp_echo_ignore_all\s*=\s*([0-9]+)"
|
||||
tmp = re.search(rep, conf).groups(0)[0]
|
||||
if tmp == '1':
|
||||
isPing = False
|
||||
except:
|
||||
isPing = True
|
||||
|
||||
import system_api
|
||||
panelsys = system_api.system_api()
|
||||
version = panelsys.getSystemVersion()
|
||||
if os.path.exists('/usr/bin/apt-get'):
|
||||
if os.path.exists('/etc/init.d/sshd'):
|
||||
cmd = "service sshd status | grep -P '(dead|stop)'|grep -v grep"
|
||||
status = mw.execShell(cmd)
|
||||
else:
|
||||
cmd = "service ssh status | grep -P '(dead|stop)'|grep -v grep"
|
||||
status = mw.execShell(cmd)
|
||||
else:
|
||||
if version.find(' 7.') != -1:
|
||||
cmd = "systemctl status sshd.service | grep 'dead'|grep -v grep"
|
||||
status = mw.execShell(cmd)
|
||||
else:
|
||||
cmd = "/etc/init.d/sshd status | grep -e 'stopped' -e '已停'|grep -v grep"
|
||||
status = mw.execShell(cmd)
|
||||
if len(status[0]) > 3:
|
||||
status = False
|
||||
else:
|
||||
status = True
|
||||
|
||||
data = {}
|
||||
data['port'] = port
|
||||
|
||||
data['status'] = status
|
||||
data['ping'] = isPing
|
||||
if mw.isAppleSystem():
|
||||
data['firewall_status'] = False
|
||||
else:
|
||||
data['firewall_status'] = self.getFwStatus()
|
||||
return mw.getJson(data)
|
||||
|
||||
def setSshPortApi(self):
|
||||
port = request.form.get('port', '1').strip()
|
||||
if int(port) < 22 or int(port) > 65535:
|
||||
return mw.returnJson(False, '端口范围必需在22-65535之间!')
|
||||
|
||||
ports = ['21', '25', '80', '443', '7200', '8080', '888', '8888']
|
||||
if port in ports:
|
||||
return mw.returnJson(False, '(' + port + ')' + '特殊端口不可设置!')
|
||||
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = mw.readFile(file)
|
||||
|
||||
rep = "#*Port\s+([0-9]+)\s*\n"
|
||||
conf = re.sub(rep, "Port " + port + "\n", conf)
|
||||
mw.writeFile(file, conf)
|
||||
|
||||
if self.__isFirewalld:
|
||||
mw.execShell('setenforce 0')
|
||||
mw.execShell(
|
||||
'sed -i "s#SELINUX=enforcing#SELINUX=disabled#" /etc/selinux/config')
|
||||
mw.execShell("systemctl restart sshd.service")
|
||||
elif self.__isUfw:
|
||||
mw.execShell('ufw allow ' + port + '/tcp')
|
||||
mw.execShell("service ssh restart")
|
||||
else:
|
||||
mw.execShell(
|
||||
'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
|
||||
mw.execShell("/etc/init.d/sshd restart")
|
||||
|
||||
self.firewallReload()
|
||||
# mw.M('firewall').where(
|
||||
# "ps=?", ('SSH远程管理服务',)).setField('port', port)
|
||||
msg = mw.getInfo('改SSH端口为[{1}]成功!', port)
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
return mw.returnJson(True, '修改成功!')
|
||||
|
||||
def setSshStatusApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不能操作!')
|
||||
|
||||
status = request.form.get('status', '1').strip()
|
||||
version = mw.readFile('/etc/redhat-release')
|
||||
if int(status) == 1:
|
||||
msg = 'SSH服务已停用'
|
||||
act = 'stop'
|
||||
else:
|
||||
msg = 'SSH服务已启用'
|
||||
act = 'start'
|
||||
|
||||
if not os.path.exists('/etc/redhat-release'):
|
||||
mw.execShell('service ssh ' + act)
|
||||
elif version.find(' 7.') != -1:
|
||||
mw.execShell("systemctl " + act + " sshd.service")
|
||||
else:
|
||||
mw.execShell("/etc/init.d/sshd " + act)
|
||||
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
return mw.returnJson(True, '操作成功!')
|
||||
|
||||
def setPingApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不能操作!')
|
||||
|
||||
status = request.form.get('status')
|
||||
filename = '/etc/sysctl.conf'
|
||||
conf = mw.readFile(filename)
|
||||
if conf.find('net.ipv4.icmp_echo') != -1:
|
||||
rep = u"net\.ipv4\.icmp_echo.*"
|
||||
conf = re.sub(rep, 'net.ipv4.icmp_echo_ignore_all=' + status, conf)
|
||||
else:
|
||||
conf += "\nnet.ipv4.icmp_echo_ignore_all=" + status
|
||||
|
||||
mw.writeFile(filename, conf)
|
||||
mw.execShell('sysctl -p')
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
def setFwApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(True, '开发机不能设置!')
|
||||
|
||||
status = request.form.get('status', '1')
|
||||
if status == '1':
|
||||
if self.__isUfw:
|
||||
mw.execShell('/usr/sbin/ufw disable')
|
||||
if self.__isFirewalld:
|
||||
mw.execShell('systemctl stop firewalld.service')
|
||||
mw.execShell('systemctl disable firewalld.service')
|
||||
elif self.__isMac:
|
||||
pass
|
||||
else:
|
||||
mw.execShell('/etc/init.d/iptables save')
|
||||
mw.execShell('/etc/init.d/iptables stop')
|
||||
else:
|
||||
if self.__isUfw:
|
||||
mw.execShell("echo 'y'|sudo ufw enable")
|
||||
if self.__isFirewalld:
|
||||
mw.execShell('systemctl start firewalld.service')
|
||||
mw.execShell('systemctl enable firewalld.service')
|
||||
elif self.__isMac:
|
||||
pass
|
||||
else:
|
||||
mw.execShell('/etc/init.d/iptables save')
|
||||
mw.execShell('/etc/init.d/iptables restart')
|
||||
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
def delPanelLogsApi(self):
|
||||
mw.M('logs').where('id>?', (0,)).delete()
|
||||
mw.writeLog('面板设置', '面板操作日志已清空!')
|
||||
return mw.returnJson(True, '面板操作日志已清空!')
|
||||
|
||||
##### ----- start ----- ###
|
||||
|
||||
def getList(self, page, limit):
|
||||
|
||||
start = (page - 1) * limit
|
||||
|
||||
_list = mw.M('firewall').field('id,port,ps,addtime').limit(
|
||||
str(start) + ',' + str(limit)).order('id desc').select()
|
||||
data = {}
|
||||
data['data'] = _list
|
||||
|
||||
count = mw.M('firewall').count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'showAccept'
|
||||
_page['p'] = page
|
||||
|
||||
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')
|
||||
elif self.__isFirewalld:
|
||||
port = port.replace(':', '-')
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
|
||||
mw.execShell(cmd)
|
||||
elif self.__isMac:
|
||||
pass
|
||||
else:
|
||||
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
|
||||
def firewallReload(self):
|
||||
if self.__isUfw:
|
||||
mw.execShell('/usr/sbin/ufw reload')
|
||||
return
|
||||
if self.__isFirewalld:
|
||||
mw.execShell('firewall-cmd --reload')
|
||||
elif self.__isMac:
|
||||
pass
|
||||
else:
|
||||
mw.execShell('/etc/init.d/iptables save')
|
||||
mw.execShell('/etc/init.d/iptables restart')
|
||||
|
||||
def getFwStatus(self):
|
||||
if self.__isUfw:
|
||||
cmd = "/usr/sbin/ufw status| grep Status | awk -F ':' '{print $2}'"
|
||||
data = mw.execShell(cmd)
|
||||
if data[0].strip() == 'inactive':
|
||||
return False
|
||||
return True
|
||||
if self.__isFirewalld:
|
||||
cmd = "ps -ef|grep firewalld |grep -v grep | awk '{print $2}'"
|
||||
data = mw.execShell(cmd)
|
||||
if data[0] == '':
|
||||
return False
|
||||
return True
|
||||
elif self.__isMac:
|
||||
return False
|
||||
else:
|
||||
cmd = "ps -ef|grep iptables |grep -v grep | awk '{print $2}'"
|
||||
data = mw.execShell(cmd)
|
||||
if data[0] == '':
|
||||
return False
|
||||
return True
|
||||
-1066
File diff suppressed because it is too large
Load Diff
@@ -1,224 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import math
|
||||
import string
|
||||
|
||||
|
||||
class Page():
|
||||
#--------------------------
|
||||
# 分页类 - JS回调版
|
||||
#--------------------------
|
||||
__PREV = '上一页'
|
||||
__NEXT = '下一页'
|
||||
__START = '首页'
|
||||
__END = '尾页'
|
||||
__COUNT_START = '共'
|
||||
__COUNT_END = '条数据'
|
||||
__FO = '从'
|
||||
__LINE = '条'
|
||||
__LIST_NUM = 4
|
||||
SHIFT = None # 偏移量
|
||||
ROW = None # 每页行数
|
||||
__C_PAGE = None # 当前页
|
||||
__COUNT_PAGE = None # 总页数
|
||||
__COUNT_ROW = None # 总行数
|
||||
__URI = None # URI
|
||||
__RTURN_JS = False # 是否返回JS回调
|
||||
__START_NUM = None # 起始行
|
||||
__END_NUM = None # 结束行
|
||||
|
||||
def __init__(self):
|
||||
if False:
|
||||
self.__PREV = tmp['PREV']
|
||||
self.__NEXT = tmp['NEXT']
|
||||
self.__START = tmp['START']
|
||||
self.__END = tmp['END']
|
||||
self.__COUNT_START = tmp['COUNT_START']
|
||||
self.__COUNT_END = tmp['COUNT_END']
|
||||
self.__FO = tmp['FO']
|
||||
self.__LINE = tmp['LINE']
|
||||
|
||||
def GetPage(self, pageInfo, limit='1,2,3,4,5,6,7,8'):
|
||||
# 取分页信息
|
||||
# @param pageInfo 传入分页参数字典
|
||||
# @param limit 返回系列
|
||||
self.__RTURN_JS = pageInfo['return_js']
|
||||
self.__COUNT_ROW = pageInfo['count']
|
||||
self.ROW = pageInfo['row']
|
||||
self.__C_PAGE = self.__GetCpage(pageInfo['p'])
|
||||
self.__START_NUM = self.__StartRow()
|
||||
self.__END_NUM = self.__EndRow()
|
||||
self.__COUNT_PAGE = self.__GetCountPage()
|
||||
self.__URI = self.__SetUri(pageInfo['uri'])
|
||||
self.SHIFT = self.__START_NUM - 1
|
||||
|
||||
keys = limit.split(',')
|
||||
pages = {}
|
||||
# 起始页
|
||||
pages['1'] = self.__GetStart()
|
||||
# 上一页
|
||||
pages['2'] = self.__GetPrev()
|
||||
# 分页
|
||||
pages['3'] = self.__GetPages()
|
||||
# 下一页
|
||||
pages['4'] = self.__GetNext()
|
||||
# 尾页
|
||||
pages['5'] = self.__GetEnd()
|
||||
|
||||
# 当前显示页与总页数
|
||||
pages['6'] = "<span class='Pnumber'>" + \
|
||||
str(self.__C_PAGE) + "/" + \
|
||||
str(self.__COUNT_PAGE) + "</span>"
|
||||
|
||||
# 本页显示开始与结束行
|
||||
pages['7'] = "<span class='Pline'>" + str(self.__FO) + \
|
||||
str(self.__START_NUM) + "-" + \
|
||||
str(self.__END_NUM) + str(self.__LINE) + "</span>"
|
||||
# 行数
|
||||
pages['8'] = "<span class='Pcount'>" + str(self.__COUNT_START) + \
|
||||
str(self.__COUNT_ROW) + str(self.__COUNT_END) + "</span>"
|
||||
|
||||
# 构造返回数据
|
||||
retuls = '<div>'
|
||||
for value in keys:
|
||||
retuls += pages[value]
|
||||
retuls += '</div>'
|
||||
|
||||
# 返回分页数据
|
||||
return retuls
|
||||
|
||||
def __GetEnd(self):
|
||||
# 构造尾页
|
||||
endStr = ""
|
||||
if self.__C_PAGE >= self.__COUNT_PAGE:
|
||||
endStr = ''
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
endStr = "<a class='Pend' href='" + self.__URI + "p=" + \
|
||||
str(self.__COUNT_PAGE) + "'>" + str(self.__END) + "</a>"
|
||||
else:
|
||||
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(self.__COUNT_PAGE) + ")'>" + \
|
||||
str(self.__END) + "</a>"
|
||||
return endStr
|
||||
|
||||
def __GetNext(self):
|
||||
# 构造下一页
|
||||
nextStr = ""
|
||||
if self.__C_PAGE >= self.__COUNT_PAGE:
|
||||
nextStr = ''
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
nextStr = "<a class='Pnext' href='" + self.__URI + "p=" + \
|
||||
str(self.__C_PAGE + 1) + "'>" + str(self.__NEXT) + "</a>"
|
||||
else:
|
||||
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(self.__C_PAGE + 1) + ")'>" + \
|
||||
str(self.__NEXT) + "</a>"
|
||||
|
||||
return nextStr
|
||||
|
||||
def __GetPages(self):
|
||||
# 构造分页
|
||||
pages = ''
|
||||
num = 0
|
||||
# 当前页之前
|
||||
if (self.__COUNT_PAGE - self.__C_PAGE) < self.__LIST_NUM:
|
||||
num = self.__LIST_NUM + \
|
||||
(self.__LIST_NUM - (self.__COUNT_PAGE - self.__C_PAGE))
|
||||
else:
|
||||
num = self.__LIST_NUM
|
||||
n = 0
|
||||
for i in range(num):
|
||||
n = num - i
|
||||
page = self.__C_PAGE - n
|
||||
if page > 0:
|
||||
if self.__RTURN_JS == "":
|
||||
pages += "<a class='Pnum' href='" + self.__URI + \
|
||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(page) + ")'>" + str(page) + "</a>"
|
||||
|
||||
# 当前页
|
||||
if self.__C_PAGE > 0:
|
||||
pages += "<span class='Pcurrent'>" + \
|
||||
str(self.__C_PAGE) + "</span>"
|
||||
|
||||
# 当前页之后
|
||||
if self.__C_PAGE <= self.__LIST_NUM:
|
||||
num = self.__LIST_NUM + (self.__LIST_NUM - self.__C_PAGE) + 1
|
||||
else:
|
||||
num = self.__LIST_NUM
|
||||
for i in range(num):
|
||||
if i == 0:
|
||||
continue
|
||||
page = self.__C_PAGE + i
|
||||
if page > self.__COUNT_PAGE:
|
||||
break
|
||||
if self.__RTURN_JS == "":
|
||||
pages += "<a class='Pnum' href='" + self.__URI + \
|
||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(page) + ")'>" + str(page) + "</a>"
|
||||
|
||||
return pages
|
||||
|
||||
def __GetPrev(self):
|
||||
# 构造上一页
|
||||
startStr = ''
|
||||
if self.__C_PAGE == 1:
|
||||
startStr = ''
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
startStr = "<a class='Ppren' href='" + self.__URI + "p=" + \
|
||||
str(self.__C_PAGE - 1) + "'>" + str(self.__PREV) + "</a>"
|
||||
else:
|
||||
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(self.__C_PAGE - 1) + ")'>" + \
|
||||
str(self.__PREV) + "</a>"
|
||||
return startStr
|
||||
|
||||
def __GetStart(self):
|
||||
# 构造起始分页
|
||||
startStr = ''
|
||||
if self.__C_PAGE == 1:
|
||||
startStr = ''
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
startStr = "<a class='Pstart' href='" + \
|
||||
self.__URI + "p=1'>" + str(self.__START) + "</a>"
|
||||
else:
|
||||
startStr = "<a class='Pstart' onclick='" + \
|
||||
self.__RTURN_JS + "(1)'>" + str(self.__START) + "</a>"
|
||||
return startStr
|
||||
|
||||
def __GetCpage(self, p):
|
||||
# 取当前页
|
||||
if p:
|
||||
return p
|
||||
return 1
|
||||
|
||||
def __StartRow(self):
|
||||
# 从多少行开始
|
||||
return (self.__C_PAGE - 1) * self.ROW + 1
|
||||
|
||||
def __EndRow(self):
|
||||
# 从多少行结束
|
||||
if self.ROW > self.__COUNT_ROW:
|
||||
return self.__COUNT_ROW
|
||||
return self.__C_PAGE * self.ROW
|
||||
|
||||
def __GetCountPage(self):
|
||||
# 取总页数
|
||||
return int(math.ceil(self.__COUNT_ROW / float(self.ROW)))
|
||||
|
||||
def __SetUri(self, sinput):
|
||||
# 构造URI
|
||||
uri = '?'
|
||||
for key in sinput:
|
||||
if key == 'p':
|
||||
continue
|
||||
uri += key + '=' + sinput[key] + '&'
|
||||
return str(uri)
|
||||
@@ -1,916 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
|
||||
import sys
|
||||
# reload(sys)
|
||||
# sys.setdefaultencoding('utf8')
|
||||
|
||||
import threading
|
||||
import multiprocessing
|
||||
|
||||
|
||||
from flask import request
|
||||
|
||||
|
||||
class pa_thread(threading.Thread):
|
||||
|
||||
def __init__(self, func, args, name=''):
|
||||
threading.Thread.__init__(self)
|
||||
self.name = name
|
||||
self.func = func
|
||||
self.args = args
|
||||
self.result = self.func(*self.args)
|
||||
|
||||
def getResult(self):
|
||||
try:
|
||||
return self.result
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
class plugins_api:
|
||||
__tasks = None
|
||||
__plugin_dir = 'plugins'
|
||||
__type = 'data/json/type.json'
|
||||
__index = 'data/json/index.json'
|
||||
setupPath = None
|
||||
|
||||
def __init__(self):
|
||||
self.setupPath = 'server'
|
||||
self.__plugin_dir = mw.getRunDir() + '/plugins'
|
||||
self.__type = mw.getRunDir() + '/data/json/type.json'
|
||||
self.__index = mw.getRunDir() + '/data/json/index.json'
|
||||
|
||||
##### ----- start ----- ###
|
||||
def listApi(self):
|
||||
sType = request.args.get('type', '0')
|
||||
sPage = request.args.get('p', '1')
|
||||
|
||||
if not mw.isNumber(sPage):
|
||||
sPage = 1
|
||||
|
||||
if not mw.isNumber(sType):
|
||||
sType = 0
|
||||
|
||||
# print sPage
|
||||
data = self.getPluginList(sType, int(sPage))
|
||||
return mw.getJson(data)
|
||||
|
||||
def fileApi(self):
|
||||
name = request.args.get('name', '')
|
||||
if name.strip() == '':
|
||||
return ''
|
||||
|
||||
f = request.args.get('f', '')
|
||||
if f.strip() == '':
|
||||
return ''
|
||||
|
||||
file = mw.getPluginDir() + '/' + name + '/' + f
|
||||
if not os.path.exists(file):
|
||||
return ''
|
||||
|
||||
c = open(file, 'rb').read()
|
||||
return c
|
||||
|
||||
def indexListApi(self):
|
||||
data = self.getIndexList()
|
||||
return mw.getJson(data)
|
||||
|
||||
def indexSortApi(self):
|
||||
sort = request.form.get('ssort', '')
|
||||
if sort.strip() == '':
|
||||
return mw.returnJson(False, '排序数据不能为空!')
|
||||
data = self.setIndexSort(sort)
|
||||
if data:
|
||||
return mw.returnJson(True, '成功!')
|
||||
return mw.returnJson(False, '失败!')
|
||||
|
||||
def installApi(self):
|
||||
rundir = mw.getRunDir()
|
||||
name = request.form.get('name', '')
|
||||
version = request.form.get('version', '')
|
||||
|
||||
mmsg = '安装'
|
||||
if hasattr(request.form, 'upgrade'):
|
||||
mtype = 'update'
|
||||
mmsg = 'upgrade'
|
||||
|
||||
if name.strip() == '':
|
||||
return mw.returnJson(False, '缺少插件名称!', ())
|
||||
|
||||
if version.strip() == '':
|
||||
return mw.returnJson(False, '缺少版本信息!', ())
|
||||
|
||||
infoJsonPos = self.__plugin_dir + '/' + name + '/' + 'info.json'
|
||||
# print infoJsonPos
|
||||
|
||||
if not os.path.exists(infoJsonPos):
|
||||
return mw.returnJson(False, '配置文件不存在!', ())
|
||||
|
||||
pluginInfo = json.loads(mw.readFile(infoJsonPos))
|
||||
self.hookInstall(pluginInfo)
|
||||
|
||||
execstr = "cd " + os.getcwd() + "/plugins/" + \
|
||||
name + " && /bin/bash " + pluginInfo["shell"] \
|
||||
+ " install " + version
|
||||
|
||||
if mw.isAppleSystem():
|
||||
print(execstr)
|
||||
|
||||
taskAdd = (None, mmsg + '[' + name + '-' + version + ']',
|
||||
'execshell', '0', time.strftime('%Y-%m-%d %H:%M:%S'), execstr)
|
||||
|
||||
mw.M('tasks').add('id,name,type,status,addtime, execstr', taskAdd)
|
||||
|
||||
# 任务执行相关
|
||||
mw.triggerTask()
|
||||
return mw.returnJson(True, '已将安装任务添加到队列!')
|
||||
|
||||
def hookInstallFile(self, hook_name, info):
|
||||
hookPath = mw.getPanelDataDir() + "/hook_" + hook_name + ".json"
|
||||
data = []
|
||||
if os.path.exists(hookPath):
|
||||
t = mw.readFile(hookPath)
|
||||
data = json.loads(t)
|
||||
|
||||
isNeedAdd = True
|
||||
for x in range(len(data)):
|
||||
if data[x]['title'] == info['title'] and data[x]['name'] == info['name']:
|
||||
isNeedAdd = False
|
||||
|
||||
if isNeedAdd:
|
||||
tmp = {}
|
||||
tmp['title'] = info['title']
|
||||
tmp['name'] = info['name']
|
||||
data.append(tmp)
|
||||
mw.writeFile(hookPath, json.dumps(data))
|
||||
|
||||
def hookUninstallFile(self, hook_name, info):
|
||||
hookPath = mw.getPanelDataDir() + "/hook_" + hook_name + ".json"
|
||||
data = []
|
||||
if os.path.exists(hookPath):
|
||||
t = mw.readFile(hookPath)
|
||||
data = json.loads(t)
|
||||
|
||||
for idx in range(len(data)):
|
||||
if data[idx]['title'] == info['title'] and data[idx]['name'] == info['name']:
|
||||
data.remove(data[idx])
|
||||
mw.writeFile(hookPath, json.dumps(data))
|
||||
|
||||
def hookInstall(self, info):
|
||||
if 'hook' in info:
|
||||
hooks = info['hook']
|
||||
for x in hooks:
|
||||
if x in ['backup']:
|
||||
self.hookInstallFile(x, info)
|
||||
return True
|
||||
return False
|
||||
|
||||
def hookUninstall(self, info):
|
||||
if 'hook' in info:
|
||||
hooks = info['hook']
|
||||
for x in hooks:
|
||||
if x in ['backup']:
|
||||
self.hookUninstallFile(x, info)
|
||||
return True
|
||||
return False
|
||||
|
||||
def uninstallOldApi(self):
|
||||
rundir = mw.getRunDir()
|
||||
name = request.form.get('name', '')
|
||||
version = request.form.get('version', '')
|
||||
if name.strip() == '':
|
||||
return mw.returnJson(False, "缺少插件名称!", ())
|
||||
|
||||
if version.strip() == '':
|
||||
return mw.returnJson(False, "缺少版本信息!", ())
|
||||
|
||||
infoJsonPos = self.__plugin_dir + '/' + name + '/' + 'info.json'
|
||||
|
||||
if not os.path.exists(infoJsonPos):
|
||||
return mw.returnJson(False, "配置文件不存在!", ())
|
||||
|
||||
pluginInfo = json.loads(mw.readFile(infoJsonPos))
|
||||
execstr = "cd " + os.getcwd() + "/plugins/" + \
|
||||
name + " && /bin/bash " + pluginInfo["shell"] \
|
||||
+ " uninstall " + version
|
||||
|
||||
taskAdd = (None, '卸载[' + name + '-' + version + ']',
|
||||
'execshell', '0', time.strftime('%Y-%m-%d %H:%M:%S'), execstr)
|
||||
|
||||
mw.M('tasks').add('id,name,type,status,addtime, execstr', taskAdd)
|
||||
return mw.returnJson(True, '已将卸载任务添加到队列!')
|
||||
|
||||
# 卸载时间短,不加入任务中...
|
||||
def uninstallApi(self):
|
||||
rundir = mw.getRunDir()
|
||||
name = request.form.get('name', '')
|
||||
version = request.form.get('version', '')
|
||||
if name.strip() == '':
|
||||
return mw.returnJson(False, "缺少插件名称!", ())
|
||||
|
||||
if version.strip() == '':
|
||||
return mw.returnJson(False, "缺少版本信息!", ())
|
||||
|
||||
infoJsonPos = self.__plugin_dir + '/' + name + '/' + 'info.json'
|
||||
|
||||
if not os.path.exists(infoJsonPos):
|
||||
return mw.returnJson(False, "配置文件不存在!", ())
|
||||
|
||||
pluginInfo = json.loads(mw.readFile(infoJsonPos))
|
||||
self.hookUninstall(pluginInfo)
|
||||
execstr = "cd " + os.getcwd() + "/plugins/" + \
|
||||
name + " && /bin/bash " + pluginInfo["shell"] \
|
||||
+ " uninstall " + version
|
||||
|
||||
data = mw.execShell(execstr)
|
||||
if mw.isDebugMode():
|
||||
print(execstr)
|
||||
print(data[0], data[1])
|
||||
self.removeIndex(name, version)
|
||||
return mw.returnJson(True, '卸载执行成功!')
|
||||
# if data[1] == '':
|
||||
# return mw.returnJson(True, '已将卸载成功!')
|
||||
# else:
|
||||
# return mw.returnJson(False, '卸载出现错误信息!' + data[1])
|
||||
|
||||
def checkApi(self):
|
||||
name = request.form.get('name', '')
|
||||
if name.strip() == '':
|
||||
return mw.returnJson(False, "缺少插件名称!", ())
|
||||
|
||||
infoJsonPos = self.__plugin_dir + '/' + name + '/' + 'info.json'
|
||||
if not os.path.exists(infoJsonPos):
|
||||
return mw.returnJson(False, "配置文件不存在!", ())
|
||||
return mw.returnJson(True, "插件存在!", ())
|
||||
|
||||
def setIndexApi(self):
|
||||
name = request.form.get('name', '')
|
||||
status = request.form.get('status', '0')
|
||||
version = request.form.get('version', '')
|
||||
if status == '1':
|
||||
return self.addIndex(name, version)
|
||||
return self.removeIndex(name, version)
|
||||
|
||||
def settingApi(self):
|
||||
name = request.args.get('name', '')
|
||||
html = self.__plugin_dir + '/' + name + '/index.html'
|
||||
return mw.readFile(html)
|
||||
|
||||
def runApi(self):
|
||||
name = request.form.get('name', '')
|
||||
func = request.form.get('func', '')
|
||||
version = request.form.get('version', '')
|
||||
args = request.form.get('args', '')
|
||||
script = request.form.get('script', 'index')
|
||||
|
||||
data = self.run(name, func, version, args, script)
|
||||
if data[1] == '':
|
||||
r = mw.returnJson(True, "OK", data[0].strip())
|
||||
else:
|
||||
r = mw.returnJson(False, data[1].strip())
|
||||
return r
|
||||
|
||||
def callbackApi(self):
|
||||
name = request.form.get('name', '')
|
||||
func = request.form.get('func', '')
|
||||
args = request.form.get('args', '')
|
||||
script = request.form.get('script', 'index')
|
||||
|
||||
data = self.callback(name, func, args, script)
|
||||
if data[0]:
|
||||
return mw.returnJson(True, "OK", data[1])
|
||||
return mw.returnJson(False, data[1])
|
||||
|
||||
def updateZipApi(self):
|
||||
tmp_path = mw.getRootDir() + '/temp'
|
||||
if not os.path.exists(tmp_path):
|
||||
os.makedirs(tmp_path)
|
||||
mw.execShell("rm -rf " + tmp_path + '/*')
|
||||
|
||||
tmp_file = tmp_path + '/plugin_tmp.zip'
|
||||
from werkzeug.utils import secure_filename
|
||||
from flask import request
|
||||
f = request.files['plugin_zip']
|
||||
if f.filename[-4:] != '.zip':
|
||||
return mw.returnJson(False, '仅支持zip文件!')
|
||||
f.save(tmp_file)
|
||||
mw.execShell('cd ' + tmp_path + ' && unzip ' + tmp_file)
|
||||
os.remove(tmp_file)
|
||||
|
||||
p_info = tmp_path + '/info.json'
|
||||
if not os.path.exists(p_info):
|
||||
d_path = None
|
||||
for df in os.walk(tmp_path):
|
||||
if len(df[2]) < 3:
|
||||
continue
|
||||
if not 'info.json' in df[2]:
|
||||
continue
|
||||
if not 'install.sh' in df[2]:
|
||||
continue
|
||||
if not os.path.exists(df[0] + '/info.json'):
|
||||
continue
|
||||
d_path = df[0]
|
||||
if d_path:
|
||||
tmp_path = d_path
|
||||
p_info = tmp_path + '/info.json'
|
||||
try:
|
||||
data = json.loads(mw.readFile(p_info))
|
||||
data['size'] = mw.getPathSize(tmp_path)
|
||||
if not 'author' in data:
|
||||
data['author'] = '未知'
|
||||
if not 'home' in data:
|
||||
data['home'] = 'https://github.com/midoks/mdserver-web'
|
||||
plugin_path = mw.getPluginDir() + data['name'] + '/info.json'
|
||||
data['old_version'] = '0'
|
||||
data['tmp_path'] = tmp_path
|
||||
if os.path.exists(plugin_path):
|
||||
try:
|
||||
old_info = json.loads(mw.ReadFile(plugin_path))
|
||||
data['old_version'] = old_info['versions']
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
mw.execShell("rm -rf " + tmp_path)
|
||||
return mw.returnJson(False, '在压缩包中没有找到插件信息,请检查插件包!')
|
||||
protectPlist = ('openresty', 'mysql', 'php', 'redis', 'memcached'
|
||||
'mongodb', 'swap', 'gogs', 'pureftp')
|
||||
if data['name'] in protectPlist:
|
||||
return mw.returnJson(False, '[' + data['name'] + '],重要插件不可修改!')
|
||||
return mw.getJson(data)
|
||||
|
||||
def inputZipApi(self):
|
||||
plugin_name = request.form.get('plugin_name', '')
|
||||
tmp_path = request.form.get('tmp_path', '')
|
||||
|
||||
if not os.path.exists(tmp_path):
|
||||
return mw.returnJson(False, '临时文件不存在,请重新上传!')
|
||||
plugin_path = mw.getPluginDir() + '/' + plugin_name
|
||||
if not os.path.exists(plugin_path):
|
||||
print(mw.execShell('mkdir -p ' + plugin_path))
|
||||
mw.execShell("\cp -rf " + tmp_path + '/* ' + plugin_path + '/')
|
||||
mw.execShell('chmod -R 755 ' + plugin_path)
|
||||
p_info = mw.readFile(plugin_path + '/info.json')
|
||||
if p_info:
|
||||
mw.writeLog('软件管理', '安装第三方插件[%s]' %
|
||||
json.loads(p_info)['title'])
|
||||
return mw.returnJson(True, '安装成功!')
|
||||
mw.execShell("rm -rf " + plugin_path)
|
||||
return mw.returnJson(False, '安装失败!')
|
||||
##### ----- end ----- ###
|
||||
|
||||
# 进程是否存在
|
||||
def processExists(self, pname, exe=None):
|
||||
try:
|
||||
if not self.pids:
|
||||
self.pids = psutil.pids()
|
||||
for pid in self.pids:
|
||||
try:
|
||||
p = psutil.Process(pid)
|
||||
if p.name() == pname:
|
||||
if not exe:
|
||||
return True
|
||||
else:
|
||||
if p.exe() == exe:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
except:
|
||||
return True
|
||||
|
||||
# 检查是否正在安装
|
||||
def checkSetupTask(self, sName, sVer, sCoexist):
|
||||
if not self.__tasks:
|
||||
self.__tasks = mw.M('tasks').where(
|
||||
"status!=?", ('1',)).field('status,name').select()
|
||||
isTask = '1'
|
||||
for task in self.__tasks:
|
||||
tmpt = mw.getStrBetween('[', ']', task['name'])
|
||||
if not tmpt:
|
||||
continue
|
||||
task_sign = tmpt.split('-')
|
||||
task_len = len(task_sign)
|
||||
|
||||
task_name = task_sign[0].lower()
|
||||
task_ver = task_sign[1]
|
||||
if task_len > 2:
|
||||
nameArr = task_sign[0:task_len - 1]
|
||||
task_name = '-'.join(nameArr).lower()
|
||||
task_ver = task_sign[task_len - 1]
|
||||
if sCoexist:
|
||||
if task_name == sName and task_ver == sVer:
|
||||
isTask = task['status']
|
||||
else:
|
||||
if task_name == sName:
|
||||
isTask = task['status']
|
||||
return isTask
|
||||
|
||||
def checkStatus(self, info):
|
||||
if not info['setup']:
|
||||
return False
|
||||
|
||||
data = self.run(info['name'], 'status', info['setup_version'])
|
||||
if data[0] == 'start':
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkStatusProcess(self, info, i, return_dict):
|
||||
if not info['setup']:
|
||||
return_dict[i] = False
|
||||
return
|
||||
|
||||
data = self.run(info['name'], 'status', info['setup_version'])
|
||||
if data[0] == 'start':
|
||||
return_dict[i] = True
|
||||
else:
|
||||
return_dict[i] = False
|
||||
|
||||
def checkStatusThreads(self, info, i):
|
||||
if not info['setup']:
|
||||
return False
|
||||
data = self.run(info['name'], 'status', info['setup_version'])
|
||||
if data[0] == 'start':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# 还无法正常运行,先保留
|
||||
def checkStatusThreadsCallback(self, info, i):
|
||||
if not info['setup']:
|
||||
return False
|
||||
|
||||
try:
|
||||
data = self.callback(info['name'], 'status', info['setup_version'])
|
||||
except Exception as e:
|
||||
data = self.callback(info['name'], 'status')
|
||||
|
||||
# data = self.run(info['name'], 'status', info['setup_version'])
|
||||
if data[0] == 'start':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def checkStatusMThreads(self, plugins_info):
|
||||
try:
|
||||
threads = []
|
||||
ntmp_list = range(len(plugins_info))
|
||||
for i in ntmp_list:
|
||||
t = pa_thread(self.checkStatusThreads,
|
||||
(plugins_info[i], i))
|
||||
threads.append(t)
|
||||
|
||||
for i in ntmp_list:
|
||||
threads[i].start()
|
||||
for i in ntmp_list:
|
||||
threads[i].join()
|
||||
|
||||
for i in ntmp_list:
|
||||
t = threads[i].getResult()
|
||||
plugins_info[i]['status'] = t
|
||||
except Exception as e:
|
||||
print('checkStatusMThreads:', str(e))
|
||||
|
||||
return plugins_info
|
||||
|
||||
def checkStatusMProcess(self, plugins_info):
|
||||
manager = multiprocessing.Manager()
|
||||
return_dict = manager.dict()
|
||||
jobs = []
|
||||
for i in range(len(plugins_info)):
|
||||
p = multiprocessing.Process(
|
||||
target=self.checkStatusProcess, args=(plugins_info[i], i, return_dict))
|
||||
jobs.append(p)
|
||||
p.start()
|
||||
|
||||
for proc in jobs:
|
||||
proc.join()
|
||||
|
||||
returnData = return_dict.values()
|
||||
for i in ntmp_list:
|
||||
plugins_info[i]['status'] = returnData[i]
|
||||
|
||||
return plugins_info
|
||||
|
||||
def checkDisplayIndex(self, name, version):
|
||||
if not os.path.exists(self.__index):
|
||||
mw.writeFile(self.__index, '[]')
|
||||
|
||||
indexList = json.loads(mw.readFile(self.__index))
|
||||
if type(version) == list:
|
||||
for index in range(len(version)):
|
||||
vname = name + '-' + version[index]
|
||||
if vname in indexList:
|
||||
return True
|
||||
else:
|
||||
vname = name + '-' + version
|
||||
if vname in indexList:
|
||||
return True
|
||||
return False
|
||||
|
||||
def getVersion(self, path):
|
||||
version_f = path + '/version.pl'
|
||||
if os.path.exists(version_f):
|
||||
return mw.readFile(version_f).strip()
|
||||
return ''
|
||||
|
||||
# 构造本地插件信息
|
||||
def getPluginInfo(self, info):
|
||||
checks = ''
|
||||
path = ''
|
||||
coexist = False
|
||||
|
||||
if info["checks"][0:1] == '/':
|
||||
checks = info["checks"]
|
||||
else:
|
||||
checks = mw.getRootDir() + '/' + info['checks']
|
||||
|
||||
if 'path' in info:
|
||||
path = info['path']
|
||||
|
||||
if path[0:1] != '/':
|
||||
path = mw.getRootDir() + '/' + path
|
||||
|
||||
if 'coexist' in info and info['coexist']:
|
||||
coexist = True
|
||||
|
||||
pInfo = {
|
||||
"id": 10000,
|
||||
"pid": info['pid'],
|
||||
"type": 1000,
|
||||
"name": info['name'],
|
||||
"title": info['title'],
|
||||
"ps": info['ps'],
|
||||
"dependnet": "",
|
||||
"mutex": "",
|
||||
"path": path,
|
||||
"install_checks": checks,
|
||||
"uninsatll_checks": checks,
|
||||
"coexist": coexist,
|
||||
"versions": info['versions'],
|
||||
# "updates": info['updates'],
|
||||
"display": False,
|
||||
"setup": False,
|
||||
"setup_version": "",
|
||||
"status": False,
|
||||
"install_pre_inspection": False,
|
||||
"uninstall_pre_inspection": False,
|
||||
}
|
||||
|
||||
if checks.find('VERSION') > -1:
|
||||
pInfo['install_checks'] = checks.replace(
|
||||
'VERSION', info['versions'])
|
||||
|
||||
if path.find('VERSION') > -1:
|
||||
pInfo['path'] = path.replace(
|
||||
'VERSION', info['versions'])
|
||||
|
||||
pInfo['task'] = self.checkSetupTask(
|
||||
pInfo['name'], info['versions'], coexist)
|
||||
pInfo['display'] = self.checkDisplayIndex(
|
||||
info['name'], pInfo['versions'])
|
||||
|
||||
pInfo['setup'] = os.path.exists(pInfo['install_checks'])
|
||||
|
||||
if coexist and pInfo['setup']:
|
||||
pInfo['setup_version'] = info['versions']
|
||||
else:
|
||||
pInfo['setup_version'] = self.getVersion(pInfo['install_checks'])
|
||||
# pluginInfo['status'] = self.checkStatus(pluginInfo)
|
||||
|
||||
if 'install_pre_inspection' in info:
|
||||
pInfo['install_pre_inspection'] = info['install_pre_inspection']
|
||||
if 'uninstall_pre_inspection' in info:
|
||||
pInfo['uninstall_pre_inspection'] = info[
|
||||
'uninstall_pre_inspection']
|
||||
|
||||
pInfo['status'] = False
|
||||
return pInfo
|
||||
|
||||
def makeCoexist(self, data):
|
||||
plugins_info = []
|
||||
for index in range(len(data['versions'])):
|
||||
tmp = data.copy()
|
||||
tmp['title'] = tmp['title'] + \
|
||||
'-' + data['versions'][index]
|
||||
tmp['versions'] = data['versions'][index]
|
||||
pg = self.getPluginInfo(tmp)
|
||||
plugins_info.append(pg)
|
||||
|
||||
return plugins_info
|
||||
|
||||
def makeList(self, data, sType='0'):
|
||||
plugins_info = []
|
||||
|
||||
if (data['pid'] == sType):
|
||||
if type(data['versions']) == list and 'coexist' in data and data['coexist']:
|
||||
tmp_data = self.makeCoexist(data)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
else:
|
||||
pg = self.getPluginInfo(data)
|
||||
plugins_info.append(pg)
|
||||
return plugins_info
|
||||
|
||||
if sType == '0':
|
||||
if type(data['versions']) == list and 'coexist' in data and data['coexist']:
|
||||
tmp_data = self.makeCoexist(data)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
else:
|
||||
pg = self.getPluginInfo(data)
|
||||
plugins_info.append(pg)
|
||||
|
||||
# print plugins_info, data
|
||||
return plugins_info
|
||||
|
||||
def getAllList(self, sType='0'):
|
||||
plugins_info = []
|
||||
for dirinfo in os.listdir(self.__plugin_dir):
|
||||
if dirinfo[0:1] == '.':
|
||||
continue
|
||||
path = self.__plugin_dir + '/' + dirinfo
|
||||
json_file = path + '/info.json'
|
||||
if os.path.exists(json_file):
|
||||
try:
|
||||
data = json.loads(mw.readFile(json_file))
|
||||
tmp_data = self.makeList(data, sType)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return plugins_info
|
||||
|
||||
def getAllListPage(self, sType='0', page=1, pageSize=10):
|
||||
plugins_info = []
|
||||
for dirinfo in os.listdir(self.__plugin_dir):
|
||||
if dirinfo[0:1] == '.':
|
||||
continue
|
||||
path = self.__plugin_dir + '/' + dirinfo
|
||||
if os.path.isdir(path):
|
||||
json_file = path + '/info.json'
|
||||
if os.path.exists(json_file):
|
||||
try:
|
||||
data = json.loads(mw.readFile(json_file))
|
||||
tmp_data = self.makeList(data, sType)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
start = (page - 1) * pageSize
|
||||
end = start + pageSize
|
||||
_plugins_info = plugins_info[start:end]
|
||||
|
||||
_plugins_info = self.checkStatusMThreads(_plugins_info)
|
||||
return (_plugins_info, len(plugins_info))
|
||||
|
||||
def makeListThread(self, data, sType='0'):
|
||||
plugins_info = []
|
||||
|
||||
if (data['pid'] == sType):
|
||||
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
|
||||
tmp_data = self.makeCoexist(data)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
else:
|
||||
pg = self.getPluginInfo(data)
|
||||
plugins_info.append(pg)
|
||||
return plugins_info
|
||||
|
||||
if sType == '0':
|
||||
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
|
||||
tmp_data = self.makeCoexist(data)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
else:
|
||||
pg = self.getPluginInfo(data)
|
||||
plugins_info.append(pg)
|
||||
|
||||
# print plugins_info, data
|
||||
return plugins_info
|
||||
|
||||
def getAllListThread(self, sType='0'):
|
||||
plugins_info = []
|
||||
tmp_list = []
|
||||
threads = []
|
||||
for dirinfo in os.listdir(self.__plugin_dir):
|
||||
if dirinfo[0:1] == '.':
|
||||
continue
|
||||
path = self.__plugin_dir + '/' + dirinfo
|
||||
if os.path.isdir(path):
|
||||
json_file = path + '/info.json'
|
||||
if os.path.exists(json_file):
|
||||
data = json.loads(mw.readFile(json_file))
|
||||
if sType == '0':
|
||||
tmp_list.append(data)
|
||||
|
||||
if (data['pid'] == sType):
|
||||
tmp_list.append(data)
|
||||
|
||||
ntmp_list = range(len(tmp_list))
|
||||
for i in ntmp_list:
|
||||
t = pa_thread(self.makeListThread, (tmp_list[i], sType))
|
||||
threads.append(t)
|
||||
for i in ntmp_list:
|
||||
threads[i].start()
|
||||
for i in ntmp_list:
|
||||
threads[i].join()
|
||||
|
||||
for i in ntmp_list:
|
||||
t = threads[i].getResult()
|
||||
for index in range(len(t)):
|
||||
plugins_info.append(t[index])
|
||||
|
||||
return plugins_info
|
||||
|
||||
def makeListProcess(self, data, sType, i, return_dict):
|
||||
plugins_info = []
|
||||
|
||||
if (data['pid'] == sType):
|
||||
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
|
||||
tmp_data = self.makeCoexist(data)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
else:
|
||||
pg = self.getPluginInfo(data)
|
||||
plugins_info.append(pg)
|
||||
# return plugins_info
|
||||
|
||||
if sType == '0':
|
||||
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
|
||||
tmp_data = self.makeCoexist(data)
|
||||
for index in range(len(tmp_data)):
|
||||
plugins_info.append(tmp_data[index])
|
||||
else:
|
||||
pg = self.getPluginInfo(data)
|
||||
plugins_info.append(pg)
|
||||
|
||||
return_dict[i] = plugins_info
|
||||
# return plugins_info
|
||||
|
||||
def getAllListProcess(self, sType='0'):
|
||||
plugins_info = []
|
||||
tmp_list = []
|
||||
manager = multiprocessing.Manager()
|
||||
return_dict = manager.dict()
|
||||
jobs = []
|
||||
for dirinfo in os.listdir(self.__plugin_dir):
|
||||
if dirinfo[0:1] == '.':
|
||||
continue
|
||||
path = self.__plugin_dir + '/' + dirinfo
|
||||
if os.path.isdir(path):
|
||||
json_file = path + '/info.json'
|
||||
if os.path.exists(json_file):
|
||||
data = json.loads(mw.readFile(json_file))
|
||||
if sType == '0':
|
||||
tmp_list.append(data)
|
||||
|
||||
if (data['pid'] == sType):
|
||||
tmp_list.append(data)
|
||||
|
||||
ntmp_list = range(len(tmp_list))
|
||||
for i in ntmp_list:
|
||||
p = multiprocessing.Process(
|
||||
target=self.makeListProcess, args=(tmp_list[i], sType, i, return_dict))
|
||||
jobs.append(p)
|
||||
p.start()
|
||||
|
||||
for proc in jobs:
|
||||
proc.join()
|
||||
|
||||
returnData = return_dict.values()
|
||||
for i in ntmp_list:
|
||||
for index in range(len(returnData[i])):
|
||||
plugins_info.append(returnData[i][index])
|
||||
|
||||
return plugins_info
|
||||
|
||||
def getPluginList(self, sType, sPage=1, sPageSize=10):
|
||||
# print sType, sPage, sPageSize
|
||||
|
||||
ret = {}
|
||||
ret['type'] = json.loads(mw.readFile(self.__type))
|
||||
# plugins_info = self.getAllListThread(sType)
|
||||
# plugins_info = self.getAllListProcess(sType)
|
||||
data = self.getAllListPage(sType, sPage, sPageSize)
|
||||
ret['data'] = data[0]
|
||||
|
||||
args = {}
|
||||
args['count'] = data[1]
|
||||
args['p'] = sPage
|
||||
args['tojs'] = 'getSList'
|
||||
args['row'] = sPageSize
|
||||
|
||||
ret['list'] = mw.getPage(args)
|
||||
return ret
|
||||
|
||||
def getIndexList(self):
|
||||
if not os.path.exists(self.__index):
|
||||
mw.writeFile(self.__index, '[]')
|
||||
|
||||
indexList = json.loads(mw.readFile(self.__index))
|
||||
plist = []
|
||||
for i in indexList:
|
||||
tmp = i.split('-')
|
||||
tmp_len = len(tmp)
|
||||
plugin_name = tmp[0]
|
||||
plugin_ver = tmp[1]
|
||||
if tmp_len > 2:
|
||||
tmpArr = tmp[0:tmp_len - 1]
|
||||
plugin_name = '-'.join(tmpArr)
|
||||
plugin_ver = tmp[tmp_len - 1]
|
||||
|
||||
json_file = self.__plugin_dir + '/' + plugin_name + '/info.json'
|
||||
if os.path.exists(json_file):
|
||||
content = mw.readFile(json_file)
|
||||
try:
|
||||
data = json.loads(content)
|
||||
data = self.makeList(data)
|
||||
for index in range(len(data)):
|
||||
if data[index]['versions'] == plugin_ver or plugin_ver in data[index]['versions']:
|
||||
data[index]['display'] = True
|
||||
plist.append(data[index])
|
||||
continue
|
||||
except Exception as e:
|
||||
print('getIndexList:', e)
|
||||
|
||||
# 使用gevent模式时,无法使用多进程
|
||||
# plist = self.checkStatusMProcess(plist)
|
||||
plist = self.checkStatusMThreads(plist)
|
||||
return plist
|
||||
|
||||
def setIndexSort(self, sort):
|
||||
data = sort.split('|')
|
||||
mw.writeFile(self.__index, json.dumps(data))
|
||||
return True
|
||||
|
||||
def addIndex(self, name, version):
|
||||
if not os.path.exists(self.__index):
|
||||
mw.writeFile(self.__index, '[]')
|
||||
|
||||
indexList = json.loads(mw.readFile(self.__index))
|
||||
vname = name + '-' + version
|
||||
|
||||
if vname in indexList:
|
||||
return mw.returnJson(False, '请不要重复添加!')
|
||||
if len(indexList) > 12:
|
||||
return mw.returnJson(False, '首页最多只能显示12个软件!')
|
||||
|
||||
indexList.append(vname)
|
||||
mw.writeFile(self.__index, json.dumps(indexList))
|
||||
return mw.returnJson(True, '添加成功!')
|
||||
|
||||
def removeIndex(self, name, version):
|
||||
if not os.path.exists(self.__index):
|
||||
mw.writeFile(self.__index, '[]')
|
||||
|
||||
indexList = json.loads(mw.readFile(self.__index))
|
||||
vname = name + '-' + version
|
||||
if not vname in indexList:
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
indexList.remove(vname)
|
||||
mw.writeFile(self.__index, json.dumps(indexList))
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
# shell 调用
|
||||
def run(self, name, func, version='', args='', script='index'):
|
||||
path = self.__plugin_dir + \
|
||||
'/' + name + '/' + script + '.py'
|
||||
py = 'python3 ' + path
|
||||
|
||||
if args == '':
|
||||
py_cmd = py + ' ' + func + ' ' + version
|
||||
else:
|
||||
py_cmd = py + ' ' + func + ' ' + version + ' ' + args
|
||||
|
||||
if not os.path.exists(path):
|
||||
return ('', '')
|
||||
data = mw.execShell(py_cmd)
|
||||
|
||||
if mw.isDebugMode():
|
||||
print('run', py_cmd)
|
||||
print(data)
|
||||
# print os.path.exists(py_cmd)
|
||||
|
||||
return (data[0].strip(), data[1].strip())
|
||||
|
||||
# 映射包调用
|
||||
def callback(self, name, func, args='', script='index'):
|
||||
package = self.__plugin_dir + '/' + name
|
||||
if not os.path.exists(package):
|
||||
return (False, "插件不存在!")
|
||||
|
||||
sys.path.append(package)
|
||||
eval_str = "__import__('" + script + "')." + func + '(' + args + ')'
|
||||
newRet = eval(eval_str)
|
||||
if mw.isDebugMode():
|
||||
print('callback', eval_str)
|
||||
|
||||
return (True, newRet)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,722 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import re
|
||||
import math
|
||||
import sys
|
||||
import json
|
||||
|
||||
from flask import Flask, session
|
||||
from flask import request
|
||||
|
||||
import db
|
||||
import mw
|
||||
|
||||
import config_api
|
||||
import requests
|
||||
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
|
||||
|
||||
def mw_async(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
thr = Thread(target=f, args=args, kwargs=kwargs)
|
||||
thr.start()
|
||||
return wrapper
|
||||
|
||||
|
||||
class system_api:
|
||||
setupPath = None
|
||||
pids = None
|
||||
|
||||
def __init__(self):
|
||||
self.setupPath = mw.getServerDir()
|
||||
|
||||
##### ----- start ----- ###
|
||||
def networkApi(self):
|
||||
data = self.getNetWork()
|
||||
return mw.getJson(data)
|
||||
|
||||
def updateServerApi(self):
|
||||
stype = request.args.get('type', 'check')
|
||||
version = request.args.get('version', '')
|
||||
return self.updateServer(stype, version)
|
||||
|
||||
def systemTotalApi(self):
|
||||
data = self.getSystemTotal()
|
||||
return mw.getJson(data)
|
||||
|
||||
def diskInfoApi(self):
|
||||
diskInfo = self.getDiskInfo()
|
||||
return mw.getJson(diskInfo)
|
||||
|
||||
def setControlApi(self):
|
||||
stype = request.form.get('type', '')
|
||||
day = request.form.get('day', '')
|
||||
data = self.setControl(stype, day)
|
||||
return data
|
||||
|
||||
def getLoadAverageApi(self):
|
||||
start = request.args.get('start', '')
|
||||
end = request.args.get('end', '')
|
||||
data = self.getLoadAverageData(start, end)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getCpuIoApi(self):
|
||||
start = request.args.get('start', '')
|
||||
end = request.args.get('end', '')
|
||||
data = self.getCpuIoData(start, end)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getDiskIoApi(self):
|
||||
start = request.args.get('start', '')
|
||||
end = request.args.get('end', '')
|
||||
data = self.getDiskIoData(start, end)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getNetworkIoApi(self):
|
||||
start = request.args.get('start', '')
|
||||
end = request.args.get('end', '')
|
||||
data = self.getNetWorkIoData(start, end)
|
||||
return mw.getJson(data)
|
||||
|
||||
def rememoryApi(self):
|
||||
os.system('sync')
|
||||
scriptFile = mw.getRunDir() + '/script/rememory.sh'
|
||||
mw.execShell("/bin/bash " + scriptFile)
|
||||
data = self.getMemInfo()
|
||||
return mw.getJson(data)
|
||||
|
||||
# 重启面板
|
||||
def restartApi(self):
|
||||
self.restartMw()
|
||||
return mw.returnJson(True, '面板已重启!')
|
||||
|
||||
def restartServerApi(self):
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(False, "开发环境不可重起")
|
||||
self.restartServer()
|
||||
return mw.returnJson(True, '正在重启服务器!')
|
||||
##### ----- end ----- ###
|
||||
|
||||
def restartTask(self):
|
||||
initd = mw.getRunDir() + '/scripts/init.d/mw'
|
||||
if os.path.exists(initd):
|
||||
os.system(initd + ' ' + 'restart_task')
|
||||
return True
|
||||
|
||||
def restartMw(self):
|
||||
mw.writeFile('data/restart.pl', 'True')
|
||||
return True
|
||||
|
||||
@mw_async
|
||||
def restartServer(self):
|
||||
if not mw.isRestart():
|
||||
return mw.returnJson(False, '请等待所有安装任务完成再执行!')
|
||||
mw.execShell("sync && init 6 &")
|
||||
return mw.returnJson(True, '命令发送成功!')
|
||||
|
||||
# 名取PID
|
||||
def getPid(self, pname):
|
||||
try:
|
||||
if not self.pids:
|
||||
self.pids = psutil.pids()
|
||||
for pid in self.pids:
|
||||
if psutil.Process(pid).name() == pname:
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
# 检查端口是否占用
|
||||
def isOpen(self, port):
|
||||
import socket
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect(('127.0.0.1', int(port)))
|
||||
s.shutdown(2)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
# 检测指定进程是否存活
|
||||
def checkProcess(self, pid):
|
||||
try:
|
||||
if not self.pids:
|
||||
self.pids = psutil.pids()
|
||||
if int(pid) in self.pids:
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def getPanelInfo(self, get=None):
|
||||
# 取面板配置
|
||||
address = mw.GetLocalIp()
|
||||
try:
|
||||
try:
|
||||
port = web.ctx.host.split(':')[1]
|
||||
except:
|
||||
port = mw.readFile('data/port.pl')
|
||||
except:
|
||||
port = '8888'
|
||||
domain = ''
|
||||
if os.path.exists('data/domain.conf'):
|
||||
domain = mw.readFile('data/domain.conf')
|
||||
|
||||
autoUpdate = ''
|
||||
if os.path.exists('data/autoUpdate.pl'):
|
||||
autoUpdate = 'checked'
|
||||
limitip = ''
|
||||
if os.path.exists('data/limitip.conf'):
|
||||
limitip = mw.readFile('data/limitip.conf')
|
||||
|
||||
templates = []
|
||||
for template in os.listdir('templates/'):
|
||||
if os.path.isdir('templates/' + template):
|
||||
templates.append(template)
|
||||
template = mw.readFile('data/templates.pl')
|
||||
|
||||
check502 = ''
|
||||
if os.path.exists('data/502Task.pl'):
|
||||
check502 = 'checked'
|
||||
return {'port': port, 'address': address, 'domain': domain, 'auto': autoUpdate, '502': check502, 'limitip': limitip, 'templates': templates, 'template': template}
|
||||
|
||||
def getSystemTotal(self, interval=1):
|
||||
# 取系统统计信息
|
||||
data = self.getMemInfo()
|
||||
cpu = self.getCpuInfo(interval)
|
||||
data['cpuNum'] = cpu[1]
|
||||
data['cpuRealUsed'] = cpu[0]
|
||||
data['time'] = self.getBootTime()
|
||||
data['system'] = self.getSystemVersion()
|
||||
data['isuser'] = mw.M('users').where(
|
||||
'username=?', ('admin',)).count()
|
||||
data['version'] = '0.0.1'
|
||||
return data
|
||||
|
||||
def getLoadAverage(self):
|
||||
c = os.getloadavg()
|
||||
data = {}
|
||||
data['one'] = float(c[0])
|
||||
data['five'] = float(c[1])
|
||||
data['fifteen'] = float(c[2])
|
||||
data['max'] = psutil.cpu_count() * 2
|
||||
data['limit'] = data['max']
|
||||
data['safe'] = data['max'] * 0.75
|
||||
return data
|
||||
|
||||
def getAllInfo(self, get):
|
||||
data = {}
|
||||
data['load_average'] = self.GetLoadAverage(get)
|
||||
data['title'] = self.GetTitle()
|
||||
data['network'] = self.GetNetWorkApi(get)
|
||||
data['panel_status'] = not os.path.exists(
|
||||
'/www/server/mdserver-web/data/close.pl')
|
||||
import firewalls
|
||||
ssh_info = firewalls.firewalls().GetSshInfo(None)
|
||||
data['enable_ssh_status'] = ssh_info['status']
|
||||
data['disable_ping_status'] = not ssh_info['ping']
|
||||
data['time'] = self.GetBootTime()
|
||||
# data['system'] = self.GetSystemVersion();
|
||||
# data['mem'] = self.GetMemInfo();
|
||||
data['version'] = web.ctx.session.version
|
||||
return data
|
||||
|
||||
def getTitle(self):
|
||||
titlePl = 'data/title.pl'
|
||||
title = 'Linux面板'
|
||||
if os.path.exists(titlePl):
|
||||
title = mw.readFile(titlePl).strip()
|
||||
return title
|
||||
|
||||
def getSystemVersion(self):
|
||||
# 取操作系统版本
|
||||
if mw.getOs() == '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
|
||||
|
||||
redhat_series = '/etc/redhat-release'
|
||||
if os.path.exists(redhat_series):
|
||||
version = mw.readFile('/etc/redhat-release')
|
||||
version = version.replace('release ', '').strip()
|
||||
return version
|
||||
|
||||
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()
|
||||
|
||||
return '未识别系统信息'
|
||||
|
||||
def getBootTime(self):
|
||||
# 取系统启动时间
|
||||
uptime = mw.readFile('/proc/uptime')
|
||||
if uptime == False:
|
||||
start_time = psutil.boot_time()
|
||||
run_time = time.time() - start_time
|
||||
else:
|
||||
run_time = uptime.split()[0]
|
||||
tStr = float(run_time)
|
||||
min = tStr / 60
|
||||
hours = min / 60
|
||||
days = math.floor(hours / 24)
|
||||
hours = math.floor(hours - (days * 24))
|
||||
min = math.floor(min - (days * 60 * 24) - (hours * 60))
|
||||
return mw.getInfo('已不间断运行: {1}天{2}小时{3}分钟', (str(int(days)), str(int(hours)), str(int(min))))
|
||||
|
||||
def getCpuInfo(self, interval=1):
|
||||
# 取CPU信息
|
||||
cpuCount = psutil.cpu_count()
|
||||
used = psutil.cpu_percent(interval=interval)
|
||||
return used, cpuCount
|
||||
|
||||
def getMemInfo(self):
|
||||
# 取内存信息
|
||||
mem = psutil.virtual_memory()
|
||||
if mw.getOs() == 'darwin':
|
||||
memInfo = {
|
||||
'memTotal': mem.total / 1024 / 1024
|
||||
}
|
||||
memInfo['memRealUsed'] = memInfo['memTotal'] * (mem.percent / 100)
|
||||
else:
|
||||
memInfo = {
|
||||
'memTotal': mem.total / 1024 / 1024,
|
||||
'memFree': mem.free / 1024 / 1024,
|
||||
'memBuffers': mem.buffers / 1024 / 1024,
|
||||
'memCached': mem.cached / 1024 / 1024
|
||||
}
|
||||
|
||||
memInfo['memRealUsed'] = memInfo['memTotal'] - \
|
||||
memInfo['memFree'] - memInfo['memBuffers'] - \
|
||||
memInfo['memCached']
|
||||
return memInfo
|
||||
|
||||
def getMemUsed(self):
|
||||
# 取内存使用率
|
||||
try:
|
||||
import psutil
|
||||
mem = psutil.virtual_memory()
|
||||
|
||||
if mw.getOs() == 'darwin':
|
||||
return mem.percent
|
||||
|
||||
memInfo = {'memTotal': mem.total / 1024 / 1024, 'memFree': mem.free / 1024 / 1024,
|
||||
'memBuffers': mem.buffers / 1024 / 1024, 'memCached': mem.cached / 1024 / 1024}
|
||||
tmp = memInfo['memTotal'] - memInfo['memFree'] - \
|
||||
memInfo['memBuffers'] - memInfo['memCached']
|
||||
tmp1 = memInfo['memTotal'] / 100
|
||||
return (tmp / tmp1)
|
||||
except Exception as ex:
|
||||
return 1
|
||||
|
||||
def getDiskInfo(self):
|
||||
info = self.getDiskInfo2()
|
||||
if len(info) != 0:
|
||||
return info
|
||||
|
||||
# 取磁盘分区信息
|
||||
diskIo = psutil.disk_partitions()
|
||||
diskInfo = []
|
||||
|
||||
for disk in diskIo:
|
||||
if disk[1] == '/mnt/cdrom':
|
||||
continue
|
||||
if disk[1] == '/boot':
|
||||
continue
|
||||
tmp = {}
|
||||
tmp['path'] = disk[1]
|
||||
size_tmp = psutil.disk_usage(disk[1])
|
||||
tmp['size'] = [mw.toSize(size_tmp[0]), mw.toSize(
|
||||
size_tmp[1]), mw.toSize(size_tmp[2]), str(size_tmp[3]) + '%']
|
||||
diskInfo.append(tmp)
|
||||
return diskInfo
|
||||
|
||||
def getDiskInfo2(self):
|
||||
# 取磁盘分区信息
|
||||
temp = mw.execShell(
|
||||
"df -h -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
|
||||
tempInodes = mw.execShell(
|
||||
"df -i -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
|
||||
temp1 = temp.split('\n')
|
||||
tempInodes1 = tempInodes.split('\n')
|
||||
diskInfo = []
|
||||
n = 0
|
||||
cuts = ['/mnt/cdrom', '/boot', '/boot/efi', '/dev',
|
||||
'/dev/shm', '/zroot', '/run/lock', '/run', '/run/shm', '/run/user']
|
||||
for tmp in temp1:
|
||||
n += 1
|
||||
inodes = tempInodes1[n - 1].split()
|
||||
disk = tmp.split()
|
||||
if len(disk) < 5:
|
||||
continue
|
||||
if disk[1].find('M') != -1:
|
||||
continue
|
||||
if disk[1].find('K') != -1:
|
||||
continue
|
||||
if len(disk[5].split('/')) > 4:
|
||||
continue
|
||||
if disk[5] in cuts:
|
||||
continue
|
||||
arr = {}
|
||||
arr['path'] = disk[5]
|
||||
tmp1 = [disk[1], disk[2], disk[3], disk[4]]
|
||||
arr['size'] = tmp1
|
||||
arr['inodes'] = [inodes[1], inodes[2], inodes[3], inodes[4]]
|
||||
diskInfo.append(arr)
|
||||
return diskInfo
|
||||
|
||||
# 清理系统垃圾
|
||||
def clearSystem(self, get):
|
||||
count = total = 0
|
||||
tmp_total, tmp_count = self.ClearMail()
|
||||
count += tmp_count
|
||||
total += tmp_total
|
||||
tmp_total, tmp_count = self.ClearOther()
|
||||
count += tmp_count
|
||||
total += tmp_total
|
||||
return count, total
|
||||
|
||||
# 清理邮件日志
|
||||
def clearMail(self):
|
||||
rpath = '/var/spool'
|
||||
total = count = 0
|
||||
import shutil
|
||||
con = ['cron', 'anacron', 'mail']
|
||||
for d in os.listdir(rpath):
|
||||
if d in con:
|
||||
continue
|
||||
dpath = rpath + '/' + d
|
||||
time.sleep(0.2)
|
||||
num = size = 0
|
||||
for n in os.listdir(dpath):
|
||||
filename = dpath + '/' + n
|
||||
fsize = os.path.getsize(filename)
|
||||
size += fsize
|
||||
if os.path.isdir(filename):
|
||||
shutil.rmtree(filename)
|
||||
else:
|
||||
os.remove(filename)
|
||||
print('mail clear ok')
|
||||
num += 1
|
||||
total += size
|
||||
count += num
|
||||
return total, count
|
||||
|
||||
# 清理其它
|
||||
def clearOther(self):
|
||||
clearPath = [
|
||||
{'path': '/www/server/mdserver-web', 'find': 'testDisk_'},
|
||||
{'path': '/www/wwwlogs', 'find': 'log'},
|
||||
{'path': '/tmp', 'find': 'panelBoot.pl'},
|
||||
{'path': '/www/server/mdserver-web/install', 'find': '.rpm'}
|
||||
]
|
||||
|
||||
total = count = 0
|
||||
for c in clearPath:
|
||||
for d in os.listdir(c['path']):
|
||||
if d.find(c['find']) == -1:
|
||||
continue
|
||||
filename = c['path'] + '/' + d
|
||||
fsize = os.path.getsize(filename)
|
||||
total += fsize
|
||||
if os.path.isdir(filename):
|
||||
shutil.rmtree(filename)
|
||||
else:
|
||||
os.remove(filename)
|
||||
count += 1
|
||||
mw.serviceReload()
|
||||
os.system('echo > /tmp/panelBoot.pl')
|
||||
return total, count
|
||||
|
||||
def psutilNetIoCounters(self):
|
||||
'''
|
||||
统计网卡流量
|
||||
'''
|
||||
stat_pl = 'data/only_netio_counters.pl'
|
||||
if os.path.exists(stat_pl):
|
||||
local_lo = (0, 0, 0, 0)
|
||||
ioName = psutil.net_io_counters(pernic=True).keys()
|
||||
for x in ioName:
|
||||
|
||||
if x.find("lo") > -1:
|
||||
local_lo = psutil.net_io_counters(
|
||||
pernic=True).get(x)[:4]
|
||||
|
||||
all_io = psutil.net_io_counters()[:4]
|
||||
result_io = tuple([all_io[i] - local_lo[i]
|
||||
for i in range(0, len(all_io))])
|
||||
|
||||
# print(local_lo)
|
||||
# print(all_io)
|
||||
# print(result_io)
|
||||
return result_io
|
||||
return psutil.net_io_counters()[:4]
|
||||
|
||||
def getNetWork(self):
|
||||
# 取网络流量信息
|
||||
try:
|
||||
# 取网络流量信息
|
||||
networkIo = self.psutilNetIoCounters()
|
||||
if not "otime" in session:
|
||||
session['up'] = networkIo[0]
|
||||
session['down'] = networkIo[1]
|
||||
session['otime'] = time.time()
|
||||
|
||||
ntime = time.time()
|
||||
networkInfo = {}
|
||||
networkInfo['upTotal'] = networkIo[0]
|
||||
networkInfo['downTotal'] = networkIo[1]
|
||||
networkInfo['up'] = round(float(
|
||||
networkIo[0] - session['up']) / 1024 / (ntime - session['otime']), 2)
|
||||
networkInfo['down'] = round(
|
||||
float(networkIo[1] - session['down']) / 1024 / (ntime - session['otime']), 2)
|
||||
networkInfo['downPackets'] = networkIo[3]
|
||||
networkInfo['upPackets'] = networkIo[2]
|
||||
|
||||
# print networkIo[1], session['down'], ntime, session['otime']
|
||||
session['up'] = networkIo[0]
|
||||
session['down'] = networkIo[1]
|
||||
session['otime'] = time.time()
|
||||
|
||||
networkInfo['cpu'] = self.getCpuInfo()
|
||||
networkInfo['load'] = self.getLoadAverage()
|
||||
networkInfo['mem'] = self.getMemInfo()
|
||||
|
||||
return networkInfo
|
||||
except Exception as e:
|
||||
print("getNetWork error:", e)
|
||||
return None
|
||||
|
||||
def getNetWorkIoData(self, start, end):
|
||||
# 取指定时间段的网络Io
|
||||
data = mw.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
|
||||
'id,up,down,total_up,total_down,down_packets,up_packets,addtime').order('id asc').select()
|
||||
return self.toAddtime(data)
|
||||
|
||||
def getDiskIoData(self, start, end):
|
||||
# 取指定时间段的磁盘Io
|
||||
data = mw.M('diskio').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
|
||||
'id,read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime').order('id asc').select()
|
||||
return self.toAddtime(data)
|
||||
|
||||
def getCpuIoData(self, start, end):
|
||||
# 取指定时间段的CpuIo
|
||||
data = mw.M('cpuio').dbfile('system').where("addtime>=? AND addtime<=?",
|
||||
(start, end)).field('id,pro,mem,addtime').order('id asc').select()
|
||||
return self.toAddtime(data, True)
|
||||
|
||||
def getLoadAverageData(self, start, end):
|
||||
data = mw.M('load_average').dbfile('system').where("addtime>=? AND addtime<=?", (
|
||||
start, end)).field('id,pro,one,five,fifteen,addtime').order('id asc').select()
|
||||
return self.toAddtime(data)
|
||||
|
||||
# 格式化addtime列
|
||||
def toAddtime(self, data, tomem=False):
|
||||
import time
|
||||
if tomem:
|
||||
import psutil
|
||||
mPre = (psutil.virtual_memory().total / 1024 / 1024) / 100
|
||||
length = len(data)
|
||||
he = 1
|
||||
if length > 100:
|
||||
he = 1
|
||||
if length > 1000:
|
||||
he = 3
|
||||
if length > 10000:
|
||||
he = 15
|
||||
if he == 1:
|
||||
for i in range(length):
|
||||
data[i]['addtime'] = time.strftime(
|
||||
'%m/%d %H:%M', time.localtime(float(data[i]['addtime'])))
|
||||
if tomem and data[i]['mem'] > 100:
|
||||
data[i]['mem'] = data[i]['mem'] / mPre
|
||||
|
||||
return data
|
||||
else:
|
||||
count = 0
|
||||
tmp = []
|
||||
for value in data:
|
||||
if count < he:
|
||||
count += 1
|
||||
continue
|
||||
value['addtime'] = time.strftime(
|
||||
'%m/%d %H:%M', time.localtime(float(value['addtime'])))
|
||||
if tomem and value['mem'] > 100:
|
||||
value['mem'] = value['mem'] / mPre
|
||||
tmp.append(value)
|
||||
count = 0
|
||||
return tmp
|
||||
|
||||
def setControl(self, stype, day):
|
||||
|
||||
filename = 'data/control.conf'
|
||||
stat_pl = 'data/only_netio_counters.pl'
|
||||
|
||||
if stype == '0':
|
||||
mw.execShell("rm -rf " + filename)
|
||||
elif stype == '1':
|
||||
_day = int(day)
|
||||
if _day < 1:
|
||||
return mw.returnJson(False, "设置失败!")
|
||||
mw.writeFile(filename, day)
|
||||
elif stype == '2':
|
||||
mw.execShell("rm -rf " + stat_pl)
|
||||
elif stype == '3':
|
||||
mw.execShell("echo 'True' > " + stat_pl)
|
||||
elif stype == 'del':
|
||||
if not mw.isRestart():
|
||||
return mw.returnJson(False, '请等待所有安装任务完成再执行')
|
||||
os.remove("data/system.db")
|
||||
|
||||
sql = db.Sql().dbfile('system')
|
||||
csql = mw.readFile('data/sql/system.sql')
|
||||
csql_list = csql.split(';')
|
||||
for index in range(len(csql_list)):
|
||||
sql.execute(csql_list[index], ())
|
||||
return mw.returnJson(True, "监控服务已关闭")
|
||||
else:
|
||||
data = {}
|
||||
if os.path.exists(filename):
|
||||
try:
|
||||
data['day'] = int(mw.readFile(filename))
|
||||
except:
|
||||
data['day'] = 30
|
||||
data['status'] = True
|
||||
else:
|
||||
data['day'] = 30
|
||||
data['status'] = False
|
||||
|
||||
if os.path.exists(stat_pl):
|
||||
data['stat_all_status'] = True
|
||||
else:
|
||||
data['stat_all_status'] = False
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
return mw.returnJson(True, "设置成功!")
|
||||
|
||||
def versionDiff(self, old, new):
|
||||
'''
|
||||
test 测试
|
||||
new 有新版本
|
||||
none 没有新版本
|
||||
'''
|
||||
new_list = new.split('.')
|
||||
if len(new_list) > 3:
|
||||
return 'test'
|
||||
|
||||
old_list = old.split('.')
|
||||
ret = 'none'
|
||||
|
||||
isHasNew = True
|
||||
if int(new_list[0]) == int(old_list[0]) and int(new_list[1]) == int(old_list[1]) and int(new_list[2]) == int(old_list[2]):
|
||||
isHasNew = False
|
||||
|
||||
if isHasNew:
|
||||
return 'new'
|
||||
return ret
|
||||
|
||||
def getServerInfo(self):
|
||||
import urllib.request
|
||||
import ssl
|
||||
upAddr = 'https://api.github.com/repos/midoks/mdserver-web/releases/latest'
|
||||
try:
|
||||
context = ssl._create_unverified_context()
|
||||
req = urllib.request.urlopen(upAddr, context=context, timeout=3)
|
||||
result = req.read().decode('utf-8')
|
||||
version = json.loads(result)
|
||||
return version
|
||||
except Exception as e:
|
||||
print('getServerInfo', e)
|
||||
return {}
|
||||
|
||||
def updateServer(self, stype, version=''):
|
||||
# 更新服务
|
||||
try:
|
||||
if not mw.isRestart():
|
||||
return mw.returnJson(False, '请等待所有安装任务完成再执行!')
|
||||
|
||||
version_new_info = self.getServerInfo()
|
||||
version_now = config_api.config_api().getVersion()
|
||||
|
||||
new_ver = version_new_info['name']
|
||||
|
||||
if stype == 'check':
|
||||
if not 'name' in version_new_info:
|
||||
return mw.returnJson(False, '服务器数据或网络有问题!')
|
||||
|
||||
diff = self.versionDiff(version_now, new_ver)
|
||||
if diff == 'new':
|
||||
return mw.returnJson(True, '有新版本!', new_ver)
|
||||
elif diff == 'test':
|
||||
return mw.returnJson(True, '有测试版本!', new_ver)
|
||||
else:
|
||||
return mw.returnJson(False, '已经是最新,无需更新!')
|
||||
|
||||
if stype == 'info':
|
||||
if not 'name' in version_new_info:
|
||||
return mw.returnJson(False, '服务器数据有问题!')
|
||||
diff = self.versionDiff(version_now, new_ver)
|
||||
data = {}
|
||||
data['version'] = new_ver
|
||||
data['content'] = version_new_info[
|
||||
'body'].replace("\n", "<br/>")
|
||||
return mw.returnJson(True, '更新信息!', data)
|
||||
|
||||
if stype == 'update':
|
||||
if version == '':
|
||||
return mw.returnJson(False, '缺少版本信息!')
|
||||
|
||||
if new_ver != version:
|
||||
return mw.returnJson(False, '更新失败,请重试!')
|
||||
|
||||
toPath = mw.getRootDir() + '/temp'
|
||||
if not os.path.exists(toPath):
|
||||
mw.execShell('mkdir -p ' + toPath)
|
||||
|
||||
newUrl = "https://github.com/midoks/mdserver-web/archive/refs/tags/" + version + ".zip"
|
||||
|
||||
dist_mw = toPath + '/mw.zip'
|
||||
if not os.path.exists(dist_mw):
|
||||
mw.execShell(
|
||||
'wget --no-check-certificate -O ' + dist_mw + ' ' + newUrl)
|
||||
|
||||
dist_to = toPath + "/mdserver-web-" + version
|
||||
if not os.path.exists(dist_to):
|
||||
os.system('unzip -o ' + toPath +
|
||||
'/mw.zip' + ' -d ' + toPath)
|
||||
|
||||
cmd_cp = 'cp -rf ' + toPath + '/mdserver-web-' + \
|
||||
version + '/* ' + mw.getServerDir() + '/mdserver-web'
|
||||
mw.execShell(cmd_cp)
|
||||
|
||||
mw.execShell('rm -rf ' + toPath + '/mdserver-web-' + version)
|
||||
mw.execShell('rm -rf ' + toPath + '/mw.zip')
|
||||
|
||||
self.restartMw()
|
||||
return mw.returnJson(True, '安装更新成功!')
|
||||
|
||||
return mw.returnJson(False, '已经是最新,无需更新!')
|
||||
except Exception as ex:
|
||||
# print('updateServer', ex)
|
||||
return mw.returnJson(False, "连接服务器失败!" + str(ex))
|
||||
|
||||
# 修复面板
|
||||
def repPanel(self, get):
|
||||
vp = ''
|
||||
if mw.readFile('/www/server/mdserver-web/class/common.py').find('checkSafe') != -1:
|
||||
vp = '_pro'
|
||||
mw.ExecShell("wget -O update.sh " + mw.get_url() +
|
||||
"/install/update" + vp + ".sh && bash update.sh")
|
||||
if hasattr(web.ctx.session, 'getCloudPlugin'):
|
||||
del(web.ctx.session['getCloudPlugin'])
|
||||
return True
|
||||
@@ -1,90 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
|
||||
from flask import request
|
||||
|
||||
|
||||
class task_api:
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def countApi(self):
|
||||
c = mw.M('tasks').where("status!=?", ('1',)).count()
|
||||
return str(c)
|
||||
|
||||
def listApi(self):
|
||||
|
||||
p = request.form.get('p', '1')
|
||||
limit = request.form.get('limit', '10').strip()
|
||||
search = request.form.get('search', '').strip()
|
||||
|
||||
start = (int(p) - 1) * int(limit)
|
||||
limit_str = str(start) + ',' + str(limit)
|
||||
|
||||
_list = mw.M('tasks').where('', ()).field(
|
||||
'id,name,type,status,addtime,start,end').limit(limit_str).order('id desc').select()
|
||||
_ret = {}
|
||||
_ret['data'] = _list
|
||||
|
||||
count = mw.M('tasks').where('', ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'remind'
|
||||
_page['p'] = p
|
||||
|
||||
# return data
|
||||
_ret['count'] = count
|
||||
_ret['page'] = mw.getPage(_page)
|
||||
return mw.getJson(_ret)
|
||||
|
||||
def getExecLogApi(self):
|
||||
file = os.getcwd() + "/tmp/panelExec.log"
|
||||
v = mw.getLastLine(file, 100)
|
||||
return v
|
||||
|
||||
def getTaskSpeedApi(self):
|
||||
tempFile = mw.getRunDir() + '/tmp/panelExec.log'
|
||||
freshFile = mw.getRunDir() + '/tmp/panelFresh'
|
||||
|
||||
find = mw.M('tasks').where('status=? OR status=?',
|
||||
('-1', '0')).field('id,type,name,execstr').find()
|
||||
if not len(find):
|
||||
return mw.returnJson(False, '当前没有任务队列在执行-2!')
|
||||
|
||||
mw.triggerTask()
|
||||
|
||||
data = {}
|
||||
data['name'] = find['name']
|
||||
data['execstr'] = find['execstr']
|
||||
if find['type'] == 'download':
|
||||
readLine = ""
|
||||
for i in range(3):
|
||||
try:
|
||||
readLine = mw.readFile(tempFile)
|
||||
if len(readLine) > 10:
|
||||
data['msg'] = json.loads(readLine)
|
||||
data['isDownload'] = True
|
||||
break
|
||||
except Exception as e:
|
||||
if i == 2:
|
||||
mw.M('tasks').where("id=?", (find['id'],)).save(
|
||||
'status', ('0',))
|
||||
return mw.returnJson(False, '当前没有任务队列在执行-4:' + str(e))
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
data['msg'] = mw.getLastLine(tempFile, 10)
|
||||
data['isDownload'] = False
|
||||
|
||||
data['task'] = mw.M('tasks').where("status!=?", ('1',)).field(
|
||||
'id,status,name,type').order("id asc").select()
|
||||
return mw.getJson(data)
|
||||
@@ -1,132 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
|
||||
import random
|
||||
import math
|
||||
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||
|
||||
|
||||
class vieCode:
|
||||
__fontSize = 20 # 字体大小
|
||||
__width = 120 # 画布宽度
|
||||
__heigth = 45 # 画布高度
|
||||
__length = 4 # 验证码长度
|
||||
__draw = None # 画布
|
||||
__img = None # 图片资源
|
||||
__code = None # 验证码字符
|
||||
__str = None # 自定义验证码字符集
|
||||
__inCurve = True # 是否画干扰线
|
||||
__inNoise = True # 是否画干扰点
|
||||
__type = 2 # 验证码类型 1、纯字母 2、数字字母混合
|
||||
__fontPatn = 'class/fonts/2.ttf' # 字体
|
||||
|
||||
def GetCodeImage(self, size=80, length=4):
|
||||
'''获取验证码图片
|
||||
@param int size 验证码大小
|
||||
@param int length 验证码长度
|
||||
'''
|
||||
# 准备基础数据
|
||||
self.__length = length
|
||||
self.__fontSize = size
|
||||
self.__width = self.__fontSize * self.__length
|
||||
self.__heigth = int(self.__fontSize * 1.5)
|
||||
|
||||
# 生成验证码图片
|
||||
self.__createCode()
|
||||
self.__createImage()
|
||||
self.__createNoise()
|
||||
self.__printString()
|
||||
self.__cerateFilter()
|
||||
|
||||
return self.__img, self.__code
|
||||
|
||||
def __cerateFilter(self):
|
||||
'''模糊处理'''
|
||||
self.__img = self.__img.filter(ImageFilter.BLUR)
|
||||
filter = ImageFilter.ModeFilter(8)
|
||||
self.__img = self.__img.filter(filter)
|
||||
|
||||
def __createCode(self):
|
||||
'''创建验证码字符'''
|
||||
# 是否自定义字符集合
|
||||
if not self.__str:
|
||||
# 源文本
|
||||
number = "3456789"
|
||||
srcLetter = "qwertyuipasdfghjkzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
|
||||
srcUpper = srcLetter.upper()
|
||||
if self.__type == 1:
|
||||
self.__str = number
|
||||
else:
|
||||
self.__str = srcLetter + srcUpper + number
|
||||
|
||||
# 构造验证码
|
||||
self.__code = random.sample(self.__str, self.__length)
|
||||
|
||||
def __createImage(self):
|
||||
'''创建画布'''
|
||||
bgColor = (random.randint(200, 255), random.randint(
|
||||
200, 255), random.randint(200, 255))
|
||||
self.__img = Image.new('RGB', (self.__width, self.__heigth), bgColor)
|
||||
self.__draw = ImageDraw.Draw(self.__img)
|
||||
|
||||
def __createNoise(self):
|
||||
'''画干扰点'''
|
||||
if not self.__inNoise:
|
||||
return
|
||||
font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5))
|
||||
for i in range(5):
|
||||
# 杂点颜色
|
||||
noiseColor = (random.randint(150, 200), random.randint(
|
||||
150, 200), random.randint(150, 200))
|
||||
putStr = random.sample(self.__str, 2)
|
||||
for j in range(2):
|
||||
# 绘杂点
|
||||
size = (random.randint(-10, self.__width),
|
||||
random.randint(-10, self.__heigth))
|
||||
self.__draw.text(size, putStr[j], font=font, fill=noiseColor)
|
||||
pass
|
||||
|
||||
def __createCurve(self):
|
||||
'''画干扰线'''
|
||||
if not self.__inCurve:
|
||||
return
|
||||
x = y = 0
|
||||
|
||||
# 计算曲线系数
|
||||
a = random.uniform(1, self.__heigth / 2)
|
||||
b = random.uniform(-self.__width / 4, self.__heigth / 4)
|
||||
f = random.uniform(-self.__heigth / 4, self.__heigth / 4)
|
||||
t = random.uniform(self.__heigth, self.__width * 2)
|
||||
xend = random.randint(self.__width / 2, self.__width * 2)
|
||||
w = (2 * math.pi) / t
|
||||
|
||||
# 画曲线
|
||||
color = (random.randint(30, 150), random.randint(
|
||||
30, 150), random.randint(30, 150))
|
||||
for x in range(xend):
|
||||
if w != 0:
|
||||
for k in range(int(self.__heigth / 10)):
|
||||
y = a * math.sin(w * x + f) + b + self.__heigth / 2
|
||||
i = int(self.__fontSize / 5)
|
||||
while i > 0:
|
||||
px = x + i
|
||||
py = y + i + k
|
||||
self.__draw.point((px, py), color)
|
||||
i -= i
|
||||
|
||||
def __printString(self):
|
||||
'''打印验证码字符串'''
|
||||
font = ImageFont.truetype(self.__fontPatn, self.__fontSize)
|
||||
x = 0
|
||||
# 打印字符到画板
|
||||
for i in range(self.__length):
|
||||
# 设置字体随机颜色
|
||||
color = (random.randint(30, 150), random.randint(
|
||||
30, 150), random.randint(30, 150))
|
||||
# 计算座标
|
||||
x = random.uniform(self.__fontSize * i * 0.95,
|
||||
self.__fontSize * i * 1.1)
|
||||
y = self.__fontSize * random.uniform(0.3, 0.5)
|
||||
# 打印字符
|
||||
self.__draw.text((x, y), self.__code[i], font=font, fill=color)
|
||||
Binary file not shown.
@@ -1,5 +0,0 @@
|
||||
|
||||
- fcgi-client.py
|
||||
```
|
||||
https://pypi.org/project/flup6/1.1.1/#files
|
||||
```
|
||||
@@ -1,408 +0,0 @@
|
||||
# Copyright (c) 2006 Allan Saddi <allan@saddi.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (c) 2011 Vladimir Rusinov <vladimir@greenmice.info>
|
||||
|
||||
__author__ = 'Allan Saddi <allan@saddi.com>'
|
||||
__version__ = '$Revision$'
|
||||
import sys
|
||||
import select
|
||||
import struct
|
||||
import socket
|
||||
import errno
|
||||
import types
|
||||
|
||||
|
||||
__all__ = ['FCGIApp']
|
||||
|
||||
# Constants from the spec.
|
||||
FCGI_LISTENSOCK_FILENO = 0
|
||||
|
||||
FCGI_HEADER_LEN = 8
|
||||
|
||||
FCGI_VERSION_1 = 1
|
||||
|
||||
FCGI_BEGIN_REQUEST = 1
|
||||
FCGI_ABORT_REQUEST = 2
|
||||
FCGI_END_REQUEST = 3
|
||||
FCGI_PARAMS = 4
|
||||
FCGI_STDIN = 5
|
||||
FCGI_STDOUT = 6
|
||||
FCGI_STDERR = 7
|
||||
FCGI_DATA = 8
|
||||
FCGI_GET_VALUES = 9
|
||||
FCGI_GET_VALUES_RESULT = 10
|
||||
FCGI_UNKNOWN_TYPE = 11
|
||||
FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
|
||||
|
||||
FCGI_NULL_REQUEST_ID = 0
|
||||
|
||||
FCGI_KEEP_CONN = 1
|
||||
|
||||
FCGI_RESPONDER = 1
|
||||
FCGI_AUTHORIZER = 2
|
||||
FCGI_FILTER = 3
|
||||
|
||||
FCGI_REQUEST_COMPLETE = 0
|
||||
FCGI_CANT_MPX_CONN = 1
|
||||
FCGI_OVERLOADED = 2
|
||||
FCGI_UNKNOWN_ROLE = 3
|
||||
|
||||
FCGI_MAX_CONNS = 'FCGI_MAX_CONNS'
|
||||
FCGI_MAX_REQS = 'FCGI_MAX_REQS'
|
||||
FCGI_MPXS_CONNS = 'FCGI_MPXS_CONNS'
|
||||
|
||||
FCGI_Header = '!BBHHBx'
|
||||
FCGI_BeginRequestBody = '!HB5x'
|
||||
FCGI_EndRequestBody = '!LB3x'
|
||||
FCGI_UnknownTypeBody = '!B7x'
|
||||
|
||||
FCGI_BeginRequestBody_LEN = struct.calcsize(FCGI_BeginRequestBody)
|
||||
FCGI_EndRequestBody_LEN = struct.calcsize(FCGI_EndRequestBody)
|
||||
FCGI_UnknownTypeBody_LEN = struct.calcsize(FCGI_UnknownTypeBody)
|
||||
|
||||
if __debug__:
|
||||
import time
|
||||
|
||||
# Set non-zero to write debug output to a file.
|
||||
DEBUG = 0
|
||||
DEBUGLOG = '/www/server/mdserver-web/logs/fastcgi.log'
|
||||
|
||||
def _debug(level, msg):
|
||||
if DEBUG < level:
|
||||
return
|
||||
|
||||
try:
|
||||
f = open(DEBUGLOG, 'a')
|
||||
f.write('%sfcgi: %s\n' % (time.ctime()[4:-4], msg))
|
||||
f.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def decode_pair(s, pos=0):
|
||||
"""
|
||||
Decodes a name/value pair.
|
||||
|
||||
The number of bytes decoded as well as the name/value pair
|
||||
are returned.
|
||||
"""
|
||||
nameLength = ord(s[pos])
|
||||
if nameLength & 128:
|
||||
nameLength = struct.unpack('!L', s[pos:pos + 4])[0] & 0x7fffffff
|
||||
pos += 4
|
||||
else:
|
||||
pos += 1
|
||||
|
||||
valueLength = ord(s[pos])
|
||||
if valueLength & 128:
|
||||
valueLength = struct.unpack('!L', s[pos:pos + 4])[0] & 0x7fffffff
|
||||
pos += 4
|
||||
else:
|
||||
pos += 1
|
||||
|
||||
name = s[pos:pos + nameLength]
|
||||
pos += nameLength
|
||||
value = s[pos:pos + valueLength]
|
||||
pos += valueLength
|
||||
|
||||
return (pos, (name, value))
|
||||
|
||||
|
||||
def encode_pair(name, value):
|
||||
"""
|
||||
Encodes a name/value pair.
|
||||
|
||||
The encoded string is returned.
|
||||
"""
|
||||
nameLength = len(name)
|
||||
if nameLength < 128:
|
||||
s = chr(nameLength).encode()
|
||||
else:
|
||||
s = struct.pack('!L', nameLength | 0x80000000)
|
||||
|
||||
valueLength = len(value)
|
||||
if valueLength < 128:
|
||||
s += chr(valueLength).encode()
|
||||
else:
|
||||
s += struct.pack('!L', valueLength | 0x80000000)
|
||||
|
||||
return s + name + value
|
||||
|
||||
|
||||
class Record(object):
|
||||
"""
|
||||
A FastCGI Record.
|
||||
|
||||
Used for encoding/decoding records.
|
||||
"""
|
||||
|
||||
def __init__(self, type=FCGI_UNKNOWN_TYPE, requestId=FCGI_NULL_REQUEST_ID):
|
||||
self.version = FCGI_VERSION_1
|
||||
self.type = type
|
||||
self.requestId = requestId
|
||||
self.contentLength = 0
|
||||
self.paddingLength = 0
|
||||
self.contentData = ''
|
||||
|
||||
def _recvall(sock, length):
|
||||
"""
|
||||
Attempts to receive length bytes from a socket, blocking if necessary.
|
||||
(Socket may be blocking or non-blocking.)
|
||||
"""
|
||||
dataList = []
|
||||
recvLen = 0
|
||||
while length:
|
||||
try:
|
||||
data = sock.recv(length)
|
||||
except socket.error as e:
|
||||
if e[0] == errno.EAGAIN:
|
||||
select.select([sock], [], [])
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
if not data: # EOF
|
||||
break
|
||||
dataList.append(data)
|
||||
dataLen = len(data)
|
||||
recvLen += dataLen
|
||||
length -= dataLen
|
||||
return b''.join(dataList), recvLen
|
||||
_recvall = staticmethod(_recvall)
|
||||
|
||||
def read(self, sock):
|
||||
"""Read and decode a Record from a socket."""
|
||||
try:
|
||||
header, length = self._recvall(sock, FCGI_HEADER_LEN)
|
||||
except:
|
||||
raise EOFError
|
||||
|
||||
if length < FCGI_HEADER_LEN:
|
||||
raise EOFError
|
||||
|
||||
self.version, self.type, self.requestId, self.contentLength, \
|
||||
self.paddingLength = struct.unpack(FCGI_Header, header)
|
||||
|
||||
if __debug__:
|
||||
_debug(9, 'read: fd = %d, type = %d, requestId = %d, '
|
||||
'contentLength = %d' %
|
||||
(sock.fileno(), self.type, self.requestId,
|
||||
self.contentLength))
|
||||
|
||||
if self.contentLength:
|
||||
try:
|
||||
self.contentData, length = self._recvall(sock,
|
||||
self.contentLength)
|
||||
except:
|
||||
raise EOFError
|
||||
|
||||
if length < self.contentLength:
|
||||
raise EOFError
|
||||
|
||||
if self.paddingLength:
|
||||
try:
|
||||
self._recvall(sock, self.paddingLength)
|
||||
except:
|
||||
raise EOFError
|
||||
|
||||
def _sendall(sock, data):
|
||||
"""
|
||||
Writes data to a socket and does not return until all the data is sent.
|
||||
"""
|
||||
length = len(data)
|
||||
while length:
|
||||
try:
|
||||
sent = sock.send(data)
|
||||
except socket.error as e:
|
||||
if e[0] == errno.EAGAIN:
|
||||
select.select([], [sock], [])
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
data = data[sent:]
|
||||
length -= sent
|
||||
_sendall = staticmethod(_sendall)
|
||||
|
||||
def write(self, sock):
|
||||
"""Encode and write a Record to a socket."""
|
||||
self.paddingLength = -self.contentLength & 7
|
||||
|
||||
if __debug__:
|
||||
_debug(9, 'write: fd = %d, type = %d, requestId = %d, '
|
||||
'contentLength = %d' %
|
||||
(sock.fileno(), self.type, self.requestId,
|
||||
self.contentLength))
|
||||
|
||||
header = struct.pack(FCGI_Header, self.version, self.type,
|
||||
self.requestId, self.contentLength,
|
||||
self.paddingLength)
|
||||
self._sendall(sock, header)
|
||||
if self.contentLength:
|
||||
self._sendall(sock, self.contentData)
|
||||
if self.paddingLength:
|
||||
self._sendall(sock, b'\x00' * self.paddingLength)
|
||||
|
||||
|
||||
class FCGIApp(object):
|
||||
|
||||
def __init__(self, connect=None, host=None, port=None, filterEnviron=True):
|
||||
if host is not None:
|
||||
assert port is not None
|
||||
connect = (host, port)
|
||||
|
||||
self._connect = connect
|
||||
self._filterEnviron = filterEnviron
|
||||
|
||||
def __call__(self, environ, io, start_response=None):
|
||||
# For sanity's sake, we don't care about FCGI_MPXS_CONN
|
||||
# (connection multiplexing). For every request, we obtain a new
|
||||
# transport socket, perform the request, then discard the socket.
|
||||
# This is, I believe, how mod_fastcgi does things...
|
||||
|
||||
sock = self._getConnection()
|
||||
|
||||
# Since this is going to be the only request on this connection,
|
||||
# set the request ID to 1.
|
||||
requestId = 1
|
||||
|
||||
# Begin the request
|
||||
rec = Record(FCGI_BEGIN_REQUEST, requestId)
|
||||
rec.contentData = struct.pack(FCGI_BeginRequestBody, FCGI_RESPONDER, 0)
|
||||
rec.contentLength = FCGI_BeginRequestBody_LEN
|
||||
rec.write(sock)
|
||||
|
||||
# Filter WSGI environ and send it as FCGI_PARAMS
|
||||
if self._filterEnviron:
|
||||
params = self._defaultFilterEnviron(environ)
|
||||
else:
|
||||
params = self._lightFilterEnviron(environ)
|
||||
# TODO: Anything not from environ that needs to be sent also?
|
||||
# return '200 OK',[],str(params),''
|
||||
self._fcgiParams(sock, requestId, params)
|
||||
self._fcgiParams(sock, requestId, {})
|
||||
|
||||
# Transfer wsgi.input to FCGI_STDIN
|
||||
content_length = int(environ.get('CONTENT_LENGTH') or 0)
|
||||
s = ''
|
||||
#io = StringIO(stdin)
|
||||
while True:
|
||||
if not io:
|
||||
break
|
||||
chunk_size = min(content_length, 4096)
|
||||
s = io.read(chunk_size)
|
||||
content_length -= len(s)
|
||||
rec = Record(FCGI_STDIN, requestId)
|
||||
rec.contentData = s
|
||||
rec.contentLength = len(s)
|
||||
rec.write(sock)
|
||||
if not s:
|
||||
break
|
||||
# Empty FCGI_DATA stream
|
||||
rec = Record(FCGI_DATA, requestId)
|
||||
rec.write(sock)
|
||||
return sock
|
||||
|
||||
def _getConnection(self):
|
||||
if self._connect is not None:
|
||||
# The simple case. Create a socket and connect to the
|
||||
# application.
|
||||
if isinstance(self._connect, str):
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.connect(self._connect)
|
||||
elif hasattr(socket, 'create_connection'):
|
||||
sock = socket.create_connection(self._connect)
|
||||
else:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect(self._connect)
|
||||
return sock
|
||||
|
||||
# To be done when I have more time...
|
||||
# , 'Launching and managing FastCGI programs not yet implemented'
|
||||
raise NotImplementedError
|
||||
|
||||
def _fcgiGetValues(self, sock, vars):
|
||||
# Construct FCGI_GET_VALUES record
|
||||
outrec = Record(FCGI_GET_VALUES)
|
||||
data = []
|
||||
for name in vars:
|
||||
data.append(encode_pair(name, ''))
|
||||
data = ''.join(data)
|
||||
outrec.contentData = data
|
||||
outrec.contentLength = len(data)
|
||||
outrec.write(sock)
|
||||
|
||||
# Await response
|
||||
inrec = Record()
|
||||
inrec.read(sock)
|
||||
result = {}
|
||||
if inrec.type == FCGI_GET_VALUES_RESULT:
|
||||
pos = 0
|
||||
while pos < inrec.contentLength:
|
||||
pos, (name, value) = decode_pair(inrec.contentData, pos)
|
||||
result[name] = value
|
||||
return result
|
||||
|
||||
def _fcgiParams(self, sock, requestId, params):
|
||||
rec = Record(FCGI_PARAMS, requestId)
|
||||
data = []
|
||||
for name, value in params.items():
|
||||
data.append(encode_pair(name.encode(
|
||||
'latin-1'), value.encode('latin-1')))
|
||||
data = b''.join(data)
|
||||
rec.contentData = data
|
||||
rec.contentLength = len(data)
|
||||
rec.write(sock)
|
||||
|
||||
_environPrefixes = ['SERVER_', 'HTTP_', 'REQUEST_', 'REMOTE_', 'PATH_',
|
||||
'CONTENT_', 'DOCUMENT_', 'SCRIPT_']
|
||||
_environCopies = ['SCRIPT_NAME', 'QUERY_STRING', 'AUTH_TYPE']
|
||||
_environRenames = []
|
||||
|
||||
def _defaultFilterEnviron(self, environ):
|
||||
result = {}
|
||||
for n in environ.keys():
|
||||
iv = False
|
||||
for p in self._environPrefixes:
|
||||
if n.startswith(p):
|
||||
result[n] = environ[n]
|
||||
iv = True
|
||||
if n in self._environCopies:
|
||||
result[n] = environ[n]
|
||||
iv = True
|
||||
if n in self._environRenames:
|
||||
result[self._environRenames[n]] = environ[n]
|
||||
iv = True
|
||||
if not iv:
|
||||
result[n] = environ[n]
|
||||
|
||||
return result
|
||||
|
||||
def _lightFilterEnviron(self, environ):
|
||||
result = {}
|
||||
for n in environ.keys():
|
||||
if n.upper() == n:
|
||||
result[n] = environ[n]
|
||||
return result
|
||||
@@ -1,208 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import struct
|
||||
import fcgi_client
|
||||
|
||||
FCGI_Header = '!BBHHBx'
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except:
|
||||
from StringIO import StringIO
|
||||
else:
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
|
||||
def get_header_data(sock):
|
||||
'''
|
||||
@name 获取头部32KB数据
|
||||
@param sock socketobject(fastcgi套接字对象)
|
||||
@return bytes
|
||||
'''
|
||||
headers_data = b''
|
||||
total_len = 0
|
||||
header_len = 1024 * 128
|
||||
while True:
|
||||
fastcgi_header = sock.recv(8)
|
||||
if not fastcgi_header:
|
||||
break
|
||||
if len(fastcgi_header) != 8:
|
||||
headers_data += fastcgi_header
|
||||
break
|
||||
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
|
||||
if fast_pack[1] == 3:
|
||||
break
|
||||
|
||||
tlen = fast_pack[3]
|
||||
while tlen > 0:
|
||||
sd = sock.recv(tlen)
|
||||
if not sd:
|
||||
break
|
||||
headers_data += sd
|
||||
tlen -= len(sd)
|
||||
|
||||
total_len += fast_pack[3]
|
||||
if fast_pack[4]:
|
||||
sock.recv(fast_pack[4])
|
||||
if total_len > header_len:
|
||||
break
|
||||
return headers_data
|
||||
|
||||
|
||||
def format_header_data(headers_data):
|
||||
'''
|
||||
@name 格式化响应头
|
||||
@param headers_data bytes(fastcgi头部32KB数据)
|
||||
@return status int(响应状态), headers dict(响应头), bdata bytes(格式化响应头后的多余数据)
|
||||
'''
|
||||
status = '200 OK'
|
||||
headers = {}
|
||||
pos = 0
|
||||
while True:
|
||||
eolpos = headers_data.find(b'\n', pos)
|
||||
if eolpos < 0:
|
||||
break
|
||||
line = headers_data[pos:eolpos - 1]
|
||||
pos = eolpos + 1
|
||||
line = line.strip()
|
||||
if len(line) < 2:
|
||||
break
|
||||
if line.find(b':') == -1:
|
||||
continue
|
||||
header, value = line.split(b':', 1)
|
||||
header = header.strip()
|
||||
value = value.strip()
|
||||
if isinstance(header, bytes):
|
||||
header = header.decode()
|
||||
value = value.decode()
|
||||
if header == 'Status':
|
||||
status = value
|
||||
if status.find(' ') < 0:
|
||||
status += ' BTPanel'
|
||||
else:
|
||||
headers[header] = value
|
||||
bdata = headers_data[pos:]
|
||||
status = int(status.split(' ')[0])
|
||||
return status, headers, bdata
|
||||
|
||||
|
||||
def resp_sock(sock, bdata):
|
||||
'''
|
||||
@name 以流的方式发送剩余数据
|
||||
@param sock socketobject(fastcgi套接字对象)
|
||||
@param bdata bytes(格式化响应头后的多余数据)
|
||||
@return yield bytes
|
||||
'''
|
||||
# 发送除响应头以外的多余头部数据
|
||||
yield bdata
|
||||
while True:
|
||||
fastcgi_header = sock.recv(8)
|
||||
if not fastcgi_header:
|
||||
break
|
||||
if len(fastcgi_header) != 8:
|
||||
yield fastcgi_header
|
||||
break
|
||||
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
|
||||
if fast_pack[1] == 3:
|
||||
break
|
||||
tlen = fast_pack[3]
|
||||
while tlen > 0:
|
||||
sd = sock.recv(tlen)
|
||||
if not sd:
|
||||
break
|
||||
tlen -= len(sd)
|
||||
if sd:
|
||||
yield sd
|
||||
|
||||
if fast_pack[4]:
|
||||
sock.recv(fast_pack[4])
|
||||
sock.close()
|
||||
|
||||
|
||||
class fpm(object):
|
||||
|
||||
def __init__(self, sock=None, document_root='', last_path=''):
|
||||
'''
|
||||
@name 实例化FPM对象
|
||||
@param sock string(unixsocket路径)
|
||||
@param document_root string(PHP文档根目录)
|
||||
@return FPM
|
||||
'''
|
||||
if sock:
|
||||
self.fcgi_sock = sock
|
||||
if document_root[-1:] != '/':
|
||||
document_root += '/'
|
||||
self.document_root = document_root
|
||||
self.last_path = last_path
|
||||
|
||||
def load_url_public(self, url, content=b'', method='GET', content_type='application/x-www-form-urlencoded'):
|
||||
'''
|
||||
@name 转发URL到PHP-FPM 公共
|
||||
@param url string(URI地址)
|
||||
@param content stream(POST数据io对象)
|
||||
@return fastcgi-socket
|
||||
'''
|
||||
fcgi = fcgi_client.FCGIApp(connect=self.fcgi_sock)
|
||||
try:
|
||||
script_name, query_string = url.split('?')
|
||||
except ValueError:
|
||||
script_name = url
|
||||
query_string = ''
|
||||
|
||||
content_length = len(content)
|
||||
if content:
|
||||
content = StringIO(content)
|
||||
|
||||
env = {
|
||||
'SCRIPT_FILENAME': '%s%s' % (self.document_root, script_name),
|
||||
'QUERY_STRING': query_string,
|
||||
'REQUEST_METHOD': method,
|
||||
'SCRIPT_NAME': self.last_path + script_name,
|
||||
'REQUEST_URI': url,
|
||||
'GATEWAY_INTERFACE': 'CGI/1.1',
|
||||
'SERVER_SOFTWARE': 'MW-Panel',
|
||||
'REDIRECT_STATUS': '200',
|
||||
'CONTENT_TYPE': content_type,
|
||||
'CONTENT_LENGTH': str(content_length),
|
||||
'DOCUMENT_URI': script_name,
|
||||
'DOCUMENT_ROOT': self.document_root,
|
||||
'SERVER_PROTOCOL': 'HTTP/1.1',
|
||||
'REMOTE_ADDR': '127.0.0.1',
|
||||
'REMOTE_PORT': '7200',
|
||||
'SERVER_ADDR': '127.0.0.1',
|
||||
'SERVER_PORT': '80',
|
||||
'SERVER_NAME': 'MW-Panel'
|
||||
}
|
||||
|
||||
fpm_sock = fcgi(env, content)
|
||||
|
||||
_data = b''
|
||||
while True:
|
||||
fastcgi_header = fpm_sock.recv(8)
|
||||
if not fastcgi_header:
|
||||
break
|
||||
if len(fastcgi_header) != 8:
|
||||
_data += fastcgi_header
|
||||
break
|
||||
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
|
||||
if fast_pack[1] == 3:
|
||||
break
|
||||
tlen = fast_pack[3]
|
||||
while tlen > 0:
|
||||
sd = fpm_sock.recv(tlen)
|
||||
if not sd:
|
||||
break
|
||||
tlen -= len(sd)
|
||||
_data += sd
|
||||
if fast_pack[4]:
|
||||
fpm_sock.recv(fast_pack[4])
|
||||
status, headers, data = format_header_data(_data)
|
||||
return data
|
||||
@@ -1,113 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pymysql.cursors
|
||||
|
||||
|
||||
class ORM:
|
||||
__DB_PASS = None
|
||||
__DB_USER = 'root'
|
||||
__DB_PORT = 3306
|
||||
__DB_NAME = ''
|
||||
__DB_HOST = 'localhost'
|
||||
__DB_CONN = None
|
||||
__DB_CUR = None
|
||||
__DB_ERR = None
|
||||
__DB_CNF = '/etc/my.cnf'
|
||||
__DB_SOCKET = '/www/server/mysql/mysql.sock'
|
||||
|
||||
__DB_CHARSET = "utf8"
|
||||
|
||||
def __Conn(self):
|
||||
'''连接数据库'''
|
||||
try:
|
||||
|
||||
if os.path.exists(self.__DB_SOCKET):
|
||||
try:
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
|
||||
except Exception as e:
|
||||
self.__DB_HOST = '127.0.0.1'
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
|
||||
else:
|
||||
try:
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
cursorclass=pymysql.cursors.DictCursor)
|
||||
except Exception as e:
|
||||
self.__DB_HOST = '127.0.0.1'
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
database=self.__DB_NAME,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
|
||||
cursorclass=pymysql.cursors.DictCursor)
|
||||
|
||||
self.__DB_CUR = self.__DB_CONN.cursor()
|
||||
return True
|
||||
except Exception as e:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
|
||||
def setDbConf(self, conf):
|
||||
self.__DB_CNF = conf
|
||||
|
||||
def setSocket(self, sock):
|
||||
self.__DB_SOCKET = sock
|
||||
|
||||
def setCharset(self, charset):
|
||||
self.__DB_CHARSET = charset
|
||||
|
||||
def setPort(self, port):
|
||||
self.__DB_PORT = port
|
||||
|
||||
def setUser(self, user):
|
||||
self.__DB_USER = user
|
||||
|
||||
def setPwd(self, pwd):
|
||||
self.__DB_PASS = pwd
|
||||
|
||||
def getPwd(self):
|
||||
return self.__DB_PASS
|
||||
|
||||
def setDbName(self, name):
|
||||
self.__DB_NAME = name
|
||||
|
||||
def execute(self, sql):
|
||||
# 执行SQL语句返回受影响行
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
result = self.__DB_CUR.execute(sql)
|
||||
self.__DB_CONN.commit()
|
||||
self.__Close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
def query(self, sql):
|
||||
# 执行SQL语句返回数据集
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
self.__DB_CUR.execute(sql)
|
||||
result = self.__DB_CUR.fetchall()
|
||||
# print(result)
|
||||
# 将元组转换成列表
|
||||
# data = map(list, result)
|
||||
self.__Close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
def __Close(self):
|
||||
# 关闭连接
|
||||
self.__DB_CUR.close()
|
||||
self.__DB_CONN.close()
|
||||
@@ -1,115 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
class ORM:
|
||||
__DB_PASS = None
|
||||
__DB_USER = 'root'
|
||||
__DB_PORT = 3306
|
||||
__DB_HOST = 'localhost'
|
||||
__DB_CONN = None
|
||||
__DB_CUR = None
|
||||
__DB_ERR = None
|
||||
__DB_CNF = '/etc/my.cnf'
|
||||
|
||||
__DB_SOCKET = '/www/server/mysql/mysql.sock'
|
||||
__DB_CHARSET = 'utf8'
|
||||
|
||||
def __Conn(self):
|
||||
'''连接MYSQL数据库'''
|
||||
try:
|
||||
|
||||
try:
|
||||
import MySQLdb
|
||||
except Exception as ex:
|
||||
self.__DB_ERR = ex
|
||||
return False
|
||||
|
||||
# print(self.__DB_HOST)
|
||||
# print(self.__DB_USER)
|
||||
# print(self.__DB_PASS)
|
||||
# print(self.__DB_PORT)
|
||||
# print(self.__DB_CHARSET)
|
||||
# print(self.__DB_SOCKET)
|
||||
if os.path.exists(self.__DB_SOCKET):
|
||||
try:
|
||||
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.__DB_HOST = '127.0.0.1'
|
||||
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET)
|
||||
else:
|
||||
try:
|
||||
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1)
|
||||
except Exception as e:
|
||||
self.__DB_HOST = '127.0.0.1'
|
||||
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
|
||||
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1)
|
||||
|
||||
self.__DB_CUR = self.__DB_CONN.cursor()
|
||||
|
||||
return True
|
||||
except MySQLdb.Error as e:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
|
||||
def setDbConf(self, conf):
|
||||
self.__DB_CNF = conf
|
||||
|
||||
def setSocket(self, sock):
|
||||
self.__DB_SOCKET = sock
|
||||
|
||||
def setCharset(self, charset):
|
||||
self.__DB_CHARSET = charset
|
||||
|
||||
def setPort(self, port):
|
||||
self.__DB_PORT = port
|
||||
|
||||
def setPwd(self, pwd):
|
||||
self.__DB_PASS = pwd
|
||||
|
||||
def getPwd(self):
|
||||
return self.__DB_PASS
|
||||
|
||||
def setDbName(self, name):
|
||||
self.__DB_NAME = name
|
||||
|
||||
def setUser(self, user):
|
||||
self.__DB_USER = user
|
||||
|
||||
def execute(self, sql):
|
||||
# 执行SQL语句返回受影响行
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
result = self.__DB_CUR.execute(sql)
|
||||
self.__DB_CONN.commit()
|
||||
self.__Close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
def query(self, sql):
|
||||
# 执行SQL语句返回数据集
|
||||
if not self.__Conn():
|
||||
return self.__DB_ERR
|
||||
try:
|
||||
self.__DB_CUR.execute(sql)
|
||||
result = self.__DB_CUR.fetchall()
|
||||
# 将元组转换成列表
|
||||
data = map(list, result)
|
||||
self.__Close()
|
||||
return data
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
# 关闭连接
|
||||
def __Close(self):
|
||||
self.__DB_CUR.close()
|
||||
self.__DB_CONN.close()
|
||||
Executable
+841
@@ -0,0 +1,841 @@
|
||||
# coding: utf-8
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import string
|
||||
|
||||
|
||||
def M(table):
|
||||
import db
|
||||
sql = db.Sql()
|
||||
return sql.table(table)
|
||||
|
||||
|
||||
def md5(str):
|
||||
# 生成MD5
|
||||
try:
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
m.update(str)
|
||||
return m.hexdigest()
|
||||
except:
|
||||
return False
|
||||
|
||||
# 文件的MD5值
|
||||
|
||||
|
||||
def GetFileMd5(filename):
|
||||
if not os.path.isfile(filename):
|
||||
return False
|
||||
import hashlib
|
||||
myhash = hashlib.md5()
|
||||
f = file(filename, 'rb')
|
||||
while True:
|
||||
b = f.read(8096)
|
||||
if not b:
|
||||
break
|
||||
myhash.update(b)
|
||||
f.close()
|
||||
return myhash.hexdigest()
|
||||
|
||||
# 取随机字符串
|
||||
|
||||
|
||||
def GetRandomString(length):
|
||||
from random import Random
|
||||
str = ''
|
||||
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
|
||||
chrlen = len(chars) - 1
|
||||
random = Random()
|
||||
for i in range(length):
|
||||
str += chars[random.randint(0, chrlen)]
|
||||
return str
|
||||
|
||||
|
||||
def checkCode(code, outime=120):
|
||||
# 校验验证码
|
||||
import time
|
||||
import web
|
||||
try:
|
||||
if md5(code.lower()) != web.ctx.session.codeStr:
|
||||
web.ctx.session.login_error = getMsg('CODE_ERR')
|
||||
return False
|
||||
if time.time() - web.ctx.session.codeTime > outime:
|
||||
web.ctx.session.login_error = getMsg('CODE_TIMEOUT')
|
||||
return False
|
||||
return True
|
||||
except:
|
||||
web.ctx.session.login_error = getMsg('CODE_NOT_EXISTS')
|
||||
return False
|
||||
|
||||
|
||||
def returnJson(status, msg, args=()):
|
||||
# 取通用Json返回
|
||||
return getJson(returnMsg(status, msg, args))
|
||||
|
||||
|
||||
def returnMsg(status, msg, args=()):
|
||||
import json
|
||||
# 取通用字曲返回
|
||||
logMessage = json.loads(
|
||||
readFile('static/language/' + get_language() + '/public.json'))
|
||||
keys = logMessage.keys()
|
||||
if msg in keys:
|
||||
msg = logMessage[msg]
|
||||
for i in range(len(args)):
|
||||
rep = '{' + str(i + 1) + '}'
|
||||
msg = msg.replace(rep, args[i])
|
||||
return {'status': status, 'msg': msg}
|
||||
|
||||
# 取提示消息
|
||||
|
||||
|
||||
def getMsg(key, args=()):
|
||||
try:
|
||||
import json
|
||||
logMessage = json.loads(
|
||||
readFile('static/language/' + get_language() + '/public.json'))
|
||||
keys = logMessage.keys()
|
||||
msg = None
|
||||
if key in keys:
|
||||
msg = logMessage[key]
|
||||
for i in range(len(args)):
|
||||
rep = '{' + str(i + 1) + '}'
|
||||
msg = msg.replace(rep, args[i])
|
||||
return msg
|
||||
except:
|
||||
return key
|
||||
|
||||
# 取提示消息
|
||||
|
||||
|
||||
def getLan(key):
|
||||
import json
|
||||
logMessage = json.loads(
|
||||
readFile('static/language/' + get_language() + '/template.json'))
|
||||
keys = logMessage.keys()
|
||||
msg = None
|
||||
if key in keys:
|
||||
msg = logMessage[key]
|
||||
return msg
|
||||
|
||||
|
||||
def getJson(data):
|
||||
import json
|
||||
import web
|
||||
web.header('Content-Type', 'application/json; charset=utf-8')
|
||||
return json.dumps(data)
|
||||
|
||||
|
||||
def readFile(filename):
|
||||
# 读文件内容
|
||||
try:
|
||||
fp = open(filename, 'r')
|
||||
fBody = fp.read()
|
||||
fp.close()
|
||||
return fBody
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def getDate():
|
||||
# 取格式时间
|
||||
import time
|
||||
return time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
|
||||
|
||||
def get_language():
|
||||
path = 'data/language.pl'
|
||||
if not os.path.exists(path):
|
||||
return 'Simplified_Chinese'
|
||||
return readFile(path).strip()
|
||||
|
||||
|
||||
def WriteLog(type, logMsg, args=()):
|
||||
# 写日志
|
||||
try:
|
||||
import time
|
||||
import db
|
||||
import json
|
||||
logMessage = json.loads(
|
||||
readFile('static/language/' + get_language() + '/log.json'))
|
||||
keys = logMessage.keys()
|
||||
if logMsg in keys:
|
||||
logMsg = logMessage[logMsg]
|
||||
for i in range(len(args)):
|
||||
rep = '{' + str(i + 1) + '}'
|
||||
logMsg = logMsg.replace(rep, args[i])
|
||||
if type in keys:
|
||||
type = logMessage[type]
|
||||
sql = db.Sql()
|
||||
mDate = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
data = (type, logMsg, mDate)
|
||||
result = sql.table('logs').add('type,log,addtime', data)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def writeFile(filename, str):
|
||||
# 写文件内容
|
||||
try:
|
||||
fp = open(filename, 'w+')
|
||||
fp.write(str)
|
||||
fp.close()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def httpGet(url, timeout=30):
|
||||
# 发送GET请求
|
||||
try:
|
||||
import urllib2
|
||||
import ssl
|
||||
try:
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
except:
|
||||
pass
|
||||
response = urllib2.urlopen(url, timeout=timeout)
|
||||
return response.read()
|
||||
except Exception, ex:
|
||||
#WriteLog('网络诊断',str(ex) + '['+url+']');
|
||||
return str(ex)
|
||||
|
||||
|
||||
def httpPost(url, data, timeout=30):
|
||||
# 发送POST请求
|
||||
try:
|
||||
import urllib
|
||||
import urllib2
|
||||
import ssl
|
||||
try:
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
except:
|
||||
pass
|
||||
data = urllib.urlencode(data)
|
||||
req = urllib2.Request(url, data)
|
||||
response = urllib2.urlopen(req, timeout=timeout)
|
||||
return response.read()
|
||||
except Exception, ex:
|
||||
#WriteLog('网络诊断',str(ex) + '['+url+']');
|
||||
return str(ex)
|
||||
|
||||
# 写进度
|
||||
|
||||
|
||||
def writeSpeed(title, used, total, speed=0):
|
||||
import json
|
||||
if not title:
|
||||
data = {'title': None, 'progress': 0,
|
||||
'total': 0, 'used': 0, 'speed': 0}
|
||||
else:
|
||||
progress = int((100.0 * used / total))
|
||||
data = {'title': title, 'progress': progress,
|
||||
'total': total, 'used': used, 'speed': speed}
|
||||
writeFile('/tmp/panelSpeed.pl', json.dumps(data))
|
||||
return True
|
||||
|
||||
# 取进度
|
||||
|
||||
|
||||
def getSpeed():
|
||||
import json
|
||||
data = readFile('/tmp/panelSpeed.pl')
|
||||
if not data:
|
||||
data = json.dumps({'title': None, 'progress': 0,
|
||||
'total': 0, 'used': 0, 'speed': 0})
|
||||
writeFile('/tmp/panelSpeed.pl', data)
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
import shlex
|
||||
import datetime
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
if shell:
|
||||
cmdstring_list = cmdstring
|
||||
else:
|
||||
cmdstring_list = shlex.split(cmdstring)
|
||||
if timeout:
|
||||
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
|
||||
|
||||
sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,
|
||||
shell=shell, bufsize=4096, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
while sub.poll() is None:
|
||||
time.sleep(0.1)
|
||||
if timeout:
|
||||
if end_time <= datetime.datetime.now():
|
||||
raise Exception("Timeout:%s" % cmdstring)
|
||||
|
||||
return sub.communicate()
|
||||
|
||||
|
||||
def serviceReload():
|
||||
# 重载Web服务配置
|
||||
if os.path.exists('/www/server/nginx/sbin/nginx'):
|
||||
result = ExecShell('/etc/init.d/nginx reload')
|
||||
if result[1].find('nginx.pid') != -1:
|
||||
ExecShell('pkill -9 nginx && sleep 1')
|
||||
ExecShell('/etc/init.d/nginx start')
|
||||
else:
|
||||
result = ExecShell('/etc/init.d/httpd reload')
|
||||
return result
|
||||
|
||||
|
||||
def phpReload(version):
|
||||
# 重载PHP配置
|
||||
import os
|
||||
if os.path.exists('/www/server/php/' + version + '/libphp5.so'):
|
||||
ExecShell('/etc/init.d/httpd reload')
|
||||
else:
|
||||
ExecShell('/etc/init.d/php-fpm-' + version + ' reload')
|
||||
|
||||
|
||||
def downloadFile(url, filename):
|
||||
import urllib
|
||||
urllib.urlretrieve(url, filename=filename, reporthook=downloadHook)
|
||||
|
||||
|
||||
def downloadHook(count, blockSize, totalSize):
|
||||
speed = {'total': totalSize, 'block': blockSize, 'count': count}
|
||||
print speed
|
||||
print '%02d%%' % (100.0 * count * blockSize / totalSize)
|
||||
|
||||
|
||||
def GetLocalIp():
|
||||
# 取本地外网IP
|
||||
try:
|
||||
import re
|
||||
filename = 'data/iplist.txt'
|
||||
ipaddress = readFile(filename)
|
||||
if not ipaddress:
|
||||
import urllib2
|
||||
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
|
||||
opener = urllib2.urlopen(url)
|
||||
str = opener.read()
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', str).group(0)
|
||||
writeFile(filename, ipaddress)
|
||||
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+', ipaddress).group(0)
|
||||
return ipaddress
|
||||
except:
|
||||
try:
|
||||
url = web.ctx.session.home + '/Api/getIpAddress'
|
||||
opener = urllib2.urlopen(url)
|
||||
return opener.read()
|
||||
except:
|
||||
import web
|
||||
return web.ctx.host.split(':')[0]
|
||||
|
||||
# 搜索数据中是否存在
|
||||
|
||||
|
||||
def inArray(arrays, searchStr):
|
||||
for key in arrays:
|
||||
if key == searchStr:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# 检查Web服务器配置文件是否有错误
|
||||
|
||||
|
||||
def checkWebConfig():
|
||||
import web
|
||||
if get_webserver() == 'nginx':
|
||||
result = ExecShell(
|
||||
"ulimit -n 10240 && /www/server/nginx/sbin/nginx -t -c /www/server/nginx/conf/nginx.conf")
|
||||
searchStr = 'successful'
|
||||
else:
|
||||
result = ExecShell(
|
||||
"ulimit -n 10240 && /www/server/apache/bin/apachectl -t")
|
||||
searchStr = 'Syntax OK'
|
||||
|
||||
if result[1].find(searchStr) == -1:
|
||||
WriteLog("TYPE_SOFT", 'CONF_CHECK_ERR', (result[1],))
|
||||
return result[1]
|
||||
return True
|
||||
|
||||
# 检查是否为IPv4地址
|
||||
|
||||
|
||||
def checkIp(ip):
|
||||
import re
|
||||
p = re.compile(
|
||||
'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')
|
||||
if p.match(ip):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# 检查端口是否合法
|
||||
|
||||
|
||||
def checkPort(port):
|
||||
ports = ['21', '25', '443', '8080', '888', '8888', '8443']
|
||||
if port in ports:
|
||||
return False
|
||||
intport = int(port)
|
||||
if intport < 1 or intport > 65535:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 字符串取中间
|
||||
|
||||
|
||||
def getStrBetween(startStr, endStr, srcStr):
|
||||
start = srcStr.find(startStr)
|
||||
if start == -1:
|
||||
return None
|
||||
end = srcStr.find(endStr)
|
||||
if end == -1:
|
||||
return None
|
||||
return srcStr[start + 1:end]
|
||||
|
||||
# 取CPU类型
|
||||
|
||||
|
||||
def getCpuType():
|
||||
import re
|
||||
cpuinfo = open('/proc/cpuinfo', 'r').read()
|
||||
rep = "model\s+name\s+:\s+(.+)"
|
||||
tmp = re.search(rep, cpuinfo)
|
||||
cpuType = None
|
||||
if tmp:
|
||||
cpuType = tmp.groups()[0]
|
||||
return cpuType
|
||||
|
||||
|
||||
# 检查是否允许重启
|
||||
def IsRestart():
|
||||
num = M('tasks').where('status!=?', ('1',)).count()
|
||||
if num > 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 加密密码字符
|
||||
|
||||
|
||||
def hasPwd(password):
|
||||
import crypt
|
||||
return crypt.crypt(password, password)
|
||||
|
||||
|
||||
# 处理MySQL配置文件
|
||||
def CheckMyCnf():
|
||||
import os
|
||||
confFile = '/etc/my.cnf'
|
||||
if os.path.exists(confFile):
|
||||
conf = readFile(confFile)
|
||||
if len(conf) > 100:
|
||||
return True
|
||||
versionFile = '/www/server/mysql/version.pl'
|
||||
if not os.path.exists(versionFile):
|
||||
return False
|
||||
|
||||
versions = ['5.1', '5.5', '5.6', '5.7', 'AliSQL']
|
||||
version = readFile(versionFile)
|
||||
for key in versions:
|
||||
if key in version:
|
||||
version = key
|
||||
break
|
||||
|
||||
shellStr = '''
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
CN='125.88.182.172'
|
||||
HK='download.bt.cn'
|
||||
HK2='103.224.251.67'
|
||||
US='174.139.221.74'
|
||||
sleep 0.5;
|
||||
CN_PING=`ping -c 1 -w 1 $CN|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
HK_PING=`ping -c 1 -w 1 $HK|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
HK2_PING=`ping -c 1 -w 1 $HK2|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
US_PING=`ping -c 1 -w 1 $US|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
|
||||
echo "$HK_PING $HK" > ping.pl
|
||||
echo "$HK2_PING $HK2" >> ping.pl
|
||||
echo "$US_PING $US" >> ping.pl
|
||||
echo "$CN_PING $CN" >> ping.pl
|
||||
nodeAddr=`sort -V ping.pl|sed -n '1p'|awk '{print $2}'`
|
||||
if [ "$nodeAddr" == "" ];then
|
||||
nodeAddr=$HK
|
||||
fi
|
||||
|
||||
Download_Url=http://$nodeAddr:5880
|
||||
|
||||
|
||||
MySQL_Opt()
|
||||
{
|
||||
MemTotal=`free -m | grep Mem | awk '{print $2}'`
|
||||
if [[ ${MemTotal} -gt 1024 && ${MemTotal} -lt 2048 ]]; then
|
||||
sed -i "s#^key_buffer_size.*#key_buffer_size = 32M#" /etc/my.cnf
|
||||
sed -i "s#^table_open_cache.*#table_open_cache = 128#" /etc/my.cnf
|
||||
sed -i "s#^sort_buffer_size.*#sort_buffer_size = 768K#" /etc/my.cnf
|
||||
sed -i "s#^read_buffer_size.*#read_buffer_size = 768K#" /etc/my.cnf
|
||||
sed -i "s#^myisam_sort_buffer_size.*#myisam_sort_buffer_size = 8M#" /etc/my.cnf
|
||||
sed -i "s#^thread_cache_size.*#thread_cache_size = 16#" /etc/my.cnf
|
||||
sed -i "s#^query_cache_size.*#query_cache_size = 16M#" /etc/my.cnf
|
||||
sed -i "s#^tmp_table_size.*#tmp_table_size = 32M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_buffer_pool_size.*#innodb_buffer_pool_size = 128M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_log_file_size.*#innodb_log_file_size = 32M#" /etc/my.cnf
|
||||
elif [[ ${MemTotal} -ge 2048 && ${MemTotal} -lt 4096 ]]; then
|
||||
sed -i "s#^key_buffer_size.*#key_buffer_size = 64M#" /etc/my.cnf
|
||||
sed -i "s#^table_open_cache.*#table_open_cache = 256#" /etc/my.cnf
|
||||
sed -i "s#^sort_buffer_size.*#sort_buffer_size = 1M#" /etc/my.cnf
|
||||
sed -i "s#^read_buffer_size.*#read_buffer_size = 1M#" /etc/my.cnf
|
||||
sed -i "s#^myisam_sort_buffer_size.*#myisam_sort_buffer_size = 16M#" /etc/my.cnf
|
||||
sed -i "s#^thread_cache_size.*#thread_cache_size = 32#" /etc/my.cnf
|
||||
sed -i "s#^query_cache_size.*#query_cache_size = 32M#" /etc/my.cnf
|
||||
sed -i "s#^tmp_table_size.*#tmp_table_size = 64M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_buffer_pool_size.*#innodb_buffer_pool_size = 256M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_log_file_size.*#innodb_log_file_size = 64M#" /etc/my.cnf
|
||||
elif [[ ${MemTotal} -ge 4096 && ${MemTotal} -lt 8192 ]]; then
|
||||
sed -i "s#^key_buffer_size.*#key_buffer_size = 128M#" /etc/my.cnf
|
||||
sed -i "s#^table_open_cache.*#table_open_cache = 512#" /etc/my.cnf
|
||||
sed -i "s#^sort_buffer_size.*#sort_buffer_size = 2M#" /etc/my.cnf
|
||||
sed -i "s#^read_buffer_size.*#read_buffer_size = 2M#" /etc/my.cnf
|
||||
sed -i "s#^myisam_sort_buffer_size.*#myisam_sort_buffer_size = 32M#" /etc/my.cnf
|
||||
sed -i "s#^thread_cache_size.*#thread_cache_size = 64#" /etc/my.cnf
|
||||
sed -i "s#^query_cache_size.*#query_cache_size = 64M#" /etc/my.cnf
|
||||
sed -i "s#^tmp_table_size.*#tmp_table_size = 64M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_buffer_pool_size.*#innodb_buffer_pool_size = 512M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_log_file_size.*#innodb_log_file_size = 128M#" /etc/my.cnf
|
||||
elif [[ ${MemTotal} -ge 8192 && ${MemTotal} -lt 16384 ]]; then
|
||||
sed -i "s#^key_buffer_size.*#key_buffer_size = 256M#" /etc/my.cnf
|
||||
sed -i "s#^table_open_cache.*#table_open_cache = 1024#" /etc/my.cnf
|
||||
sed -i "s#^sort_buffer_size.*#sort_buffer_size = 4M#" /etc/my.cnf
|
||||
sed -i "s#^read_buffer_size.*#read_buffer_size = 4M#" /etc/my.cnf
|
||||
sed -i "s#^myisam_sort_buffer_size.*#myisam_sort_buffer_size = 64M#" /etc/my.cnf
|
||||
sed -i "s#^thread_cache_size.*#thread_cache_size = 128#" /etc/my.cnf
|
||||
sed -i "s#^query_cache_size.*#query_cache_size = 128M#" /etc/my.cnf
|
||||
sed -i "s#^tmp_table_size.*#tmp_table_size = 128M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_buffer_pool_size.*#innodb_buffer_pool_size = 1024M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_log_file_size.*#innodb_log_file_size = 256M#" /etc/my.cnf
|
||||
elif [[ ${MemTotal} -ge 16384 && ${MemTotal} -lt 32768 ]]; then
|
||||
sed -i "s#^key_buffer_size.*#key_buffer_size = 512M#" /etc/my.cnf
|
||||
sed -i "s#^table_open_cache.*#table_open_cache = 2048#" /etc/my.cnf
|
||||
sed -i "s#^sort_buffer_size.*#sort_buffer_size = 8M#" /etc/my.cnf
|
||||
sed -i "s#^read_buffer_size.*#read_buffer_size = 8M#" /etc/my.cnf
|
||||
sed -i "s#^myisam_sort_buffer_size.*#myisam_sort_buffer_size = 128M#" /etc/my.cnf
|
||||
sed -i "s#^thread_cache_size.*#thread_cache_size = 256#" /etc/my.cnf
|
||||
sed -i "s#^query_cache_size.*#query_cache_size = 256M#" /etc/my.cnf
|
||||
sed -i "s#^tmp_table_size.*#tmp_table_size = 256M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_buffer_pool_size.*#innodb_buffer_pool_size = 2048M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_log_file_size.*#innodb_log_file_size = 512M#" /etc/my.cnf
|
||||
elif [[ ${MemTotal} -ge 32768 ]]; then
|
||||
sed -i "s#^key_buffer_size.*#key_buffer_size = 1024M#" /etc/my.cnf
|
||||
sed -i "s#^table_open_cache.*#table_open_cache = 4096#" /etc/my.cnf
|
||||
sed -i "s#^sort_buffer_size.*#sort_buffer_size = 16M#" /etc/my.cnf
|
||||
sed -i "s#^read_buffer_size.*#read_buffer_size = 16M#" /etc/my.cnf
|
||||
sed -i "s#^myisam_sort_buffer_size.*#myisam_sort_buffer_size = 256M#" /etc/my.cnf
|
||||
sed -i "s#^thread_cache_size.*#thread_cache_size = 512#" /etc/my.cnf
|
||||
sed -i "s#^query_cache_size.*#query_cache_size = 512M#" /etc/my.cnf
|
||||
sed -i "s#^tmp_table_size.*#tmp_table_size = 512M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_buffer_pool_size.*#innodb_buffer_pool_size = 4096M#" /etc/my.cnf
|
||||
sed -i "s#^innodb_log_file_size.*#innodb_log_file_size = 1024M#" /etc/my.cnf
|
||||
fi
|
||||
}
|
||||
|
||||
wget -O /etc/my.cnf $Download_Url/install/conf/mysql-%s.conf -T 5
|
||||
MySQL_Opt
|
||||
''' % (version,)
|
||||
# 判断是否迁移目录
|
||||
if os.path.exists('data/datadir.pl'):
|
||||
newPath = public.readFile('data/datadir.pl')
|
||||
mycnf = public.readFile('/etc/my.cnf')
|
||||
mycnf = mycnf.replace('/www/server/data', newPath)
|
||||
public.writeFile('/etc/my.cnf', mycnf)
|
||||
|
||||
os.system(shellStr)
|
||||
WriteLog('TYPE_SOFE', 'MYSQL_CHECK_ERR')
|
||||
return True
|
||||
|
||||
|
||||
def get_url(timeout=0.5):
|
||||
import json
|
||||
try:
|
||||
nodeFile = '/www/server/panel/data/node.json'
|
||||
node_list = json.loads(readFile(nodeFile))
|
||||
mnode = None
|
||||
for node in node_list:
|
||||
node['ping'] = get_timeout(
|
||||
node['protocol'] + node['address'] + ':' + node['port'] + '/check.txt')
|
||||
if not node['ping']:
|
||||
continue
|
||||
if not mnode:
|
||||
mnode = node
|
||||
if node['ping'] < mnode['ping']:
|
||||
mnode = node
|
||||
return mnode['protocol'] + mnode['address'] + ':' + mnode['port']
|
||||
except:
|
||||
return 'http://download.bt.cn'
|
||||
|
||||
|
||||
def get_timeout(url):
|
||||
start = time.time()
|
||||
result = httpGet(url)
|
||||
if result != 'True':
|
||||
return False
|
||||
return int((time.time() - start) * 1000)
|
||||
|
||||
|
||||
# 获取Token
|
||||
def GetToken():
|
||||
try:
|
||||
from json import loads
|
||||
tokenFile = 'data/token.json'
|
||||
if not os.path.exists(tokenFile):
|
||||
return False
|
||||
token = loads(public.readFile(tokenFile))
|
||||
return token
|
||||
except:
|
||||
return False
|
||||
|
||||
# 解密数据
|
||||
|
||||
|
||||
def auth_decode(data):
|
||||
token = GetToken()
|
||||
# 是否有生成Token
|
||||
if not token:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 校验access_key是否正确
|
||||
if token['access_key'] != data['btauth_key']:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 解码数据
|
||||
import binascii
|
||||
import hashlib
|
||||
import urllib
|
||||
import hmac
|
||||
import json
|
||||
tdata = binascii.unhexlify(data['data'])
|
||||
|
||||
# 校验signature是否正确
|
||||
signature = binascii.hexlify(
|
||||
hmac.new(token['secret_key'], tdata, digestmod=hashlib.sha256).digest())
|
||||
if signature != data['signature']:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 返回
|
||||
return json.loads(urllib.unquote(tdata))
|
||||
|
||||
|
||||
# 数据加密
|
||||
def auth_encode(data):
|
||||
token = GetToken()
|
||||
pdata = {}
|
||||
|
||||
# 是否有生成Token
|
||||
if not token:
|
||||
return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
# 生成signature
|
||||
import binascii
|
||||
import hashlib
|
||||
import urllib
|
||||
import hmac
|
||||
import json
|
||||
tdata = urllib.quote(json.dumps(data))
|
||||
# 公式 hex(hmac_sha256(data))
|
||||
pdata['signature'] = binascii.hexlify(
|
||||
hmac.new(token['secret_key'], tdata, digestmod=hashlib.sha256).digest())
|
||||
|
||||
# 加密数据
|
||||
pdata['btauth_key'] = token['access_key']
|
||||
pdata['data'] = binascii.hexlify(tdata)
|
||||
pdata['timestamp'] = time.time()
|
||||
|
||||
# 返回
|
||||
return pdata
|
||||
|
||||
# 检查Token
|
||||
|
||||
|
||||
def checkToken(get):
|
||||
tempFile = 'data/tempToken.json'
|
||||
if not os.path.exists(tempFile):
|
||||
return False
|
||||
import json
|
||||
import time
|
||||
tempToken = json.loads(readFile(tempFile))
|
||||
if time.time() > tempToken['timeout']:
|
||||
return False
|
||||
if get.token != tempToken['token']:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 获取Web服务器
|
||||
|
||||
|
||||
def get_webserver():
|
||||
webserver = 'nginx'
|
||||
if not os.path.exists('/www/server/nginx/sbin/nginx'):
|
||||
webserver = 'apache'
|
||||
return webserver
|
||||
|
||||
# 过滤输入
|
||||
|
||||
|
||||
def checkInput(data):
|
||||
if not data:
|
||||
return data
|
||||
if type(data) != str:
|
||||
return data
|
||||
checkList = [
|
||||
{'d': '<', 'r': '<'},
|
||||
{'d': '>', 'r': '>'},
|
||||
{'d': '\'', 'r': '‘'},
|
||||
{'d': '"', 'r': '“'},
|
||||
{'d': '&', 'r': '&'},
|
||||
{'d': '#', 'r': '#'},
|
||||
{'d': '<', 'r': '<'}
|
||||
]
|
||||
for v in checkList:
|
||||
data = data.replace(v['d'], v['r'])
|
||||
return data
|
||||
|
||||
# 取文件指定尾行数
|
||||
|
||||
|
||||
def GetNumLines(path, num, p=1):
|
||||
try:
|
||||
import cgi
|
||||
if not os.path.exists(path):
|
||||
return ""
|
||||
start_line = (p - 1) * num
|
||||
count = start_line + num
|
||||
fp = open(path)
|
||||
buf = ""
|
||||
fp.seek(-1, 2)
|
||||
if fp.read(1) == "\n":
|
||||
fp.seek(-1, 2)
|
||||
data = []
|
||||
b = True
|
||||
n = 0
|
||||
for i in range(count):
|
||||
while True:
|
||||
newline_pos = string.rfind(buf, "\n")
|
||||
pos = fp.tell()
|
||||
if newline_pos != -1:
|
||||
if n >= start_line:
|
||||
line = buf[newline_pos + 1:]
|
||||
try:
|
||||
data.insert(0, cgi.escape(line))
|
||||
except:
|
||||
pass
|
||||
buf = buf[:newline_pos]
|
||||
n += 1
|
||||
break
|
||||
else:
|
||||
if pos == 0:
|
||||
b = False
|
||||
break
|
||||
to_read = min(4096, pos)
|
||||
fp.seek(-to_read, 1)
|
||||
buf = fp.read(to_read) + buf
|
||||
fp.seek(-to_read, 1)
|
||||
if pos - to_read == 0:
|
||||
buf = "\n" + buf
|
||||
if not b:
|
||||
break
|
||||
fp.close()
|
||||
except:
|
||||
data = []
|
||||
return "\n".join(data)
|
||||
|
||||
# 验证证书
|
||||
|
||||
|
||||
def CheckCert(certPath='ssl/certificate.pem'):
|
||||
openssl = '/usr/local/openssl/bin/openssl'
|
||||
if not os.path.exists(openssl):
|
||||
openssl = 'openssl'
|
||||
certPem = readFile(certPath)
|
||||
s = "\n-----BEGIN CERTIFICATE-----"
|
||||
tmp = certPem.strip().split(s)
|
||||
for tmp1 in tmp:
|
||||
if tmp1.find('-----BEGIN CERTIFICATE-----') == -1:
|
||||
tmp1 = s + tmp1
|
||||
writeFile(certPath, tmp1)
|
||||
result = ExecShell(openssl + " x509 -in " +
|
||||
certPath + " -noout -subject")
|
||||
if result[1].find('-bash:') != -1:
|
||||
return True
|
||||
if len(result[1]) > 2:
|
||||
return False
|
||||
if result[0].find('error:') != -1:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 获取面板地址
|
||||
|
||||
|
||||
def getPanelAddr():
|
||||
import web
|
||||
protocol = 'https://' if os.path.exists("data/ssl.pl") else 'http://'
|
||||
h = web.ctx.host.split(':')
|
||||
try:
|
||||
result = protocol + h[0] + ':' + h[1]
|
||||
except:
|
||||
result = protocol + h[0] + ':' + readFile('data/port.pl').strip()
|
||||
return result
|
||||
|
||||
|
||||
# 字节单位转换
|
||||
def to_size(size):
|
||||
d = ('b', 'KB', 'MB', 'GB', 'TB')
|
||||
s = d[0]
|
||||
for b in d:
|
||||
if size < 1024:
|
||||
return str(size) + ' ' + b
|
||||
size = size / 1024
|
||||
s = b
|
||||
return str(size) + ' ' + b
|
||||
|
||||
|
||||
def get_string(t):
|
||||
if t != -1:
|
||||
max = 126
|
||||
m_types = [{'m': 122, 'n': 97}, {'m': 90, 'n': 65}, {'m': 57, 'n': 48}, {
|
||||
'm': 47, 'n': 32}, {'m': 64, 'n': 58}, {'m': 96, 'n': 91}, {'m': 125, 'n': 123}]
|
||||
else:
|
||||
max = 256
|
||||
t = 0
|
||||
m_types = [{'m': 255, 'n': 0}]
|
||||
arr = []
|
||||
for i in range(max):
|
||||
if i < m_types[t]['n'] or i > m_types[t]['m']:
|
||||
continue
|
||||
arr.append(chr(i))
|
||||
return arr
|
||||
|
||||
|
||||
def get_string_find(t):
|
||||
if type(t) != list:
|
||||
t = [t]
|
||||
return_str = ''
|
||||
for s1 in t:
|
||||
return_str += get_string(int(s1[0]))[int(s1[1:])]
|
||||
return return_str
|
||||
|
||||
|
||||
def get_string_arr(t):
|
||||
s_arr = {}
|
||||
t_arr = []
|
||||
for s1 in t:
|
||||
for i in range(6):
|
||||
if not i in s_arr:
|
||||
s_arr[i] = get_string(i)
|
||||
for j in range(len(s_arr[i])):
|
||||
if s1 == s_arr[i][j]:
|
||||
t_arr.append(str(i) + str(j))
|
||||
return t_arr
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/usr/local/lib/python2.7/bin
|
||||
|
||||
|
||||
|
||||
find . -name .DS_Store | xargs rm -rf
|
||||
find . -type d -name "*.pyc" | xargs rm -rf
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
DIR=$(cd "$(dirname "$0")"; pwd)
|
||||
MDIR=$(dirname "$DIR")
|
||||
|
||||
|
||||
PATH=$PATH:$DIR/bin
|
||||
if [ -f bin/activate ];then
|
||||
source bin/activate
|
||||
fi
|
||||
|
||||
# export LC_ALL="en_US.UTF-8"
|
||||
|
||||
|
||||
mw_start_task()
|
||||
{
|
||||
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
|
||||
if [ "$isStart" == '' ];then
|
||||
echo -e "Starting mw-tasks... \c"
|
||||
cd $DIR && python3 task.py >> ${DIR}/logs/task.log 2>&1 &
|
||||
sleep 0.3
|
||||
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
|
||||
if [ "$isStart" == '' ];then
|
||||
echo -e "\033[31mfailed\033[0m"
|
||||
echo '------------------------------------------------------'
|
||||
tail -n 20 $DIR/logs/task.log
|
||||
echo '------------------------------------------------------'
|
||||
echo -e "\033[31mError: mw-tasks service startup failed.\033[0m"
|
||||
return;
|
||||
fi
|
||||
echo -e "\033[32mdone\033[0m"
|
||||
else
|
||||
echo "Starting mw-tasks... mw-tasks (pid $(echo $isStart)) already running"
|
||||
fi
|
||||
}
|
||||
|
||||
mw_start(){
|
||||
gunicorn -c setting.py app:app
|
||||
#安全启动
|
||||
mw_start_task
|
||||
}
|
||||
|
||||
|
||||
mw_start_debug(){
|
||||
python3 task.py >> $DIR/logs/task.log 2>&1 &
|
||||
gunicorn -b :7200 -k gevent -w 1 app:app
|
||||
}
|
||||
|
||||
mw_start_debug2(){
|
||||
python3 task.py >> $DIR/logs/task.log 2>&1 &
|
||||
gunicorn -b :7200 -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
|
||||
}
|
||||
|
||||
|
||||
mw_stop()
|
||||
{
|
||||
PLIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
|
||||
for i in $PLIST
|
||||
do
|
||||
kill -9 $i
|
||||
done
|
||||
|
||||
pids=`ps -ef|grep task.py | grep -v grep |awk '{print $2}'`
|
||||
arr=($pids)
|
||||
for p in ${arr[@]}
|
||||
do
|
||||
kill -9 $p
|
||||
done
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start') mw_start;;
|
||||
'stop') mw_stop;;
|
||||
'restart')
|
||||
mw_stop
|
||||
mw_start
|
||||
;;
|
||||
'debug')
|
||||
mw_stop
|
||||
mw_start_debug
|
||||
;;
|
||||
'debug2')
|
||||
mw_stop
|
||||
mw_start_debug2
|
||||
;;
|
||||
esac
|
||||
@@ -1,68 +0,0 @@
|
||||
### 常用命令说明
|
||||
|
||||
|
||||
- 面板相关命令
|
||||
|
||||
```
|
||||
/etc/init.d/mw default
|
||||
|
||||
service mw [start|stop|reload|restart|status]
|
||||
```
|
||||
|
||||
- OpenResty
|
||||
|
||||
```
|
||||
|
||||
sytemctl [start|stop|reload|restart|status] openresty
|
||||
|
||||
```
|
||||
|
||||
- MySQL
|
||||
|
||||
```
|
||||
|
||||
sytemctl [start|stop|reload|restart|status] mysql
|
||||
|
||||
```
|
||||
|
||||
- MariaDB
|
||||
|
||||
```
|
||||
|
||||
sytemctl [start|stop|reload|restart|status] mariadb
|
||||
|
||||
```
|
||||
|
||||
- PHP
|
||||
|
||||
```
|
||||
|
||||
sytemctl [start|stop|reload|restart|status] php[54-81]
|
||||
|
||||
sytemctl start php71
|
||||
```
|
||||
|
||||
- Redis
|
||||
|
||||
```
|
||||
|
||||
sytemctl [start|stop|reload|restart|status] redis
|
||||
|
||||
```
|
||||
|
||||
- Memcached
|
||||
|
||||
```
|
||||
|
||||
sytemctl [start|stop|reload|restart|status] memcached
|
||||
|
||||
```
|
||||
|
||||
|
||||
- sphinx
|
||||
|
||||
```
|
||||
|
||||
sytemctl [start|stop|reload|restart|status] sphinx
|
||||
|
||||
```
|
||||
@@ -1,68 +0,0 @@
|
||||
### 兼容性测试报告
|
||||
|
||||
快速测试命令
|
||||
|
||||
```
|
||||
cd /www/server/mdserver-web/scripts/quick && bash debug.sh
|
||||
cd /www/server/mdserver-web/plugins/php/versions && bash all_test.sh
|
||||
```
|
||||
|
||||
|
||||
| 系统名称 | 面板 | OpenResty |
|
||||
| ----------------- |---------------|---------------|
|
||||
| CentOS 7.9 |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |
|
||||
|
||||
|
||||
|
||||
| 系统名称 |PHP53 |PHP54 |PHP55 |PHP56 |PHP70 |PHP71 |PHP72 |PHP73 |PHP74 |PHP80 |PHP81 |
|
||||
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
|
||||
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
|
||||
|
||||
|
||||
| 系统名称 | MySQL55|MySQL56|MySQL57|MySQL80|
|
||||
| ----------------- |-------|--------|-------|-------|
|
||||
| CentOS 7.9 |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |✅ |✅ |
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
True
|
||||
@@ -1,121 +0,0 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `backup` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`type` INTEGER,
|
||||
`name` TEXT,
|
||||
`pid` INTEGER,
|
||||
`filename` TEXT,
|
||||
`size` INTEGER,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `binding` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`pid` INTEGER,
|
||||
`domain` TEXT,
|
||||
`path` TEXT,
|
||||
`port` INTEGER,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `crontab` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT,
|
||||
`type` TEXT,
|
||||
`where1` TEXT,
|
||||
`where_hour` INTEGER,
|
||||
`where_minute` INTEGER,
|
||||
`echo` TEXT,
|
||||
`addtime` TEXT,
|
||||
`status` INTEGER DEFAULT '1',
|
||||
`save` INTEGER DEFAULT '3',
|
||||
`backup_to` TEXT DEFAULT 'off',
|
||||
`sname` TEXT,
|
||||
`sbody` TEXT,
|
||||
'stype' TEXT,
|
||||
`urladdress` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `firewall` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`port` TEXT,
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
INSERT INTO `firewall` (`id`, `port`, `ps`, `addtime`) VALUES
|
||||
(1, '80', '网站默认端口', '0000-00-00 00:00:00'),
|
||||
(2, '7200', 'WEB面板', '0000-00-00 00:00:00'),
|
||||
(3, '22', 'SSH远程管理服务', '0000-00-00 00:00:00'),
|
||||
(4, '888', 'phpMyAdmin默认端口', '0000-00-00 00:00:00'),
|
||||
(5, '443', 'HTTPS', '0000-00-00 00:00:00');
|
||||
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `logs` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`type` TEXT,
|
||||
`log` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sites` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT,
|
||||
`path` TEXT,
|
||||
`status` TEXT,
|
||||
`index` TEXT,
|
||||
`type_id` INTEGER,
|
||||
`ps` TEXT,
|
||||
`edate` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `site_types` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `domain` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`pid` INTEGER,
|
||||
`name` TEXT,
|
||||
`port` INTEGER,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`username` TEXT,
|
||||
`password` TEXT,
|
||||
`login_ip` TEXT,
|
||||
`login_time` TEXT,
|
||||
`phone` TEXT,
|
||||
`email` TEXT
|
||||
);
|
||||
|
||||
INSERT INTO `users` (`id`, `username`, `password`, `login_ip`, `login_time`, `phone`, `email`) VALUES
|
||||
(1, 'admin', '21232f297a57a5a743894a0e4a801fc3', '192.168.0.10', '2022-02-02 00:00:00', 0, 'midoks@163.com');
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tasks` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` TEXT,
|
||||
`type` TEXT,
|
||||
`status` TEXT,
|
||||
`addtime` TEXT,
|
||||
`start` INTEGER,
|
||||
`end` INTEGER,
|
||||
`execstr` TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `panel` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`title` TEXT,
|
||||
`url` TEXT,
|
||||
`username` TEXT,
|
||||
`password` TEXT,
|
||||
`click` INTEGER,
|
||||
`addtime` INTEGER
|
||||
);
|
||||
@@ -1,37 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `network` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`up` INTEGER,
|
||||
`down` INTEGER,
|
||||
`total_up` INTEGER,
|
||||
`total_down` INTEGER,
|
||||
`down_packets` INTEGER,
|
||||
`up_packets` INTEGER,
|
||||
`addtime` INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `cpuio` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`pro` INTEGER,
|
||||
`mem` INTEGER,
|
||||
`addtime` INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `diskio` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`read_count` INTEGER,
|
||||
`write_count` INTEGER,
|
||||
`read_bytes` INTEGER,
|
||||
`write_bytes` INTEGER,
|
||||
`read_time` INTEGER,
|
||||
`write_time` INTEGER,
|
||||
`addtime` INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `load_average` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`pro` REAL,
|
||||
`one` REAL,
|
||||
`five` REAL,
|
||||
`fifteen` REAL,
|
||||
`addtime` INTEGER
|
||||
);
|
||||
@@ -1,57 +0,0 @@
|
||||
server
|
||||
{
|
||||
listen {$PORT};
|
||||
server_name {$SERVER_NAME};
|
||||
index index.php index.html index.htm default.php default.htm default.html;
|
||||
root {$ROOT_DIR};
|
||||
|
||||
#SSL-START
|
||||
#error_page 404/404.html;
|
||||
#SSL-END
|
||||
|
||||
#301-START
|
||||
|
||||
#PROXY-START
|
||||
|
||||
#ERROR-PAGE-START
|
||||
error_page 404 /404.html;
|
||||
error_page 502 /502.html;
|
||||
#ERROR-PAGE-END
|
||||
|
||||
#PHP-INFO-START
|
||||
include {$PHP_DIR}/conf/enable-php-{$PHPVER}.conf;
|
||||
#PHP-INFO-END
|
||||
|
||||
#REWRITE-START
|
||||
include {$OR_REWRITE}/{$SERVER_NAME}.conf;
|
||||
#REWRITE-END
|
||||
|
||||
|
||||
#禁止访问的文件或目录
|
||||
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
|
||||
{
|
||||
return 404;
|
||||
}
|
||||
|
||||
#一键申请SSL证书验证目录相关设置
|
||||
location ~ \.well-known{
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
|
||||
{
|
||||
expires 30d;
|
||||
error_log off;
|
||||
access_log /dev/null;
|
||||
}
|
||||
|
||||
location ~ .*\\.(js|css)?$
|
||||
{
|
||||
expires 12h;
|
||||
error_log off;
|
||||
access_log /dev/null;
|
||||
}
|
||||
|
||||
access_log {$LOGPATH}/{$SERVER_NAME}.log main;
|
||||
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
|
||||
#BINDING-{$DIRBIND}-START
|
||||
server
|
||||
{
|
||||
listen {$PORT};
|
||||
server_name {$DIRBIND};
|
||||
index index.php index.html index.htm default.php default.htm default.html;
|
||||
root {$ROOT_DIR};
|
||||
|
||||
#SSL-START
|
||||
#error_page 404/404.html;
|
||||
#SSL-END
|
||||
|
||||
#ERROR-PAGE-START
|
||||
error_page 404 /404.html;
|
||||
error_page 502 /502.html;
|
||||
#ERROR-PAGE-END
|
||||
|
||||
#PHP-INFO-START
|
||||
include enable-php-{$PHPVER}.conf;
|
||||
#PHP-INFO-END
|
||||
|
||||
#REWRITE-START
|
||||
include {$OR_REWRITE}/{$SERVER_MAIN}.conf;
|
||||
#REWRITE-END
|
||||
|
||||
#禁止访问的文件或目录
|
||||
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
|
||||
{
|
||||
return 404;
|
||||
}
|
||||
|
||||
#一键申请SSL证书验证目录相关设置
|
||||
location ~ \.well-known{
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
|
||||
{
|
||||
expires 30d;
|
||||
error_log off;
|
||||
access_log /dev/null;
|
||||
}
|
||||
|
||||
location ~ .*\\.(js|css)?$
|
||||
{
|
||||
expires 12h;
|
||||
error_log off;
|
||||
access_log /dev/null;
|
||||
}
|
||||
|
||||
access_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.log;
|
||||
error_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.error.log;
|
||||
}
|
||||
#BINDING-{$DIRBIND}-END
|
||||
@@ -10,28 +10,13 @@
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"数据软件",
|
||||
"title":"系统工具",
|
||||
"type":2,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"代码管理",
|
||||
"type":3,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"系统工具",
|
||||
"type":4,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"其他插件",
|
||||
"type":5,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"辅助插件",
|
||||
"type":6,
|
||||
"type":3,
|
||||
"ps":""
|
||||
}
|
||||
]
|
||||
@@ -1,62 +0,0 @@
|
||||
FROM debian:10.12-slim
|
||||
|
||||
STOPSIGNAL SIGRTMIN+3
|
||||
|
||||
RUN rm -f /lib/systemd/system/multi-user.target.wants/* \
|
||||
/etc/systemd/system/*.wants/* \
|
||||
/lib/systemd/system/local-fs.target.wants/* \
|
||||
/lib/systemd/system/sockets.target.wants/*udev* \
|
||||
/lib/systemd/system/sockets.target.wants/*initctl* \
|
||||
/lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \
|
||||
/lib/systemd/system/systemd-update-utmp*
|
||||
|
||||
RUN apt update -y && \
|
||||
apt install -y devscripts && \
|
||||
apt install -y wget zip unzip && \
|
||||
apt-get install -y locales && \
|
||||
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && \
|
||||
locale-gen en_US.UTF-8 && \
|
||||
export LC_ALL=en_US.UTF-8 && \
|
||||
export LANG=en_US.UTF-8 && \
|
||||
export LANGUAGE=en_US.UTF-8 && \
|
||||
localedef -i en_US -f UTF-8 en_US.UTF-8 && \
|
||||
mkdir -p /www/server && \
|
||||
mkdir -p /www/wwwroot && \
|
||||
mkdir -p /www/wwwlogs && \
|
||||
mkdir -p /www/backup/database && \
|
||||
mkdir -p /www/backup/site && \
|
||||
wget -O /tmp/dev.zip https://github.com/midoks/mdserver-web/archive/refs/heads/dev.zip && \
|
||||
cd /tmp && unzip /tmp/dev.zip && \
|
||||
mv -f /tmp/mdserver-web-dev /www/server/mdserver-web && \
|
||||
rm -rf /tmp/dev.zip && \
|
||||
rm -rf /tmp/mdserver-web-dev && \
|
||||
cd /www/server/mdserver-web && \
|
||||
bash scripts/install/debian.sh && \
|
||||
cd /www/server/mdserver-web/ && \
|
||||
/www/server/mdserver-web/bin/python tools.py username username && \
|
||||
cd /www/server/mdserver-web/ && \
|
||||
/www/server/mdserver-web/bin/python tools.py panel password
|
||||
|
||||
RUN cd /www/server/mdserver-web/plugins/php && \
|
||||
bash install.sh install 74 && \
|
||||
cd /www/server/mdserver-web/plugins/openresty && \
|
||||
bash install.sh install 1.21.4.1 && \
|
||||
cd /www/server/mdserver-web/plugins/mysql && \
|
||||
bash install.sh install 5.6 && \
|
||||
cd /www/server/mdserver-web/plugins/phpmyadmin && \
|
||||
bash install.sh install 4.4.15 && \
|
||||
systemctl enable openresty && \
|
||||
systemctl enable php74 && \
|
||||
systemctl enable mysql
|
||||
|
||||
RUN rm -rf /www/server/mysql/data
|
||||
|
||||
ADD ./start.sh /start.sh
|
||||
ADD start.service /usr/lib/systemd/system/start.service
|
||||
#RUN systemctl enable start
|
||||
|
||||
CMD [ "/lib/systemd/systemd", "log-level=info", "unit=sysinit.target" ]
|
||||
|
||||
EXPOSE 7200 80 443 888
|
||||
|
||||
VOLUME [ "/www" ]
|
||||
@@ -1,9 +0,0 @@
|
||||
[Unit]
|
||||
Description=Customize the script
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/start.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1 +0,0 @@
|
||||
#!/bin/bash
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
LANG=en_US.UTF-8
|
||||
is64bit=`getconf LONG_BIT`
|
||||
|
||||
startTime=`date +%s`
|
||||
|
||||
echo "hello"
|
||||
|
||||
endTime=`date +%s`
|
||||
((outTime=($endTime-$startTime)/60))
|
||||
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/www/server/mdserver-web/bin/python
|
||||
# description: mdserver-web cli tools
|
||||
# ln -s /www/server/mdserver-web/mw-cli /usr/bin/mw-cli
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def mw_start():
|
||||
"""
|
||||
Start mdserver-web
|
||||
"""
|
||||
os.system('systemctl start mw')
|
||||
print("服务已启动")
|
||||
|
||||
|
||||
def mw_stop():
|
||||
"""
|
||||
stop mdserver-web
|
||||
"""
|
||||
os.system('systemctl stop mw')
|
||||
print("服务已停止")
|
||||
|
||||
|
||||
def mw_restart():
|
||||
"""
|
||||
restart mdserver-web
|
||||
"""
|
||||
os.system('systemctl restart mw')
|
||||
print("服务已重启")
|
||||
|
||||
|
||||
def mw_reset_username():
|
||||
"""
|
||||
reset mdserver-web username
|
||||
"""
|
||||
from tools import set_panel_username
|
||||
user_name = input("请输入新的用户名: ")
|
||||
set_panel_username(user_name)
|
||||
|
||||
|
||||
def mw_reset_pwd():
|
||||
"""
|
||||
reset mdserver-web password
|
||||
"""
|
||||
from tools import set_panel_pwd
|
||||
pwd = input("请输入新的密码: ")
|
||||
set_panel_pwd(pwd, True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if os.geteuid() != 0:
|
||||
print("请使用root账户执行该命令.")
|
||||
sys.exit(1)
|
||||
|
||||
os.chdir("/www/server/mdserver-web")
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
|
||||
try:
|
||||
str = '''
|
||||
==== mdserver-web cli tools ====
|
||||
1. 启动服务 2. 停止服务
|
||||
3. 重启服务 4. 修改用户名
|
||||
5. 修改密码
|
||||
=================================
|
||||
'''
|
||||
if len(sys.argv) == 2:
|
||||
sw = sys.argv[1]
|
||||
else:
|
||||
print(str)
|
||||
sw = input("请输入您要进行的操作: ")
|
||||
|
||||
if sw == '1':
|
||||
mw_start()
|
||||
elif sw == '2':
|
||||
mw_stop()
|
||||
elif sw == '3':
|
||||
mw_restart()
|
||||
elif sw == '4':
|
||||
mw_reset_username()
|
||||
elif sw == '5':
|
||||
mw_reset_pwd()
|
||||
else:
|
||||
print("操作不存在")
|
||||
except KeyboardInterrupt:
|
||||
print("\n操作已终止")
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 254 B |
@@ -1,24 +0,0 @@
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('clean');">服务</p>
|
||||
<p onclick="pluginConfig('clean');">配置修改</p>
|
||||
<p onclick="pRead()">说明</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
pluginService('clean');
|
||||
|
||||
|
||||
function pRead(){
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>cd /www/server/mdserver-web && python3 /www/server/mdserver-web/plugins/clean/index.py clean</li>';
|
||||
readme += '</ul>';
|
||||
|
||||
$('.soft-man-con').html(readme);
|
||||
}
|
||||
</script>
|
||||
@@ -1,200 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'clean'
|
||||
|
||||
|
||||
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 getConf():
|
||||
path = getServerDir() + "/clean.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
t = t.split(':')
|
||||
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 status():
|
||||
if os.path.exists(getConf()):
|
||||
return "start"
|
||||
return 'stop'
|
||||
|
||||
|
||||
def start():
|
||||
file = initDreplace()
|
||||
data = mw.execShell(file + ' start')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return 'fail'
|
||||
|
||||
|
||||
def stop():
|
||||
file = initDreplace()
|
||||
data = mw.execShell(file + ' stop')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return 'fail'
|
||||
|
||||
|
||||
def reload():
|
||||
file = initDreplace()
|
||||
data = mw.execShell(file + ' reload')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return 'fail'
|
||||
|
||||
|
||||
def get_filePath_fileName_fileExt(filename):
|
||||
(filepath, tempfilename) = os.path.split(filename)
|
||||
(shotname, extension) = os.path.splitext(tempfilename)
|
||||
return filepath, shotname, extension
|
||||
|
||||
|
||||
def cleanFileLog(path):
|
||||
filepath, shotname, extension = get_filePath_fileName_fileExt(path)
|
||||
if extension == ".log":
|
||||
cmd = "echo \"\" > " + path
|
||||
print(cmd)
|
||||
print(mw.execShell(cmd))
|
||||
|
||||
|
||||
def cleanSelfFileLog(path):
|
||||
filepath, shotname, extension = get_filePath_fileName_fileExt(path)
|
||||
cmd = "echo \"\" > " + path
|
||||
print(cmd)
|
||||
print(mw.execShell(cmd))
|
||||
|
||||
|
||||
def cleanDirLog(path):
|
||||
l = os.listdir(path)
|
||||
for x in range(len(l)):
|
||||
abspath = path + "/" + l[x]
|
||||
if os.path.isfile(abspath):
|
||||
cleanFileLog(abspath)
|
||||
if os.path.isdir(abspath):
|
||||
cleanDirLog(abspath)
|
||||
|
||||
|
||||
def cleanLog():
|
||||
# 清理日志
|
||||
rootDir = "/var/log"
|
||||
print("clean start")
|
||||
|
||||
clog = [
|
||||
"rm -rf /var/log/cron-*",
|
||||
"rm -rf /var/log/maillog-*",
|
||||
"rm -rf /var/log/secure-*",
|
||||
"rm -rf /var/log/spooler-*",
|
||||
"rm -rf /var/log/yum.log-*",
|
||||
"rm -rf /var/log/messages-*",
|
||||
"rm -rf /var/log/btmp-*",
|
||||
"rm -rf /var/log/audit/audit.log.*",
|
||||
"rm -rf /var/log/rhsm/rhsm.log-*",
|
||||
"rm -rf /var/log/rhsm/rhsmcertd.log-*",
|
||||
"rm -rf /tmp/yum_save_*",
|
||||
"rm -rf /tmp/tmp.*",
|
||||
]
|
||||
|
||||
for i in clog:
|
||||
print(i)
|
||||
mw.execShell(i)
|
||||
|
||||
# 常用日志
|
||||
clogcom = [
|
||||
"/var/log/messages",
|
||||
"/var/log/btmp",
|
||||
"/var/log/wtmp",
|
||||
"/var/log/secure",
|
||||
"/var/log/lastlog",
|
||||
"/var/log/cron",
|
||||
]
|
||||
for i in clogcom:
|
||||
if os.path.exists(i):
|
||||
mw.execShell("echo \"\" > " + i)
|
||||
|
||||
l = os.listdir(rootDir)
|
||||
for x in range(len(l)):
|
||||
abspath = rootDir + "/" + l[x]
|
||||
if os.path.isfile(abspath):
|
||||
cleanFileLog(abspath)
|
||||
|
||||
if os.path.isdir(abspath):
|
||||
cleanDirLog(abspath)
|
||||
|
||||
print("conf clean")
|
||||
|
||||
confFile = getServerDir()
|
||||
# mw.readFile()
|
||||
confFile = confFile + "/clean.conf"
|
||||
clist = mw.readFile(confFile).strip()
|
||||
clist = clist.split("\n")
|
||||
|
||||
for x in clist:
|
||||
abspath = x.strip()
|
||||
if os.path.exists(abspath):
|
||||
if os.path.isfile(abspath):
|
||||
cleanSelfFileLog(abspath)
|
||||
|
||||
if os.path.isdir(abspath):
|
||||
cleanDirLog(abspath)
|
||||
print("conf clean end")
|
||||
|
||||
print("clean end")
|
||||
|
||||
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 == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'clean':
|
||||
cleanLog()
|
||||
else:
|
||||
print('error')
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"title":"日志清理",
|
||||
"tip":"soft",
|
||||
"name":"clean",
|
||||
"type":"运行环境",
|
||||
"ps":"日志清理",
|
||||
"versions":"1.0",
|
||||
"updates":"1.0",
|
||||
"shell":"install.sh",
|
||||
"checks":"server/clean",
|
||||
"path": "server/clean",
|
||||
"author":"clean",
|
||||
"home":"https://github.com/midoks",
|
||||
"date":"2021-11-23",
|
||||
"pid": "5"
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
|
||||
# cd /www/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
|
||||
Install_app()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/clean
|
||||
|
||||
echo "" > $serverPath/clean/clean.conf
|
||||
|
||||
echo "${VERSION}" > $serverPath/clean/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
{
|
||||
rm -rf $serverPath/clean
|
||||
echo "Uninstall_clean" > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_app
|
||||
else
|
||||
Uninstall_app
|
||||
fi
|
||||
Executable
+350
@@ -0,0 +1,350 @@
|
||||
#coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板 x3
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2017 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: 黄文良 <2879625666@qq.com>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
#+--------------------------------------------------------------------
|
||||
#| 自动部署网站
|
||||
#+--------------------------------------------------------------------
|
||||
|
||||
import public,json,os,time;
|
||||
class obj: id=0;
|
||||
class deployment_main:
|
||||
__setupPath = '/www/server/panel/plugin/deployment';
|
||||
__panelPath = '/www/server/panel';
|
||||
logPath = '/www/server/panel/plugin/deployment/speed.json'
|
||||
timeoutCount = 0;
|
||||
oldTime = 0;
|
||||
|
||||
#获取列表
|
||||
def GetList(self,get):
|
||||
self.GetCloudList(get);
|
||||
jsonFile = self.__setupPath + '/list.json';
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'配置文件不存在!');
|
||||
data = {}
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
|
||||
if not hasattr(get,'type'):
|
||||
get.type = 0;
|
||||
else:
|
||||
get.type = int(get.type)
|
||||
if not hasattr(get,'search'):
|
||||
search = None
|
||||
m = 0
|
||||
else:
|
||||
search = get.search.encode('utf-8').lower();
|
||||
m = 1
|
||||
|
||||
tmp = [];
|
||||
for d in data:
|
||||
i=0;
|
||||
if get.type > 0:
|
||||
if get.type == d['type']: i+=1
|
||||
else:
|
||||
i+=1
|
||||
if search:
|
||||
if d['name'].lower().find(search) != -1: i+=1;
|
||||
if d['title'].lower().find(search) != -1: i+=1;
|
||||
if get.type > 0 and get.type != d['type']: i -= 1;
|
||||
if i>m:tmp.append(d);
|
||||
|
||||
data = tmp;
|
||||
result = {}
|
||||
result['data'] = data;
|
||||
jsonFile = self.__setupPath + '/type.json';
|
||||
if not os.path.exists(jsonFile): self.GetCloudList(get);
|
||||
result['type'] = json.loads(public.readFile(jsonFile));
|
||||
return result;
|
||||
|
||||
#获取插件列表
|
||||
def GetDepList(self,get):
|
||||
jsonFile = self.__setupPath + '/list.json';
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'配置文件不存在!');
|
||||
data = {}
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
return data;
|
||||
|
||||
|
||||
#从云端获取列表
|
||||
def GetCloudList(self,get):
|
||||
try:
|
||||
import web
|
||||
if not hasattr(web.ctx.session,'package'):
|
||||
downloadUrl = public.get_url() + '/install/lib/plugin/deployment/package.json';
|
||||
tmp = json.loads(public.httpGet(downloadUrl));
|
||||
if not tmp: return public.returnMsg(False,'从云端获取失败!');
|
||||
jsonFile = self.__setupPath + '/list.json';
|
||||
public.writeFile(jsonFile,json.dumps(tmp));
|
||||
|
||||
downloadUrl = public.get_url() + '/install/lib/plugin/deployment/type.json';
|
||||
tmp = json.loads(public.httpGet(downloadUrl));
|
||||
if not tmp: return public.returnMsg(False,'从云端获取失败!');
|
||||
jsonFile = self.__setupPath + '/type.json';
|
||||
public.writeFile(jsonFile,json.dumps(tmp));
|
||||
|
||||
web.ctx.session.package = True
|
||||
return public.returnMsg(True,'更新成功!');
|
||||
return public.returnMsg(True,'无需更新!');
|
||||
except:
|
||||
return public.returnMsg(False,'从云端获取失败!');
|
||||
|
||||
|
||||
|
||||
#添加程序包
|
||||
def AddPackage(self,get):
|
||||
jsonFile = self.__setupPath + '/list.json';
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'配置文件不存在!');
|
||||
|
||||
data = {}
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
for d in data:
|
||||
if d['name'] == get.dname: return public.returnMsg(False,'您要添加的程序标识已存在!');
|
||||
if d['title'] == get.title: return public.returnMsg(False,'您要添加的程序名称已存在!');
|
||||
|
||||
if hasattr(get,'rewrite'): get.rewrite = True;
|
||||
|
||||
pinfo = {}
|
||||
pinfo['name'] = get.dname;
|
||||
pinfo['title'] = get.title;
|
||||
pinfo['version'] = get.version;
|
||||
pinfo['md5'] = get.md5;
|
||||
pinfo['rewrite'] = get.rewrite;
|
||||
pinfo['php'] = get.php;
|
||||
pinfo['ps'] = get.ps;
|
||||
pinfo['shell'] = get.shell;
|
||||
pinfo['download'] = get.download;
|
||||
data.append(pinfo);
|
||||
public.writeFile(jsonFile,json.dumps(data));
|
||||
return public.returnMsg(True,'添加成功!');
|
||||
|
||||
#删除程序包
|
||||
def DelPackage(self,get):
|
||||
jsonFile = self.__setupPath + '/list.json';
|
||||
if not os.path.exists(jsonFile): return public.returnMsg(False,'配置文件不存在!');
|
||||
|
||||
data = {}
|
||||
data = json.loads(public.readFile(jsonFile));
|
||||
|
||||
tmp = [];
|
||||
for d in data:
|
||||
if d['name'].find(get.dname) != -1: continue;
|
||||
tmp.append(d);
|
||||
|
||||
data = tmp;
|
||||
public.writeFile(jsonFile,json.dumps(data));
|
||||
return public.returnMsg(True,'删除成功!');
|
||||
|
||||
#下载文件
|
||||
def DownloadFile(self,url,filename):
|
||||
try:
|
||||
import urllib,socket
|
||||
socket.setdefaulttimeout(10)
|
||||
self.pre = 0;
|
||||
self.oldTime = time.time();
|
||||
urllib.urlretrieve(url,filename=filename,reporthook= self.DownloadHook)
|
||||
self.WriteLogs(json.dumps({'name':'下载文件','total':0,'used':0,'pre':0,'speed':0}));
|
||||
except:
|
||||
if self.timeoutCount > 5: return;
|
||||
self.timeoutCount += 1
|
||||
time.sleep(5)
|
||||
self.DownloadFile(url,filename)
|
||||
|
||||
#下载文件进度回调
|
||||
def DownloadHook(self,count, blockSize, totalSize):
|
||||
used = count * blockSize
|
||||
pre1 = int((100.0 * used / totalSize))
|
||||
if self.pre != pre1:
|
||||
dspeed = used / (time.time() - self.oldTime);
|
||||
speed = {'name':'下载文件','total':totalSize,'used':used,'pre':self.pre,'speed':dspeed}
|
||||
self.WriteLogs(json.dumps(speed))
|
||||
self.pre = pre1
|
||||
|
||||
#写输出日志
|
||||
def WriteLogs(self,logMsg):
|
||||
fp = open(self.logPath,'w+');
|
||||
fp.write(logMsg)
|
||||
fp.close()
|
||||
|
||||
#一键安装网站程序
|
||||
#param string name 程序名称
|
||||
#param string site_name 网站名称
|
||||
#param string php_version PHP版本
|
||||
def SetupPackage(self,get):
|
||||
name = get.dname
|
||||
site_name = get.site_name;
|
||||
php_version = get.php_version;
|
||||
#取基础信息
|
||||
find = public.M('sites').where('name=?',(site_name,)).field('id,path').find();
|
||||
path = find['path'];
|
||||
|
||||
#获取包信息
|
||||
pinfo = self.GetPackageInfo(name);
|
||||
if not pinfo: return public.returnMsg(False,'指定软件包不存在!');
|
||||
|
||||
#检查本地包
|
||||
self.WriteLogs(json.dumps({'name':'检查软件包','total':0,'used':0,'pre':0,'speed':0}));
|
||||
packageZip = self.__setupPath + '/package/' + name + '.zip';
|
||||
isDownload = False;
|
||||
if os.path.exists(packageZip):
|
||||
md5str = self.GetFileMd5(packageZip);
|
||||
if md5str != pinfo['md5']: isDownload = True;
|
||||
else:
|
||||
isDownload = True;
|
||||
|
||||
#下载文件
|
||||
|
||||
if isDownload:
|
||||
self.WriteLogs(json.dumps({'name':'下载文件','total':0,'used':0,'pre':0,'speed':0}));
|
||||
self.DownloadFile(pinfo['download'], packageZip);
|
||||
if not os.path.exists(packageZip): return public.returnMsg(False,'文件下载失败!');
|
||||
os.system('unzip -o '+packageZip+' -d ' + path + '/');
|
||||
|
||||
#设置权限
|
||||
self.WriteLogs(json.dumps({'name':'设置权限','total':0,'used':0,'pre':0,'speed':0}));
|
||||
os.system('chmod -R 755 ' + path);
|
||||
os.system('chown -R www.www ' + path);
|
||||
if pinfo['chmod'] != "":
|
||||
access = pinfo['chmod'].split(',')
|
||||
for chm in access:
|
||||
tmp = chm.split('|');
|
||||
if len(tmp) != 2: continue;
|
||||
os.system('chmod -R ' + tmp[0] + ' ' + path + '/' + tmp[1]);
|
||||
|
||||
#安装PHP扩展
|
||||
self.WriteLogs(json.dumps({'name':'安装必要的PHP扩展','total':0,'used':0,'pre':0,'speed':0}));
|
||||
if pinfo['ext'] != '':
|
||||
exts = pinfo['ext'].split(',');
|
||||
import files
|
||||
mfile = files.files();
|
||||
for ext in exts:
|
||||
if ext == 'pathinfo':
|
||||
import config
|
||||
con = config.config();
|
||||
get.version = php_version;
|
||||
get.type = 'on';
|
||||
con.setPathInfo(get);
|
||||
else:
|
||||
get.name = ext
|
||||
get.version = php_version
|
||||
get.type = '1';
|
||||
mfile.InstallSoft(get);
|
||||
|
||||
|
||||
#执行额外shell进行依赖安装
|
||||
self.WriteLogs(json.dumps({'name':'执行额外SHELL','total':0,'used':0,'pre':0,'speed':0}));
|
||||
if os.path.exists(path+'/install.sh'):
|
||||
os.system('cd '+path+' && bash ' + 'install.sh');
|
||||
os.system('rm -f ' + path+'/install.sh')
|
||||
|
||||
#是否执行Composer
|
||||
if os.path.exists(path + '/composer.json'):
|
||||
self.WriteLogs(json.dumps({'name':'执行Composer','total':0,'used':0,'pre':0,'speed':0}));
|
||||
if not os.path.exists(path + '/composer.lock'):
|
||||
execPHP = '/www/server/php/' + php_version +'/bin/php';
|
||||
if execPHP:
|
||||
if public.get_url().find('125.88'):
|
||||
os.system('cd ' +path+' && '+execPHP+' /usr/bin/composer config repo.packagist composer https://packagist.phpcomposer.com');
|
||||
import panelSite;
|
||||
phpini = '/www/server/php/' + php_version + '/etc/php.ini'
|
||||
phpiniConf = public.readFile(phpini);
|
||||
phpiniConf = phpiniConf.replace('proc_open,proc_get_status,','');
|
||||
public.writeFile(phpini,phpiniConf);
|
||||
os.system('nohup cd '+path+' && '+execPHP+' /usr/bin/composer install -vvv > /tmp/composer.log 2>&1 &');
|
||||
|
||||
#写伪静态
|
||||
self.WriteLogs(json.dumps({'name':'设置伪静态','total':0,'used':0,'pre':0,'speed':0}));
|
||||
swfile = path + '/nginx.rewrite';
|
||||
if os.path.exists(swfile):
|
||||
rewriteConf = public.readFile(swfile);
|
||||
dwfile = self.__panelPath + '/vhost/rewrite/' + site_name + '.conf';
|
||||
public.writeFile(dwfile,rewriteConf);
|
||||
|
||||
#设置运行目录
|
||||
self.WriteLogs(json.dumps({'name':'设置运行目录','total':0,'used':0,'pre':0,'speed':0}));
|
||||
if pinfo['run'] != '/':
|
||||
import panelSite;
|
||||
siteObj = panelSite.panelSite();
|
||||
mobj = obj();
|
||||
mobj.id = find['id'];
|
||||
mobj.runPath = pinfo['run'];
|
||||
siteObj.SetSiteRunPath(mobj);
|
||||
|
||||
#导入数据
|
||||
self.WriteLogs(json.dumps({'name':'导入数据库','total':0,'used':0,'pre':0,'speed':0}));
|
||||
if os.path.exists(path+'/import.sql'):
|
||||
databaseInfo = public.M('databases').where('pid=?',(find['id'],)).field('username,password').find();
|
||||
if databaseInfo:
|
||||
os.system('/www/server/mysql/bin/mysql -u' + databaseInfo['username'] + ' -p' + databaseInfo['password'] + ' ' + databaseInfo['username'] + ' < ' + path + '/import.sql');
|
||||
os.system('rm -f ' + path + '/import.sql');
|
||||
siteConfigFile = path + '/' + pinfo['config'];
|
||||
if os.path.exists(siteConfigFile):
|
||||
siteConfig = public.readFile(siteConfigFile)
|
||||
siteConfig = siteConfig.replace('BT_DB_USERNAME',databaseInfo['username'])
|
||||
siteConfig = siteConfig.replace('BT_DB_PASSWORD',databaseInfo['password'])
|
||||
siteConfig = siteConfig.replace('BT_DB_NAME',databaseInfo['username'])
|
||||
public.writeFile(siteConfigFile,siteConfig)
|
||||
|
||||
public.serviceReload();
|
||||
self.depTotal(name);
|
||||
self.WriteLogs(json.dumps({'name':'准备部署','total':0,'used':0,'pre':0,'speed':0}));
|
||||
return public.returnMsg(True,pinfo);
|
||||
|
||||
#提交安装统计
|
||||
def depTotal(self,name):
|
||||
try:
|
||||
import urllib2
|
||||
urllib2.urlopen("https://www.bt.cn/Api/depTotal?name=" + name, timeout = 3)
|
||||
return True
|
||||
except:
|
||||
return False;
|
||||
|
||||
#获取进度
|
||||
def GetSpeed(self,get):
|
||||
try:
|
||||
if not os.path.exists(self.logPath): public.returnMsg(False,'当前没有部署任务!');
|
||||
return json.loads(public.readFile(self.logPath));
|
||||
except:
|
||||
return {'name':'准备部署','total':0,'used':0,'pre':0,'speed':0}
|
||||
|
||||
#获取包信息
|
||||
def GetPackageInfo(self,name):
|
||||
data = self.GetDepList(None);
|
||||
if not data: return False;
|
||||
downUrl = public.get_url() + '/install/package';
|
||||
for info in data:
|
||||
if info['name'] == name:
|
||||
info['download'] = info['download'].replace('{Download}',downUrl);
|
||||
return info;
|
||||
return False;
|
||||
|
||||
#检查指定包是否存在
|
||||
def CheckPackageExists(self,name):
|
||||
data = self.GetDepList(None);
|
||||
if not data: return False;
|
||||
for info in data:
|
||||
if info['name'] == name: return True;
|
||||
|
||||
return False;
|
||||
|
||||
#文件的MD5值
|
||||
def GetFileMd5(self,filename):
|
||||
if not os.path.isfile(filename): return False;
|
||||
import hashlib;
|
||||
myhash = hashlib.md5()
|
||||
f = file(filename,'rb')
|
||||
while True:
|
||||
b = f.read(8096)
|
||||
if not b :
|
||||
break
|
||||
myhash.update(b)
|
||||
f.close()
|
||||
return myhash.hexdigest();
|
||||
|
||||
#获取站点标识
|
||||
def GetSiteId(self,get):
|
||||
return public.M('sites').where('name=?',(get.webname,)).getField('id');
|
||||
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 553 B |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 553 B |
Executable
+415
@@ -0,0 +1,415 @@
|
||||
<style>
|
||||
.disable {
|
||||
background-color: #ededed;
|
||||
}
|
||||
.onekeyCode .table > tbody > tr > td{
|
||||
line-height:1.7;
|
||||
}
|
||||
.oneKeysearchBar{
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right:15px;
|
||||
z-index: 20;
|
||||
}
|
||||
.success-msg .suc-con {
|
||||
float: right;
|
||||
width: 280px;
|
||||
}
|
||||
.bt-progress {
|
||||
background-color: #e2e2e2;
|
||||
border-radius: 8px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
position: relative;
|
||||
margin:5px 0;
|
||||
}
|
||||
.bt-progress-bar {
|
||||
background-color: #5ab76c;
|
||||
border-radius: 8px;
|
||||
height: 16px;
|
||||
max-width: 100%;
|
||||
position: absolute;
|
||||
text-align: right;
|
||||
transition: all 0.3s ease 0s;
|
||||
width: 0;
|
||||
}
|
||||
.bt-progress-text {
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
padding: 0 10px;
|
||||
position: static;
|
||||
}
|
||||
.onekey-menu-sub{
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
.onekey-menu-sub span{
|
||||
height: 50px;
|
||||
padding: 0 15px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
}
|
||||
.onekey-menu-sub .on {
|
||||
border-bottom: 2px solid #20a53a;
|
||||
color: #20a53a;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<div class="oneKeysearchBar">
|
||||
<input class="searchInput bt-input-text" type="text" placeholder="请输入检索条件" value="" style="width:140px" />
|
||||
<button class="btn btn-default btn-sm va0" onclick="GetSrcList();">查找</button>
|
||||
</div>
|
||||
<div class="onekey-menu-sub mlr15 onekey-type"></div>
|
||||
<div class="divtable pd15 onekeyCode" style="max-height:500px; overflow:auto">
|
||||
<table class="table table-hover" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>版本</th>
|
||||
<th>简介</th>
|
||||
<th>支持PHP版本</th>
|
||||
<th style="text-align: right;" width="80">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="zipBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script type="javascript/text">
|
||||
$('.layui-layer-page').css({'width':'760px'});
|
||||
var openId = add = null;
|
||||
function AddDeployment(maction){
|
||||
if(maction == 1){
|
||||
var pdata = 'title=' + $("input[name='title']").val()
|
||||
+'&dname=' + $("input[name='name']").val()
|
||||
+'&ps=' + $("input[name='ps']").val()
|
||||
+'&version=' + $("input[name='version']").val()
|
||||
+'&rewrite=' + ($("input[name='rewrite']").attr('checked')?1:0)
|
||||
+'&shell=' + ($("input[name='shell']").attr('checked')?1:0)
|
||||
+'&php=' + $("input[name='php']").val()
|
||||
+'&md5=' + $("input[name='md5']").val()
|
||||
+'&download=' + $("input[name='download']").val()
|
||||
var loadT = layer.msg('正在提交 <img src="/static/img/ing.gif">',{icon:16,time:0,shade: [0.3, '#000']});
|
||||
$.post('/plugin?action=a&name=deployment&s=AddPackage',pdata,function(rdata){
|
||||
layer.close(loadT);
|
||||
layer.msg(rdata.msg,{icon:rdata.status?1:5});
|
||||
if(rdata.status) {
|
||||
GetSrcList();
|
||||
layer.close(openId);
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
openId = layer.open({
|
||||
type: 1,
|
||||
skin: 'demo-class',
|
||||
area: '480px',
|
||||
title: '添加源码包',
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
content:'标题:<input type="text" name="title"><br>\
|
||||
标识:<input type="text" name="name"><br>\
|
||||
描述:<input type="text" name="ps"><br>\
|
||||
版本:<input type="text" name="version"><br>\
|
||||
是否写伪静态:<input type="checkbox" name="rewrite"><br>\
|
||||
是否执行安装脚本:<input type="checkbox" name="shell"><br>\
|
||||
支持的PHP版本:<input type="text" name="php"><br>\
|
||||
md5:<input type="text" name="md5">\
|
||||
下载地址:<input type="text" name="download"><br>\
|
||||
<button class="btn btn-default btn-sm" onclick="AddDeployment(1);">提交</button>'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$(".searchInput").keyup(function(e){
|
||||
if(e.keyCode == 13){
|
||||
GetSrcList();
|
||||
}
|
||||
});
|
||||
|
||||
function AddSite(codename){
|
||||
var array;
|
||||
var str="";
|
||||
var domainlist='';
|
||||
var domain = array = $("#mainDomain").val().split("\n");
|
||||
var Webport=[];
|
||||
var checkDomain = domain[0].split('.');
|
||||
if(checkDomain.length < 1){
|
||||
layer.msg('域名格式不正确,请重新输入!',{icon:2});
|
||||
return;
|
||||
}
|
||||
for(var i=1; i<domain.length; i++){
|
||||
domainlist += '"'+domain[i]+'",';
|
||||
}
|
||||
Webport = domain[0].split(":")[1];//主域名端口
|
||||
if(Webport==undefined){
|
||||
Webport="80";
|
||||
}
|
||||
domainlist = domainlist.substring(0,domainlist.length-1);//子域名json
|
||||
mainDomain = domain[0].split(':')[0];
|
||||
domain ='{"domain":"'+domain[0]+'","domainlist":['+domainlist+'],"count":'+domain.length+'}';//拼接joson
|
||||
var php_version = $("select[name='version']").val();
|
||||
var loadT = layer.msg('正在创建站点 <img src="/static/img/ing.gif">',{icon:16,time:0,shade: [0.3, "#000"]})
|
||||
var data = $("#addweb").serialize()+"&port="+Webport+"&webname="+domain+'&ftp=false&sql=true&address=localhost&codeing=utf8&version='+php_version;
|
||||
$.post('/site?action=AddSite', data, function(ret) {
|
||||
layer.close(loadT)
|
||||
if(!ret.siteStatus){
|
||||
layer.msg(ret.msg,{icon:5});
|
||||
return;
|
||||
}
|
||||
layer.close(add)
|
||||
var sqlData = '';
|
||||
if (ret.databaseStatus) {
|
||||
sqlData = "<p class='p1'>数据库账号资料</p>\
|
||||
<p><span>数据库名:</span><strong>" + ret.databaseUser + "</strong></p>\
|
||||
<p><span>用户:</span><strong>" + ret.databaseUser + "</strong></p>\
|
||||
<p><span>密码:</span><strong>" + ret.databasePass + "</strong></p>\
|
||||
"
|
||||
}
|
||||
var pdata = 'dname=' + codename + '&site_name=' + mainDomain + '&php_version='+php_version;
|
||||
var loadT = layer.msg('<div class="depSpeed">正在提交 <img src="/static/img/ing.gif"></div>',{icon:16,time:0,shade: [0.3, "#000"]});
|
||||
|
||||
setTimeout(function(){
|
||||
GetSpeed();
|
||||
},2000);
|
||||
|
||||
$.post('/plugin?action=a&name=deployment&s=SetupPackage',pdata,function(rdata){
|
||||
layer.close(loadT)
|
||||
if(!rdata.status){
|
||||
layer.msg('源码下载失败!',{icon:5});
|
||||
return;
|
||||
}
|
||||
|
||||
if(rdata.msg.username != ''){
|
||||
sqlData = "<p class='p1'>已成功部署,无需安装,请登录修改默认账号密码</p>\
|
||||
<p><span>用户:</span><strong>" + rdata.msg.username + "</strong></p>\
|
||||
<p><span>密码:</span><strong>" + rdata.msg.password + "</strong></p>\
|
||||
"
|
||||
}
|
||||
sqlData += "<p><span>访问站点:</span><a class='btlink' href='http://" + mainDomain + rdata.msg.install + "' target='_blank'>http://" + mainDomain + rdata.msg.install + "</a></p>";
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: '600px',
|
||||
title: '已成功部署'+codename,
|
||||
closeBtn:2,
|
||||
shadeClose: false,
|
||||
content: "<div class='success-msg'>\
|
||||
<div class='pic'><img src='/static/img/success-pic.png'></div>\
|
||||
<div class='suc-con'>\
|
||||
" + sqlData + "\
|
||||
</div>\
|
||||
</div>",
|
||||
});
|
||||
if ($(".success-msg").height() < 150) {
|
||||
$(".success-msg").find("img").css({
|
||||
"width": "150px",
|
||||
"margin-top": "30px"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function GetSpeed(){
|
||||
if(!$('.depSpeed')) return;
|
||||
$.get('/plugin?action=a&name=deployment&s=GetSpeed',function(speed){
|
||||
if(speed.status === false) return;
|
||||
if(speed.name == '下载文件'){
|
||||
speed = '<p>正在'+speed.name+' <img src="/static/img/ing.gif"></p>\
|
||||
<div class="bt-progress"><div class="bt-progress-bar" style="width:'+speed.pre+'%"><span class="bt-progress-text">'+speed.pre+'%</span></div></div>\
|
||||
<p class="f12 c9"><span class="pull-left">'+ToSize(speed.used)+'/'+ToSize(speed.total)+'</span><span class="pull-right">'+ToSize(speed.speed)+'/s</span></p>';
|
||||
$('.depSpeed').prev().hide();
|
||||
$('.depSpeed').css({"margin-left":"-37px","width":"380px"});
|
||||
$('.depSpeed').parents(".layui-layer").css({"margin-left":"-100px"});
|
||||
}else{
|
||||
speed = '<p>'+speed.name+'</p>';
|
||||
$('.depSpeed').prev().show();
|
||||
$('.depSpeed').removeAttr("style");
|
||||
$('.depSpeed').parents(".layui-layer").css({"margin-left":"0"});
|
||||
}
|
||||
|
||||
$('.depSpeed').html(speed);
|
||||
setTimeout(function(){
|
||||
GetSpeed();
|
||||
},1000);
|
||||
});
|
||||
}
|
||||
|
||||
function onekeyCodeSite(codename,versions){
|
||||
$.post('/site?action=GetPHPVersion',function(rdata){
|
||||
var php_version = "";
|
||||
var n = 0;
|
||||
for(var i=rdata.length-1;i>=0;i--){
|
||||
if(versions.indexOf(rdata[i].version) != -1){
|
||||
php_version += "<option value='"+rdata[i].version+"'>"+rdata[i].name+"</option>";
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if(n == 0){
|
||||
layer.msg('缺少被支持的PHP版本,请安装!',{icon:5});
|
||||
return;
|
||||
}
|
||||
var con='<form class="bt-form pd20 pb70" id="addweb">\
|
||||
<div class="line"><span class="tname">域名</span>\
|
||||
<div class="info-r c4"><textarea id="mainDomain" class="bt-input-text" name="webname" style="width:398px;height:100px;line-height:22px"></textarea>\
|
||||
<div class="placeholder c9" style="top:10px;left:10px">每行填写一个域名,默认为80端口<br>泛解析添加方法 *.domain.com<br>如另加端口格式为 www.domain.com:88</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="line"><span class="tname">备注</span>\
|
||||
<div class="info-r c4"><input id="Wbeizhu" class="bt-input-text" name="ps" placeholder="网站备注" style="width:398px" type="text"> </div>\
|
||||
</div>\
|
||||
<div class="line"><span class="tname">根目录</span>\
|
||||
<div class="info-r c4"><input id="inputPath" class="bt-input-text mr5" name="path" value="/www/wwwroot/" placeholder="网站根目录" style="width:398px" type="text"><span class="glyphicon glyphicon-folder-open cursor" onclick="ChangePath(\'inputPath\')"></span> </div>\
|
||||
</div>\
|
||||
<div class="line"><span class="tname">数据库</span>\
|
||||
<div class="info-r c4">\
|
||||
<input id="datauser" class="bt-input-text" name="datauser" placeholder="用户名/数据库名" style="width:190px;margin-right:13px" type="text">\
|
||||
<input id="datapassword" class="bt-input-text" name="datapassword" placeholder="密码" style="width:190px" type="text">\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="line"><span class="tname">源码</span>\
|
||||
<input class="bt-input-text mr5 disable" name="code" style="width:100px" value="'+codename+'" disabled>\
|
||||
<span class="c9">准备为你部署的源码程序</span>\
|
||||
</div>\
|
||||
<div class="line"><span class="tname">PHP版本</span>\
|
||||
<select class="bt-input-text mr5" name="version" id="c_k3" style="width:100px">\
|
||||
'+php_version+'\
|
||||
</select>\
|
||||
<span class="c9">请选择源码程序支持的php版本</span>\
|
||||
</div>\
|
||||
<div class="bt-form-submit-btn">\
|
||||
<button type="button" class="btn btn-danger btn-sm onekeycodeclose">取消</button>\
|
||||
<button type="button" class="btn btn-success btn-sm" onclick="AddSite(\''+codename+'\')">提交</button>\
|
||||
</div>\
|
||||
</from>';
|
||||
add = layer.open({
|
||||
type: 1,
|
||||
title: "宝塔一键部署"+codename,
|
||||
area: '560px',
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
content:con
|
||||
});
|
||||
var placeholder = "<div class='placeholder c9' style='top:10px;left:10px'>每行填写一个域名,默认为80端口<br>泛解析添加方法 *.domain.com<br>如另加端口格式为 www.domain.com:88</div>";
|
||||
$(".onekeycodeclose").click(function(){
|
||||
layer.close(add);
|
||||
});
|
||||
$('#mainDomain').after(placeholder);
|
||||
$(".placeholder").click(function(){
|
||||
$(this).hide();
|
||||
$('#mainDomain').focus();
|
||||
})
|
||||
$('#mainDomain').focus(function() {
|
||||
$(".placeholder").hide();
|
||||
});
|
||||
|
||||
$('#mainDomain').blur(function() {
|
||||
if($(this).val().length==0){
|
||||
$(".placeholder").show();
|
||||
}
|
||||
});
|
||||
//FTP账号数据绑定域名
|
||||
$('#mainDomain').on('input', function() {
|
||||
var defaultPath = '/www/wwwroot';
|
||||
var array;
|
||||
var res,ress;
|
||||
var str = $(this).val();
|
||||
var len = str.replace(/[^\x00-\xff]/g, "**").length;
|
||||
array = str.split("\n");
|
||||
ress =array[0].split(":")[0];
|
||||
res = ress.replace(new RegExp(/([-.])/g), '_');
|
||||
if(res.length > 15) res = res.substr(0,15);
|
||||
if($("#inputPath").val().substr(0,defaultPath.length) == defaultPath) $("#inputPath").val(defaultPath+'/'+ress);
|
||||
if(!isNaN(res.substr(0,1))) res = "sql"+res;
|
||||
if(res.length > 15) res = res.substr(0,15);
|
||||
$("#Wbeizhu").val(ress);
|
||||
$("#datauser").val(res);
|
||||
})
|
||||
$('#Wbeizhu').on('input', function() {
|
||||
var str = $(this).val();
|
||||
var len = str.replace(/[^\x00-\xff]/g, "**").length;
|
||||
if (len > 20) {
|
||||
str = str.substring(0, 20);
|
||||
$(this).val(str);
|
||||
layer.msg('不要超出20个字符', {
|
||||
icon: 0
|
||||
});
|
||||
}
|
||||
})
|
||||
//获取当前时间时间戳,截取后6位
|
||||
var timestamp = new Date().getTime().toString();
|
||||
var dtpw = timestamp.substring(7);
|
||||
$("#datauser").val("sql" + dtpw);
|
||||
$("#datapassword").val(_getRandomString(10));
|
||||
});
|
||||
}
|
||||
|
||||
//生成n位随机密码
|
||||
function _getRandomString(len) {
|
||||
len = len || 32;
|
||||
var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; // 默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
|
||||
var maxPos = $chars.length;
|
||||
var pwd = '';
|
||||
for (i = 0; i < len; i++) {
|
||||
pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
|
||||
}
|
||||
return pwd;
|
||||
}
|
||||
function GetSrcList(){
|
||||
var loadT = layer.msg('正在获取列表 <img src="/static/img/ing.gif">',{icon:16,time:0,shade: [0.3, '#000']});
|
||||
var search = $(".searchInput").val();
|
||||
if(search != ''){
|
||||
search = '&search=' + search+'&';
|
||||
}
|
||||
var type = '';
|
||||
var istype = getCookie('depType');
|
||||
if(istype == 'undefined' || istype == 'null' || !istype) {
|
||||
istype = '0';
|
||||
}
|
||||
type = '&type='+istype;
|
||||
|
||||
$.get('/plugin?action=a&name=deployment&s=GetList' + search + type,function(mlist){
|
||||
layer.close(loadT);
|
||||
|
||||
tbody = '';
|
||||
for(var i=0;i<mlist.type.length;i++){
|
||||
var c = '';
|
||||
if(istype == mlist.type[i].type){
|
||||
c = 'class="on"';
|
||||
}
|
||||
tbody += '<span typeid="'+mlist.type[i].type+'" '+c+'>'+mlist.type[i].title+'</span>';
|
||||
}
|
||||
|
||||
$(".onekey-type").html(tbody);
|
||||
|
||||
var zbody = '';
|
||||
for(var i=mlist.data.length-1;i>=0;i--){
|
||||
zbody += '<tr>'
|
||||
+'<td>'+mlist.data[i].title+'</td>'
|
||||
+'<td>'+mlist.data[i].version+'</td>'
|
||||
+'<td>'+mlist.data[i].ps+'</td>'
|
||||
+'<td>'+mlist.data[i].php+'</td>'
|
||||
+'<td class="text-right"><a href="javascript:onekeyCodeSite(\''+mlist.data[i].name+'\',\''+mlist.data[i].php+'\');" class="btlink">一键部署</a></td>'
|
||||
+'</tr>'
|
||||
}
|
||||
$("#zipBody").html(zbody);
|
||||
$(".searchInput").val('');
|
||||
|
||||
$(".onekey-menu-sub span").click(function(){
|
||||
setCookie('depType',$(this).attr('typeid'));
|
||||
$(this).addClass("on").siblings().removeClass("on");
|
||||
GetSrcList();
|
||||
});
|
||||
});
|
||||
}
|
||||
GetSrcList();
|
||||
</script>
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"title":"宝塔一键部署源码",
|
||||
"tip":"lib",
|
||||
"name":"deployment",
|
||||
"type":"扩展",
|
||||
"ps":"快速部署常用程序!",
|
||||
"versions":"1.1",
|
||||
"shell":"deployment.sh",
|
||||
"checks":"/www/server/panel/plugin/deployment",
|
||||
"author":"宝塔",
|
||||
"home":"http://www.bt.cn/bbs",
|
||||
"date":"2017-07-26",
|
||||
"default":false,
|
||||
"display":1,
|
||||
"pid":"2"
|
||||
}
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
install_tmp='/tmp/bt_install.pl'
|
||||
CN='125.88.182.172'
|
||||
HK='download.bt.cn'
|
||||
HK2='103.224.251.67'
|
||||
US='174.139.221.74'
|
||||
sleep 0.5;
|
||||
CN_PING=`ping -c 1 -w 1 $CN|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
HK_PING=`ping -c 1 -w 1 $HK|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
HK2_PING=`ping -c 1 -w 1 $HK2|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
US_PING=`ping -c 1 -w 1 $US|grep time=|awk '{print $7}'|sed "s/time=//"`
|
||||
|
||||
echo "$HK_PING $HK" > ping.pl
|
||||
echo "$HK2_PING $HK2" >> ping.pl
|
||||
echo "$US_PING $US" >> ping.pl
|
||||
echo "$CN_PING $CN" >> ping.pl
|
||||
nodeAddr=`sort -V ping.pl|sed -n '1p'|awk '{print $2}'`
|
||||
if [ "$nodeAddr" == "" ];then
|
||||
nodeAddr=$HK2
|
||||
fi
|
||||
|
||||
download_Url=http://$nodeAddr:5880
|
||||
|
||||
Install_deployment()
|
||||
{
|
||||
mkdir -p /www/server/panel/plugin/deployment
|
||||
mkdir -p /www/server/panel/plugin/deployment/package
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
wget -O /www/server/panel/plugin/deployment/deployment_main.py $download_Url/install/lib/plugin/deployment/deployment_main.py -T 5
|
||||
wget -O /www/server/panel/plugin/deployment/index.html $download_Url/install/lib/plugin/deployment/index.html -T 5
|
||||
wget -O /www/server/panel/plugin/deployment/info.json $download_Url/install/lib/plugin/deployment/info.json -T 5
|
||||
wget -O /www/server/panel/plugin/deployment/list.json $download_Url/install/lib/plugin/deployment/list.json -T 5
|
||||
wget -O /www/server/panel/plugin/deployment/type.json $download_Url/install/lib/plugin/deployment/type.json -T 5
|
||||
wget -O /www/server/panel/plugin/deployment/icon.png $download_Url/install/lib/plugin/deployment/icon.png -T 5
|
||||
wget -O /www/server/panel/static/img/soft_ico/ico-deployment.png $download_Url/install/lib/plugin/deployment/icon.png -T 5
|
||||
echo '安装完成' > $install_tmp
|
||||
}
|
||||
|
||||
Uninstall_deployment()
|
||||
{
|
||||
rm -rf /www/server/panel/plugin/deployment
|
||||
}
|
||||
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_deployment
|
||||
else
|
||||
Uninstall_deployment
|
||||
fi
|
||||
Executable
+495
@@ -0,0 +1,495 @@
|
||||
[
|
||||
{
|
||||
"name":"niucms",
|
||||
"title":"NIUCMS",
|
||||
"type":1,
|
||||
"version":"3.6",
|
||||
"md5":"f5ea5a231a7d25d66ee324d60dcdd4f1",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install/index.php",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"智慧城市生活系统(商业软件)",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/niucms.zip"
|
||||
},
|
||||
{
|
||||
"name":"tpt-blog",
|
||||
"title":"Tpt-Blog",
|
||||
"type":4,
|
||||
"version":"1.1",
|
||||
"md5":"aa195fece581582182e17143f53b2dfc",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/admin.php",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"免费开源的博客程序",
|
||||
"config":"/Application/Common/Conf/db.php",
|
||||
"username":"admin",
|
||||
"password":"admin<br>口令:123456",
|
||||
"run":"/",
|
||||
"download":"{Download}/tpt-blog_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"phpcms",
|
||||
"title":"PHPCMS",
|
||||
"type":1,
|
||||
"version":"9.6.3",
|
||||
"md5":"4de608ae7b74175dd4513911ef7ebf78",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70",
|
||||
"ps":"PHPCMS内容管理系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/phpcms.zip"
|
||||
},
|
||||
{
|
||||
"name":"ecshop_2.7",
|
||||
"title":"EcShop-2.7",
|
||||
"type":2,
|
||||
"version":"2.7.3",
|
||||
"md5":"9115294f5a458249a5f2c793eab3639c",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53",
|
||||
"ps":"B2C独立网店系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/ecshop_2.7.zip"
|
||||
},
|
||||
{
|
||||
"name":"ecshop_3.6",
|
||||
"title":"EcShop-3.6",
|
||||
"type":2,
|
||||
"version":"3.6.0",
|
||||
"md5":"38fdc7fe8faf67edd91ebfbb8291cbc7",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"B2C独立网店系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/ecshop",
|
||||
"download":"{Download}/ecshop_3.6.zip"
|
||||
},
|
||||
{
|
||||
"name":"emlog",
|
||||
"title":"Emlog",
|
||||
"type":4,
|
||||
"version":"5.3.1",
|
||||
"md5":"cecaa55d8d9644e8d8b7098c836af1ad",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"博客程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/emlog.zip"
|
||||
},
|
||||
{
|
||||
"name":"empirecms",
|
||||
"title":"帝国CMS",
|
||||
"type":1,
|
||||
"version":"7.2",
|
||||
"md5":"07bb4ffe56c939170ff080744fc13dd8",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/e/install",
|
||||
"php":"52,53,54,55,56",
|
||||
"ps":"帝国内容管理系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/empirecms.zip"
|
||||
},
|
||||
{
|
||||
"name":"jieqiarticle170",
|
||||
"title":"杰奇1.7",
|
||||
"type":1,
|
||||
"version":"1.7",
|
||||
"md5":"e5168ea7b27f5c6de2a01dbf40f772b7",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52",
|
||||
"ps":"小说连载程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/jieqiarticle170.zip"
|
||||
},
|
||||
{
|
||||
"name":"codeigniter",
|
||||
"title":"CI框架",
|
||||
"type":6,
|
||||
"version":"3.1.5",
|
||||
"md5":"47a615ef55910a908aff367dc5f59a70",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"知名PHP框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/public",
|
||||
"download":"{Download}/codeIgniter.zip"
|
||||
},
|
||||
{
|
||||
"name":"laravel",
|
||||
"title":"Laravel",
|
||||
"type":6,
|
||||
"version":"5.4",
|
||||
"md5":"988566e8982e835ffa6f7d9ad14b5330",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"56,70,71,72",
|
||||
"ps":"优雅的PHP开发框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/public",
|
||||
"download":"{Download}/laravel.zip"
|
||||
},
|
||||
{
|
||||
"name":"thinkphp_3.2",
|
||||
"title":"ThinkPHP-3.2",
|
||||
"type":6,
|
||||
"version":"3.2.3",
|
||||
"md5":"6cd0e16bf478e7df2fc62b6819eebcce",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"国内知名PHP框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/thinkphp-3.2.zip"
|
||||
},
|
||||
{
|
||||
"name":"thinkphp_5.0",
|
||||
"title":"ThinkPHP-5.0",
|
||||
"type":6,
|
||||
"version":"5.0.15",
|
||||
"md5":"830fd878a802237a968ba36fceb1ae92",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"54,55,56,70,71,72",
|
||||
"ps":"国内知名PHP框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/public",
|
||||
"download":"{Download}/thinkphp-5.0.zip"
|
||||
},
|
||||
{
|
||||
"name":"dedecms",
|
||||
"title":"织梦CMS",
|
||||
"type":1,
|
||||
"version":"v5.7SP2",
|
||||
"md5":"6f64be35597dbd2c51b1954f74cfb3ad",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名内容管理系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/dedecms.zip"
|
||||
},
|
||||
{
|
||||
"name":"discuz_x3.4",
|
||||
"title":"Discuz 3.4",
|
||||
"type":3,
|
||||
"version":"x3.4",
|
||||
"md5":"44c4250ebdf5fa796712f336fbd2ef42",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名论坛程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/discuz_x3.4.zip"
|
||||
},
|
||||
{
|
||||
"name":"discuz",
|
||||
"title":"Discuz",
|
||||
"type":3,
|
||||
"version":"x3.3",
|
||||
"md5":"b31e43927daa00c7c3d92818298943fa",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名论坛程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/discuz.zip"
|
||||
},
|
||||
{
|
||||
"name":"typecho",
|
||||
"title":"Typecho",
|
||||
"type":4,
|
||||
"version":"1.1",
|
||||
"md5":"8b638551974e98994401cda253a3f836",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"54,55,56,70,71,72",
|
||||
"ps":"轻量级博客程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/typecho.zip"
|
||||
},
|
||||
{
|
||||
"name":"wordpress",
|
||||
"title":"Wordpress",
|
||||
"type":4,
|
||||
"version":"4.9.2",
|
||||
"md5":"6d7285257c7df3791255d8c4975804b5",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"最多人用的博客程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/wordpress.zip"
|
||||
},
|
||||
{
|
||||
"name":"metInfo",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=metInfo' class='btlink' target='_blank'>MetInfo</a>",
|
||||
"type":1,
|
||||
"version":"6.0.0",
|
||||
"md5":"fff363bc0cbb13a5c2dc8c2a652da825",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70",
|
||||
"ps":"企业建站系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/metInfo.zip"
|
||||
},
|
||||
{
|
||||
"name":"chanzhi",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=chanzhi' class='btlink' target='_blank'>蝉知CMS</a>",
|
||||
"type":1,
|
||||
"version":"6.5",
|
||||
"md5":"793af27f2984127c34490229124644b8",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/admin.php",
|
||||
"php":"53,54,55,56,70,71",
|
||||
"ps":"开源免费的企业门户系统,CMS系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"/system/config/my.php",
|
||||
"username":"admin",
|
||||
"password":"admin",
|
||||
"run":"/www",
|
||||
"download":"{Download}/chanzhi_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"cscms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=cscms' class='btlink' target='_blank'>CSCMS</a>",
|
||||
"type":1,
|
||||
"version":"4.1",
|
||||
"md5":"12b66ea05ad3b829be916fe541c1dedc",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install.php",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"多元化内容管理系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/cscms.zip"
|
||||
},
|
||||
{
|
||||
"name":"kodexplorer",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=kodexplorer' class='btlink' target='_blank'>可道云KodExplorer</a>",
|
||||
"type":1,
|
||||
"version":"4.06",
|
||||
"md5":"2907559eac6714394eb9f5a44e005eea",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/index.php",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"强大易用的私有云/在线文档管理<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/kodexplorer.zip"
|
||||
},
|
||||
{
|
||||
"name":"tipask",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=tipask' class='btlink' target='_blank'>Tipask</a>",
|
||||
"type":1,
|
||||
"version":"3.2",
|
||||
"md5":"ae99702f944bf1c60b14065d00a3d676",
|
||||
"ext":"fileinfo,opcache,pathinfo",
|
||||
"chmod":"775|storage/app/,775|storage/framework/,775|storage/logs/,775|bootstrap/cache/,664|.env",
|
||||
"install":"",
|
||||
"php":"55,56,70,71,72",
|
||||
"ps":"国内知名问答程序<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":".env",
|
||||
"username":"admin@tipask.com",
|
||||
"password":"tipask",
|
||||
"run":"/public",
|
||||
"download":"{Download}/tipask_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"maccms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=maccms' class='btlink' target='_blank'>苹果CMS</a>",
|
||||
"type":1,
|
||||
"version":"8.0",
|
||||
"md5":"a9801d94d1c592b5bb6d2474e5c0c37e",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"PHP开源建站系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/maccms.zip"
|
||||
},
|
||||
{
|
||||
"name":"seacms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=seacms' class='btlink' target='_blank'>海洋CMS</a>",
|
||||
"type":1,
|
||||
"version":"6.54",
|
||||
"md5":"ca43469682b8e5e7cdceba020bf39375",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/admin",
|
||||
"php":"52,53,54,55,56.70",
|
||||
"ps":"完全开源免费的PHP视频管理系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"data/common.inc.php",
|
||||
"username":"admin",
|
||||
"password":"admin",
|
||||
"run":"/",
|
||||
"download":"{Download}/seacms_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"cxxcms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=cxxcms' class='btlink' target='_blank'>程序侠CMS</a>",
|
||||
"type":1,
|
||||
"version":"1.1.2",
|
||||
"md5":"8ad9c0671e41eeed34f046bf2abc3f22",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"777|runtime,777|data,777|application/extra,777|application/database.php",
|
||||
"install":"/admin",
|
||||
"php":"54,55,56,70,71,72",
|
||||
"ps":"专业、安全的淘宝客CMS系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"application/database.php",
|
||||
"username":"admin",
|
||||
"password":"chengxuxia.com",
|
||||
"run":"/",
|
||||
"download":"{Download}/cxxcms_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"z-blog",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=z-blog' class='btlink' target='_blank'>Z-Blog</a>",
|
||||
"type":4,
|
||||
"version":"1.5.2",
|
||||
"md5":"07faf7fbeecfe9cad10872fe03ab3127",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名博客程序<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"zb_users/c_option.php",
|
||||
"username":"admin",
|
||||
"password":"zblogger",
|
||||
"run":"/",
|
||||
"download":"{Download}/z-blog_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"dbshop",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=dbshop' class='btlink' target='_blank'>DBShop</a>",
|
||||
"type":2,
|
||||
"version":"v1.2",
|
||||
"md5":"f3c5559fa8eb04bdc9938382658f3a03",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/admin",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"专业且良心的商城系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"data/Database.ini.php",
|
||||
"username":"admin",
|
||||
"password":"1234567",
|
||||
"run":"/",
|
||||
"download":"{Download}/dbshop_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"niushop",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=niushop' class='btlink' target='_blank'>NiuShop</a>",
|
||||
"type":2,
|
||||
"version":"1.1.9",
|
||||
"md5":"637c6ad54fa4732df35857304e5eeb82",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"54,55,56,70",
|
||||
"ps":"优秀的TP5.0开源商城系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"application/database.php",
|
||||
"username":"admin",
|
||||
"password":"123456",
|
||||
"run":"/",
|
||||
"download":"{Download}/niushop_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"weengine",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=weengine' class='btlink' target='_blank'>微擎</a>",
|
||||
"type":5,
|
||||
"version":"1.0",
|
||||
"md5":"8424881fe0e60042df5064ca4638f56c",
|
||||
"ext":"fileinfo,pathinfo,ioncube",
|
||||
"chmod":"755|addons,755|api,755|app,755|data,755|attachment,755|framework,755|payment,755|web",
|
||||
"install":"/index.php",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"微信第三方管理引擎<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"data/config.php",
|
||||
"username":"admin",
|
||||
"password":"we7.cc",
|
||||
"run":"/",
|
||||
"download":"{Download}/weengine_auto.zip"
|
||||
}
|
||||
]
|
||||
Executable
+495
@@ -0,0 +1,495 @@
|
||||
[
|
||||
{
|
||||
"name":"niucms",
|
||||
"title":"NIUCMS",
|
||||
"type":1,
|
||||
"version":"3.6",
|
||||
"md5":"f5ea5a231a7d25d66ee324d60dcdd4f1",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install/index.php",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"智慧城市生活系统(商业软件)",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/niucms.zip"
|
||||
},
|
||||
{
|
||||
"name":"tpt-blog",
|
||||
"title":"Tpt-Blog",
|
||||
"type":4,
|
||||
"version":"1.1",
|
||||
"md5":"aa195fece581582182e17143f53b2dfc",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/admin.php",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"免费开源的博客程序",
|
||||
"config":"/Application/Common/Conf/db.php",
|
||||
"username":"admin",
|
||||
"password":"admin<br>口令:123456",
|
||||
"run":"/",
|
||||
"download":"{Download}/tpt-blog_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"phpcms",
|
||||
"title":"PHPCMS",
|
||||
"type":1,
|
||||
"version":"9.6.3",
|
||||
"md5":"4de608ae7b74175dd4513911ef7ebf78",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70",
|
||||
"ps":"PHPCMS内容管理系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/phpcms.zip"
|
||||
},
|
||||
{
|
||||
"name":"ecshop_2.7",
|
||||
"title":"EcShop-2.7",
|
||||
"type":2,
|
||||
"version":"2.7.3",
|
||||
"md5":"9115294f5a458249a5f2c793eab3639c",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53",
|
||||
"ps":"B2C独立网店系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/ecshop_2.7.zip"
|
||||
},
|
||||
{
|
||||
"name":"ecshop_3.6",
|
||||
"title":"EcShop-3.6",
|
||||
"type":2,
|
||||
"version":"3.6.0",
|
||||
"md5":"38fdc7fe8faf67edd91ebfbb8291cbc7",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"B2C独立网店系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/ecshop",
|
||||
"download":"{Download}/ecshop_3.6.zip"
|
||||
},
|
||||
{
|
||||
"name":"emlog",
|
||||
"title":"Emlog",
|
||||
"type":4,
|
||||
"version":"5.3.1",
|
||||
"md5":"cecaa55d8d9644e8d8b7098c836af1ad",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"博客程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/emlog.zip"
|
||||
},
|
||||
{
|
||||
"name":"empirecms",
|
||||
"title":"帝国CMS",
|
||||
"type":1,
|
||||
"version":"7.2",
|
||||
"md5":"07bb4ffe56c939170ff080744fc13dd8",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/e/install",
|
||||
"php":"52,53,54,55,56",
|
||||
"ps":"帝国内容管理系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/empirecms.zip"
|
||||
},
|
||||
{
|
||||
"name":"jieqiarticle170",
|
||||
"title":"杰奇1.7",
|
||||
"type":1,
|
||||
"version":"1.7",
|
||||
"md5":"e5168ea7b27f5c6de2a01dbf40f772b7",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52",
|
||||
"ps":"小说连载程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/jieqiarticle170.zip"
|
||||
},
|
||||
{
|
||||
"name":"codeigniter",
|
||||
"title":"CI框架",
|
||||
"type":6,
|
||||
"version":"3.1.5",
|
||||
"md5":"47a615ef55910a908aff367dc5f59a70",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"知名PHP框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/public",
|
||||
"download":"{Download}/codeIgniter.zip"
|
||||
},
|
||||
{
|
||||
"name":"laravel",
|
||||
"title":"Laravel",
|
||||
"type":6,
|
||||
"version":"5.4",
|
||||
"md5":"988566e8982e835ffa6f7d9ad14b5330",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"56,70,71,72",
|
||||
"ps":"优雅的PHP开发框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/public",
|
||||
"download":"{Download}/laravel.zip"
|
||||
},
|
||||
{
|
||||
"name":"thinkphp_3.2",
|
||||
"title":"ThinkPHP-3.2",
|
||||
"type":6,
|
||||
"version":"3.2.3",
|
||||
"md5":"6cd0e16bf478e7df2fc62b6819eebcce",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"国内知名PHP框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/thinkphp-3.2.zip"
|
||||
},
|
||||
{
|
||||
"name":"thinkphp_5.0",
|
||||
"title":"ThinkPHP-5.0",
|
||||
"type":6,
|
||||
"version":"5.0.15",
|
||||
"md5":"830fd878a802237a968ba36fceb1ae92",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"54,55,56,70,71,72",
|
||||
"ps":"国内知名PHP框架",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/public",
|
||||
"download":"{Download}/thinkphp-5.0.zip"
|
||||
},
|
||||
{
|
||||
"name":"dedecms",
|
||||
"title":"织梦CMS",
|
||||
"type":1,
|
||||
"version":"v5.7SP2",
|
||||
"md5":"6f64be35597dbd2c51b1954f74cfb3ad",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名内容管理系统",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/dedecms.zip"
|
||||
},
|
||||
{
|
||||
"name":"discuz_x3.4",
|
||||
"title":"Discuz 3.4",
|
||||
"type":3,
|
||||
"version":"x3.4",
|
||||
"md5":"44c4250ebdf5fa796712f336fbd2ef42",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名论坛程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/discuz_x3.4.zip"
|
||||
},
|
||||
{
|
||||
"name":"discuz",
|
||||
"title":"Discuz",
|
||||
"type":3,
|
||||
"version":"x3.3",
|
||||
"md5":"b31e43927daa00c7c3d92818298943fa",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/install",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名论坛程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/discuz.zip"
|
||||
},
|
||||
{
|
||||
"name":"typecho",
|
||||
"title":"Typecho",
|
||||
"type":4,
|
||||
"version":"1.1",
|
||||
"md5":"8b638551974e98994401cda253a3f836",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"54,55,56,70,71,72",
|
||||
"ps":"轻量级博客程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/typecho.zip"
|
||||
},
|
||||
{
|
||||
"name":"wordpress",
|
||||
"title":"Wordpress",
|
||||
"type":4,
|
||||
"version":"4.9.2",
|
||||
"md5":"6d7285257c7df3791255d8c4975804b5",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"最多人用的博客程序",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/wordpress.zip"
|
||||
},
|
||||
{
|
||||
"name":"metInfo",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=metInfo' class='btlink' target='_blank'>MetInfo</a>",
|
||||
"type":1,
|
||||
"version":"6.0.0",
|
||||
"md5":"fff363bc0cbb13a5c2dc8c2a652da825",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70",
|
||||
"ps":"企业建站系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/metInfo.zip"
|
||||
},
|
||||
{
|
||||
"name":"chanzhi",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=chanzhi' class='btlink' target='_blank'>蝉知CMS</a>",
|
||||
"type":1,
|
||||
"version":"6.5",
|
||||
"md5":"793af27f2984127c34490229124644b8",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/admin.php",
|
||||
"php":"53,54,55,56,70,71",
|
||||
"ps":"开源免费的企业门户系统,CMS系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"/system/config/my.php",
|
||||
"username":"admin",
|
||||
"password":"admin",
|
||||
"run":"/www",
|
||||
"download":"{Download}/chanzhi_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"cscms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=cscms' class='btlink' target='_blank'>CSCMS</a>",
|
||||
"type":1,
|
||||
"version":"4.1",
|
||||
"md5":"12b66ea05ad3b829be916fe541c1dedc",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/install.php",
|
||||
"php":"53,54,55,56",
|
||||
"ps":"多元化内容管理系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/cscms.zip"
|
||||
},
|
||||
{
|
||||
"name":"kodexplorer",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=kodexplorer' class='btlink' target='_blank'>可道云KodExplorer</a>",
|
||||
"type":1,
|
||||
"version":"4.06",
|
||||
"md5":"2907559eac6714394eb9f5a44e005eea",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/index.php",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"强大易用的私有云/在线文档管理<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/kodexplorer.zip"
|
||||
},
|
||||
{
|
||||
"name":"tipask",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=tipask' class='btlink' target='_blank'>Tipask</a>",
|
||||
"type":1,
|
||||
"version":"3.2",
|
||||
"md5":"ae99702f944bf1c60b14065d00a3d676",
|
||||
"ext":"fileinfo,opcache,pathinfo",
|
||||
"chmod":"775|storage/app/,775|storage/framework/,775|storage/logs/,775|bootstrap/cache/,664|.env",
|
||||
"install":"",
|
||||
"php":"55,56,70,71,72",
|
||||
"ps":"国内知名问答程序<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":".env",
|
||||
"username":"admin@tipask.com",
|
||||
"password":"tipask",
|
||||
"run":"/public",
|
||||
"download":"{Download}/tipask_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"maccms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=maccms' class='btlink' target='_blank'>苹果CMS</a>",
|
||||
"type":1,
|
||||
"version":"8.0",
|
||||
"md5":"a9801d94d1c592b5bb6d2474e5c0c37e",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"PHP开源建站系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"",
|
||||
"username":"",
|
||||
"password":"",
|
||||
"run":"/",
|
||||
"download":"{Download}/maccms.zip"
|
||||
},
|
||||
{
|
||||
"name":"seacms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=seacms' class='btlink' target='_blank'>海洋CMS</a>",
|
||||
"type":1,
|
||||
"version":"6.54",
|
||||
"md5":"ca43469682b8e5e7cdceba020bf39375",
|
||||
"ext":"",
|
||||
"chmod":"",
|
||||
"install":"/admin",
|
||||
"php":"52,53,54,55,56.70",
|
||||
"ps":"完全开源免费的PHP视频管理系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"data/common.inc.php",
|
||||
"username":"admin",
|
||||
"password":"admin",
|
||||
"run":"/",
|
||||
"download":"{Download}/seacms_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"cxxcms",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=cxxcms' class='btlink' target='_blank'>程序侠CMS</a>",
|
||||
"type":1,
|
||||
"version":"1.1.2",
|
||||
"md5":"8ad9c0671e41eeed34f046bf2abc3f22",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"777|runtime,777|data,777|application/extra,777|application/database.php",
|
||||
"install":"/admin",
|
||||
"php":"54,55,56,70,71,72",
|
||||
"ps":"专业、安全的淘宝客CMS系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"application/database.php",
|
||||
"username":"admin",
|
||||
"password":"chengxuxia.com",
|
||||
"run":"/",
|
||||
"download":"{Download}/cxxcms_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"z-blog",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=z-blog' class='btlink' target='_blank'>Z-Blog</a>",
|
||||
"type":4,
|
||||
"version":"1.5.2",
|
||||
"md5":"07faf7fbeecfe9cad10872fe03ab3127",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"52,53,54,55,56,70,71,72",
|
||||
"ps":"国内知名博客程序<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"zb_users/c_option.php",
|
||||
"username":"admin",
|
||||
"password":"zblogger",
|
||||
"run":"/",
|
||||
"download":"{Download}/z-blog_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"dbshop",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=dbshop' class='btlink' target='_blank'>DBShop</a>",
|
||||
"type":2,
|
||||
"version":"v1.2",
|
||||
"md5":"f3c5559fa8eb04bdc9938382658f3a03",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"/admin",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"专业且良心的商城系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"data/Database.ini.php",
|
||||
"username":"admin",
|
||||
"password":"1234567",
|
||||
"run":"/",
|
||||
"download":"{Download}/dbshop_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"niushop",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=niushop' class='btlink' target='_blank'>NiuShop</a>",
|
||||
"type":2,
|
||||
"version":"1.1.9",
|
||||
"md5":"637c6ad54fa4732df35857304e5eeb82",
|
||||
"ext":"pathinfo",
|
||||
"chmod":"",
|
||||
"install":"",
|
||||
"php":"54,55,56,70",
|
||||
"ps":"优秀的TP5.0开源商城系统<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"application/database.php",
|
||||
"username":"admin",
|
||||
"password":"123456",
|
||||
"run":"/",
|
||||
"download":"{Download}/niushop_auto.zip"
|
||||
},
|
||||
{
|
||||
"name":"weengine",
|
||||
"title":"<a href='https://www.bt.cn/redirect?name=weengine' class='btlink' target='_blank'>微擎</a>",
|
||||
"type":5,
|
||||
"version":"1.0",
|
||||
"md5":"8424881fe0e60042df5064ca4638f56c",
|
||||
"ext":"fileinfo,pathinfo,ioncube",
|
||||
"chmod":"755|addons,755|api,755|app,755|data,755|attachment,755|framework,755|payment,755|web",
|
||||
"install":"/index.php",
|
||||
"php":"53,54,55,56,70,71,72",
|
||||
"ps":"微信第三方管理引擎<font style='color: #fff;padding: 1px 4px;position: relative;margin-left: 6px;border-radius: 3px;background-color: #fc6d26;'>推荐</font>",
|
||||
"config":"data/config.php",
|
||||
"username":"admin",
|
||||
"password":"we7.cc",
|
||||
"run":"/",
|
||||
"download":"{Download}/weengine_auto.zip"
|
||||
}
|
||||
]
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"title":"推荐",
|
||||
"type":0,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"建站",
|
||||
"type":1,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"商城",
|
||||
"type":2,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"论坛",
|
||||
"type":3,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"博客",
|
||||
"type":4,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"微信",
|
||||
"type":5,
|
||||
"ps":""
|
||||
},
|
||||
{
|
||||
"title":"框架",
|
||||
"type":6,
|
||||
"ps":""
|
||||
}
|
||||
]
|
||||
@@ -1,704 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
|
||||
cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
|
||||
info = mw.execShell(cmd)
|
||||
p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
|
||||
sys.path.append(p)
|
||||
import psutil
|
||||
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'gogs'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
import mysqlDb
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
if app_debug:
|
||||
return '/tmp/' + getPluginName()
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
t = t.split(':', 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 getInitdConfTpl():
|
||||
path = getPluginDir() + "/init.d/gogs.tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getInitdConf():
|
||||
path = getServerDir() + "/init.d/gogs"
|
||||
return path
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/custom/conf/app.ini"
|
||||
return path
|
||||
|
||||
|
||||
def getConfTpl():
|
||||
path = getPluginDir() + "/conf/app.ini"
|
||||
return path
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def getHomeDir():
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
return '/Users/' + user
|
||||
else:
|
||||
return '/root'
|
||||
|
||||
|
||||
def getRunUser():
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
return user
|
||||
else:
|
||||
return 'root'
|
||||
|
||||
__SR = '''#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
export USER=%s
|
||||
export HOME=%s && ''' % ( getRunUser(), getHomeDir())
|
||||
|
||||
|
||||
def contentReplace(content):
|
||||
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$RUN_USER}', getRunUser())
|
||||
content = content.replace('{$HOME_DIR}', getHomeDir())
|
||||
|
||||
return content
|
||||
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitdConfTpl()
|
||||
service_path = mw.getServerDir()
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
conf_bin = getConf()
|
||||
if not os.path.exists(conf_bin):
|
||||
mw.execShell('mkdir -p ' + getServerDir() + '/custom/conf')
|
||||
conf_tpl = getConfTpl()
|
||||
content = mw.readFile(conf_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(conf_bin, content)
|
||||
|
||||
log_path = getServerDir() + '/log'
|
||||
if not os.path.exists(log_path):
|
||||
os.mkdir(log_path)
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def getRootUrl():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'ROOT_URL\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getSshPort():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'SSH_PORT\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getHttpPort():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'HTTP_PORT\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getRootPath():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'ROOT\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getDbConfValue():
|
||||
content = mw.readFile(getConf())
|
||||
|
||||
rep_scope = "\[database\](.*?)\["
|
||||
tmp = re.findall(rep_scope, content, re.S)
|
||||
|
||||
rep = '(\w*)\s*=\s*(.*)'
|
||||
tmp = re.findall(rep, tmp[0])
|
||||
r = {}
|
||||
for x in range(len(tmp)):
|
||||
k = tmp[x][0]
|
||||
v = tmp[x][1]
|
||||
r[k] = v
|
||||
return r
|
||||
|
||||
|
||||
def pMysqlDb():
|
||||
conf = getDbConfValue()
|
||||
|
||||
host = conf['HOST'].split(':')
|
||||
conn = mysqlDb.mysqlDb()
|
||||
|
||||
conn.setHost(host[0])
|
||||
conn.setUser(conf['USER'])
|
||||
conn.setPwd(conf['PASSWD'])
|
||||
conn.setPort(int(host[1]))
|
||||
conn.setDb(conf['NAME'])
|
||||
return conn
|
||||
|
||||
|
||||
def isSqlError(mysqlMsg):
|
||||
# 检测数据库执行错误
|
||||
_mysqlMsg = str(mysqlMsg)
|
||||
# print _mysqlMsg
|
||||
if "MySQLdb" in _mysqlMsg:
|
||||
return mw.returnData(False, 'MySQLdb组件缺失! <br>进入SSH命令行输入: pip install mysql-python')
|
||||
if "2002," in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||
if "using password:" in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库管理密码错误!')
|
||||
if "Connection refused" in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||
if "1133," in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库用户不存在!')
|
||||
if "1007," in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库已经存在!')
|
||||
if "1044," in _mysqlMsg:
|
||||
return mw.returnData(False, mysqlMsg[1])
|
||||
if "2003," in _mysqlMsg:
|
||||
return mw.returnData(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
||||
return mw.returnData(True, 'OK')
|
||||
|
||||
|
||||
def start():
|
||||
|
||||
is_frist = True
|
||||
conf_bin = getConf()
|
||||
if os.path.exists(conf_bin):
|
||||
is_frist = False
|
||||
|
||||
file = initDreplace()
|
||||
|
||||
if is_frist:
|
||||
return "第一次启动Gogs,默认使用MySQL连接!<br>可以在配置文件中重新设置,再启动!"
|
||||
|
||||
conn = pMysqlDb()
|
||||
list_table = conn.query('show tables')
|
||||
data = isSqlError(list_table)
|
||||
if not data['status']:
|
||||
return data['msg']
|
||||
|
||||
data = mw.execShell(__SR + file + ' start')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[0]
|
||||
|
||||
|
||||
def stop():
|
||||
file = initDreplace()
|
||||
data = mw.execShell(__SR + file + ' stop')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def restart():
|
||||
file = initDreplace()
|
||||
data = mw.execShell(__SR + file + ' restart')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def reload():
|
||||
file = initDreplace()
|
||||
data = mw.execShell(__SR + file + ' reload')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def initdStatus():
|
||||
if not app_debug:
|
||||
os_name = mw.getOs()
|
||||
if os_name == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
return 'fail'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
import shutil
|
||||
if not app_debug:
|
||||
os_name = mw.getOs()
|
||||
if os_name == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mem_bin = initDreplace()
|
||||
initd_bin = getInitDFile()
|
||||
shutil.copyfile(mem_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
mw.execShell('chkconfig --add ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
if not app_debug:
|
||||
os_name = mw.getOs()
|
||||
if os_name == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
initd_bin = getInitDFile()
|
||||
os.remove(initd_bin)
|
||||
mw.execShell('chkconfig --del ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def runLog():
|
||||
log_path = getServerDir() + '/log/gogs.log'
|
||||
return log_path
|
||||
|
||||
|
||||
def postReceiveLog():
|
||||
log_path = getServerDir() + '/log/hooks/post-receive.log'
|
||||
return log_path
|
||||
|
||||
|
||||
def getGogsConf():
|
||||
gets = [
|
||||
{'name': 'DOMAIN', 'type': -1, 'ps': '服务器域名'},
|
||||
{'name': 'ROOT_URL', 'type': -1, 'ps': '公开的完整URL路径'},
|
||||
{'name': 'HTTP_ADDR', 'type': -1, 'ps': '应用HTTP监听地址'},
|
||||
{'name': 'HTTP_PORT', 'type': -1, 'ps': '应用 HTTP 监听端口号'},
|
||||
|
||||
{'name': 'START_SSH_SERVER', 'type': 2, 'ps': '启动内置SSH服务器'},
|
||||
{'name': 'SSH_PORT', 'type': -1, 'ps': 'SSH 端口号'},
|
||||
|
||||
{'name': 'REQUIRE_SIGNIN_VIEW', 'type': 2, 'ps': '强制登录浏览'},
|
||||
{'name': 'ENABLE_CAPTCHA', 'type': 2, 'ps': '启用验证码服务'},
|
||||
{'name': 'DISABLE_REGISTRATION', 'type': 2, 'ps': '禁止注册,只能由管理员创建帐号'},
|
||||
{'name': 'ENABLE_NOTIFY_MAIL', 'type': 2, 'ps': '是否开启邮件通知'},
|
||||
|
||||
{'name': 'FORCE_PRIVATE', 'type': 2, 'ps': '强制要求所有新建的仓库都是私有'},
|
||||
|
||||
{'name': 'SHOW_FOOTER_BRANDING', 'type': 2, 'ps': 'Gogs推广信息'},
|
||||
{'name': 'SHOW_FOOTER_VERSION', 'type': 2, 'ps': 'Gogs版本信息'},
|
||||
{'name': 'SHOW_FOOTER_TEMPLATE_LOAD_TIME', 'type': 2, 'ps': 'Gogs模板加载时间'},
|
||||
]
|
||||
conf = mw.readFile(getConf())
|
||||
result = []
|
||||
|
||||
for g in gets:
|
||||
rep = g['name'] + '\s*=\s*(.*)'
|
||||
tmp = re.search(rep, conf)
|
||||
if not tmp:
|
||||
continue
|
||||
g['value'] = tmp.groups()[0]
|
||||
result.append(g)
|
||||
return mw.getJson(result)
|
||||
|
||||
|
||||
def submitGogsConf():
|
||||
gets = ['DOMAIN',
|
||||
'ROOT_URL',
|
||||
'HTTP_ADDR',
|
||||
'HTTP_PORT',
|
||||
'START_SSH_SERVER',
|
||||
'SSH_PORT',
|
||||
'REQUIRE_SIGNIN_VIEW',
|
||||
'FORCE_PRIVATE',
|
||||
'ENABLE_CAPTCHA',
|
||||
'DISABLE_REGISTRATION',
|
||||
'ENABLE_NOTIFY_MAIL',
|
||||
'SHOW_FOOTER_BRANDING',
|
||||
'SHOW_FOOTER_VERSION',
|
||||
'SHOW_FOOTER_TEMPLATE_LOAD_TIME']
|
||||
args = getArgs()
|
||||
filename = getConf()
|
||||
conf = mw.readFile(filename)
|
||||
for g in gets:
|
||||
if g in args:
|
||||
rep = g + '\s*=\s*(.*)'
|
||||
val = g + ' = ' + args[g]
|
||||
conf = re.sub(rep, val, conf)
|
||||
mw.writeFile(filename, conf)
|
||||
reload()
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
|
||||
def userList():
|
||||
import math
|
||||
args = getArgs()
|
||||
|
||||
page = 1
|
||||
page_size = 10
|
||||
search = ''
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
data = {}
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
|
||||
pm = pMysqlDb()
|
||||
start = (page - 1) * page_size
|
||||
list_count = pm.query('select count(id) as num from user')
|
||||
count = list_count[0][0]
|
||||
|
||||
list_data = pm.query(
|
||||
'select id,name,email from user order by id desc limit ' + str(start) + ',' + str(page_size))
|
||||
|
||||
page_info = {'count': count, 'p': page,
|
||||
'row': page_size, 'tojs': 'gogsUserList'}
|
||||
data['list'] = mw.getPage(page_info)
|
||||
data['page'] = page
|
||||
data['page_size'] = page_size
|
||||
data['page_count'] = int(math.ceil(count / page_size))
|
||||
data['data'] = list_data
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
|
||||
def getAllUserProject(user, search=''):
|
||||
path = getRootPath() + '/' + user
|
||||
dlist = []
|
||||
if os.path.exists(path):
|
||||
for filename in os.listdir(path):
|
||||
tmp = {}
|
||||
filePath = path + '/' + filename
|
||||
if os.path.isdir(filePath):
|
||||
if search == '':
|
||||
tmp['name'] = filename.replace('.git', '')
|
||||
dlist.append(tmp)
|
||||
else:
|
||||
if filename.find(search) != -1:
|
||||
tmp['name'] = filename.replace('.git', '')
|
||||
dlist.append(tmp)
|
||||
return dlist
|
||||
|
||||
|
||||
def checkProjectListIsHasScript(user, data):
|
||||
path = getRootPath() + '/' + user
|
||||
for x in range(len(data)):
|
||||
name = data[x]['name'] + '.git'
|
||||
path_tmp = path + '/' + name + '/custom_hooks/post-receive'
|
||||
if os.path.exists(path_tmp):
|
||||
data[x]['has_hook'] = True
|
||||
else:
|
||||
data[x]['has_hook'] = False
|
||||
return data
|
||||
|
||||
|
||||
def userProjectList():
|
||||
import math
|
||||
args = getArgs()
|
||||
# print args
|
||||
|
||||
page = 1
|
||||
page_size = 5
|
||||
search = ''
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(False, '缺少参数name')
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
data = {}
|
||||
|
||||
ulist = getAllUserProject(args['name'])
|
||||
dlist_sum = len(ulist)
|
||||
|
||||
start = (page - 1) * page_size
|
||||
ret_data = ulist[start:start + page_size]
|
||||
ret_data = checkProjectListIsHasScript(args['name'], ret_data)
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
data['data'] = ret_data
|
||||
data['args'] = args
|
||||
data['list'] = mw.getPage(
|
||||
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectList'})
|
||||
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
|
||||
def projectScriptEdit():
|
||||
args = getArgs()
|
||||
|
||||
if not 'user' in args:
|
||||
return mw.returnJson(True, 'username missing')
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(True, 'project name missing')
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
post_receive = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/commit'
|
||||
if os.path.exists(post_receive):
|
||||
return mw.returnJson(True, 'OK', {'path': post_receive})
|
||||
else:
|
||||
return mw.returnJson(False, 'file does not exist')
|
||||
|
||||
|
||||
def projectScriptLoad():
|
||||
args = getArgs()
|
||||
if not 'user' in args:
|
||||
return mw.returnJson(True, 'username missing')
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(True, 'project name missing')
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
path = getRootPath() + '/' + user + '/' + name
|
||||
post_receive_tpl = getPluginDir() + '/hook/post-receive.tpl'
|
||||
post_receive = path + '/custom_hooks/post-receive'
|
||||
|
||||
if not os.path.exists(path + '/custom_hooks'):
|
||||
mw.execShell('mkdir -p ' + path + '/custom_hooks')
|
||||
|
||||
pct_content = mw.readFile(post_receive_tpl)
|
||||
pct_content = pct_content.replace('{$PATH}', path + '/custom_hooks')
|
||||
mw.writeFile(post_receive, pct_content)
|
||||
mw.execShell('chmod 777 ' + post_receive)
|
||||
|
||||
commit_tpl = getPluginDir() + '/hook/commit.tpl'
|
||||
commit = path + '/custom_hooks/commit'
|
||||
|
||||
codeDir = mw.getRootDir() + '/git'
|
||||
|
||||
cc_content = mw.readFile(commit_tpl)
|
||||
|
||||
sshUrl = 'http://127.0.0.1:' + getHttpPort()
|
||||
cc_content = cc_content.replace('{$GITROOTURL}', sshUrl)
|
||||
cc_content = cc_content.replace('{$CODE_DIR}', codeDir)
|
||||
cc_content = cc_content.replace('{$USERNAME}', user)
|
||||
cc_content = cc_content.replace('{$PROJECT}', args['name'])
|
||||
cc_content = cc_content.replace('{$WEB_ROOT}', mw.getWwwDir())
|
||||
mw.writeFile(commit, cc_content)
|
||||
mw.execShell('chmod 777 ' + commit)
|
||||
|
||||
return 'ok'
|
||||
|
||||
|
||||
def projectScriptUnload():
|
||||
args = getArgs()
|
||||
if not 'user' in args:
|
||||
return mw.returnJson(True, 'username missing')
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(True, 'project name missing')
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
post_receive = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/post-receive'
|
||||
mw.execShell('rm -f ' + post_receive)
|
||||
|
||||
commit = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/commit'
|
||||
mw.execShell('rm -f ' + commit)
|
||||
return 'ok'
|
||||
|
||||
|
||||
def projectScriptDebug():
|
||||
args = getArgs()
|
||||
if not 'user' in args:
|
||||
return mw.returnJson(True, 'username missing')
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(True, 'project name missing')
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
commit_log = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/sh.log'
|
||||
|
||||
data = {}
|
||||
if os.path.exists(commit_log):
|
||||
data['status'] = True
|
||||
data['path'] = commit_log
|
||||
else:
|
||||
data['status'] = False
|
||||
data['msg'] = '没有日志文件'
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def gogsEdit():
|
||||
data = {}
|
||||
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
|
||||
data['commit'] = getPluginDir() + '/hook/commit.tpl'
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def getRsaPublic():
|
||||
path = getHomeDir()
|
||||
path += '/.ssh/id_rsa.pub'
|
||||
|
||||
content = mw.readFile(path)
|
||||
|
||||
data = {}
|
||||
data['mw'] = content
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def getTotalStatistics():
|
||||
st = status()
|
||||
data = {}
|
||||
if st.strip() == 'start':
|
||||
pm = pMysqlDb()
|
||||
list_count = pm.query('select count(id) as num from repository')
|
||||
|
||||
if list_count.find("error") > -1:
|
||||
data['status'] = False
|
||||
data['count'] = 0
|
||||
return mw.returnJson(False, 'fail', data)
|
||||
|
||||
data['status'] = True
|
||||
data['count'] = count
|
||||
data['ver'] = mw.readFile(getServerDir() + '/version.pl').strip()
|
||||
return mw.returnJson(True, 'ok', data)
|
||||
|
||||
data['status'] = False
|
||||
data['count'] = 0
|
||||
return mw.returnJson(False, 'fail', data)
|
||||
|
||||
|
||||
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_log':
|
||||
print(runLog())
|
||||
elif func == 'post_receive_log':
|
||||
print(postReceiveLog())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'init_conf':
|
||||
print(getInitdConf())
|
||||
elif func == 'get_gogs_conf':
|
||||
print(getGogsConf())
|
||||
elif func == 'submit_gogs_conf':
|
||||
print(submitGogsConf())
|
||||
elif func == 'user_list':
|
||||
print(userList())
|
||||
elif func == 'user_project_list':
|
||||
print(userProjectList())
|
||||
elif func == 'project_script_edit':
|
||||
print(projectScriptEdit())
|
||||
elif func == 'project_script_load':
|
||||
print(projectScriptLoad())
|
||||
elif func == 'project_script_unload':
|
||||
print(projectScriptUnload())
|
||||
elif func == 'project_script_debug':
|
||||
print(projectScriptDebug())
|
||||
elif func == 'gogs_edit':
|
||||
print(gogsEdit())
|
||||
elif func == 'get_rsa_public':
|
||||
print(getRsaPublic())
|
||||
elif func == 'get_total_statistics':
|
||||
print(getTotalStatistics())
|
||||
else:
|
||||
print('fail')
|
||||
@@ -1,63 +0,0 @@
|
||||
APP_NAME = Gogs
|
||||
RUN_USER = {$RUN_USER}
|
||||
RUN_MODE = prod
|
||||
|
||||
[database]
|
||||
DB_TYPE = mysql
|
||||
HOST = 127.0.0.1:3306
|
||||
NAME = gogs
|
||||
USER = gogs
|
||||
PASSWD = gogs
|
||||
SSL_MODE = disable
|
||||
PATH = data/gogs.db
|
||||
|
||||
[repository]
|
||||
ROOT = {$ROOT_PATH}/gogs-repositories
|
||||
FORCE_PRIVATE = true
|
||||
|
||||
[server]
|
||||
DOMAIN = 127.0.0.1
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL = http://127.0.0.1:3000/
|
||||
DISABLE_SSH = true
|
||||
SSH_PORT = 2000
|
||||
START_SSH_SERVER = false
|
||||
OFFLINE_MODE = false
|
||||
LANDING_PAGE = home
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
HOST = smtp.163.com:465
|
||||
USER = midoks@163.com
|
||||
PASSWD = ***
|
||||
USE_PLAIN_TEXT = true
|
||||
|
||||
[service]
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
DISABLE_REGISTRATION = true
|
||||
ENABLE_CAPTCHA = true
|
||||
REQUIRE_SIGNIN_VIEW = true
|
||||
|
||||
[picture]
|
||||
DISABLE_GRAVATAR = false
|
||||
ENABLE_FEDERATED_AVATAR = false
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
|
||||
[log]
|
||||
MODE = console, file
|
||||
LEVEL = Info
|
||||
ROOT_PATH = {$SERVER_PATH}/gogs/log
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = jmGSJXDBH5Ng4wt
|
||||
|
||||
|
||||
[other]
|
||||
SHOW_FOOTER_BRANDING = false
|
||||
SHOW_FOOTER_VERSION = false
|
||||
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo `date`
|
||||
|
||||
GITADDR="{$GITROOTURL}/{$USERNAME}/{$PROJECT}.git"
|
||||
GIT_SDIR="{$CODE_DIR}"
|
||||
|
||||
GIT_USER_DIR="${GIT_SDIR}/{$USERNAME}"
|
||||
GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
|
||||
|
||||
|
||||
git config --global credential.helper store
|
||||
|
||||
# echo $GIT_PROJECT_DIR
|
||||
if [ ! -d $GIT_PROJECT_DIR ];then
|
||||
mkdir -p $GIT_USER_DIR && cd $GIT_USER_DIR
|
||||
git clone $GITADDR
|
||||
fi
|
||||
|
||||
unset GIT_DIR
|
||||
cd $GIT_PROJECT_DIR && git pull
|
||||
|
||||
# func 2
|
||||
# cd $GIT_PROJECT_DIR && env -i git pull origin master
|
||||
|
||||
|
||||
#更新的目的地址
|
||||
WEB_PATH={$WEB_ROOT}/{$USERNAME}/{$PROJECT}
|
||||
mkdir -p $WEB_PATH
|
||||
|
||||
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
|
||||
sysName=`uname`
|
||||
if [ $sysName == 'Darwin' ]; then
|
||||
USER=$(who | sed -n "2,1p" |awk '{print $1}')
|
||||
chown -R $USER:staff $WEB_PATH
|
||||
else
|
||||
chown -R www:www $WEB_PATH
|
||||
fi
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo `date`
|
||||
|
||||
GITADDR="{$GITROOTURL}/{$USERNAME}/{$PROJECT}"
|
||||
GIT_SDIR="{$CODE_DIR}"
|
||||
|
||||
GIT_USER_DIR="${GIT_SDIR}/{$USERNAME}"
|
||||
GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
|
||||
|
||||
# echo $GIT_PROJECT_DIR
|
||||
if [ ! -d $GIT_PROJECT_DIR ];then
|
||||
mkdir -p $GIT_USER_DIR && cd $GIT_USER_DIR
|
||||
git clone $GITADDR
|
||||
fi
|
||||
|
||||
unset GIT_DIR
|
||||
cd $GIT_PROJECT_DIR && git pull
|
||||
|
||||
# func 2
|
||||
# cd $GIT_PROJECT_DIR && env -i git pull origin master
|
||||
|
||||
|
||||
|
||||
WEB_PATH={$WEB_ROOT}/{$USERNAME}/{$PROJECT}
|
||||
mkdir -p $WEB_PATH
|
||||
|
||||
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
|
||||
sysName=`uname`
|
||||
if [ $sysName == 'Darwin' ]; then
|
||||
USER=$(who | sed -n "2,1p" |awk '{print $1}')
|
||||
chown -R $USER:staff $WEB_PATH
|
||||
else
|
||||
chown -R www:www $WEB_PATH
|
||||
fi
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
sh -x {$PATH}/commit 2>{$PATH}/sh.log
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,23 +0,0 @@
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('gogs');">服务</p>
|
||||
<p onclick="pluginInitD('gogs');">自启动</p>
|
||||
<!-- <p onclick="pluginConfig('gogs',null, 'init_conf');">启动配置</p> -->
|
||||
<p onclick="gogsEdit();">手动编辑</p>
|
||||
<p onclick="pluginConfig('gogs',null, 'conf');">配置文件</p>
|
||||
<p onclick="gogsSetConfig();">配置修改</p>
|
||||
<p onclick="gogsUserList();">用户列表</p>
|
||||
<p onclick="pluginLogs('gogs',null,'run_log');">运行日志</p>
|
||||
<p onclick="pluginLogs('gogs',null,'post_receive_log');" title="提交post-receive日志">提交日志</p>
|
||||
<p onclick="gogsRead();">使用说明</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=gogs&f=js/gogs.js");
|
||||
pluginService('gogs');
|
||||
</script>
|
||||
@@ -1,749 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
|
||||
# cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
|
||||
# info = mw.execShell(cmd)
|
||||
# p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
|
||||
# sys.path.append(p)
|
||||
|
||||
import psutil
|
||||
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'gogs'
|
||||
|
||||
|
||||
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 getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
t = t.split(':', 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 getInitdConfTpl():
|
||||
path = getPluginDir() + "/init.d/gogs.tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getInitdConf():
|
||||
path = getServerDir() + "/init.d/gogs"
|
||||
return path
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/custom/conf/app.ini"
|
||||
return path
|
||||
|
||||
|
||||
def getConfTpl():
|
||||
path = getPluginDir() + "/conf/app.ini"
|
||||
return path
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def getHomeDir():
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
return '/Users/' + user
|
||||
else:
|
||||
return '/root'
|
||||
|
||||
|
||||
def getRunUser():
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
return user
|
||||
else:
|
||||
return 'root'
|
||||
|
||||
__SR = '''#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
export USER=%s
|
||||
export HOME=%s && ''' % ( getRunUser(), getHomeDir())
|
||||
|
||||
|
||||
def contentReplace(content):
|
||||
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$RUN_USER}', getRunUser())
|
||||
content = content.replace('{$HOME_DIR}', getHomeDir())
|
||||
|
||||
return content
|
||||
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitdConfTpl()
|
||||
service_path = mw.getServerDir()
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# conf_bin = getConf()
|
||||
# if not os.path.exists(conf_bin):
|
||||
# mw.execShell('mkdir -p ' + getServerDir() + '/custom/conf')
|
||||
# conf_tpl = getConfTpl()
|
||||
# content = mw.readFile(conf_tpl)
|
||||
# content = contentReplace(content)
|
||||
# mw.writeFile(conf_bin, content)
|
||||
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/gogs.service'
|
||||
systemServiceTpl = getPluginDir() + '/init.d/gogs.service.tpl'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
service_path = mw.getServerDir()
|
||||
se_content = mw.readFile(systemServiceTpl)
|
||||
se_content = se_content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(systemService, se_content)
|
||||
mw.execShell('systemctl daemon-reload')
|
||||
|
||||
log_path = getServerDir() + '/log'
|
||||
if not os.path.exists(log_path):
|
||||
os.mkdir(log_path)
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def getRootUrl():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'ROOT_URL\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if tmp:
|
||||
return tmp.groups()[0]
|
||||
|
||||
rep = 'EXTERNAL_URL\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if tmp:
|
||||
return tmp.groups()[0]
|
||||
return ''
|
||||
|
||||
|
||||
def getSshPort():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'SSH_PORT\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getHttpPort():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'HTTP_PORT\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getRootPath():
|
||||
content = mw.readFile(getConf())
|
||||
rep = 'ROOT\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
if not tmp:
|
||||
return ''
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getDbConfValue():
|
||||
conf = getConf()
|
||||
if not os.path.exists(conf):
|
||||
return {}
|
||||
|
||||
content = mw.readFile(conf)
|
||||
rep_scope = "\[database\](.*?)\["
|
||||
tmp = re.findall(rep_scope, content, re.S)
|
||||
|
||||
rep = '(\w*)\s*=\s*(.*)'
|
||||
tmp = re.findall(rep, tmp[0])
|
||||
r = {}
|
||||
for x in range(len(tmp)):
|
||||
k = tmp[x][0]
|
||||
v = tmp[x][1]
|
||||
r[k] = v
|
||||
return r
|
||||
|
||||
|
||||
def pMysqlDb(conf):
|
||||
host = conf['HOST'].split(':')
|
||||
# pymysql
|
||||
db = mw.getMyORM()
|
||||
# MySQLdb |
|
||||
# db = mw.getMyORMDb()
|
||||
|
||||
db.setPort(int(host[1]))
|
||||
db.setUser(conf['USER'])
|
||||
db.setPwd(conf['PASSWD'])
|
||||
db.setDbName(conf['NAME'])
|
||||
# db.setSocket(getSocketFile())
|
||||
db.setCharset("utf8")
|
||||
return db
|
||||
|
||||
|
||||
def pSqliteDb(conf):
|
||||
# print(conf)
|
||||
import db
|
||||
psDb = db.Sql()
|
||||
|
||||
# 默认
|
||||
gsdir = getServerDir() + '/data'
|
||||
dbname = 'gogs'
|
||||
if conf['PATH'][0] == '/':
|
||||
# 绝对路径
|
||||
pass
|
||||
else:
|
||||
path = conf['PATH'].split('/')
|
||||
gsdir = getServerDir() + '/' + path[0]
|
||||
dbname = path[1].split('.')[0]
|
||||
|
||||
# print(gsdir, dbname)
|
||||
psDb.dbPos(gsdir, dbname)
|
||||
return psDb
|
||||
|
||||
|
||||
def getGogsDbType(conf):
|
||||
|
||||
if 'DB_TYPE' in conf:
|
||||
return conf['DB_TYPE']
|
||||
|
||||
if 'TYPE' in conf:
|
||||
return conf['TYPE']
|
||||
|
||||
return 'NONE'
|
||||
|
||||
|
||||
def pQuery(sql):
|
||||
conf = getDbConfValue()
|
||||
gtype = getGogsDbType(conf)
|
||||
if gtype == 'sqlite3':
|
||||
db = pSqliteDb(conf)
|
||||
data = db.query(sql, []).fetchall()
|
||||
return data
|
||||
elif gtype == 'mysql':
|
||||
db = pMysqlDb(conf)
|
||||
return db.query(sql)
|
||||
|
||||
print("仅支持mysql|sqlite3配置")
|
||||
exit(0)
|
||||
|
||||
|
||||
def isSqlError(mysqlMsg):
|
||||
# 检测数据库执行错误
|
||||
_mysqlMsg = str(mysqlMsg)
|
||||
# print _mysqlMsg
|
||||
if "MySQLdb" in _mysqlMsg:
|
||||
return mw.returnData(False, 'MySQLdb组件缺失! <br>进入SSH命令行输入: pip install mysql-python')
|
||||
if "2002," in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||
if "using password:" in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库管理密码错误!')
|
||||
if "Connection refused" in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
|
||||
if "1133," in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库用户不存在!')
|
||||
if "1007," in _mysqlMsg:
|
||||
return mw.returnData(False, '数据库已经存在!')
|
||||
if "1044," in _mysqlMsg:
|
||||
return mw.returnData(False, mysqlMsg[1])
|
||||
if "2003," in _mysqlMsg:
|
||||
return mw.returnData(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
|
||||
return mw.returnData(True, 'OK')
|
||||
|
||||
|
||||
def gogsOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
data = mw.execShell('systemctl ' + method + ' gogs')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return 'fail'
|
||||
|
||||
data = mw.execShell(__SR + file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[0]
|
||||
|
||||
|
||||
def start():
|
||||
return gogsOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return gogsOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
return gogsOp('restart')
|
||||
|
||||
|
||||
def reload():
|
||||
return gogsOp('reload')
|
||||
|
||||
|
||||
def initdStatus():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
shell_cmd = 'systemctl status gogs | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl enable gogs')
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl disable gogs')
|
||||
return 'ok'
|
||||
|
||||
|
||||
def runLog():
|
||||
log_path = getServerDir() + '/log/gogs.log'
|
||||
return log_path
|
||||
|
||||
|
||||
def postReceiveLog():
|
||||
log_path = getServerDir() + '/log/hooks/post-receive.log'
|
||||
return log_path
|
||||
|
||||
|
||||
def getGogsConf():
|
||||
conf = getConf()
|
||||
if not os.path.exists(conf):
|
||||
return mw.returnJson(False, "请先安装初始化!<br/>默认地址:http://" + mw.getLocalIp() + ":3000")
|
||||
|
||||
gets = [
|
||||
{'name': 'DOMAIN', 'type': -1, 'ps': '服务器域名'},
|
||||
{'name': 'ROOT_URL', 'type': -1, 'ps': '公开的完整URL路径'},
|
||||
{'name': 'HTTP_ADDR', 'type': -1, 'ps': '应用HTTP监听地址'},
|
||||
{'name': 'HTTP_PORT', 'type': -1, 'ps': '应用 HTTP 监听端口号'},
|
||||
|
||||
{'name': 'START_SSH_SERVER', 'type': 2, 'ps': '启动内置SSH服务器'},
|
||||
{'name': 'SSH_PORT', 'type': -1, 'ps': 'SSH 端口号'},
|
||||
|
||||
{'name': 'REQUIRE_SIGNIN_VIEW', 'type': 2, 'ps': '强制登录浏览'},
|
||||
{'name': 'ENABLE_CAPTCHA', 'type': 2, 'ps': '启用验证码服务'},
|
||||
{'name': 'DISABLE_REGISTRATION', 'type': 2, 'ps': '禁止注册,只能由管理员创建帐号'},
|
||||
{'name': 'ENABLE_NOTIFY_MAIL', 'type': 2, 'ps': '是否开启邮件通知'},
|
||||
|
||||
{'name': 'FORCE_PRIVATE', 'type': 2, 'ps': '强制要求所有新建的仓库都是私有'},
|
||||
|
||||
{'name': 'SHOW_FOOTER_BRANDING', 'type': 2, 'ps': 'Gogs推广信息'},
|
||||
{'name': 'SHOW_FOOTER_VERSION', 'type': 2, 'ps': 'Gogs版本信息'},
|
||||
{'name': 'SHOW_FOOTER_TEMPLATE_LOAD_TIME', 'type': 2, 'ps': 'Gogs模板加载时间'},
|
||||
]
|
||||
conf = mw.readFile(conf)
|
||||
result = []
|
||||
|
||||
for g in gets:
|
||||
rep = g['name'] + '\s*=\s*(.*)'
|
||||
tmp = re.search(rep, conf)
|
||||
if not tmp:
|
||||
continue
|
||||
g['value'] = tmp.groups()[0]
|
||||
result.append(g)
|
||||
return mw.returnJson(True, 'OK', result)
|
||||
|
||||
|
||||
def submitGogsConf():
|
||||
gets = ['DOMAIN',
|
||||
'ROOT_URL',
|
||||
'HTTP_ADDR',
|
||||
'HTTP_PORT',
|
||||
'START_SSH_SERVER',
|
||||
'SSH_PORT',
|
||||
'REQUIRE_SIGNIN_VIEW',
|
||||
'FORCE_PRIVATE',
|
||||
'ENABLE_CAPTCHA',
|
||||
'DISABLE_REGISTRATION',
|
||||
'ENABLE_NOTIFY_MAIL',
|
||||
'SHOW_FOOTER_BRANDING',
|
||||
'SHOW_FOOTER_VERSION',
|
||||
'SHOW_FOOTER_TEMPLATE_LOAD_TIME']
|
||||
args = getArgs()
|
||||
filename = getConf()
|
||||
conf = mw.readFile(filename)
|
||||
for g in gets:
|
||||
if g in args:
|
||||
rep = g + '\s*=\s*(.*)'
|
||||
val = g + ' = ' + args[g]
|
||||
conf = re.sub(rep, val, conf)
|
||||
mw.writeFile(filename, conf)
|
||||
reload()
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
|
||||
def userList():
|
||||
|
||||
conf = getConf()
|
||||
if not os.path.exists(conf):
|
||||
return mw.returnJson(False, "请先安装初始化!<br/>默认地址:http://" + mw.getLocalIp() + ":3000")
|
||||
|
||||
import math
|
||||
args = getArgs()
|
||||
|
||||
data = checkArgs(args, ['page', 'page_size'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
page = int(args['page'])
|
||||
page_size = int(args['page_size'])
|
||||
search = ''
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
data = {}
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
|
||||
start = (page - 1) * page_size
|
||||
list_count = pQuery('select count(id) as num from user')
|
||||
count = list_count[0]["num"]
|
||||
list_data = pQuery(
|
||||
'select id,name,email from user order by id desc limit ' + str(start) + ',' + str(page_size))
|
||||
data['list'] = mw.getPage({'count': count, 'p': page,
|
||||
'row': page_size, 'tojs': 'gogsUserList'})
|
||||
data['page'] = page
|
||||
data['page_size'] = page_size
|
||||
data['page_count'] = int(math.ceil(count / page_size))
|
||||
data['data'] = list_data
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
|
||||
def getAllUserProject(user, search=''):
|
||||
path = getRootPath() + '/' + user
|
||||
dlist = []
|
||||
if os.path.exists(path):
|
||||
for filename in os.listdir(path):
|
||||
tmp = {}
|
||||
filePath = path + '/' + filename
|
||||
if os.path.isdir(filePath):
|
||||
if search == '':
|
||||
tmp['name'] = filename.replace('.git', '')
|
||||
dlist.append(tmp)
|
||||
else:
|
||||
if filename.find(search) != -1:
|
||||
tmp['name'] = filename.replace('.git', '')
|
||||
dlist.append(tmp)
|
||||
return dlist
|
||||
|
||||
|
||||
def checkProjectListIsHasScript(user, data):
|
||||
path = getRootPath() + '/' + user
|
||||
for x in range(len(data)):
|
||||
name = data[x]['name'] + '.git'
|
||||
path_tmp = path + '/' + name + '/custom_hooks/post-receive'
|
||||
if os.path.exists(path_tmp):
|
||||
data[x]['has_hook'] = True
|
||||
else:
|
||||
data[x]['has_hook'] = False
|
||||
return data
|
||||
|
||||
|
||||
def userProjectList():
|
||||
import math
|
||||
args = getArgs()
|
||||
# print args
|
||||
|
||||
page = 1
|
||||
page_size = 5
|
||||
search = ''
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(False, '缺少参数name')
|
||||
if 'page' in args:
|
||||
page = int(args['page'])
|
||||
|
||||
if 'page_size' in args:
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
data = {}
|
||||
|
||||
ulist = getAllUserProject(args['name'])
|
||||
dlist_sum = len(ulist)
|
||||
|
||||
start = (page - 1) * page_size
|
||||
ret_data = ulist[start:start + page_size]
|
||||
ret_data = checkProjectListIsHasScript(args['name'], ret_data)
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
data['data'] = ret_data
|
||||
data['args'] = args
|
||||
data['list'] = mw.getPage(
|
||||
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectList'})
|
||||
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
|
||||
def projectScriptEdit():
|
||||
args = getArgs()
|
||||
|
||||
if not 'user' in args:
|
||||
return mw.returnJson(True, 'username missing')
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(True, 'project name missing')
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
post_receive = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/commit'
|
||||
if os.path.exists(post_receive):
|
||||
return mw.returnJson(True, 'OK', {'path': post_receive})
|
||||
else:
|
||||
return mw.returnJson(False, 'file does not exist')
|
||||
|
||||
|
||||
def projectScriptLoad():
|
||||
args = getArgs()
|
||||
if not 'user' in args:
|
||||
return mw.returnJson(True, 'username missing')
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(True, 'project name missing')
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
path = getRootPath() + '/' + user + '/' + name
|
||||
post_receive_tpl = getPluginDir() + '/hook/post-receive.tpl'
|
||||
post_receive = path + '/custom_hooks/post-receive'
|
||||
|
||||
if not os.path.exists(path + '/custom_hooks'):
|
||||
mw.execShell('mkdir -p ' + path + '/custom_hooks')
|
||||
|
||||
pct_content = mw.readFile(post_receive_tpl)
|
||||
pct_content = pct_content.replace('{$PATH}', path + '/custom_hooks')
|
||||
mw.writeFile(post_receive, pct_content)
|
||||
mw.execShell('chmod 777 ' + post_receive)
|
||||
|
||||
commit_tpl = getPluginDir() + '/hook/commit.tpl'
|
||||
commit = path + '/custom_hooks/commit'
|
||||
|
||||
codeDir = mw.getRootDir() + '/git'
|
||||
|
||||
cc_content = mw.readFile(commit_tpl)
|
||||
|
||||
gitPath = getRootPath()
|
||||
cc_content = cc_content.replace('{$GITROOTURL}', gitPath)
|
||||
cc_content = cc_content.replace('{$CODE_DIR}', codeDir)
|
||||
cc_content = cc_content.replace('{$USERNAME}', user)
|
||||
cc_content = cc_content.replace('{$PROJECT}', args['name'])
|
||||
cc_content = cc_content.replace('{$WEB_ROOT}', mw.getWwwDir())
|
||||
mw.writeFile(commit, cc_content)
|
||||
mw.execShell('chmod 777 ' + commit)
|
||||
|
||||
return 'ok'
|
||||
|
||||
|
||||
def projectScriptUnload():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
post_receive = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/post-receive'
|
||||
mw.execShell('rm -f ' + post_receive)
|
||||
|
||||
commit = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/commit'
|
||||
mw.execShell('rm -f ' + commit)
|
||||
return 'ok'
|
||||
|
||||
|
||||
def projectScriptDebug():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
commit_log = getRootPath() + '/' + user + '/' + name + \
|
||||
'/custom_hooks/sh.log'
|
||||
|
||||
data = {}
|
||||
if os.path.exists(commit_log):
|
||||
data['status'] = True
|
||||
data['path'] = commit_log
|
||||
else:
|
||||
data['status'] = False
|
||||
data['msg'] = '没有日志文件'
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def gogsEdit():
|
||||
data = {}
|
||||
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
|
||||
data['commit'] = getPluginDir() + '/hook/commit.tpl'
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def getRsaPublic():
|
||||
path = getHomeDir()
|
||||
path += '/.ssh/id_rsa.pub'
|
||||
|
||||
content = mw.readFile(path)
|
||||
|
||||
data = {}
|
||||
data['mw'] = content
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def getTotalStatistics():
|
||||
st = status()
|
||||
data = {}
|
||||
if st.strip() == 'start':
|
||||
list_count = pQuery('select count(id) as num from repository')
|
||||
|
||||
if list_count.find("error") > -1:
|
||||
data['status'] = False
|
||||
data['count'] = 0
|
||||
return mw.returnJson(False, 'fail', data)
|
||||
|
||||
data['status'] = True
|
||||
data['count'] = count
|
||||
data['ver'] = mw.readFile(getServerDir() + '/version.pl').strip()
|
||||
return mw.returnJson(True, 'ok', data)
|
||||
|
||||
data['status'] = False
|
||||
data['count'] = 0
|
||||
return mw.returnJson(False, 'fail', data)
|
||||
|
||||
|
||||
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_log':
|
||||
print(runLog())
|
||||
elif func == 'post_receive_log':
|
||||
print(postReceiveLog())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'init_conf':
|
||||
print(getInitdConf())
|
||||
elif func == 'get_gogs_conf':
|
||||
print(getGogsConf())
|
||||
elif func == 'submit_gogs_conf':
|
||||
print(submitGogsConf())
|
||||
elif func == 'user_list':
|
||||
print(userList())
|
||||
elif func == 'user_project_list':
|
||||
print(userProjectList())
|
||||
elif func == 'project_script_edit':
|
||||
print(projectScriptEdit())
|
||||
elif func == 'project_script_load':
|
||||
print(projectScriptLoad())
|
||||
elif func == 'project_script_unload':
|
||||
print(projectScriptUnload())
|
||||
elif func == 'project_script_debug':
|
||||
print(projectScriptDebug())
|
||||
elif func == 'gogs_edit':
|
||||
print(gogsEdit())
|
||||
elif func == 'get_rsa_public':
|
||||
print(getRsaPublic())
|
||||
elif func == 'get_total_statistics':
|
||||
print(getTotalStatistics())
|
||||
else:
|
||||
print('fail')
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"ps": "Gogs是一款极易搭建的自助Git服务",
|
||||
"name": "gogs",
|
||||
"title": "Gogs",
|
||||
"versions": ["0.11.86","0.12.9"],
|
||||
"tip": "soft",
|
||||
"checks": "server/gogs",
|
||||
"path":"server/gogs",
|
||||
"author": "midoks",
|
||||
"date": "2018-04-01",
|
||||
"home": "https://gogs.io",
|
||||
"type": "Git服务器",
|
||||
"shell": "install.sh",
|
||||
"pid": "3",
|
||||
"sort": 7
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
[Unit]
|
||||
Description=Gogs
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
# Modify these two values and uncomment them if you have
|
||||
# repos with lots of files and get an HTTP error 500 because
|
||||
# of that
|
||||
###
|
||||
#LimitMEMLOCK=infinity
|
||||
#LimitNOFILE=65535
|
||||
Type=simple
|
||||
User=git
|
||||
Group=git
|
||||
WorkingDirectory={$SERVER_PATH}/gogs
|
||||
ExecStart={$SERVER_PATH}/gogs/gogs web
|
||||
ExecReload=/bin/kill -USR2 $MAINPID
|
||||
Restart=always
|
||||
Environment=USER=git HOME=/home/git
|
||||
|
||||
# Some distributions may not support these hardening directives. If you cannot start the service due
|
||||
# to an unknown option, comment out the ones not supported by your version of systemd.
|
||||
ProtectSystem=full
|
||||
PrivateDevices=yes
|
||||
PrivateTmp=yes
|
||||
NoNewPrivileges=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,12 +0,0 @@
|
||||
[Unit]
|
||||
Description=Gogs
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart={$SERVER_PATH}/gogs/init.d/gogs start
|
||||
ExecStop={$SERVER_PATH}/gogs/init.d/gogs stop
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,110 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# /etc/rc.d/init.d/gogs
|
||||
#
|
||||
# Runs the Gogs
|
||||
#
|
||||
#
|
||||
# chkconfig: - 85 15
|
||||
#
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: gogs
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Should-Start: mysql postgresql
|
||||
# Should-Stop: mysql postgresql
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start gogs at boot time.
|
||||
# Description: Control gogs.
|
||||
### END INIT INFO
|
||||
|
||||
# Source function library.
|
||||
if [ -f /etc/init.d/functions ];then
|
||||
. /etc/init.d/functions
|
||||
fi
|
||||
|
||||
if [ -f /etc/rc.d/init.d/functions ];then
|
||||
. /etc/rc.d/init.d/functions
|
||||
fi
|
||||
|
||||
# Default values
|
||||
export HOME={$HOME_DIR}
|
||||
export USER={$RUN_USER}
|
||||
NAME=gogs
|
||||
GOGS_HOME={$SERVER_PATH}/gogs
|
||||
GOGS_PATH=${GOGS_HOME}/$NAME
|
||||
GOGS_USER={$RUN_USER}
|
||||
SERVICENAME="Gogs"
|
||||
LOCKFILE=/tmp/gogs.lock
|
||||
LOGPATH=${GOGS_HOME}/log
|
||||
LOGFILE=${LOGPATH}/gogs.log
|
||||
RETVAL=0
|
||||
|
||||
|
||||
[ -r /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME
|
||||
DAEMON_OPTS="--check $NAME"
|
||||
[ ! -z "$GOGS_USER" ] && DAEMON_OPTS="$DAEMON_OPTS --user=${GOGS_USER}"
|
||||
|
||||
|
||||
status(){
|
||||
isStart=`ps -ef|grep 'gogs web' |grep -v grep|awk '{print $2}'`
|
||||
if [ "$isStart" == '' ];then
|
||||
echo -e "${SERVICENAME} not running"
|
||||
else
|
||||
echo -e "${SERVICENAME}(pid $(echo $isStart)) already running"
|
||||
fi
|
||||
}
|
||||
|
||||
start() {
|
||||
isStart=`ps -ef|grep 'gogs web' |grep -v grep|awk '{print $2}'`
|
||||
if [ "$isStart" != '' ];then
|
||||
echo "${SERVICENAME}(pid $(echo $isStart)) already running"
|
||||
return $RETVAL
|
||||
fi
|
||||
|
||||
cd ${GOGS_HOME}
|
||||
echo -e "Starting ${SERVICENAME}: \c"
|
||||
${GOGS_PATH} web > ${LOGFILE} 2>&1 &
|
||||
RETVAL=$?
|
||||
[ $RETVAL = 0 ] && touch ${LOCKFILE} && echo -e "\033[32mdone\033[0m"
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
||||
pids=`ps -ef|grep 'gogs web' |grep -v grep|awk '{print $2}'`
|
||||
arr=($pids)
|
||||
echo -e "Stopping gogs... \c"
|
||||
for p in ${arr[@]}
|
||||
do
|
||||
kill -9 $p
|
||||
done
|
||||
echo -e "\033[32mdone\033[0m"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
reload)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: ${NAME} {start|stop|status|restart}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $RETVAL
|
||||
@@ -1,106 +0,0 @@
|
||||
#!/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
|
||||
|
||||
|
||||
GOGS_DOWNLOAD='https://dl.gogs.io'
|
||||
|
||||
getOs(){
|
||||
os=`uname`
|
||||
if [ "Darwin" == "$os" ];then
|
||||
echo 'darwin'
|
||||
else
|
||||
echo 'linux'
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
getBit(){
|
||||
echo `getconf LONG_BIT`
|
||||
}
|
||||
|
||||
|
||||
Install_gogs()
|
||||
{
|
||||
pip3 install mysqlclient
|
||||
|
||||
mkdir -p $serverPath/source/gogs
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
version=$1
|
||||
os=`getOs`
|
||||
|
||||
# if id git &> /dev/null ;then
|
||||
# echo "git uid is `id -u git`"
|
||||
# echo "git shell is `grep "^git:" /etc/passwd |cut -d':' -f7 `"
|
||||
# else
|
||||
# groupadd git
|
||||
# useradd -g git git
|
||||
# fi
|
||||
|
||||
git config --global push.default simple
|
||||
|
||||
if [ "darwin" == "$os" ];then
|
||||
file=gogs_${version}_darwin_amd64.zip
|
||||
else
|
||||
file=gogs_${version}_linux_amd64.zip
|
||||
fi
|
||||
|
||||
if [ ! -f $serverPath/source/gogs/$file ];then
|
||||
wget -O $serverPath/source/gogs/$file ${GOGS_DOWNLOAD}/${version}/${file}
|
||||
fi
|
||||
|
||||
cd $serverPath/source/gogs && unzip -o $file -d gogs_${version}
|
||||
mv $serverPath/source/gogs/gogs_${version}/gogs/ $serverPath/gogs
|
||||
|
||||
|
||||
if [ -d $serverPath/gogs ];then
|
||||
echo $version > $serverPath/gogs/version.pl
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/gogs/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/gogs/index.py initd_install
|
||||
fi
|
||||
# if id -u gogs > /dev/null 2>&1; then
|
||||
# echo "gogs user exists"
|
||||
# else
|
||||
# useradd gogs
|
||||
# cp /etc/sudoers{,.`date +"%Y-%m-%d_%H-%M-%S"`}
|
||||
# echo "gogs ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||
# fi
|
||||
|
||||
echo 'install success' > $install_tmp
|
||||
}
|
||||
|
||||
Uninstall_gogs()
|
||||
{
|
||||
|
||||
if [ -f /usr/lib/systemd/system/gogs.service ];then
|
||||
systemctl stop gogs
|
||||
systemctl disable gogs
|
||||
rm -rf /usr/lib/systemd/system/gogs.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f $serverPath/gogs/initd/gogs ];then
|
||||
$serverPath/gogs/initd/gogs stop
|
||||
fi
|
||||
|
||||
rm -rf $serverPath/gogs
|
||||
echo 'uninstall success' > $install_tmp
|
||||
}
|
||||
|
||||
|
||||
action=$1
|
||||
version=$2
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_gogs $version
|
||||
else
|
||||
Uninstall_gogs $version
|
||||
fi
|
||||
@@ -1,352 +0,0 @@
|
||||
|
||||
function str2Obj(str){
|
||||
var data = {};
|
||||
kv = str.split('&');
|
||||
for(i in kv){
|
||||
v = kv[i].split('=');
|
||||
data[v[0]] = v[1];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function gogsPost(method,args,callback, title){
|
||||
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(str2Obj(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
|
||||
var _title = '正在获取...';
|
||||
if (typeof(title) != 'undefined'){
|
||||
_title = title;
|
||||
}
|
||||
|
||||
var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'gogs', 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 gogsSetConfig(){
|
||||
gogsPost('get_gogs_conf', '', function(data){
|
||||
var rrdata = $.parseJSON(data.data);
|
||||
if (!rrdata.status){
|
||||
layer.msg(rrdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
var rdata = rrdata.data;
|
||||
var mlist = '';
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
var w = '140';
|
||||
if (rdata[i].name == 'error_reporting') w = '250';
|
||||
var ibody = '<input style="width: ' + w + 'px;" class="bt-input-text mr5" name="' + rdata[i].name + '" value="' + rdata[i].value + '" type="text" >';
|
||||
switch (rdata[i].type) {
|
||||
case 0:
|
||||
var selected_1 = (rdata[i].value == 1) ? 'selected' : '';
|
||||
var selected_0 = (rdata[i].value == 0) ? 'selected' : '';
|
||||
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
|
||||
<option value="1" ' + selected_1 + '>开启</option>\
|
||||
<option value="0" ' + selected_0 + '>关闭</option>\
|
||||
</select>';
|
||||
break;
|
||||
case 1:
|
||||
var selected_1 = (rdata[i].value == 'On') ? 'selected' : '';
|
||||
var selected_0 = (rdata[i].value == 'Off') ? 'selected' : '';
|
||||
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
|
||||
<option value="On" ' + selected_1 + '>开启</option>\
|
||||
<option value="Off" ' + selected_0 + '>关闭</option></select>'
|
||||
break;
|
||||
case 2:
|
||||
var selected_1 = (rdata[i].value == 'true') ? 'selected' : '';
|
||||
var selected_0 = (rdata[i].value == 'false') ? 'selected' : '';
|
||||
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
|
||||
<option value="true" ' + selected_1 + '>开启</option>\
|
||||
<option value="false" ' + selected_0 + '>关闭</option></select>'
|
||||
break;
|
||||
}
|
||||
mlist += '<p><span>' + rdata[i].name + '</span>' + ibody + ', <font>' + rdata[i].ps + '</font></p>'
|
||||
}
|
||||
var html = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">\
|
||||
' + mlist + '\
|
||||
<div style="margin-top:10px; padding-right:15px" class="text-right">\
|
||||
<button class="btn btn-success btn-sm mr5" onclick="gogsSetConfig()">刷新</button>\
|
||||
<button class="btn btn-success btn-sm" onclick="submitGogsConf()">保存</button></div>\
|
||||
</div>';
|
||||
$(".soft-man-con").html(html);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//提交PHP配置
|
||||
function submitGogsConf() {
|
||||
var data = {
|
||||
DOMAIN: $("input[name='DOMAIN']").val(),
|
||||
ROOT_URL: $("input[name='ROOT_URL']").val(),
|
||||
HTTP_ADDR: $("select[name='HTTP_ADDR']").val(),
|
||||
HTTP_PORT: $("input[name='HTTP_PORT']").val(),
|
||||
START_SSH_SERVER: $("select[name='START_SSH_SERVER']").val() || 'false',
|
||||
SSH_PORT: $("input[name='SSH_PORT']").val(),
|
||||
REQUIRE_SIGNIN_VIEW: $("select[name='REQUIRE_SIGNIN_VIEW']").val() || 'false',
|
||||
ENABLE_CAPTCHA: $("select[name='ENABLE_CAPTCHA']").val() || 'true',
|
||||
DISABLE_REGISTRATION: $("select[name='DISABLE_REGISTRATION']").val() || 'false',
|
||||
ENABLE_NOTIFY_MAIL: $("select[name='ENABLE_NOTIFY_MAIL']").val() || 'false',
|
||||
FORCE_PRIVATE: $("select[name='FORCE_PRIVATE']").val() || 'false',
|
||||
SHOW_FOOTER_BRANDING: $("select[name='SHOW_FOOTER_BRANDING']").val() || 'false',
|
||||
SHOW_FOOTER_VERSION: $("select[name='SHOW_FOOTER_VERSION']").val() || 'false',
|
||||
SHOW_FOOTER_TEMPLATE_LOAD_TIME: $("select[name='SHOW_FOOTER_TEMPLATE_LOAD_TIME']").val() || 'false',
|
||||
};
|
||||
|
||||
gogsPost('submit_gogs_conf', data, function(ret_data){
|
||||
var rdata = $.parseJSON(ret_data.data);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
gogsSetConfig();
|
||||
});
|
||||
}
|
||||
|
||||
function gogsEdit(){
|
||||
|
||||
gogsPost('gogs_edit',{} , function(data){
|
||||
// console.log(data);
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var edit = '<p class="status">通用的手动编辑:</p>';
|
||||
edit +='<div class="sfm-opt">\
|
||||
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['post_receive']+'\');">post-receive.tpl</button>\
|
||||
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['commit']+'\');">commit.tpl</button>\
|
||||
</div>';
|
||||
$(".soft-man-con").html(edit);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function gogsUserList(page, search) {
|
||||
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['search'] = search;
|
||||
}
|
||||
|
||||
gogsPost('user_list', _data, function(data){
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (!rdata.status){
|
||||
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找用户名" id="find_user" style="height: 28px; border-radius: 3px;width: 435px;">';
|
||||
content += '<button class="btn btn-success btn-sm" onclick="userFind();">查找</button></div>';
|
||||
|
||||
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
|
||||
content += '<thead><tr>';
|
||||
content += '<th>序号</th>';
|
||||
content += '<th>用户或组织</th>';
|
||||
content += '<th>邮件地址</th>';
|
||||
content += '<th>操作(<a href="'+rdata['data']['root_url']+'" class="btlink" target="_blank">WEB管理</a>)</th>';
|
||||
content += '</tr></thead>';
|
||||
|
||||
content += '<tbody>';
|
||||
|
||||
ulist = rdata['data']['data'];
|
||||
for (i in ulist){
|
||||
email = ulist[i]["email"] == '' ? '无' : ulist[i]["email"];
|
||||
content += '<tr><td>'+ulist[i]["id"]+'</td>'+
|
||||
'<td>'+ulist[i]["name"]+'</td>'+
|
||||
'<td>'+email+'</td>'+
|
||||
'<td><a class="btlink" onclick="userProjectList(\''+ulist[i]["name"]+'\')">项目管理</a></td>'+
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
content += '</tbody>';
|
||||
content += '</table></div>';
|
||||
|
||||
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
|
||||
page += rdata['data']['list'];
|
||||
page += '</div></ul></div>';
|
||||
|
||||
content += page;
|
||||
|
||||
$(".soft-man-con").html(content);
|
||||
});
|
||||
}
|
||||
|
||||
function userProjectList(user, search){
|
||||
var req = {};
|
||||
if (!isNaN(user)){
|
||||
req['page'] = user;
|
||||
req['name'] = user = getCookie('gogsUserSelected');
|
||||
} else {
|
||||
req['page'] = 1;
|
||||
req['name'] = user;
|
||||
setCookie('gogsUserSelected', user);
|
||||
}
|
||||
|
||||
req['page_size'] = 5;
|
||||
req['search'] = '';
|
||||
if(typeof(search) != 'undefined'){
|
||||
req['search'] = search;
|
||||
}
|
||||
|
||||
$('.layui-layer-close1').click();
|
||||
gogsPost('user_project_list', req, function(data){
|
||||
var rdata = [];
|
||||
try {
|
||||
rdata = $.parseJSON(data.data);
|
||||
} catch(e){}
|
||||
|
||||
if (!rdata['status']){
|
||||
layer.msg(rdata['msg'], { icon: 2 });
|
||||
return;
|
||||
}
|
||||
|
||||
var list = '';
|
||||
// console.log(rdata);
|
||||
var project_list = rdata['data']['data'];
|
||||
for (i in project_list) {
|
||||
var name = project_list[i]['name'];
|
||||
list += '<tr><td>'+name+'</td>\
|
||||
<td>\
|
||||
<a class="btlink" target="_blank" href="'+rdata['data']['root_url']+user+'/'+name+'">源码</a> | \
|
||||
<a class="btlink" onclick="projectScript(\''+user+'\',\''+name+'\','+project_list[i]['has_hook']+');">脚本</a>\
|
||||
</td>\
|
||||
</tr>';
|
||||
}
|
||||
|
||||
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
|
||||
page += rdata['data']['list'];
|
||||
page += '</div></ul></div>';
|
||||
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '用户('+user+')项目列表',
|
||||
area: '500px',
|
||||
content:"<div class='bt-form pd20 c6'>\
|
||||
<div>\
|
||||
<div class='divtable' style='margin-top:5px;'>\
|
||||
<table class='table table-hover'>\
|
||||
<thead><tr><th>项目</th><th>操作</th></tr></thead>\
|
||||
<tbody>" + list + "</tbody>\
|
||||
</table>" +
|
||||
page +
|
||||
"</div></div></div>"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function projectScript(user, name,has_hook){
|
||||
// console.log(user,name,has_hook);
|
||||
var html = '';
|
||||
if (has_hook){
|
||||
html += '<button onclick="projectScriptEdit(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">手动编辑</button>';
|
||||
html += '<button onclick="projectScriptDebug(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">调试日志</button>';
|
||||
html += '<button onclick="projectScriptLoad(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">重新加载</button>';
|
||||
html += '<button onclick="projectScriptUnload(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">卸载脚本</button>';
|
||||
} else {
|
||||
html += '<button onclick="projectScriptLoad(\''+user+'\',\''+name+'\')" class="btn btn-default btn-sm">加载脚本</button>';
|
||||
}
|
||||
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '['+user+']['+name+']脚本设置',
|
||||
area: '240px',
|
||||
content:'<div class="change-default pd20">'+html+'</div>'
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptEdit(user,name){
|
||||
gogsPost('project_script_edit', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['data']['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptLoad(user,name){
|
||||
gogsPost('project_script_load', {'user':user,'name':name}, function(data){
|
||||
if (data.data != 'ok'){
|
||||
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
userProjectList(1);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptUnload(user,name){
|
||||
gogsPost('project_script_unload', {'user':user,'name':name}, function(data){
|
||||
if (data.data != 'ok'){
|
||||
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
userProjectList(1);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptDebug(user,name){
|
||||
gogsPost('project_script_debug', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getRsaPublic(){
|
||||
gogsPost('get_rsa_public', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var con = '<div class="tab-con">\
|
||||
<div class="myKeyCon ptb15">\
|
||||
<textarea style="margin:0px;width:580px;height:110px;outline:none;" spellcheck="false">'+rdata.mw+'</textarea>\
|
||||
</div>\
|
||||
<ul class="help-info-text c7 pull-left"></ul>\
|
||||
</div>'
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "600px",
|
||||
title: '本机公钥',
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
content:con
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function gogsRead(){
|
||||
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>默认使用MySQL,第一个启动加载各种配置,并修改成正确的数据库配置</li>';
|
||||
readme += '<li>邮件端口使用456,gogs仅支持使用STARTTLS的SMTP协议</li>';
|
||||
readme += '<li>如果使用项目中脚本本地同步,<a target="_blank" href="https://github.com/midoks/mdserver-web/wiki/%E6%8F%92%E4%BB%B6%E7%AE%A1%E7%90%86%5Bgogs%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%5D#%E5%90%AF%E5%8A%A8gogs%E5%90%8E%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BD%BF%E7%94%A8hook%E8%84%9A%E6%9C%AC%E5%90%8C%E6%AD%A5%E4%BB%A3%E7%A0%81%E9%9C%80%E8%A6%81%E5%BC%80%E5%90%AFssh%E7%AB%AF%E5%8F%A3">点击查看</></li>';
|
||||
readme += '<li><a href="#" onclick="getRsaPublic();">点击查看本机公钥</></li>';
|
||||
readme += '</ul>';
|
||||
|
||||
$('.soft-man-con').html(readme);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
global
|
||||
daemon
|
||||
log 127.0.0.1 local0
|
||||
pidfile /tmp/haproxy.pid
|
||||
maxconn 4000
|
||||
user haproxy
|
||||
group haproxy
|
||||
|
||||
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
option httplog
|
||||
timeout connect 10s
|
||||
timeout client 15s
|
||||
timeout server 15s
|
||||
|
||||
|
||||
listen stats
|
||||
mode http
|
||||
bind *:10800
|
||||
stats enable
|
||||
stats uri /haproxy
|
||||
stats realm Haproxy\ Statistics
|
||||
stats auth admin:admin
|
||||
|
||||
frontend http-in
|
||||
bind *:1080
|
||||
default_backend servers
|
||||
option forwardfor
|
||||
option httpclose
|
||||
|
||||
backend servers
|
||||
balance roundrobin
|
||||
server web1 0.0.0.0:9090 check
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,18 +0,0 @@
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('haproxy');">服务</p>
|
||||
<p onclick="pluginInitD('haproxy');">自启动</p>
|
||||
<p onclick="pluginConfigTpl('haproxy');">配置修改</p>
|
||||
<p onclick="pluginLogs('haproxy','','run_log',30);">运行日志</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=haproxy&f=js/haproxy.js", function(){
|
||||
pluginService('haproxy');
|
||||
});
|
||||
</script>
|
||||
@@ -1,253 +0,0 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import string
|
||||
import subprocess
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'haproxy'
|
||||
|
||||
|
||||
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 getConfTpl():
|
||||
path = getPluginDir() + "/conf/haproxy.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/haproxy.conf"
|
||||
return path
|
||||
|
||||
|
||||
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('}')
|
||||
t = t.split(':')
|
||||
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 configTpl():
|
||||
path = getPluginDir() + '/tpl'
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def readConfigTpl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
content = mw.readFile(args['file'])
|
||||
content = contentReplace(content)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$SERVER_APP}', service_path + '/haproxy')
|
||||
return content
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps -ef|grep haproxy |grep -v grep | grep -v python | awk '{print $2}'")
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# initd replace
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# config replace
|
||||
conf_bin = getConf()
|
||||
if not os.path.exists(conf_bin):
|
||||
conf_content = mw.readFile(getConfTpl())
|
||||
conf_content = contentReplace(conf_content)
|
||||
mw.writeFile(getServerDir() + '/haproxy.conf', conf_content)
|
||||
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/haproxy.service'
|
||||
systemServiceTpl = getPluginDir() + '/init.d/haproxy.service.tpl'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
service_path = mw.getServerDir()
|
||||
se_content = mw.readFile(systemServiceTpl)
|
||||
se_content = se_content.replace('{$SERVER_PATH}', service_path)
|
||||
mw.writeFile(systemService, se_content)
|
||||
mw.execShell('systemctl daemon-reload')
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def haOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
data = mw.execShell('systemctl ' + method + ' haproxy')
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return 'fail'
|
||||
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def start():
|
||||
return haOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return haOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
return haOp('restart')
|
||||
|
||||
|
||||
def reload():
|
||||
return haOp('reload')
|
||||
|
||||
|
||||
def initdStatus():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
shell_cmd = 'systemctl status haproxy | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl enable haproxy')
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl disable haproxy')
|
||||
return 'ok'
|
||||
|
||||
|
||||
def runLog():
|
||||
path = getConf()
|
||||
content = mw.readFile(path)
|
||||
rep = 'log\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getPort():
|
||||
path = getConf()
|
||||
content = mw.readFile(path)
|
||||
rep = 'listen\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
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 == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'config_tpl':
|
||||
print(configTpl())
|
||||
elif func == 'read_config_tpl':
|
||||
print(readConfigTpl())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'query_log':
|
||||
print(queryLog())
|
||||
else:
|
||||
print('error')
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "可靠、高性能的TCP/HTTP负载平衡器",
|
||||
"name": "haproxy",
|
||||
"title": "haproxy",
|
||||
"shell": "install.sh",
|
||||
"versions":["2.6"],
|
||||
"updates":["2.6"],
|
||||
"tip": "soft",
|
||||
"checks": "server/haproxy",
|
||||
"path": "server/haproxy",
|
||||
"display": 1,
|
||||
"author": "midoks",
|
||||
"date": "2022-08-26",
|
||||
"home": "https://www.haproxy.org/",
|
||||
"doc1": "https://www.haproxy.org/",
|
||||
"type": 0,
|
||||
"pid": "4"
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=he Reliable, High Performance TCP/HTTP Load Balancer
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStartPre={$SERVER_PATH}/haproxy/sbin/haproxy -c -f {$SERVER_PATH}/haproxy/haproxy.conf
|
||||
ExecStart={$SERVER_PATH}/haproxy/sbin/haproxy -D -f {$SERVER_PATH}/haproxy/haproxy.conf
|
||||
ExecReload={$SERVER_PATH}/haproxy/sbin/haproxy -f {$SERVER_PATH}/haproxy/haproxy.conf -c -q
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,119 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# chkconfig: - 85 15
|
||||
# description: HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited \
|
||||
# for high availability environments.
|
||||
# processname: haproxy
|
||||
# config: /etc/haproxy/haproxy.cfg
|
||||
# pidfile: /var/run/haproxy.pid
|
||||
# Script Author: Simon Matter <simon.matter@invoca.ch>
|
||||
# Version: 2004060600
|
||||
# Source function library.
|
||||
|
||||
if [ -f /etc/init.d/functions ]; then
|
||||
. /etc/init.d/functions
|
||||
elif [ -f /etc/rc.d/init.d/functions ] ; then
|
||||
. /etc/rc.d/init.d/functions
|
||||
else
|
||||
echo ".."
|
||||
fi
|
||||
|
||||
# Source networking configuration.
|
||||
if [ -f /etc/sysconfig/network ];then
|
||||
. /etc/sysconfig/network
|
||||
fi
|
||||
|
||||
# Check that networking is up.
|
||||
# [ ${NETWORKING} = "no" ] && exit 0
|
||||
|
||||
HAPROXYDIR={$SERVER_PATH}/haproxy
|
||||
BASENAME=haproxy
|
||||
|
||||
# This is our service name
|
||||
|
||||
#BASENAME=`basename $0`
|
||||
#if [ -L $0 ]; then
|
||||
# BASENAME=`find $0 -name $BASENAME -printf %l`
|
||||
# BASENAME=`basename $BASENAME`
|
||||
#fi
|
||||
|
||||
[ -f $HAPROXYDIR/etc/$BASENAME.conf ] || exit 1
|
||||
|
||||
RETVAL=0
|
||||
|
||||
start() {
|
||||
$HAPROXYDIR/sbin/$BASENAME -c -q -f $HAPROXYDIR/etc/$BASENAME.conf
|
||||
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Errors found in configuration file, check it with '$BASENAME check'."
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -n "Starting $BASENAME: "
|
||||
daemon $HAPROXYDIR/sbin/$BASENAME -D -f $HAPROXYDIR/etc/$BASENAME.conf
|
||||
RETVAL=$?
|
||||
# echo
|
||||
# [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$BASENAME
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
|
||||
stop() {
|
||||
|
||||
echo -n "Shutting down $BASENAME: "
|
||||
killproc $BASENAME -USR1
|
||||
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$BASENAME
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/run/$BASENAME.pid
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
restart() {
|
||||
$HAPROXYDIR/sbin/$BASENAME -c -q -f $HAPROXYDIR/etc/$BASENAME.conf
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Errors found in configuration file, check it with '$BASENAME check'."
|
||||
return 1
|
||||
fi
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
reload() {
|
||||
$HAPROXYDIR/sbin/$BASENAME -c -q -f $HAPROXYDIR/etc/$BASENAME.conf
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Errors found in configuration file, check it with '$BASENAME check'."
|
||||
return 1
|
||||
fi
|
||||
$HAPROXYDIR/sbin/$BASENAME -D -f $HAPROXYDIR/$BASENAME.conf -p /var/run/$BASENAME.pid -sf $(cat /var/run/$BASENAME.pid)
|
||||
}
|
||||
|
||||
check() {
|
||||
$HAPROXYDIR/sbin/$BASENAME -c -q -V -f $HAPROXYDIR/etc/$BASENAME.conf
|
||||
}
|
||||
|
||||
rhstatus() {
|
||||
status $BASENAME
|
||||
}
|
||||
|
||||
condrestart() {
|
||||
[ -e /var/lock/subsys/$BASENAME ] && restart || :
|
||||
}
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start) start ;;
|
||||
stop) stop ;;
|
||||
restart) restart;;
|
||||
reload) reload;;
|
||||
condrestart) condrestart ;;
|
||||
status) rhstatus ;;
|
||||
check) check ;;
|
||||
*)
|
||||
echo $"Usage: $BASENAME {start|stop|restart|reload|condrestart|status|check}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
||||
@@ -1,52 +0,0 @@
|
||||
#!/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
|
||||
|
||||
|
||||
action=$1
|
||||
type=$2
|
||||
|
||||
echo $action $type
|
||||
|
||||
if id haproxy &> /dev/null ;then
|
||||
echo "haproxy UID is `id -u haproxy`"
|
||||
echo "haproxy Shell is `grep "^haproxy:" /etc/passwd |cut -d':' -f7 `"
|
||||
else
|
||||
groupadd haproxy
|
||||
useradd -g haproxy haproxy
|
||||
fi
|
||||
|
||||
if [ "${2}" == "" ];then
|
||||
echo '缺少安装脚本...' > $install_tmp
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -d $curPath/versions/$2 ];then
|
||||
echo '缺少安装脚本2...' > $install_tmp
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${action}" == "uninstall" ];then
|
||||
|
||||
if [ -f /usr/lib/systemd/system/haproxy.service ] || [ -f /lib/systemd/system/haproxy.service ];then
|
||||
systemctl stop haproxy
|
||||
systemctl disable haproxy
|
||||
rm -rf /usr/lib/systemd/system/haproxy.service
|
||||
rm -rf /lib/systemd/system/haproxy.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
fi
|
||||
|
||||
sh -x $curPath/versions/$2/install.sh $1
|
||||
|
||||
if [ "${action}" == "install" ] && [ -d $serverPath/haproxy ];then
|
||||
#初始化
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/haproxy/index.py start ${type}
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/haproxy/index.py initd_install ${type}
|
||||
fi
|
||||
@@ -1,53 +0,0 @@
|
||||
function spPostMin(method, args, callback){
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'haproxy';
|
||||
req_data['func'] = method;
|
||||
|
||||
if (typeof(args) != 'undefined' && args!=''){
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function spPost(method, args, callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
spPostMin(method,args,function(data){
|
||||
layer.close(loadT);
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function secToTime(s) {
|
||||
var t;
|
||||
if(s > -1){
|
||||
var hour = Math.floor(s/3600);
|
||||
var min = Math.floor(s/60) % 60;
|
||||
var sec = s % 60;
|
||||
if(hour < 10) {
|
||||
t = '0'+ hour + ":";
|
||||
} else {
|
||||
t = hour + ":";
|
||||
}
|
||||
|
||||
if(min < 10){t += "0";}
|
||||
t += min + ":";
|
||||
if(sec < 10){t += "0";}
|
||||
t += sec.toFixed(2);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/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")
|
||||
sysName=`uname`
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
|
||||
|
||||
bash ${rootPath}/scripts/getos.sh
|
||||
OSNAME=`cat ${rootPath}/data/osname.pl`
|
||||
OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
|
||||
|
||||
VERSION=2.6.4
|
||||
MIN_VERSION=2.6
|
||||
Install_App()
|
||||
{
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/haproxy
|
||||
|
||||
APP_DIR=${serverPath}/source/haproxy
|
||||
mkdir -p $APP_DIR
|
||||
|
||||
if [ ! -f ${APP_DIR}/haproxy-${VERSION}.tar.gz ];then
|
||||
if [ $sysName == 'Darwin' ]; then
|
||||
wget -O ${APP_DIR}/haproxy-${VERSION}.tar.gz https://www.haproxy.org/download/${MIN_VERSION}/src/haproxy-${VERSION}.tar.gz
|
||||
else
|
||||
curl -sSLo ${APP_DIR}/haproxy-${VERSION}.tar.gz https://www.haproxy.org/download/${MIN_VERSION}/src/haproxy-${VERSION}.tar.gz
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f ${APP_DIR}/haproxy-${VERSION}.tar.gz ];then
|
||||
curl -sSLo ${APP_DIR}/haproxy-${VERSION}.tar.gz https://www.haproxy.org/download/${MIN_VERSION}/src/haproxy-${VERSION}.tar.gz
|
||||
fi
|
||||
|
||||
|
||||
cd ${APP_DIR} && tar -zxvf haproxy-${VERSION}.tar.gz
|
||||
|
||||
if [ "$OSNAME" == "macos" ];then
|
||||
cd ${APP_DIR}/haproxy-${VERSION} && make TARGET=osx && make install PREFIX=$serverPath/haproxy
|
||||
else
|
||||
cd ${APP_DIR}/haproxy-${VERSION} && make TARGET=linux-glibc && make install PREFIX=$serverPath/haproxy
|
||||
fi
|
||||
|
||||
echo $MIN_VERSION > $serverPath/haproxy/version.pl
|
||||
echo 'Install_HA' > $install_tmp
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
if [ -f $serverPath/haproxy/initd/haproxy ];then
|
||||
$serverPath/haproxy/initd/haproxy stop
|
||||
fi
|
||||
|
||||
rm -rf $serverPath/haproxy
|
||||
echo "Uninstall_HA" > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
@@ -1,4 +0,0 @@
|
||||
[mysqld]
|
||||
# SHOW GLOBAL VARIABLES LIKE '%gtid%'
|
||||
gtid_mode=ON
|
||||
enforce_gtid_consistency=ON
|
||||
@@ -1,43 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `config` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`mysql_root` TEXT
|
||||
);
|
||||
|
||||
INSERT INTO `config` (`id`, `mysql_root`) VALUES (1, 'admin');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `databases` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`pid` INTEGER,
|
||||
`name` TEXT,
|
||||
`username` TEXT,
|
||||
`password` TEXT,
|
||||
`accept` TEXT,
|
||||
`rw` TEXT DEFAULT 'rw',
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
-- ALTER TABLE `databases` ADD COLUMN `rw` TEXT DEFAULT 'rw';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `master_replication_user` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`username` TEXT,
|
||||
`password` TEXT,
|
||||
`accept` TEXT,
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
-- 从库配置主库的[ssh private key]
|
||||
-- drop table `slave_id_rsa`;
|
||||
CREATE TABLE IF NOT EXISTS `slave_id_rsa` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`ip` TEXT,
|
||||
`port` TEXT,
|
||||
`user` TEXT,
|
||||
`db_user` TEXT,
|
||||
`id_rsa` TEXT,
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
[client]
|
||||
user = root
|
||||
#password = your_password
|
||||
port = 33106
|
||||
socket = {$SERVER_APP_PATH}/mysql.sock
|
||||
|
||||
[mysqld]
|
||||
|
||||
!include {$SERVER_APP_PATH}/etc/mode/classic.cnf
|
||||
|
||||
pid-file = {$SERVER_APP_PATH}/data/mysql.pid
|
||||
user = mysql
|
||||
port = 33106
|
||||
socket = {$SERVER_APP_PATH}/mysql.sock
|
||||
basedir = {$SERVER_APP_PATH}
|
||||
datadir = {$SERVER_APP_PATH}/data
|
||||
log-error = {$SERVER_APP_PATH}/data/error.log
|
||||
server-id = {$SERVER_ID}
|
||||
|
||||
default_storage_engine = InnoDB
|
||||
|
||||
key_buffer_size = 8M
|
||||
max_allowed_packet = 100M
|
||||
table_open_cache = 32
|
||||
sort_buffer_size = 256K
|
||||
net_buffer_length = 4K
|
||||
read_buffer_size = 128K
|
||||
read_rnd_buffer_size = 256K
|
||||
myisam_sort_buffer_size = 4M
|
||||
thread_cache_size = 4
|
||||
lower_case_table_names=1
|
||||
query_cache_size = 4M
|
||||
tmp_table_size = 8M
|
||||
|
||||
max_connections = 500
|
||||
max_connect_errors = 100
|
||||
open_files_limit = 65535
|
||||
|
||||
skip-name-resolve = on
|
||||
#skip-networking
|
||||
#skip-external-locking
|
||||
#loose-skip-innodb
|
||||
#skip-grant-tables
|
||||
|
||||
|
||||
log-bin=mysql-bin
|
||||
binlog_format=mixed
|
||||
slow_query_log=1
|
||||
slow-query-log-file={$SERVER_APP_PATH}/data/mysql-slow.log
|
||||
long_query_time=3
|
||||
#log_queries_not_using_indexes=on
|
||||
binlog-expire-logs-seconds = 2592000
|
||||
|
||||
relay-log=mdserver
|
||||
relay-log-index=mdserver
|
||||
|
||||
#master
|
||||
#binlog-do-db
|
||||
binlog-ignore-db = test
|
||||
binlog-ignore-db = mysql
|
||||
binlog-ignore-db = information_schema
|
||||
binlog-ignore-db = performance_schema
|
||||
|
||||
#slave
|
||||
log-slave-updates
|
||||
#replicate-do-db
|
||||
replicate-ignore-db = information_schema
|
||||
replicate-ignore-db = performance_schema
|
||||
replicate-ignore-db = mysql
|
||||
replicate-ignore-db = test
|
||||
|
||||
|
||||
innodb_data_home_dir = {$SERVER_APP_PATH}/data
|
||||
innodb_data_file_path = ibdata1:10M:autoextend
|
||||
innodb_log_group_home_dir = {$SERVER_APP_PATH}/data
|
||||
innodb_buffer_pool_size = 16M
|
||||
innodb_log_file_size = 5M
|
||||
innodb_log_buffer_size = 8M
|
||||
innodb_flush_log_at_trx_commit = 1
|
||||
innodb_lock_wait_timeout = 120
|
||||
innodb_max_dirty_pages_pct = 90
|
||||
innodb_read_io_threads = 1
|
||||
innodb_write_io_threads = 2
|
||||
innodb_file_per_table=1
|
||||
|
||||
|
||||
secure-file-priv={$SERVER_APP_PATH}/tmp
|
||||
|
||||
[mysqldump]
|
||||
quick
|
||||
max_allowed_packet = 16M
|
||||
|
||||
[mysql]
|
||||
no-auto-rehash
|
||||
|
||||
[myisamchk]
|
||||
key_buffer_size = 20M
|
||||
sort_buffer_size = 20M
|
||||
read_buffer = 2M
|
||||
write_buffer = 2M
|
||||
|
||||
[mysqlhotcopy]
|
||||
interactive-timeout
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,61 +0,0 @@
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<script type="text/javascript">console.log($('.plugin_version').attr('version'));</script>
|
||||
<p class="bgw" onclick="pluginService('mariadb', $('.plugin_version').attr('version'));">服务</p>
|
||||
<p onclick="pluginInitD('mariadb', $('.plugin_version').attr('version'));">自启动</p>
|
||||
<p onclick="pluginConfig('mariadb', $('.plugin_version').attr('version'));">配置文件</p>
|
||||
<p onclick="myDbPos();">存储位置</p>
|
||||
<p onclick="myPort();">端口</p>
|
||||
<p onclick="runInfo();">当前状态</p>
|
||||
<p onclick="myPerfOpt();">性能优化</p>
|
||||
<p onclick="myLogs();">日志</p>
|
||||
<p onclick="pluginLogs('mariadb',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
|
||||
<p onclick="dbList()">管理列表</p>
|
||||
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
.db_list{
|
||||
padding: 0px 0 10px 0;
|
||||
font-size: 13px;
|
||||
line-height: 35px;
|
||||
height: 45px;
|
||||
}
|
||||
.db_list a{
|
||||
margin-right: 15px;
|
||||
color: #555;
|
||||
font-weight: 600;
|
||||
}
|
||||
.db_list span:nth-child(1){
|
||||
display: block;
|
||||
float: left;
|
||||
padding-left: 15px;
|
||||
background: #ececec;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#db_tools button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
#db_tools button:last-child{
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinWidth(800);
|
||||
|
||||
var loading = layer.msg("资源加载中...", { icon: 16, time: 0, shade: 0.3 });
|
||||
$.getScript( "/plugins/file?name=mariadb&f=js/mariadb.js", function(){
|
||||
layer.close(loading);
|
||||
pluginService('mariadb',$('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user