mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-14 19:17:14 +08:00
Compare commits
471
Commits
dev
..
old_version
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9615fb2203 | ||
|
|
49c181c577 | ||
|
|
0fa5e4fb48 | ||
|
|
8e7130c382 | ||
|
|
33c1ac82c8 | ||
|
|
df5aec2e8f | ||
|
|
6c864177ee | ||
|
|
9ee09b0e7d | ||
|
|
b7da91f92b | ||
|
|
17e6703c07 | ||
|
|
a5f77a37f2 | ||
|
|
78fc9fd90f | ||
|
|
700f042033 | ||
|
|
e44768e608 | ||
|
|
2acef86207 | ||
|
|
6256bb02da | ||
|
|
04f5a27492 | ||
|
|
7cd476696a | ||
|
|
2ecaf0e2a3 | ||
|
|
c5d3494a94 | ||
|
|
af0658fd41 | ||
|
|
cccbd88145 | ||
|
|
48aad5b248 | ||
|
|
d843213c39 | ||
|
|
7ad33c5c59 | ||
|
|
ee56cfe5ab | ||
|
|
c6b38aa996 | ||
|
|
c5205c2d55 | ||
|
|
1be07f96ff | ||
|
|
9f4af88c1e | ||
|
|
ebc0559dff | ||
|
|
fe320ecd3b | ||
|
|
02c06e7ff1 | ||
|
|
6d90d6fde5 | ||
|
|
bfc0b9efa3 | ||
|
|
6e4e7bcf68 | ||
|
|
5da505084d | ||
|
|
f19df17ef5 | ||
|
|
d99e89744d | ||
|
|
9695fe4b9b | ||
|
|
5907dc36c5 | ||
|
|
d694af9358 | ||
|
|
4dc2828c59 | ||
|
|
37519b4c92 | ||
|
|
90999c7ae1 | ||
|
|
f16d9ea269 | ||
|
|
86098541e0 | ||
|
|
9ef04a4d9e | ||
|
|
752f8fae5a | ||
|
|
c5fdecf459 | ||
|
|
19284cd5ef | ||
|
|
da92ab1c89 | ||
|
|
18ca47e8b3 | ||
|
|
8b624297ba | ||
|
|
f0d9ff2ae9 | ||
|
|
21b2c17220 | ||
|
|
0df898a7d9 | ||
|
|
cf1f4c8538 | ||
|
|
89ecdcd29a | ||
|
|
0c8fa5e616 | ||
|
|
f9252da1b0 | ||
|
|
e31cbad7dd | ||
|
|
5bed9f0802 | ||
|
|
1ae4b54779 | ||
|
|
2b2a75adf0 | ||
|
|
55184341d7 | ||
|
|
6504decc30 | ||
|
|
843d798b91 | ||
|
|
087a6b4809 | ||
|
|
44438bd9aa | ||
|
|
c33cba0e85 | ||
|
|
cdc3c95367 | ||
|
|
222cebe1b3 | ||
|
|
2fc2eff97e | ||
|
|
79f8baeeb3 | ||
|
|
0399219df6 | ||
|
|
cd0d5ede16 | ||
|
|
1e6d1c6127 | ||
|
|
ff87dbe258 | ||
|
|
7d6ddb40db | ||
|
|
1cb57d3f65 | ||
|
|
9ed434d274 | ||
|
|
f532a376a7 | ||
|
|
4405f7720b | ||
|
|
fbde4aab88 | ||
|
|
864691d357 | ||
|
|
95bf0cb1e8 | ||
|
|
126f2d553d | ||
|
|
2fb88be080 | ||
|
|
fa307cdb49 | ||
|
|
0850b6ed44 | ||
|
|
ec1e99f9ca | ||
|
|
546dc4d7eb | ||
|
|
9b0b4ac305 | ||
|
|
23a1f3936d | ||
|
|
4cb22a1e35 | ||
|
|
3e3cdbe18c | ||
|
|
bdc46d9401 | ||
|
|
64986dd125 | ||
|
|
7ee00ab0b5 | ||
|
|
488d92ba19 | ||
|
|
9cebfb64cb | ||
|
|
7800429f8d | ||
|
|
7954714bb7 | ||
|
|
1d396b73f0 | ||
|
|
5f95a1d56a | ||
|
|
51951a2685 | ||
|
|
737453600d | ||
|
|
17ef460f4c | ||
|
|
38be955738 | ||
|
|
daf5c7c2b0 | ||
|
|
acdb35f395 | ||
|
|
5e8a15c230 | ||
|
|
34bcdd915c | ||
|
|
aa718adfea | ||
|
|
936592661b | ||
|
|
c740b4affb | ||
|
|
042b07efa2 | ||
|
|
6a6d22fd2d | ||
|
|
f99502d2c8 | ||
|
|
1cf41348b7 | ||
|
|
acdb226df9 | ||
|
|
6259f21196 | ||
|
|
6ad1292003 | ||
|
|
a682ba3e43 | ||
|
|
7509b259e7 | ||
|
|
8d170d87e4 | ||
|
|
bc4e5f6a87 | ||
|
|
954f66c8dc | ||
|
|
a7f860de2b | ||
|
|
6e7e291da3 | ||
|
|
2bca78c32d | ||
|
|
fb4311cdbf | ||
|
|
d889bf2cf3 | ||
|
|
511a7ac12b | ||
|
|
03e126cb48 | ||
|
|
2acbe56e21 | ||
|
|
8425aa4942 | ||
|
|
17ad9abe6b | ||
|
|
11166bbab1 | ||
|
|
f5f3f7ded5 | ||
|
|
26bae283be | ||
|
|
bfb12692a6 | ||
|
|
6bc6f17783 | ||
|
|
cd6f86ebfa | ||
|
|
5abb2613a1 | ||
|
|
a08dee242a | ||
|
|
2700b6b67b | ||
|
|
e41148d72d | ||
|
|
9b5c80bc72 | ||
|
|
958755d18d | ||
|
|
9af7e0f95b | ||
|
|
90e86cda0d | ||
|
|
ea2ed9d003 | ||
|
|
67eb3590c7 | ||
|
|
e66afbbb2d | ||
|
|
f959391b85 | ||
|
|
663e95288a | ||
|
|
0af3c7622d | ||
|
|
40e2186a5b | ||
|
|
121c972951 | ||
|
|
229cb977a1 | ||
|
|
ae845a702c | ||
|
|
35b0b1d153 | ||
|
|
4801850373 | ||
|
|
8b3d0cbba4 | ||
|
|
4f580d0427 | ||
|
|
2f794c5b73 | ||
|
|
21cd34d272 | ||
|
|
c58e1f7278 | ||
|
|
5b49f24a8d | ||
|
|
ce89a2a275 | ||
|
|
35f905e94c | ||
|
|
1c431286e4 | ||
|
|
705cef730b | ||
|
|
2a5da5593b | ||
|
|
22692d8ed4 | ||
|
|
5cdae707e9 | ||
|
|
5be9f1ae66 | ||
|
|
ba931a0c2a | ||
|
|
5b87572bff | ||
|
|
d51de312ac | ||
|
|
bcd2e7298b | ||
|
|
a985511b3b | ||
|
|
abb9fb72f0 | ||
|
|
b36ad3a595 | ||
|
|
a118f33f57 | ||
|
|
58b888edcd | ||
|
|
43d906139e | ||
|
|
b91bc040d4 | ||
|
|
c6eba5bbf1 | ||
|
|
1adbf733d8 | ||
|
|
913d483e63 | ||
|
|
9951f7151e | ||
|
|
167a386a0d | ||
|
|
5473ee74cb | ||
|
|
dbeefc06c8 | ||
|
|
444730e553 | ||
|
|
8a2e17198e | ||
|
|
bc41788d49 | ||
|
|
ebd8e93b16 | ||
|
|
a45994c3c7 | ||
|
|
f41f616daf | ||
|
|
da5b9351e2 | ||
|
|
3c080e0264 | ||
|
|
dc62aabfd4 | ||
|
|
c6da2e56ee | ||
|
|
461f3dcb0a | ||
|
|
ee5b9f35ad | ||
|
|
3ad8496daf | ||
|
|
77023263a6 | ||
|
|
6497627931 | ||
|
|
2ae3426c82 | ||
|
|
dbeb919f05 | ||
|
|
2106746f6c | ||
|
|
31d5b90670 | ||
|
|
ceaf9c42db | ||
|
|
9067778bf3 | ||
|
|
99053b67ce | ||
|
|
07b8d91f31 | ||
|
|
e9d4e09049 | ||
|
|
629416760f | ||
|
|
d1ade4355e | ||
|
|
4508e30ea7 | ||
|
|
b1c5c90bef | ||
|
|
e9a7db2c1d | ||
|
|
63e5f26491 | ||
|
|
ed93ccc0ee | ||
|
|
929a50c137 | ||
|
|
fe87092750 | ||
|
|
c144cead18 | ||
|
|
afdc9720fc | ||
|
|
194c7b9d45 | ||
|
|
162557230a | ||
|
|
f4dfe502cb | ||
|
|
7a3d49a9cf | ||
|
|
49f1407c42 | ||
|
|
319f72865d | ||
|
|
0eaa6f38e0 | ||
|
|
eeef8d488c | ||
|
|
4e69f9540a | ||
|
|
a0e8d75af7 | ||
|
|
f54f7d4ce3 | ||
|
|
5f4893c115 | ||
|
|
a48b869fe9 | ||
|
|
266a8cf806 | ||
|
|
13e4dcf8ad | ||
|
|
1ca469518d | ||
|
|
4284a3daf4 | ||
|
|
84995650ee | ||
|
|
fa662d75d6 | ||
|
|
842c0daf70 | ||
|
|
798608287e | ||
|
|
437225374e | ||
|
|
3a442570db | ||
|
|
366c3677c2 | ||
|
|
6dcf1db856 | ||
|
|
b3ca295e51 | ||
|
|
03f06ee384 | ||
|
|
2dc96cd04e | ||
|
|
a875293116 | ||
|
|
8735fb9238 | ||
|
|
58fcf0e8f9 | ||
|
|
fccc30ebb1 | ||
|
|
6b9da57ff2 | ||
|
|
cd6b2ad65e | ||
|
|
60b2834adf | ||
|
|
c74e0428fd | ||
|
|
20d486629e | ||
|
|
f984e4ecc7 | ||
|
|
0bdea14560 | ||
|
|
0c3599facb | ||
|
|
05eb434bf8 | ||
|
|
12dccc1df0 | ||
|
|
11e7316911 | ||
|
|
26a6a80504 | ||
|
|
498799578a | ||
|
|
6a5b009766 | ||
|
|
8e23411be8 | ||
|
|
b597255d68 | ||
|
|
8979011ec3 | ||
|
|
11a21f9a8b | ||
|
|
1a12f625cd | ||
|
|
11e44d5b0e | ||
|
|
47c1394de6 | ||
|
|
5e7fa28feb | ||
|
|
d04f891ee7 | ||
|
|
3d28e0a3cb | ||
|
|
37112546b9 | ||
|
|
cb719c9973 | ||
|
|
7ec5fe84b2 | ||
|
|
c68cce0198 | ||
|
|
0d7fd11de5 | ||
|
|
643a2e8cf8 | ||
|
|
35ee7d3d10 | ||
|
|
2ce3871ee2 | ||
|
|
812ce86187 | ||
|
|
3d44b3014f | ||
|
|
092494a216 | ||
|
|
a21ad254b7 | ||
|
|
ebd6b9f389 | ||
|
|
33b90a976b | ||
|
|
2518d32019 | ||
|
|
4ded4679f3 | ||
|
|
28d3996d17 | ||
|
|
b76950ed3b | ||
|
|
d49aa168eb | ||
|
|
5304d0b228 | ||
|
|
56e4ef1a4e | ||
|
|
91fc83e0ba | ||
|
|
fc0fdd5772 | ||
|
|
0d0007d9a1 | ||
|
|
a74ace856a | ||
|
|
f46af799a9 | ||
|
|
3e4facbf57 | ||
|
|
ff9466d0a4 | ||
|
|
9cbcff5dbc | ||
|
|
90834415bf | ||
|
|
c2862ab5d4 | ||
|
|
664a7864bc | ||
|
|
9cf6a40493 | ||
|
|
028422337e | ||
|
|
5f10d9433c | ||
|
|
ed49f0b0bd | ||
|
|
090fc0f243 | ||
|
|
f2df81694f | ||
|
|
6cf2e2d6b6 | ||
|
|
defdc3d3b8 | ||
|
|
6d1d1b882e | ||
|
|
54f90c9300 | ||
|
|
a1aa7d465d | ||
|
|
62214c2a88 | ||
|
|
d5a4958566 | ||
|
|
0bca4a3589 | ||
|
|
30bc8b1ec1 | ||
|
|
0472102a3a | ||
|
|
2da863d98a | ||
|
|
88bab4b15b | ||
|
|
d1b4a1cde1 | ||
|
|
d88f6903da | ||
|
|
3a53b360b7 | ||
|
|
3e5b951a41 | ||
|
|
272b6fdeea | ||
|
|
49ac781e87 | ||
|
|
b4f9fa0976 | ||
|
|
96baa99bdc | ||
|
|
5db4f39c76 | ||
|
|
23dadd7f6f | ||
|
|
7d8d48f3d5 | ||
|
|
74fd4bbe08 | ||
|
|
30240443e6 | ||
|
|
e069c3a24e | ||
|
|
73e75abb5f | ||
|
|
b35d516a8e | ||
|
|
aa1875612b | ||
|
|
b189d5b485 | ||
|
|
33b43b253c | ||
|
|
86cfb1b9cf | ||
|
|
f93afb772c | ||
|
|
bd49bd3004 | ||
|
|
db26b09eba | ||
|
|
85da65ad1e | ||
|
|
d9a409ffcc | ||
|
|
ea923a45a6 | ||
|
|
7480cfb5d8 | ||
|
|
be513af18e | ||
|
|
1c5e61a3de | ||
|
|
d26474f222 | ||
|
|
03c796775a | ||
|
|
182d434f84 | ||
|
|
7c1d409e61 | ||
|
|
dab12535f2 | ||
|
|
deffb3d61b | ||
|
|
a4a45f2005 | ||
|
|
32d6a89bd4 | ||
|
|
f41c2454ee | ||
|
|
76dba077c0 | ||
|
|
1c34488abb | ||
|
|
6742d971eb | ||
|
|
3de01da4ba | ||
|
|
4ba526ca2b | ||
|
|
a4e8b6a137 | ||
|
|
50ad3ed7e7 | ||
|
|
64d29659f7 | ||
|
|
2794f49df4 | ||
|
|
3e27f85719 | ||
|
|
a4d70f2294 | ||
|
|
f3cd1f597e | ||
|
|
489c363daf | ||
|
|
77f44481b3 | ||
|
|
fcd4ba024a | ||
|
|
ce6b15939d | ||
|
|
baaccb7960 | ||
|
|
fb559e9f11 | ||
|
|
283a2c052b | ||
|
|
a7bd9e3290 | ||
|
|
b64dbb9aa4 | ||
|
|
d9f63c3a9a | ||
|
|
3c02af41bc | ||
|
|
ac87a6c8b1 | ||
|
|
f19dd2a2b9 | ||
|
|
cef7215fdc | ||
|
|
edb4fc96e1 | ||
|
|
af9f8b73ba | ||
|
|
c85152e85a | ||
|
|
2ee2440c68 | ||
|
|
ecfafc9723 | ||
|
|
dbb4414e65 | ||
|
|
a028e93881 | ||
|
|
475cb5176d | ||
|
|
8b07bd80e6 | ||
|
|
50d26d932f | ||
|
|
22b5ab1179 | ||
|
|
f7c76fb261 | ||
|
|
6531f686ad | ||
|
|
b716f05fb4 | ||
|
|
9a98f1c859 | ||
|
|
e92fc4cfd1 | ||
|
|
da1a76cbef | ||
|
|
fa6b7c21ac | ||
|
|
11748fd33b | ||
|
|
267bbe3865 | ||
|
|
dd27e4b076 | ||
|
|
459229ba15 | ||
|
|
94c5161fde | ||
|
|
5646d1404c | ||
|
|
ef8a10b68d | ||
|
|
c772696f3e | ||
|
|
45faf4e9dd | ||
|
|
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,5 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: midoks
|
|
||||||
|
|
||||||
custom: https://afdian.net/a/mdserver-web
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
---
|
|
||||||
name: BUG提交
|
|
||||||
about: 问题描述
|
|
||||||
---
|
|
||||||
|
|
||||||
## 什么系统 ?
|
|
||||||
|
|
||||||
Debian x, Centos x, Centos x stream, Ubuntu x?
|
|
||||||
|
|
||||||
## 错误信息 ?
|
|
||||||
|
|
||||||
Ex:
|
|
||||||
```bash
|
|
||||||
一个issue,一个问题。多余问题,视情况而答。
|
|
||||||
```
|
|
||||||
|
|
||||||
## 错误截图 ?
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
## 浏览器版本 ?
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
## 软件版本(插件/面板) ?
|
|
||||||
|
|
||||||
...
|
|
||||||
@@ -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,3 +0,0 @@
|
|||||||
### 合并描述
|
|
||||||
|
|
||||||
- 我添加了测试用例来覆盖新代码。
|
|
||||||
@@ -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: |
|
|
||||||
cd web && gunicorn -c setting.py app:app
|
|
||||||
python3 panel_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: |
|
|
||||||
cd web && gunicorn -c setting.py app:app
|
|
||||||
python3 panel_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: |
|
|
||||||
cd web && gunicorn -c setting.py app:app
|
|
||||||
python3 panel_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: |
|
|
||||||
cd web && gunicorn -c setting.py app:app
|
|
||||||
python3 panel_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.27.1
|
|
||||||
- name: Start DEBUG
|
|
||||||
run: |
|
|
||||||
source /www/server/mdserver-web/bin/activate && cd web && gunicorn -c setting.py app:app
|
|
||||||
cd /www/server/mdserver-web && python3 panel_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: |
|
|
||||||
source /www/server/mdserver-web/bin/activate && cd web && gunicorn -c setting.py app:app
|
|
||||||
cd /www/server/mdserver-web && python3 panel_task.py &
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
name: sync2gitee
|
|
||||||
on: [push]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
repo-sync:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Mirror the Github organization repos to Gitee.
|
|
||||||
uses: Yikun/hub-mirror-action@master
|
|
||||||
with:
|
|
||||||
src: 'github/midoks'
|
|
||||||
dst: 'gitee/midoks'
|
|
||||||
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
|
|
||||||
dst_token: ${{ secrets.GITEE_TOKEN }}
|
|
||||||
static_list: "mdserver-web"
|
|
||||||
force_update: true
|
|
||||||
+5
-86
@@ -8,6 +8,7 @@ __pycache__/
|
|||||||
|
|
||||||
# Distribution / packaging
|
# Distribution / packaging
|
||||||
.Python
|
.Python
|
||||||
|
build/
|
||||||
develop-eggs/
|
develop-eggs/
|
||||||
dist/
|
dist/
|
||||||
downloads/
|
downloads/
|
||||||
@@ -87,7 +88,6 @@ venv/
|
|||||||
ENV/
|
ENV/
|
||||||
env.bak/
|
env.bak/
|
||||||
venv.bak/
|
venv.bak/
|
||||||
lib/python*
|
|
||||||
|
|
||||||
# Spyder project settings
|
# Spyder project settings
|
||||||
.spyderproject
|
.spyderproject
|
||||||
@@ -99,100 +99,19 @@ lib/python*
|
|||||||
# mkdocs documentation
|
# mkdocs documentation
|
||||||
/site
|
/site
|
||||||
|
|
||||||
bin
|
|
||||||
pyvenv.cfg
|
|
||||||
include
|
|
||||||
share
|
|
||||||
pip-selfcheck.json
|
|
||||||
|
|
||||||
# mypy
|
# mypy
|
||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.idea/*.xml
|
.idea/*.xml
|
||||||
.idea/*.iml
|
.idea/*.iml
|
||||||
tmp/*
|
tmp/*.pl
|
||||||
|
tmp/*.log
|
||||||
*.swp
|
*.swp
|
||||||
*.pem
|
|
||||||
*.zip
|
*.zip
|
||||||
debug.out
|
|
||||||
mdioks.session-journal
|
|
||||||
*.session
|
|
||||||
|
|
||||||
temp
|
|
||||||
|
|
||||||
logs/panel.pid
|
|
||||||
logs/panel.log
|
|
||||||
logs/panel_task.log
|
|
||||||
logs/panel_exec.log
|
|
||||||
logs/panel_task.lock
|
|
||||||
|
|
||||||
ssl/local
|
|
||||||
ssl/nginx
|
|
||||||
ssl/choose.pl
|
|
||||||
|
|
||||||
scripts/init.d/mw
|
scripts/init.d/mw
|
||||||
scripts/mdserver-web
|
logs/*
|
||||||
|
|
||||||
data/api_login.txt
|
|
||||||
data/sessions
|
|
||||||
|
|
||||||
data/*.db
|
data/*.db
|
||||||
|
data/control.conf
|
||||||
data/iplist.txt
|
data/iplist.txt
|
||||||
data/json/index.json
|
data/json/index.json
|
||||||
data/json/config.json
|
|
||||||
data/site.pl
|
|
||||||
data/admin_path.pl
|
|
||||||
data/close.pl
|
|
||||||
data/datadir.pl
|
|
||||||
data/502Task.pl
|
|
||||||
data/default.pl
|
|
||||||
data/backup.pl
|
|
||||||
data/debug.pl
|
|
||||||
data/default_site.pl
|
|
||||||
data/ssl.pl
|
|
||||||
|
|
||||||
data/port.pl
|
|
||||||
data/ipv6.pl
|
|
||||||
data/restart.pl
|
|
||||||
data/edate.pl
|
|
||||||
data/osname.pl
|
|
||||||
data/only_netio_counters.pl
|
|
||||||
data/system.db-journal
|
|
||||||
data/hook_*.json
|
|
||||||
data/letsencrypt.json
|
|
||||||
data/basic_auth.json
|
|
||||||
data/notify.json
|
|
||||||
data/api.json
|
|
||||||
data/bind_domain.pl
|
|
||||||
data/unauthorized_status.pl
|
|
||||||
data/auth_secret.pl
|
|
||||||
data/panelSpeed.pl
|
|
||||||
|
|
||||||
plugins/vip_*
|
|
||||||
plugins/own_*
|
|
||||||
plugins/my_*
|
|
||||||
plugins/op_auth
|
|
||||||
plugins/l2tp
|
|
||||||
plugins/openlitespeed
|
|
||||||
plugins/tamper_proof
|
|
||||||
plugins/zimg
|
|
||||||
plugins/bk_demo
|
|
||||||
plugins/mail
|
|
||||||
plugins/fastdfs
|
|
||||||
plugins/v2ray
|
|
||||||
plugins/frp
|
|
||||||
plugins/file_search
|
|
||||||
plugins/proxysql
|
|
||||||
plugins/tidb
|
|
||||||
plugins/goedge-admin
|
|
||||||
plugins/goedge-node
|
|
||||||
plugins/goedge-happy
|
|
||||||
|
|
||||||
/logs
|
|
||||||
/data
|
|
||||||
/plugins/flexcdn
|
|
||||||
/plugins/tools
|
|
||||||
/plugins/choose-linux-python
|
|
||||||
*.md5
|
|
||||||
/bak
|
|
||||||
|
|||||||
@@ -186,7 +186,7 @@
|
|||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,235 +1,7 @@
|
|||||||
<p align="center">
|
# mdserver-web
|
||||||
<img alt="logo" src="https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/logo.png" height="140" />
|
简单的Linux面板
|
||||||
<h3 align="center">mdserver-web</h3>
|
|
||||||
<p align="center">一款简单Linux面板服务</p>
|
|
||||||
<p align="center">强烈推荐系统:debian</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
|
|
||||||
- 交流论坛 - https://bbs.midoks.icu
|
|
||||||
|
|
||||||
|
### 自动安装
|
||||||
```
|
```
|
||||||
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
|
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | sh
|
||||||
Talk is cheap, show me the code. -- linus
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- [兼容性测试报告](/compatibility.md)
|
|
||||||
- [常用命令说明](/cmd.md) [ mw default ] [ mw dev ]
|
|
||||||
|
|
||||||
### 特别赞助
|
|
||||||
|
|
||||||
- [虚位以待](https://bbs.midoks.icu)
|
|
||||||
|
|
||||||
### 主要插件介绍
|
|
||||||
|
|
||||||
* OpenResty - 轻量级,占有内存少,并发能力强。
|
|
||||||
* PHP[53-85] - PHP是世界上最好的编程语言。
|
|
||||||
* MySQL - 一种关系数据库管理系统。
|
|
||||||
* MariaDB - 是MySQL的一个重要分支。
|
|
||||||
* MySQL[community] - 一种关系数据库管理系统。
|
|
||||||
* MongoDB - 一种非关系NOSQL数据库管理系统。
|
|
||||||
* PostgreSQL - 功能强大的开源数据库。
|
|
||||||
* phpMyAdmin - 著名Web端MySQL管理工具。
|
|
||||||
* Memcached - 一个高性能的分布式内存对象缓存系统。
|
|
||||||
* Redis - 一个高性能的KV数据库。
|
|
||||||
* PureFtpd - 一款专注于程序健壮和软件安全的免费FTP服务器软件。
|
|
||||||
* Gogs - 一款极易搭建的自助Git服务。
|
|
||||||
* Rsyncd - 通用同步服务。
|
|
||||||
|
|
||||||
|
|
||||||
### 插件开发相关
|
|
||||||
|
|
||||||
```
|
|
||||||
插件文档还不完善,如果有不明白的地方提Issue! 我会尽力完善。
|
|
||||||
如果你自己写了插件,想分享出来,也可以提Issue。
|
|
||||||
```
|
|
||||||
|
|
||||||
- 简单例子 - https://github.com/mw-plugin/simple-plugin
|
|
||||||
- 插件地址 - https://github.com/mw-plugin
|
|
||||||
- 开发文档 - https://github.com/midoks/mdserver-web/wiki/插件开发
|
|
||||||
|
|
||||||
## 其他插件
|
|
||||||
|
|
||||||
- OP鉴权 - https://github.com/mw-plugin/op_auth
|
|
||||||
|
|
||||||
|
|
||||||
# Note
|
|
||||||
|
|
||||||
```
|
|
||||||
phpMyAdmin[4.4.15]支持MySQL[5.5-5.7]
|
|
||||||
phpMyAdmin[5.2.1]支持MySQL[8.0+]
|
|
||||||
|
|
||||||
PHP[53-72]支持phpMyAdmin[4.4.15]
|
|
||||||
PHP[72-84]支持phpMyAdmin[5.2.1]
|
|
||||||
```
|
|
||||||
|
|
||||||
# 郑重声明
|
|
||||||
|
|
||||||
不卖、不会监控(统计使用除外)、更不会注入病毒,大家使用方便(望大家不吝捐赠)。
|
|
||||||
|
|
||||||
- https://www.youtube.com/watch?v=2taa5K-Jmmw
|
|
||||||
|
|
||||||
|
|
||||||
# AD - VPS推荐 - 🙏
|
|
||||||
|
|
||||||
| 服务商 | LOGO | 推广地址 | 优惠码 |
|
|
||||||
| ------------- |----------|-----------|-------|
|
|
||||||
| digitalvirt |[](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | mdserver-web |
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
|
|
||||||
- 由[DDS-Derek](https://github.com/DDS-Derek)开发维护。
|
|
||||||
- https://github.com/DDS-Derek/mdserver-web-Docker
|
|
||||||
|
|
||||||
```
|
|
||||||
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.18.6
|
|
||||||
|
|
||||||
- 常规优化。
|
|
||||||
|
|
||||||
### JSDelivr安装地址
|
|
||||||
|
|
||||||
- 初始安装
|
|
||||||
|
|
||||||
```
|
|
||||||
bash <(curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh)
|
|
||||||
```
|
|
||||||
|
|
||||||
- 直接更新
|
|
||||||
|
|
||||||
```
|
|
||||||
bash <(curl --insecure -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh)
|
|
||||||
```
|
|
||||||
|
|
||||||
- 卸载脚本
|
|
||||||
|
|
||||||
```
|
|
||||||
wget --no-check-certificate -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh && bash uninstall.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 备用地址
|
|
||||||
|
|
||||||
- 初始安装
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install.sh)
|
|
||||||
bash <(curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/master/scripts/install.sh)
|
|
||||||
```
|
|
||||||
|
|
||||||
- 直接更新
|
|
||||||
|
|
||||||
```
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh)
|
|
||||||
```
|
|
||||||
|
|
||||||
- 卸载脚本
|
|
||||||
|
|
||||||
```
|
|
||||||
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh && bash uninstall.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### 通用软件安装[命令行安装]
|
|
||||||
|
|
||||||
- 需已经安装mdserver-web
|
|
||||||
|
|
||||||
```
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### DEV使用
|
|
||||||
|
|
||||||
```
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install.sh)
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update.sh)
|
|
||||||
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh)
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh)
|
|
||||||
|
|
||||||
wget --no-check-certificate -O install.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install.sh && bash install.sh
|
|
||||||
|
|
||||||
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
|
|
||||||
|
|
||||||
bash <(curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh)
|
|
||||||
|
|
||||||
bash <(curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/install.sh)
|
|
||||||
bash <(curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update.sh)
|
|
||||||
|
|
||||||
bash <(curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh)
|
|
||||||
bash <(curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 旧版安装/更新
|
|
||||||
```
|
|
||||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/old/install.sh | bash
|
|
||||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/old/update.sh | bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### 偶然问题
|
|
||||||
- 在安装/更新时,突然出现python插件pip,psutil,可尝试如下解决方案
|
|
||||||
```
|
|
||||||
cd /www/server/mdserver-web rm -rf lib
|
|
||||||
cd /www/server/mdserver-web && rm -rf lib64
|
|
||||||
cd /www/server/mdserver-web && rm -rf bin
|
|
||||||
cd /www/server/mdserver-web && rm -rf include
|
|
||||||
|
|
||||||
mw update/mw update_dev/mw dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 捐赠地址 USDT(TRC20)
|
|
||||||
|
|
||||||
TVbNgrpeGBGZVm5gTLa21ADP7RpnPFhjya
|
|
||||||
|
|
||||||
日行一善,以后必定大富大贵
|
|
||||||
|
|
||||||
|
|
||||||
### 支付宝赞助
|
|
||||||
|
|
||||||
[](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/alipay_zz.png)
|
|
||||||
|
|
||||||
|
|
||||||
### 无图不真相
|
|
||||||
|
|
||||||
[](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) 文件中。
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# coding:utf-8
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
|
||||||
|
sys.path.append(os.getcwd() + "/class/core")
|
||||||
|
import config
|
||||||
|
|
||||||
|
app = config.config().makeApp(__name__)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
|
except Exception as ex:
|
||||||
|
print ex
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
# coding:utf-8
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
|
||||||
|
from flask import Flask, session
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
sys.path.append(os.getcwd() + "/class/core")
|
||||||
|
import db
|
||||||
|
import public
|
||||||
|
|
||||||
|
|
||||||
|
class middleWare:
|
||||||
|
|
||||||
|
def __init__(self, wsgi_app):
|
||||||
|
self.wsgi_app = wsgi_app
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.wsgi_app(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class config:
|
||||||
|
__version = '0.0.1'
|
||||||
|
__app = None
|
||||||
|
__modules = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def makeApp(self, name):
|
||||||
|
app = Flask(name)
|
||||||
|
self.__app = app
|
||||||
|
|
||||||
|
app.config.version = self.__version
|
||||||
|
app.config['SECRET_KEY'] = os.urandom(24)
|
||||||
|
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
|
||||||
|
|
||||||
|
self.initDB()
|
||||||
|
self.initInitD()
|
||||||
|
self.initRoute()
|
||||||
|
# self.startDebug()
|
||||||
|
app.wsgi_app = middleWare(app.wsgi_app)
|
||||||
|
return app
|
||||||
|
|
||||||
|
def startDebug(self):
|
||||||
|
self.__app.debug = True
|
||||||
|
self.__app.config.version = self.__version + str(time.time())
|
||||||
|
|
||||||
|
def initDB(self):
|
||||||
|
try:
|
||||||
|
sql = db.Sql().dbfile('default')
|
||||||
|
csql = public.readFile('data/sql/default.sql')
|
||||||
|
csql_list = csql.split(';')
|
||||||
|
for index in range(len(csql_list)):
|
||||||
|
sql.execute(csql_list[index], ())
|
||||||
|
except Exception, ex:
|
||||||
|
print str(ex)
|
||||||
|
|
||||||
|
def initUser(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def initInitD(self):
|
||||||
|
script = public.getRunDir() + '/scripts/init.d/mw.tpl'
|
||||||
|
script_bin = public.getRunDir() + '/scripts/init.d/mw'
|
||||||
|
if os.path.exists(script_bin):
|
||||||
|
return
|
||||||
|
|
||||||
|
content = public.readFile(script)
|
||||||
|
content = content.replace("{$SERVER_PATH}", public.getRunDir())
|
||||||
|
|
||||||
|
public.writeFile(script_bin, content)
|
||||||
|
public.execShell('chmod +x ' + script_bin)
|
||||||
|
|
||||||
|
if public.getOs() != 'darwin':
|
||||||
|
initd_bin = '/etc/init.d/mw'
|
||||||
|
if not os.path.exists(initd_bin):
|
||||||
|
shutil.copyfile(script_bin, initd_bin)
|
||||||
|
public.execShell('chmod +x ' + initd_bin)
|
||||||
|
|
||||||
|
def getVersion(self):
|
||||||
|
return self.__version
|
||||||
|
|
||||||
|
def getApp(self):
|
||||||
|
return self.__app
|
||||||
|
|
||||||
|
def initRoute(self):
|
||||||
|
import route
|
||||||
|
DEFAULT_MODULES = (
|
||||||
|
(route.dashboard, "/"),
|
||||||
|
(route.site, "/site"),
|
||||||
|
(route.files, "/files"),
|
||||||
|
(route.soft, "/soft"),
|
||||||
|
(route.config, "/config"),
|
||||||
|
(route.plugins, "/plugins"),
|
||||||
|
(route.task, "/task"),
|
||||||
|
(route.system, "/system"),
|
||||||
|
(route.database, "/database"),
|
||||||
|
(route.crontab, "/crontab"),
|
||||||
|
(route.firewall, "/firewall"),
|
||||||
|
(route.control, "/control")
|
||||||
|
)
|
||||||
|
self.modules = DEFAULT_MODULES
|
||||||
|
self.settingModules(self.__app, DEFAULT_MODULES)
|
||||||
|
|
||||||
|
def settingModules(self, app, modules):
|
||||||
|
for module, url_prefix in modules:
|
||||||
|
app.register_blueprint(module, url_prefix=url_prefix)
|
||||||
Executable
+276
@@ -0,0 +1,276 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
|
||||||
|
import sqlite3
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class Sql():
|
||||||
|
#------------------------------
|
||||||
|
# 数据库操作类 For sqlite3
|
||||||
|
#------------------------------
|
||||||
|
__DB_FILE = None # 数据库文件
|
||||||
|
__DB_CONN = None # 数据库连接对象
|
||||||
|
__DB_TABLE = "" # 被操作的表名称
|
||||||
|
__OPT_WHERE = "" # where条件
|
||||||
|
__OPT_LIMIT = "" # limit条件
|
||||||
|
__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)
|
||||||
|
except Exception, ex:
|
||||||
|
return "error: " + str(ex)
|
||||||
|
|
||||||
|
def dbfile(self, name):
|
||||||
|
self.__DB_FILE = 'data/' + 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 order(self, order):
|
||||||
|
# ORDER条件
|
||||||
|
if len(order):
|
||||||
|
self.__OPT_ORDER = " ORDER BY " + order
|
||||||
|
return self
|
||||||
|
|
||||||
|
def limit(self, limit):
|
||||||
|
# LIMIT条件
|
||||||
|
if len(limit):
|
||||||
|
self.__OPT_LIMIT = " LIMIT " + 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_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, 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()
|
||||||
|
self.__DB_CONN.text_factory = str
|
||||||
|
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)
|
||||||
|
id = result.lastrowid
|
||||||
|
self.__close()
|
||||||
|
self.__DB_CONN.commit()
|
||||||
|
return id
|
||||||
|
except Exception, 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()
|
||||||
|
self.__DB_CONN.text_factory = str
|
||||||
|
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, ex:
|
||||||
|
return "error: " + str(ex)
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
self.__close()
|
||||||
|
self.__DB_CONN.commit()
|
||||||
|
|
||||||
|
def save(self, keys, param):
|
||||||
|
# 更新数据
|
||||||
|
self.__GetConn()
|
||||||
|
self.__DB_CONN.text_factory = str
|
||||||
|
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 public
|
||||||
|
public.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, 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, ex:
|
||||||
|
return "error: " + str(ex)
|
||||||
|
|
||||||
|
def execute(self, sql, param):
|
||||||
|
# 执行SQL语句返回受影响行
|
||||||
|
self.__GetConn()
|
||||||
|
try:
|
||||||
|
result = self.__DB_CONN.execute(sql, param)
|
||||||
|
self.__DB_CONN.commit()
|
||||||
|
return result.rowcount
|
||||||
|
except Exception, 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 data
|
||||||
|
except Exception, ex:
|
||||||
|
return "error: " + str(ex)
|
||||||
|
|
||||||
|
def create(self, name):
|
||||||
|
# 创建数据表
|
||||||
|
self.__GetConn()
|
||||||
|
import public
|
||||||
|
script = public.readFile('data/' + name + '.sql')
|
||||||
|
result = self.__DB_CONN.executescript(script)
|
||||||
|
self.__DB_CONN.commit()
|
||||||
|
return result.rowcount
|
||||||
|
|
||||||
|
def fofile(self, filename):
|
||||||
|
# 执行脚本
|
||||||
|
self.__GetConn()
|
||||||
|
import public
|
||||||
|
script = public.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
|
||||||
Executable
+250
@@ -0,0 +1,250 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import public
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import pwd
|
||||||
|
|
||||||
|
|
||||||
|
class file_api:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def setFileAccept(self, filename):
|
||||||
|
auth = 'www:www'
|
||||||
|
if public.getOs() == 'darwin':
|
||||||
|
user = public.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 = public.getRootDir() + '/recycle_bin/'
|
||||||
|
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)
|
||||||
|
public.writeLog('TYPE_FILE', public.getInfo(
|
||||||
|
'移动文件[{1}]到回收站成功!', (path)))
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
public.writeLog('TYPE_FILE', public.getInfo(
|
||||||
|
'移动文件[{1}]到回收站失败!', (path)))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def getBody(self, path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return public.returnJson(False, '文件不存在', (path,))
|
||||||
|
|
||||||
|
if os.path.getsize(path) > 2097152:
|
||||||
|
return public.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 public.returnJson(True, 'OK', data)
|
||||||
|
except Exception as ex:
|
||||||
|
return public.returnJson(False, u'文件编码不被兼容,无法正确读取文件!' + str(ex))
|
||||||
|
|
||||||
|
def saveBody(self, path, data, encoding='utf-8'):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return public.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()
|
||||||
|
|
||||||
|
public.writeLog('TYPE_FILE', '文件保存成功', (path,))
|
||||||
|
return public.returnJson(True, '文件保存成功')
|
||||||
|
except Exception as ex:
|
||||||
|
return public.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 public.returnMsg(False, '指定文件不存在!')
|
||||||
|
|
||||||
|
try:
|
||||||
|
tmps = public.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)
|
||||||
|
public.writeLog("TYPE_FILE", '文件压缩成功!', (sfile, dfile))
|
||||||
|
return public.returnJson(True, '文件压缩成功!')
|
||||||
|
except:
|
||||||
|
return public.returnJson(False, '文件压缩失败!')
|
||||||
|
|
||||||
|
def delete(self, path):
|
||||||
|
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return public.returnJson(False, '指定文件不存在!')
|
||||||
|
|
||||||
|
# 检查是否为.user.ini
|
||||||
|
if path.find('.user.ini') >= 0:
|
||||||
|
os.system("chattr -i '" + path + "'")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists('data/recycle_bin.pl'):
|
||||||
|
if self.mvRecycleBin(path):
|
||||||
|
return public.returnJson(True, '已将文件移动到回收站!')
|
||||||
|
os.remove(path)
|
||||||
|
public.writeLog('TYPE_FILE', public.getInfo(
|
||||||
|
'删除文件[{1}]成功!', (path)))
|
||||||
|
return public.returnJson(True, '删除文件成功!')
|
||||||
|
except:
|
||||||
|
return public.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 = public.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).encode('utf8')
|
||||||
|
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:
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
|
||||||
|
data['DIR'] = sorted(dirnames)
|
||||||
|
data['FILES'] = sorted(filenames)
|
||||||
|
if path[0:2] == '//':
|
||||||
|
data['PATH'] = path[1:]
|
||||||
|
else:
|
||||||
|
data['PATH'] = path
|
||||||
|
return public.getJson(data)
|
||||||
Executable
+56
@@ -0,0 +1,56 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import public
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import pwd
|
||||||
|
|
||||||
|
|
||||||
|
class firewall_api:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getList(self, page, limit):
|
||||||
|
|
||||||
|
start = (page - 1) * limit
|
||||||
|
|
||||||
|
_list = public.M('firewall').field('id,port,ps,addtime').limit(
|
||||||
|
str(start) + ',' + str(limit)).order('id desc').select()
|
||||||
|
data = {}
|
||||||
|
data['data'] = _list
|
||||||
|
|
||||||
|
count = public.M('firewall').count()
|
||||||
|
_page = {}
|
||||||
|
_page['count'] = count
|
||||||
|
_page['tojs'] = 'showAccept'
|
||||||
|
_page['p'] = page
|
||||||
|
|
||||||
|
data['page'] = public.getPage(_page)
|
||||||
|
return public.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 = public.M('logs').where(find_search, ()).field(
|
||||||
|
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
|
||||||
|
data = {}
|
||||||
|
data['data'] = _list
|
||||||
|
|
||||||
|
count = public.M('logs').where(find_search, ()).count()
|
||||||
|
_page = {}
|
||||||
|
_page['count'] = count
|
||||||
|
_page['tojs'] = 'getLogs'
|
||||||
|
_page['p'] = page
|
||||||
|
|
||||||
|
data['page'] = public.getPage(_page)
|
||||||
|
return public.getJson(data)
|
||||||
@@ -1,20 +1,8 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# MW-Linux面板
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# Author: midoks <midoks@163.com>
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# 分页库操作
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import string
|
import string
|
||||||
|
import public
|
||||||
|
|
||||||
|
|
||||||
class Page():
|
class Page():
|
||||||
@@ -39,10 +27,10 @@ class Page():
|
|||||||
__RTURN_JS = False # 是否返回JS回调
|
__RTURN_JS = False # 是否返回JS回调
|
||||||
__START_NUM = None # 起始行
|
__START_NUM = None # 起始行
|
||||||
__END_NUM = None # 结束行
|
__END_NUM = None # 结束行
|
||||||
__ARGS_TPL = ''
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
if False:
|
tmp = public.getMsg('PAGE')
|
||||||
|
if tmp:
|
||||||
self.__PREV = tmp['PREV']
|
self.__PREV = tmp['PREV']
|
||||||
self.__NEXT = tmp['NEXT']
|
self.__NEXT = tmp['NEXT']
|
||||||
self.__START = tmp['START']
|
self.__START = tmp['START']
|
||||||
@@ -52,19 +40,12 @@ class Page():
|
|||||||
self.__FO = tmp['FO']
|
self.__FO = tmp['FO']
|
||||||
self.__LINE = tmp['LINE']
|
self.__LINE = tmp['LINE']
|
||||||
|
|
||||||
def getPageNum(self, num):
|
|
||||||
return str(num) + self.__ARGS_TPL
|
|
||||||
|
|
||||||
def GetPage(self, pageInfo, limit='1,2,3,4,5,6,7,8'):
|
def GetPage(self, pageInfo, limit='1,2,3,4,5,6,7,8'):
|
||||||
# 取分页信息
|
# 取分页信息
|
||||||
# @param pageInfo 传入分页参数字典
|
# @param pageInfo 传入分页参数字典
|
||||||
# @param limit 返回系列
|
# @param limit 返回系列
|
||||||
self.__RTURN_JS = pageInfo['return_js']
|
self.__RTURN_JS = pageInfo['return_js']
|
||||||
self.__COUNT_ROW = pageInfo['count']
|
self.__COUNT_ROW = pageInfo['count']
|
||||||
|
|
||||||
if 'args_tpl' in pageInfo:
|
|
||||||
self.__ARGS_TPL = pageInfo['args_tpl']
|
|
||||||
|
|
||||||
self.ROW = pageInfo['row']
|
self.ROW = pageInfo['row']
|
||||||
self.__C_PAGE = self.__GetCpage(pageInfo['p'])
|
self.__C_PAGE = self.__GetCpage(pageInfo['p'])
|
||||||
self.__START_NUM = self.__StartRow()
|
self.__START_NUM = self.__StartRow()
|
||||||
@@ -74,6 +55,7 @@ class Page():
|
|||||||
self.SHIFT = self.__START_NUM - 1
|
self.SHIFT = self.__START_NUM - 1
|
||||||
|
|
||||||
keys = limit.split(',')
|
keys = limit.split(',')
|
||||||
|
|
||||||
pages = {}
|
pages = {}
|
||||||
# 起始页
|
# 起始页
|
||||||
pages['1'] = self.__GetStart()
|
pages['1'] = self.__GetStart()
|
||||||
@@ -88,16 +70,14 @@ class Page():
|
|||||||
|
|
||||||
# 当前显示页与总页数
|
# 当前显示页与总页数
|
||||||
pages['6'] = "<span class='Pnumber'>" + \
|
pages['6'] = "<span class='Pnumber'>" + \
|
||||||
str(self.__C_PAGE) + "/" + \
|
bytes(self.__C_PAGE) + "/" + bytes(self.__COUNT_PAGE) + "</span>"
|
||||||
str(self.__COUNT_PAGE) + "</span>"
|
|
||||||
|
|
||||||
# 本页显示开始与结束行
|
# 本页显示开始与结束行
|
||||||
pages['7'] = "<span class='Pline'>" + str(self.__FO) + \
|
pages['7'] = "<span class='Pline'>" + self.__FO + \
|
||||||
str(self.__START_NUM) + "-" + \
|
bytes(self.__START_NUM) + "-" + \
|
||||||
str(self.__END_NUM) + str(self.__LINE) + "</span>"
|
bytes(self.__END_NUM) + self.__LINE + "</span>"
|
||||||
# 行数
|
# 行数
|
||||||
pages['8'] = "<span class='Pcount'>" + str(self.__COUNT_START) + \
|
pages['8'] = "<span class='Pcount'>" + self.__COUNT_START + \
|
||||||
str(self.__COUNT_ROW) + str(self.__COUNT_END) + "</span>"
|
bytes(self.__COUNT_ROW) + self.__COUNT_END + "</span>"
|
||||||
|
|
||||||
# 构造返回数据
|
# 构造返回数据
|
||||||
retuls = '<div>'
|
retuls = '<div>'
|
||||||
@@ -116,11 +96,10 @@ class Page():
|
|||||||
else:
|
else:
|
||||||
if self.__RTURN_JS == "":
|
if self.__RTURN_JS == "":
|
||||||
endStr = "<a class='Pend' href='" + self.__URI + "p=" + \
|
endStr = "<a class='Pend' href='" + self.__URI + "p=" + \
|
||||||
str(self.__COUNT_PAGE) + "'>" + str(self.__END) + "</a>"
|
bytes(self.__COUNT_PAGE) + "'>" + self.__END + "</a>"
|
||||||
else:
|
else:
|
||||||
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + \
|
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + \
|
||||||
"(" + self.getPageNum(self.__COUNT_PAGE) + ")'>" + \
|
"(" + bytes(self.__COUNT_PAGE) + ")'>" + self.__END + "</a>"
|
||||||
str(self.__END) + "</a>"
|
|
||||||
return endStr
|
return endStr
|
||||||
|
|
||||||
def __GetNext(self):
|
def __GetNext(self):
|
||||||
@@ -131,11 +110,10 @@ class Page():
|
|||||||
else:
|
else:
|
||||||
if self.__RTURN_JS == "":
|
if self.__RTURN_JS == "":
|
||||||
nextStr = "<a class='Pnext' href='" + self.__URI + "p=" + \
|
nextStr = "<a class='Pnext' href='" + self.__URI + "p=" + \
|
||||||
str(self.__C_PAGE + 1) + "'>" + str(self.__NEXT) + "</a>"
|
bytes(self.__C_PAGE + 1) + "'>" + self.__NEXT + "</a>"
|
||||||
else:
|
else:
|
||||||
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + \
|
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + \
|
||||||
"(" + self.getPageNum(self.__C_PAGE + 1) + ")'>" + \
|
"(" + bytes(self.__C_PAGE + 1) + ")'>" + self.__NEXT + "</a>"
|
||||||
str(self.__NEXT) + "</a>"
|
|
||||||
|
|
||||||
return nextStr
|
return nextStr
|
||||||
|
|
||||||
@@ -156,15 +134,15 @@ class Page():
|
|||||||
if page > 0:
|
if page > 0:
|
||||||
if self.__RTURN_JS == "":
|
if self.__RTURN_JS == "":
|
||||||
pages += "<a class='Pnum' href='" + self.__URI + \
|
pages += "<a class='Pnum' href='" + self.__URI + \
|
||||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
"p=" + bytes(page) + "'>" + bytes(page) + "</a>"
|
||||||
else:
|
else:
|
||||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||||
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
|
"(" + bytes(page) + ")'>" + bytes(page) + "</a>"
|
||||||
|
|
||||||
# 当前页
|
# 当前页
|
||||||
if self.__C_PAGE > 0:
|
if self.__C_PAGE > 0:
|
||||||
pages += "<span class='Pcurrent'>" + \
|
pages += "<span class='Pcurrent'>" + \
|
||||||
str(self.__C_PAGE) + "</span>"
|
bytes(self.__C_PAGE) + "</span>"
|
||||||
|
|
||||||
# 当前页之后
|
# 当前页之后
|
||||||
if self.__C_PAGE <= self.__LIST_NUM:
|
if self.__C_PAGE <= self.__LIST_NUM:
|
||||||
@@ -179,10 +157,10 @@ class Page():
|
|||||||
break
|
break
|
||||||
if self.__RTURN_JS == "":
|
if self.__RTURN_JS == "":
|
||||||
pages += "<a class='Pnum' href='" + self.__URI + \
|
pages += "<a class='Pnum' href='" + self.__URI + \
|
||||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
"p=" + bytes(page) + "'>" + bytes(page) + "</a>"
|
||||||
else:
|
else:
|
||||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||||
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
|
"(" + bytes(page) + ")'>" + bytes(page) + "</a>"
|
||||||
|
|
||||||
return pages
|
return pages
|
||||||
|
|
||||||
@@ -194,11 +172,10 @@ class Page():
|
|||||||
else:
|
else:
|
||||||
if self.__RTURN_JS == "":
|
if self.__RTURN_JS == "":
|
||||||
startStr = "<a class='Ppren' href='" + self.__URI + "p=" + \
|
startStr = "<a class='Ppren' href='" + self.__URI + "p=" + \
|
||||||
str(self.__C_PAGE - 1) + "'>" + str(self.__PREV) + "</a>"
|
bytes(self.__C_PAGE - 1) + "'>" + self.__PREV + "</a>"
|
||||||
else:
|
else:
|
||||||
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + \
|
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + \
|
||||||
"(" + self.getPageNum(self.__C_PAGE - 1) + ")'>" + \
|
"(" + bytes(self.__C_PAGE - 1) + ")'>" + self.__PREV + "</a>"
|
||||||
str(self.__PREV) + "</a>"
|
|
||||||
return startStr
|
return startStr
|
||||||
|
|
||||||
def __GetStart(self):
|
def __GetStart(self):
|
||||||
@@ -209,10 +186,10 @@ class Page():
|
|||||||
else:
|
else:
|
||||||
if self.__RTURN_JS == "":
|
if self.__RTURN_JS == "":
|
||||||
startStr = "<a class='Pstart' href='" + \
|
startStr = "<a class='Pstart' href='" + \
|
||||||
self.__URI + "p=1'>" + str(self.__START) + "</a>"
|
self.__URI + "p=1'>" + self.__START + "</a>"
|
||||||
else:
|
else:
|
||||||
startStr = "<a class='Pstart' onclick='" + \
|
startStr = "<a class='Pstart' onclick='" + \
|
||||||
self.__RTURN_JS + "("+self.getPageNum(1)+")'>" + str(self.__START) + "</a>"
|
self.__RTURN_JS + "(1)'>" + self.__START + "</a>"
|
||||||
return startStr
|
return startStr
|
||||||
|
|
||||||
def __GetCpage(self, p):
|
def __GetCpage(self, p):
|
||||||
@@ -235,11 +212,11 @@ class Page():
|
|||||||
# 取总页数
|
# 取总页数
|
||||||
return int(math.ceil(self.__COUNT_ROW / float(self.ROW)))
|
return int(math.ceil(self.__COUNT_ROW / float(self.ROW)))
|
||||||
|
|
||||||
def __SetUri(self, sinput):
|
def __SetUri(self, input):
|
||||||
# 构造URI
|
# 构造URI
|
||||||
uri = '?'
|
uri = '?'
|
||||||
for key in sinput:
|
for key in input:
|
||||||
if key == 'p':
|
if key == 'p':
|
||||||
continue
|
continue
|
||||||
uri += key + '=' + sinput[key] + '&'
|
uri += key + '=' + input[key] + '&'
|
||||||
return str(uri)
|
return str(uri)
|
||||||
Executable
+512
@@ -0,0 +1,512 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import public
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
|
import threading
|
||||||
|
import multiprocessing
|
||||||
|
|
||||||
|
|
||||||
|
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 plugin_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 = public.getRunDir() + '/plugins'
|
||||||
|
|
||||||
|
# 进程是否存在
|
||||||
|
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):
|
||||||
|
if not self.__tasks:
|
||||||
|
self.__tasks = public.M('tasks').where(
|
||||||
|
"status!=?", ('1',)).field('status,name').select()
|
||||||
|
|
||||||
|
if sName.find('php-') != -1:
|
||||||
|
tmp = sName.split('-')
|
||||||
|
sName = tmp[0]
|
||||||
|
version = tmp[1]
|
||||||
|
isTask = '1'
|
||||||
|
for task in self.__tasks:
|
||||||
|
tmpt = public.getStrBetween('[', ']', task['name'])
|
||||||
|
if not tmpt:
|
||||||
|
continue
|
||||||
|
tmp1 = tmpt.split('-')
|
||||||
|
name1 = tmp1[0].lower()
|
||||||
|
if sName == 'php':
|
||||||
|
if name1 == sName and tmp1[1] == version:
|
||||||
|
isTask = task['status']
|
||||||
|
else:
|
||||||
|
if name1 == 'pure':
|
||||||
|
name1 = 'pure-ftpd'
|
||||||
|
if name1 == 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 checkStatusMProcess(self, plugins_info):
|
||||||
|
manager = multiprocessing.Manager()
|
||||||
|
return_dict = manager.dict()
|
||||||
|
jobs = []
|
||||||
|
ntmp_list = range(len(plugins_info))
|
||||||
|
for i in ntmp_list:
|
||||||
|
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):
|
||||||
|
public.writeFile(self.__index, '[]')
|
||||||
|
|
||||||
|
indexList = json.loads(public.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 public.readFile(version_f).strip()
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# 构造本地插件信息
|
||||||
|
def getPluginInfo(self, info):
|
||||||
|
checks = ''
|
||||||
|
path = ''
|
||||||
|
coexist = False
|
||||||
|
|
||||||
|
if info["checks"][0:1] == '/':
|
||||||
|
checks = info["checks"]
|
||||||
|
else:
|
||||||
|
checks = public.getRootDir() + '/' + info['checks']
|
||||||
|
|
||||||
|
if info.has_key('path'):
|
||||||
|
path = info['path']
|
||||||
|
|
||||||
|
if path[0:1] != '/':
|
||||||
|
path = public.getRootDir() + '/' + path
|
||||||
|
|
||||||
|
if info.has_key('coexist') and info['coexist']:
|
||||||
|
coexist = True
|
||||||
|
|
||||||
|
pluginInfo = {
|
||||||
|
"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,
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginInfo['task'] = self.checkSetupTask(pluginInfo['name'])
|
||||||
|
|
||||||
|
if checks.find('VERSION') > -1:
|
||||||
|
pluginInfo['install_checks'] = checks.replace(
|
||||||
|
'VERSION', info['versions'])
|
||||||
|
|
||||||
|
if path.find('VERSION') > -1:
|
||||||
|
pluginInfo['path'] = path.replace(
|
||||||
|
'VERSION', info['versions'])
|
||||||
|
|
||||||
|
pluginInfo['display'] = self.checkDisplayIndex(
|
||||||
|
info['name'], pluginInfo['versions'])
|
||||||
|
|
||||||
|
pluginInfo['setup'] = os.path.exists(pluginInfo['install_checks'])
|
||||||
|
|
||||||
|
if coexist and pluginInfo['setup']:
|
||||||
|
pluginInfo['setup_version'] = info['versions']
|
||||||
|
else:
|
||||||
|
pluginInfo['setup_version'] = self.getVersion(
|
||||||
|
pluginInfo['install_checks'])
|
||||||
|
# pluginInfo['status'] = self.checkStatus(pluginInfo)
|
||||||
|
return pluginInfo
|
||||||
|
|
||||||
|
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 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 getAllList(self, sType='0'):
|
||||||
|
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(public.readFile(json_file))
|
||||||
|
tmp_data = self.makeList(data, sType)
|
||||||
|
for index in range(len(tmp_data)):
|
||||||
|
plugins_info.append(tmp_data[index])
|
||||||
|
except Exception, 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(public.readFile(json_file))
|
||||||
|
tmp_data = self.makeList(data, sType)
|
||||||
|
for index in range(len(tmp_data)):
|
||||||
|
plugins_info.append(tmp_data[index])
|
||||||
|
except Exception, e:
|
||||||
|
print e
|
||||||
|
|
||||||
|
start = (page - 1) * pageSize
|
||||||
|
end = start + pageSize
|
||||||
|
_plugins_info = plugins_info[start:end]
|
||||||
|
|
||||||
|
_plugins_info = self.checkStatusMProcess(_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(public.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(public.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):
|
||||||
|
|
||||||
|
ret = {}
|
||||||
|
ret['type'] = json.loads(public.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'] = public.getPage(args)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def getIndexList(self):
|
||||||
|
if not os.path.exists(self.__index):
|
||||||
|
public.writeFile(self.__index, '[]')
|
||||||
|
|
||||||
|
indexList = json.loads(public.readFile(self.__index))
|
||||||
|
|
||||||
|
plist = []
|
||||||
|
app = []
|
||||||
|
for i in indexList:
|
||||||
|
info = i.split('-')
|
||||||
|
if not info[0] in app:
|
||||||
|
app.append(info[0])
|
||||||
|
path = self.__plugin_dir + '/' + info[0]
|
||||||
|
if os.path.isdir(path):
|
||||||
|
json_file = path + '/info.json'
|
||||||
|
if os.path.exists(json_file):
|
||||||
|
try:
|
||||||
|
data = json.loads(public.readFile(json_file))
|
||||||
|
tmp_data = self.makeList(data)
|
||||||
|
for index in range(len(tmp_data)):
|
||||||
|
if tmp_data[index]['versions'] == info[1] or info[1] in tmp_data[index]['versions']:
|
||||||
|
tmp_data[index]['display'] = True
|
||||||
|
plist.append(tmp_data[index])
|
||||||
|
continue
|
||||||
|
except Exception, e:
|
||||||
|
print e
|
||||||
|
|
||||||
|
plist = self.checkStatusMProcess(plist)
|
||||||
|
return plist
|
||||||
|
|
||||||
|
def setIndexSort(self, sort):
|
||||||
|
data = sort.split('|')
|
||||||
|
public.writeFile(self.__index, json.dumps(data))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def addIndex(self, name, version):
|
||||||
|
if not os.path.exists(self.__index):
|
||||||
|
public.writeFile(self.__index, '[]')
|
||||||
|
|
||||||
|
indexList = json.loads(public.readFile(self.__index))
|
||||||
|
vname = name + '-' + version
|
||||||
|
|
||||||
|
if vname in indexList:
|
||||||
|
return public.returnJson(False, '请不要重复添加!')
|
||||||
|
if len(indexList) >= 12:
|
||||||
|
return public.returnJson(False, '首页最多只能显示12个软件!')
|
||||||
|
|
||||||
|
indexList.append(vname)
|
||||||
|
public.writeFile(self.__index, json.dumps(indexList))
|
||||||
|
return public.returnJson(True, '添加成功!')
|
||||||
|
|
||||||
|
def removeIndex(self, name, version):
|
||||||
|
if not os.path.exists(self.__index):
|
||||||
|
public.writeFile(self.__index, '[]')
|
||||||
|
|
||||||
|
indexList = json.loads(public.readFile(self.__index))
|
||||||
|
vname = name + '-' + version
|
||||||
|
if not vname in indexList:
|
||||||
|
return public.returnJson(True, '删除成功!')
|
||||||
|
indexList.remove(vname)
|
||||||
|
public.writeFile(self.__index, json.dumps(indexList))
|
||||||
|
return public.returnJson(True, '删除成功!')
|
||||||
|
|
||||||
|
def run(self, name, func, version, args='', script='index'):
|
||||||
|
path = public.getRunDir() + '/' + self.__plugin_dir + \
|
||||||
|
'/' + name + '/' + script + '.py'
|
||||||
|
py = 'python ' + path
|
||||||
|
if args == '':
|
||||||
|
py_cmd = py + ' ' + func + ' ' + version
|
||||||
|
else:
|
||||||
|
py_cmd = py + ' ' + func + ' ' + version + ' ' + args
|
||||||
|
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return ('', '')
|
||||||
|
data = public.execShell(py_cmd)
|
||||||
|
|
||||||
|
print py_cmd
|
||||||
|
# print os.path.exists(py_cmd)
|
||||||
|
return (data[0].strip(), data[1].strip())
|
||||||
Executable
+723
@@ -0,0 +1,723 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
import db
|
||||||
|
|
||||||
|
from random import Random
|
||||||
|
|
||||||
|
|
||||||
|
def execShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||||
|
|
||||||
|
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 getRunDir():
|
||||||
|
return os.getcwd()
|
||||||
|
|
||||||
|
|
||||||
|
def getRootDir():
|
||||||
|
return os.path.dirname(os.path.dirname(getRunDir()))
|
||||||
|
|
||||||
|
|
||||||
|
def getPluginDir():
|
||||||
|
return getRunDir() + '/plugins'
|
||||||
|
|
||||||
|
|
||||||
|
def getServerDir():
|
||||||
|
return getRootDir() + '/server'
|
||||||
|
|
||||||
|
|
||||||
|
def getWwwDir():
|
||||||
|
return getRootDir() + '/wwwroot'
|
||||||
|
|
||||||
|
|
||||||
|
def getLogsDir():
|
||||||
|
return getRootDir() + '/wwwlogs'
|
||||||
|
|
||||||
|
|
||||||
|
def getOs():
|
||||||
|
os = execShell('uname')
|
||||||
|
return os[0].lower().strip()
|
||||||
|
|
||||||
|
|
||||||
|
def isAppleSystem():
|
||||||
|
if getOs() == 'darwin':
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def isInstalledWeb():
|
||||||
|
path = getServerDir() + '/openresty/nginx/sbin/nginx'
|
||||||
|
if os.path.exists(path):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def restartWeb():
|
||||||
|
if isInstalledWeb():
|
||||||
|
initd = getServerDir() + '/openresty/init.d/openresty'
|
||||||
|
execShell(initd + ' ' + 'reload')
|
||||||
|
|
||||||
|
|
||||||
|
def M(table):
|
||||||
|
sql = db.Sql()
|
||||||
|
return sql.table(table)
|
||||||
|
|
||||||
|
|
||||||
|
def getPage(args, result='1,2,3,4,5,8'):
|
||||||
|
data = getPageObject(args, result)
|
||||||
|
return data[0]
|
||||||
|
|
||||||
|
|
||||||
|
def getPageObject(args, result='1,2,3,4,5,8'):
|
||||||
|
# 取分页
|
||||||
|
import page
|
||||||
|
# 实例化分页类
|
||||||
|
page = page.Page()
|
||||||
|
info = {}
|
||||||
|
|
||||||
|
info['count'] = 0
|
||||||
|
if args.has_key('count'):
|
||||||
|
info['count'] = int(args['count'])
|
||||||
|
|
||||||
|
info['row'] = 10
|
||||||
|
if args.has_key('row'):
|
||||||
|
info['row'] = int(args['row'])
|
||||||
|
|
||||||
|
info['p'] = 1
|
||||||
|
if args.has_key('p'):
|
||||||
|
info['p'] = int(args['p'])
|
||||||
|
info['uri'] = {}
|
||||||
|
info['return_js'] = ''
|
||||||
|
if args.has_key('tojs'):
|
||||||
|
info['return_js'] = args['tojs']
|
||||||
|
|
||||||
|
return (page.GetPage(info, result), page)
|
||||||
|
|
||||||
|
|
||||||
|
def md5(str):
|
||||||
|
# 生成MD5
|
||||||
|
try:
|
||||||
|
m = hashlib.md5()
|
||||||
|
m.update(str)
|
||||||
|
return m.hexdigest()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def getFileMd5(filename):
|
||||||
|
# 文件的MD5值
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
return False
|
||||||
|
|
||||||
|
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):
|
||||||
|
# 取随机字符串
|
||||||
|
str = ''
|
||||||
|
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
|
||||||
|
chrlen = len(chars) - 1
|
||||||
|
random = Random()
|
||||||
|
for i in range(length):
|
||||||
|
str += chars[random.randint(0, chrlen)]
|
||||||
|
return str
|
||||||
|
|
||||||
|
|
||||||
|
def getJson(data):
|
||||||
|
import json
|
||||||
|
return json.dumps(data)
|
||||||
|
|
||||||
|
|
||||||
|
def returnJson(status, msg, args=()):
|
||||||
|
# 取通用Json返回
|
||||||
|
return getJson(returnMsg(status, msg, args))
|
||||||
|
|
||||||
|
|
||||||
|
def returnMsg(status, msg, args=()):
|
||||||
|
# 取通用字曲返回
|
||||||
|
pjson = 'static/language/' + getLanguage() + '/public.json'
|
||||||
|
logMessage = json.loads(readFile(pjson))
|
||||||
|
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, 'data': args}
|
||||||
|
|
||||||
|
|
||||||
|
def getInfo(msg, args=()):
|
||||||
|
# 取提示消息
|
||||||
|
for i in range(len(args)):
|
||||||
|
rep = '{' + str(i + 1) + '}'
|
||||||
|
msg = msg.replace(rep, args[i])
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def getMsg(key, args=()):
|
||||||
|
# 取提示消息
|
||||||
|
try:
|
||||||
|
logMessage = json.loads(
|
||||||
|
readFile('static/language/' + getLanguage() + '/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):
|
||||||
|
# 取提示消息
|
||||||
|
logMessage = json.loads(
|
||||||
|
readFile('static/language/' + getLanguage() + '/template.json'))
|
||||||
|
keys = logMessage.keys()
|
||||||
|
msg = None
|
||||||
|
if key in keys:
|
||||||
|
msg = logMessage[key]
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
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 getLanguage():
|
||||||
|
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/' + getLanguage() + '/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):
|
||||||
|
# 写进度
|
||||||
|
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():
|
||||||
|
# 取进度
|
||||||
|
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 getLastLine(inputfile, lineNum):
|
||||||
|
# 读文件指定倒数行数
|
||||||
|
try:
|
||||||
|
fp = open(inputfile, 'r')
|
||||||
|
lastLine = ""
|
||||||
|
|
||||||
|
lines = fp.readlines()
|
||||||
|
count = len(lines)
|
||||||
|
if count > lineNum:
|
||||||
|
num = lineNum
|
||||||
|
else:
|
||||||
|
num = count
|
||||||
|
i = 1
|
||||||
|
lastre = []
|
||||||
|
for i in range(1, (num + 1)):
|
||||||
|
if lines:
|
||||||
|
n = -i
|
||||||
|
lastLine = lines[n].strip()
|
||||||
|
fp.close()
|
||||||
|
lastre.append(lastLine)
|
||||||
|
|
||||||
|
result = ''
|
||||||
|
num -= 1
|
||||||
|
while num >= 0:
|
||||||
|
result += lastre[num] + "\n"
|
||||||
|
num -= 1
|
||||||
|
return result
|
||||||
|
except:
|
||||||
|
return getMsg('TASK_SLEEP')
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
return '127.0.0.1'
|
||||||
|
|
||||||
|
|
||||||
|
def inArray(arrays, searchStr):
|
||||||
|
# 搜索数据中是否存在
|
||||||
|
for key in arrays:
|
||||||
|
if key == searchStr:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def checkIp(ip):
|
||||||
|
# 检查是否为IPv4地址
|
||||||
|
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]
|
||||||
|
|
||||||
|
|
||||||
|
def getCpuType():
|
||||||
|
# 取CPU类型
|
||||||
|
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 isUpdateLocalSoft():
|
||||||
|
num = M('tasks').where('status!=?', ('1',)).count()
|
||||||
|
if os.path.exists('mdserver-web.zip'):
|
||||||
|
return True
|
||||||
|
|
||||||
|
if num > 0:
|
||||||
|
data = M('tasks').where('status!=?', ('1',)).field(
|
||||||
|
'id,type,execstr').limit('1').select()
|
||||||
|
argv = data[0]['execstr'].split('|dl|')
|
||||||
|
if data[0]['type'] == 'download' and argv[1] == 'mdserver-web.zip':
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def hasPwd(password):
|
||||||
|
# 加密密码字符
|
||||||
|
import crypt
|
||||||
|
return crypt.crypt(password, password)
|
||||||
|
|
||||||
|
|
||||||
|
def getTimeout(url):
|
||||||
|
start = time.time()
|
||||||
|
result = httpGet(url)
|
||||||
|
if result != 'True':
|
||||||
|
return False
|
||||||
|
return int((time.time() - start) * 1000)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def checkToken(get):
|
||||||
|
# 检查Token
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
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 toSize(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 getMacAddress():
|
||||||
|
# 获取mac
|
||||||
|
import uuid
|
||||||
|
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
|
||||||
|
return ":".join([mac[e:e + 2] for e in range(0, 11, 2)])
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
Executable
+399
@@ -0,0 +1,399 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import public
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import pwd
|
||||||
|
|
||||||
|
|
||||||
|
class site_api:
|
||||||
|
siteName = None # 网站名称
|
||||||
|
sitePath = None # 根目录
|
||||||
|
sitePort = None # 端口
|
||||||
|
phpVersion = None # PHP版本
|
||||||
|
setupPath = None # 安装路径
|
||||||
|
isWriteLogs = None # 是否写日志
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.setupPath = public.getServerDir()
|
||||||
|
path = self.setupPath + '/openresty/nginx/conf/vhost'
|
||||||
|
if not os.path.exists(path):
|
||||||
|
public.execShell("mkdir -p " + path + " && chmod -R 755 " + path)
|
||||||
|
path = self.setupPath + '/openresty/nginx/conf/rewrite'
|
||||||
|
if not os.path.exists(path):
|
||||||
|
public.execShell("mkdir -p " + path + " && chmod -R 755 " + path)
|
||||||
|
|
||||||
|
# 域名编码转换
|
||||||
|
def toPunycode(self, domain):
|
||||||
|
import re
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
domain = domain.encode('utf8')
|
||||||
|
tmp = domain.split('.')
|
||||||
|
newdomain = ''
|
||||||
|
for dkey in tmp:
|
||||||
|
# 匹配非ascii字符
|
||||||
|
match = re.search(u"[\x80-\xff]+", dkey)
|
||||||
|
if not match:
|
||||||
|
newdomain += dkey + '.'
|
||||||
|
else:
|
||||||
|
newdomain += 'xn--' + \
|
||||||
|
dkey.decode('utf-8').encode('punycode') + '.'
|
||||||
|
return newdomain[0:-1]
|
||||||
|
|
||||||
|
# 中文路径处理
|
||||||
|
def toPunycodePath(self, path):
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
path = path.encode('utf-8')
|
||||||
|
if os.path.exists(path):
|
||||||
|
return path
|
||||||
|
import re
|
||||||
|
match = re.search(u"[\x80-\xff]+", path)
|
||||||
|
if not match:
|
||||||
|
return path
|
||||||
|
npath = ''
|
||||||
|
for ph in path.split('/'):
|
||||||
|
npath += '/' + self.toPunycode(ph)
|
||||||
|
return npath.replace('//', '/')
|
||||||
|
|
||||||
|
# 路径处理
|
||||||
|
def getPath(self, path):
|
||||||
|
if path[-1] == '/':
|
||||||
|
return path[0:-1]
|
||||||
|
return path
|
||||||
|
|
||||||
|
def getHostConf(self, siteName):
|
||||||
|
return public.getServerDir() + '/openresty/nginx/conf/vhost/' + siteName + '.conf'
|
||||||
|
|
||||||
|
def getRewriteConf(self, siteName):
|
||||||
|
return public.getServerDir() + '/openresty/nginx/conf/rewrite/' + siteName + '.conf'
|
||||||
|
|
||||||
|
def getIndexConf(self):
|
||||||
|
return public.getServerDir() + '/openresty/nginx/conf/nginx.conf'
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
_list = public.M('sites').where('', ()).field(
|
||||||
|
'id,name,path,status,ps,addtime,edate').limit('0,5').order('id desc').select()
|
||||||
|
_ret = {}
|
||||||
|
_ret['data'] = _list
|
||||||
|
|
||||||
|
count = public.M('sites').where('', ()).count()
|
||||||
|
_page = {}
|
||||||
|
_page['count'] = count
|
||||||
|
_page['tojs'] = 'getWeb'
|
||||||
|
|
||||||
|
_ret['page'] = public.getPage(_page)
|
||||||
|
return public.getJson(_ret)
|
||||||
|
|
||||||
|
def getDomain(self, pid):
|
||||||
|
_list = public.M('domain').where("pid=?", (pid,)).field(
|
||||||
|
'id,pid,name,port,addtime').select()
|
||||||
|
return public.getJson(_list)
|
||||||
|
|
||||||
|
def getLogs(self, siteName):
|
||||||
|
logPath = public.getLogsDir() + '/' + siteName + '.log'
|
||||||
|
if not os.path.exists(logPath):
|
||||||
|
return public.returnJson(False, '日志为空')
|
||||||
|
return public.returnJson(True, public.getNumLines(logPath, 1000))
|
||||||
|
|
||||||
|
def getSitePhpVersion(self, siteName):
|
||||||
|
conf = public.readFile(self.getHostConf(siteName))
|
||||||
|
rep = "enable-php-([0-9]{2,3})\.conf"
|
||||||
|
tmp = re.search(rep, conf).groups()
|
||||||
|
data = {}
|
||||||
|
data['phpversion'] = tmp[0]
|
||||||
|
return public.getJson(data)
|
||||||
|
|
||||||
|
def getIndex(self, sid):
|
||||||
|
print sid
|
||||||
|
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
|
||||||
|
file = self.getHostConf(siteName)
|
||||||
|
conf = public.readFile(file)
|
||||||
|
rep = "\s+index\s+(.+);"
|
||||||
|
tmp = re.search(rep, conf).groups()
|
||||||
|
return tmp[0].replace(' ', ',')
|
||||||
|
|
||||||
|
def setIndex(self, sid, index):
|
||||||
|
if index.find('.') == -1:
|
||||||
|
return public.returnJson(False, '默认文档格式不正确,例:index.html')
|
||||||
|
|
||||||
|
index = index.replace(' ', '')
|
||||||
|
index = index.replace(',,', ',')
|
||||||
|
|
||||||
|
if len(index) < 3:
|
||||||
|
return public.returnJson(False, '默认文档不能为空!')
|
||||||
|
|
||||||
|
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
|
||||||
|
index_l = index.replace(",", " ")
|
||||||
|
file = self.getHostConf(siteName)
|
||||||
|
conf = public.readFile(file)
|
||||||
|
if conf:
|
||||||
|
rep = "\s+index\s+.+;"
|
||||||
|
conf = re.sub(rep, "\n\tindex " + index_l + ";", conf)
|
||||||
|
public.writeFile(file, conf)
|
||||||
|
|
||||||
|
public.writeLog('TYPE_SITE', 'SITE_INDEX_SUCCESS', (siteName, index_l))
|
||||||
|
return public.returnJson(True, '设置成功!')
|
||||||
|
|
||||||
|
def getLimitNet(self, sid):
|
||||||
|
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
|
||||||
|
filename = self.getHostConf(siteName)
|
||||||
|
# 站点总并发
|
||||||
|
data = {}
|
||||||
|
conf = public.readFile(filename)
|
||||||
|
try:
|
||||||
|
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
|
||||||
|
tmp = re.search(rep, conf).groups()
|
||||||
|
data['perserver'] = int(tmp[0])
|
||||||
|
|
||||||
|
# IP并发限制
|
||||||
|
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
|
||||||
|
tmp = re.search(rep, conf).groups()
|
||||||
|
data['perip'] = int(tmp[0])
|
||||||
|
|
||||||
|
# 请求并发限制
|
||||||
|
rep = "\s+limit_rate\s+([0-9]+)\w+;"
|
||||||
|
tmp = re.search(rep, conf).groups()
|
||||||
|
data['limit_rate'] = int(tmp[0])
|
||||||
|
except:
|
||||||
|
data['perserver'] = 0
|
||||||
|
data['perip'] = 0
|
||||||
|
data['limit_rate'] = 0
|
||||||
|
|
||||||
|
return public.getJson(data)
|
||||||
|
|
||||||
|
def checkIndexConf(self):
|
||||||
|
limit = self.getIndexConf()
|
||||||
|
nginxConf = public.readFile(limit)
|
||||||
|
limitConf = "limit_conn_zone $binary_remote_addr zone=perip:10m;\n\t\tlimit_conn_zone $server_name zone=perserver:10m;"
|
||||||
|
nginxConf = nginxConf.replace(
|
||||||
|
"#limit_conn_zone $binary_remote_addr zone=perip:10m;", limitConf)
|
||||||
|
public.writeFile(limit, nginxConf)
|
||||||
|
|
||||||
|
def saveLimitNet(self, sid, perserver, perip, limit_rate):
|
||||||
|
|
||||||
|
str_perserver = 'limit_conn perserver ' + perserver + ';'
|
||||||
|
str_perip = 'limit_conn perip ' + perip + ';'
|
||||||
|
str_limit_rate = 'limit_rate ' + limit_rate + 'k;'
|
||||||
|
|
||||||
|
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
|
||||||
|
filename = self.getHostConf(siteName)
|
||||||
|
|
||||||
|
conf = public.readFile(filename)
|
||||||
|
if(conf.find('limit_conn perserver') != -1):
|
||||||
|
# 替换总并发
|
||||||
|
rep = "limit_conn\s+perserver\s+([0-9]+);"
|
||||||
|
conf = re.sub(rep, str_perserver, conf)
|
||||||
|
|
||||||
|
# 替换IP并发限制
|
||||||
|
rep = "limit_conn\s+perip\s+([0-9]+);"
|
||||||
|
conf = re.sub(rep, str_perip, conf)
|
||||||
|
|
||||||
|
# 替换请求流量限制
|
||||||
|
rep = "limit_rate\s+([0-9]+)\w+;"
|
||||||
|
conf = re.sub(rep, str_limit_rate, conf)
|
||||||
|
else:
|
||||||
|
conf = conf.replace('#error_page 404/404.html;', "#error_page 404/404.html;\n " +
|
||||||
|
str_perserver + "\n " + str_perip + "\n " + str_limit_rate)
|
||||||
|
|
||||||
|
public.writeFile(filename, conf)
|
||||||
|
public.restartWeb()
|
||||||
|
public.writeLog('TYPE_SITE', 'SITE_NETLIMIT_OPEN_SUCCESS', (siteName,))
|
||||||
|
return public.returnJson(True, '设置成功!')
|
||||||
|
|
||||||
|
def closeLimitNet(self, sid):
|
||||||
|
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
|
||||||
|
filename = self.getHostConf(siteName)
|
||||||
|
conf = public.readFile(filename)
|
||||||
|
# 清理总并发
|
||||||
|
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
|
||||||
|
conf = re.sub(rep, '', conf)
|
||||||
|
|
||||||
|
# 清理IP并发限制
|
||||||
|
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
|
||||||
|
conf = re.sub(rep, '', conf)
|
||||||
|
|
||||||
|
# 清理请求流量限制
|
||||||
|
rep = "\s+limit_rate\s+([0-9]+)\w+;"
|
||||||
|
conf = re.sub(rep, '', conf)
|
||||||
|
public.writeFile(filename, conf)
|
||||||
|
public.restartWeb()
|
||||||
|
public.writeLog(
|
||||||
|
'TYPE_SITE', 'SITE_NETLIMIT_CLOSE_SUCCESS', (siteName,))
|
||||||
|
return public.returnJson(True, '已关闭流量限制!')
|
||||||
|
|
||||||
|
def getSecurity(self, sid, name):
|
||||||
|
filename = self.getHostConf(name)
|
||||||
|
conf = public.readFile(filename)
|
||||||
|
data = {}
|
||||||
|
if conf.find('SECURITY-START') != -1:
|
||||||
|
rep = "#SECURITY-START(\n|.){1,500}#SECURITY-END"
|
||||||
|
tmp = re.search(rep, conf).group()
|
||||||
|
data['fix'] = re.search(
|
||||||
|
"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
|
||||||
|
data['domains'] = ','.join(re.search(
|
||||||
|
"valid_referers\s+none\s+blocked\s+(.+);\n", tmp).groups()[0].split())
|
||||||
|
data['status'] = True
|
||||||
|
else:
|
||||||
|
data['fix'] = 'jpg,jpeg,gif,png,js,css'
|
||||||
|
domains = public.M('domain').where(
|
||||||
|
'pid=?', (sid,)).field('name').select()
|
||||||
|
tmp = []
|
||||||
|
for domain in domains:
|
||||||
|
tmp.append(domain['name'])
|
||||||
|
data['domains'] = ','.join(tmp)
|
||||||
|
data['status'] = False
|
||||||
|
return public.getJson(data)
|
||||||
|
|
||||||
|
def setSecurity(self, sid, name, fix, domains, status):
|
||||||
|
if len(fix) < 2:
|
||||||
|
return public.returnJson(False, 'URL后缀不能为空!')
|
||||||
|
file = self.getHostConf(name)
|
||||||
|
if os.path.exists(file):
|
||||||
|
conf = public.readFile(file)
|
||||||
|
if conf.find('SECURITY-START') != -1:
|
||||||
|
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
||||||
|
conf = re.sub(rep, '', conf)
|
||||||
|
public.writeLog('网站管理', '站点[' + name + ']已关闭防盗链设置!')
|
||||||
|
else:
|
||||||
|
rconf = '''#SECURITY-START 防盗链配置
|
||||||
|
location ~ .*\.(%s)$
|
||||||
|
{
|
||||||
|
expires 30d;
|
||||||
|
access_log /dev/null;
|
||||||
|
valid_referers none blocked %s;
|
||||||
|
if ($invalid_referer){
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#SECURITY-END
|
||||||
|
include enable-php-''' % (fix.strip().replace(',', '|'), domains.strip().replace(',', ' '))
|
||||||
|
conf = re.sub("include\s+enable-php-", rconf, conf)
|
||||||
|
public.writeLog('网站管理', '站点[' + name + ']已开启防盗链!')
|
||||||
|
public.writeFile(file, conf)
|
||||||
|
public.restartWeb()
|
||||||
|
return public.returnJson(True, '设置成功!')
|
||||||
|
|
||||||
|
def getPhpVersion(self):
|
||||||
|
phpVersions = ('00', '52', '53', '54', '55',
|
||||||
|
'56', '70', '71', '72', '73', '74')
|
||||||
|
data = []
|
||||||
|
for val in phpVersions:
|
||||||
|
tmp = {}
|
||||||
|
if val == '00':
|
||||||
|
tmp['name'] = '纯静态'
|
||||||
|
data.append(tmp)
|
||||||
|
|
||||||
|
checkPath = public.getServerDir() + '/php/' + val + '/bin/php'
|
||||||
|
if os.path.exists(checkPath):
|
||||||
|
tmp['version'] = val
|
||||||
|
tmp['name'] = 'PHP-' + val
|
||||||
|
data.append(tmp)
|
||||||
|
|
||||||
|
return public.getJson(data)
|
||||||
|
|
||||||
|
def getRewriteList(self):
|
||||||
|
rewriteList = {}
|
||||||
|
rewriteList['rewrite'] = []
|
||||||
|
rewriteList['rewrite'].append('0.当前')
|
||||||
|
for ds in os.listdir('rewrite/nginx'):
|
||||||
|
rewriteList['rewrite'].append(ds[0:len(ds) - 5])
|
||||||
|
rewriteList['rewrite'] = sorted(rewriteList['rewrite'])
|
||||||
|
return rewriteList
|
||||||
|
|
||||||
|
def createRootDir(self, path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
if not public.isAppleSystem():
|
||||||
|
public.execShell('chown -R www:www ' + path)
|
||||||
|
public.execShell('chmod -R 755 ' + path)
|
||||||
|
|
||||||
|
def addDomain(self, domain, webname, pid):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def nginxAddConf(self):
|
||||||
|
source_tpl = public.getRunDir() + '/data/tpl/nginx.conf'
|
||||||
|
vhost_file = self.setupPath + '/openresty/nginx/conf/vhost/' + self.siteName + '.conf'
|
||||||
|
content = public.readFile(source_tpl)
|
||||||
|
|
||||||
|
content = content.replace('{$PORT}', self.sitePort)
|
||||||
|
content = content.replace('{$SERVER_NAME}', self.siteName)
|
||||||
|
content = content.replace('{$ROOT_DIR}', self.sitePath)
|
||||||
|
content = content.replace('{$PHPVER}', self.phpVersion)
|
||||||
|
|
||||||
|
or_rewrite = self.setupPath + '/openresty/nginx/conf/rewrite'
|
||||||
|
content = content.replace('{$OR_REWRITE}', or_rewrite)
|
||||||
|
|
||||||
|
logsPath = public.getLogsDir()
|
||||||
|
content = content.replace('{$LOGPATH}', logsPath)
|
||||||
|
public.writeFile(vhost_file, content)
|
||||||
|
|
||||||
|
rewrite_file = self.setupPath + \
|
||||||
|
'/openresty/nginx/conf/rewrite/' + self.siteName + '.conf'
|
||||||
|
public.writeFile(rewrite_file, '')
|
||||||
|
|
||||||
|
def add(self, webname, port, ps, path, version):
|
||||||
|
|
||||||
|
siteMenu = json.loads(webname)
|
||||||
|
self.siteName = self.toPunycode(
|
||||||
|
siteMenu['domain'].strip().split(':')[0]).strip()
|
||||||
|
self.sitePath = self.toPunycodePath(
|
||||||
|
self.getPath(path.replace(' ', '')))
|
||||||
|
self.sitePort = port.strip().replace(' ', '')
|
||||||
|
self.phpVersion = version
|
||||||
|
|
||||||
|
siteM = public.M('sites')
|
||||||
|
if siteM.where("name=?", (self.siteName,)).count():
|
||||||
|
return public.returnJson(False, '您添加的站点已存在!')
|
||||||
|
|
||||||
|
# 写入数据库
|
||||||
|
pid = siteM.add('name,path,status,ps,edate,addtime',
|
||||||
|
(self.siteName, self.sitePath, '1', ps, '0000-00-00', public.getDate()))
|
||||||
|
opid = public.M('domain').where(
|
||||||
|
"name=?", (self.siteName,)).getField('pid')
|
||||||
|
if opid:
|
||||||
|
if public.M('sites').where('id=?', (opid,)).count():
|
||||||
|
return public.returnJson(False, '您添加的域名已存在!')
|
||||||
|
public.M('domain').where('pid=?', (opid,)).delete()
|
||||||
|
|
||||||
|
# 添加更多域名
|
||||||
|
for domain in siteMenu['domainlist']:
|
||||||
|
sdomain = domain
|
||||||
|
swebname = self.siteName
|
||||||
|
spid = str(get.pid)
|
||||||
|
# self.addDomain(domain, webname, pid)
|
||||||
|
|
||||||
|
public.M('domain').add('pid,name,port,addtime',
|
||||||
|
(pid, self.siteName, self.sitePort, public.getDate()))
|
||||||
|
|
||||||
|
self.createRootDir(self.sitePath)
|
||||||
|
|
||||||
|
self.nginxAddConf()
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
data['siteStatus'] = False
|
||||||
|
public.restartWeb()
|
||||||
|
return public.getJson(data)
|
||||||
|
|
||||||
|
def delete(self, sid, webname):
|
||||||
|
|
||||||
|
confFile = self.setupPath + '/openresty/nginx/conf/vhost/' + webname + '.conf'
|
||||||
|
if os.path.exists(confFile):
|
||||||
|
os.remove(confFile)
|
||||||
|
|
||||||
|
rewriteFile = self.setupPath + '/openresty/nginx/conf/rewrite/' + webname + '.conf'
|
||||||
|
if os.path.exists(rewriteFile):
|
||||||
|
os.remove(rewriteFile)
|
||||||
|
|
||||||
|
public.M('sites').where("id=?", (sid,)).delete()
|
||||||
|
return public.returnJson(True, '站点删除成功!')
|
||||||
|
|
||||||
|
def setEndDate(self, sid, edate):
|
||||||
|
result = public.M('sites').where(
|
||||||
|
'id=?', (sid,)).setField('edate', edate)
|
||||||
|
siteName = public.M('sites').where('id=?', (sid,)).getField('name')
|
||||||
|
public.writeLog('TYPE_SITE', '设置成功,站点到期后将自动停止!', (siteName, edate))
|
||||||
|
return public.returnJson(True, '设置成功,站点到期后将自动停止!')
|
||||||
Executable
+643
@@ -0,0 +1,643 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import math
|
||||||
|
import json
|
||||||
|
|
||||||
|
from flask import Flask, session
|
||||||
|
|
||||||
|
import db
|
||||||
|
import public
|
||||||
|
import config
|
||||||
|
|
||||||
|
|
||||||
|
class system_api:
|
||||||
|
setupPath = None
|
||||||
|
pids = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.setupPath = public.getServerDir()
|
||||||
|
|
||||||
|
# 名取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 = public.GetLocalIp()
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
port = web.ctx.host.split(':')[1]
|
||||||
|
except:
|
||||||
|
port = public.readFile('data/port.pl')
|
||||||
|
except:
|
||||||
|
port = '8888'
|
||||||
|
domain = ''
|
||||||
|
if os.path.exists('data/domain.conf'):
|
||||||
|
domain = public.readFile('data/domain.conf')
|
||||||
|
|
||||||
|
autoUpdate = ''
|
||||||
|
if os.path.exists('data/autoUpdate.pl'):
|
||||||
|
autoUpdate = 'checked'
|
||||||
|
limitip = ''
|
||||||
|
if os.path.exists('data/limitip.conf'):
|
||||||
|
limitip = public.readFile('data/limitip.conf')
|
||||||
|
|
||||||
|
templates = []
|
||||||
|
for template in os.listdir('templates/'):
|
||||||
|
if os.path.isdir('templates/' + template):
|
||||||
|
templates.append(template)
|
||||||
|
template = public.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'] = public.M('users').where(
|
||||||
|
'username=?', ('admin',)).count()
|
||||||
|
data['version'] = '0.0.1'
|
||||||
|
return data
|
||||||
|
|
||||||
|
def getLoadAverage(self, get=None):
|
||||||
|
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/panel/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 = public.readFile(titlePl).strip()
|
||||||
|
return title
|
||||||
|
|
||||||
|
def getSystemVersion(self):
|
||||||
|
# 取操作系统版本
|
||||||
|
os = public.getOs()
|
||||||
|
if os == 'darwin':
|
||||||
|
data = public.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
|
||||||
|
|
||||||
|
version = public.readFile('/etc/redhat-release')
|
||||||
|
if not version:
|
||||||
|
version = public.readFile(
|
||||||
|
'/etc/issue').strip().split("\n")[0].replace('\\n', '').replace('\l', '').strip()
|
||||||
|
else:
|
||||||
|
version = version.replace('release ', '').strip()
|
||||||
|
return version
|
||||||
|
|
||||||
|
def getBootTime(self):
|
||||||
|
# 取系统启动时间
|
||||||
|
start_time = psutil.boot_time()
|
||||||
|
run_time = time.time() - start_time
|
||||||
|
# conf = public.readFile('/proc/uptime').split()
|
||||||
|
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 public.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, get=None):
|
||||||
|
# 取内存信息
|
||||||
|
mem = psutil.virtual_memory()
|
||||||
|
if public.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 public.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, ex:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def getDiskInfo(self, get=None):
|
||||||
|
return self.getDiskInfo2()
|
||||||
|
# 取磁盘分区信息
|
||||||
|
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]
|
||||||
|
tmp['size'] = psutil.disk_usage(disk[1])
|
||||||
|
diskInfo.append(tmp)
|
||||||
|
return diskInfo
|
||||||
|
|
||||||
|
def getDiskInfo2(self):
|
||||||
|
# 取磁盘分区信息
|
||||||
|
temp = public.execShell(
|
||||||
|
"df -h -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
|
||||||
|
tempInodes = public.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', '/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]]
|
||||||
|
if disk[5] == '/':
|
||||||
|
bootLog = os.getcwd() + '/tmp/panelBoot.pl'
|
||||||
|
if disk[2].find('M') != -1:
|
||||||
|
if os.path.exists(bootLog):
|
||||||
|
os.system('rm -f ' + bootLog)
|
||||||
|
else:
|
||||||
|
if not os.path.exists(bootLog):
|
||||||
|
pass
|
||||||
|
if inodes[2] != '0':
|
||||||
|
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 '\t\033[1;32m[OK]\033[0m'
|
||||||
|
num += 1
|
||||||
|
total += size
|
||||||
|
count += num
|
||||||
|
return total, count
|
||||||
|
|
||||||
|
# 清理其它
|
||||||
|
def clearOther(self):
|
||||||
|
clearPath = [
|
||||||
|
{'path': '/www/server/panel', 'find': 'testDisk_'},
|
||||||
|
{'path': '/www/wwwlogs', 'find': 'log'},
|
||||||
|
{'path': '/tmp', 'find': 'panelBoot.pl'},
|
||||||
|
{'path': '/www/server/panel/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
|
||||||
|
public.serviceReload()
|
||||||
|
os.system('echo > /tmp/panelBoot.pl')
|
||||||
|
return total, count
|
||||||
|
|
||||||
|
def getNetWork(self, get=None):
|
||||||
|
# return self.GetNetWorkApi(get);
|
||||||
|
# 取网络流量信息
|
||||||
|
try:
|
||||||
|
# 取网络流量信息
|
||||||
|
networkIo = psutil.net_io_counters()[:4]
|
||||||
|
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(get)
|
||||||
|
networkInfo['mem'] = self.getMemInfo(get)
|
||||||
|
|
||||||
|
return networkInfo
|
||||||
|
except Exception, e:
|
||||||
|
print e
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getNetWorkApi(self, get=None):
|
||||||
|
# 取网络流量信息
|
||||||
|
try:
|
||||||
|
tmpfile = 'data/network.temp'
|
||||||
|
networkIo = psutil.net_io_counters()[:4]
|
||||||
|
|
||||||
|
if not os.path.exists(tmpfile):
|
||||||
|
public.writeFile(tmpfile, str(
|
||||||
|
networkIo[0]) + '|' + str(networkIo[1]) + '|' + str(int(time.time())))
|
||||||
|
|
||||||
|
lastValue = public.readFile(tmpfile).split('|')
|
||||||
|
|
||||||
|
ntime = time.time()
|
||||||
|
networkInfo = {}
|
||||||
|
networkInfo['upTotal'] = networkIo[0]
|
||||||
|
networkInfo['downTotal'] = networkIo[1]
|
||||||
|
networkInfo['up'] = round(
|
||||||
|
float(networkIo[0] - int(lastValue[0])) / 1024 / (ntime - int(lastValue[2])), 2)
|
||||||
|
networkInfo['down'] = round(
|
||||||
|
float(networkIo[1] - int(lastValue[1])) / 1024 / (ntime - int(lastValue[2])), 2)
|
||||||
|
networkInfo['downPackets'] = networkIo[3]
|
||||||
|
networkInfo['upPackets'] = networkIo[2]
|
||||||
|
|
||||||
|
public.writeFile(tmpfile, str(
|
||||||
|
networkIo[0]) + '|' + str(networkIo[1]) + '|' + str(int(time.time())))
|
||||||
|
|
||||||
|
# networkInfo['cpu'] = self.GetCpuInfo(0.1)
|
||||||
|
return networkInfo
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def restartServer(self, get):
|
||||||
|
if not public.isRestart():
|
||||||
|
return public.returnMsg(False, 'EXEC_ERR_TASK')
|
||||||
|
public.ExecShell("sync && /etc/init.d/bt stop && init 6 &")
|
||||||
|
return public.returnMsg(True, 'SYS_REBOOT')
|
||||||
|
|
||||||
|
# 释放内存
|
||||||
|
def reMemory(self, get):
|
||||||
|
os.system('sync')
|
||||||
|
scriptFile = 'script/rememory.sh'
|
||||||
|
if not os.path.exists(scriptFile):
|
||||||
|
public.downloadFile(web.ctx.session.home +
|
||||||
|
'/script/rememory.sh', scriptFile)
|
||||||
|
public.ExecShell("/bin/bash " + self.setupPath +
|
||||||
|
'/panel/' + scriptFile)
|
||||||
|
return self.GetMemInfo()
|
||||||
|
|
||||||
|
def getNetWorkIoData(self, start, end):
|
||||||
|
# 取指定时间段的网络Io
|
||||||
|
data = public.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 = public.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 = public.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 = public.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'
|
||||||
|
|
||||||
|
if stype == '0':
|
||||||
|
public.execShell("rm -f " + filename)
|
||||||
|
elif stype == '1':
|
||||||
|
_day = int(day)
|
||||||
|
if _day < 1:
|
||||||
|
return public.returnJson(False, "设置失败!")
|
||||||
|
public.writeFile(filename, day)
|
||||||
|
elif stype == 'del':
|
||||||
|
if not public.isRestart():
|
||||||
|
return public.returnJson(False, '请等待所有安装任务完成再执行')
|
||||||
|
os.remove("data/system.db")
|
||||||
|
|
||||||
|
sql = db.Sql().dbfile('system')
|
||||||
|
csql = public.readFile('data/sql/system.sql')
|
||||||
|
csql_list = csql.split(';')
|
||||||
|
for index in range(len(csql_list)):
|
||||||
|
sql.execute(csql_list[index], ())
|
||||||
|
return public.returnJson(True, "监控服务已关闭")
|
||||||
|
else:
|
||||||
|
data = {}
|
||||||
|
if os.path.exists(filename):
|
||||||
|
try:
|
||||||
|
data['day'] = int(public.readFile(filename))
|
||||||
|
except:
|
||||||
|
data['day'] = 30
|
||||||
|
data['status'] = True
|
||||||
|
else:
|
||||||
|
data['day'] = 30
|
||||||
|
data['status'] = False
|
||||||
|
return public.getJson(data)
|
||||||
|
|
||||||
|
return public.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'
|
||||||
|
for i in range(len(old_list)):
|
||||||
|
tm_new = int(new_list[i])
|
||||||
|
tm_old = int(new_list[i])
|
||||||
|
if tm_new > tm_old:
|
||||||
|
return 'new'
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def getServerInfo(self):
|
||||||
|
|
||||||
|
upAddr = 'https://raw.githubusercontent.com/midoks/mdserver-web/master/version'
|
||||||
|
try:
|
||||||
|
version = public.httpGet(
|
||||||
|
upAddr + '/info.json')
|
||||||
|
version = json.loads(version)
|
||||||
|
return version[0]
|
||||||
|
except Exception as e:
|
||||||
|
print e
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def updateServer(self, stype, version=''):
|
||||||
|
# 更新服务
|
||||||
|
try:
|
||||||
|
|
||||||
|
if public.isUpdateLocalSoft():
|
||||||
|
if stype == 'check' or stype == 'info' or stype == 'update':
|
||||||
|
return public.returnJson(True, '正在安装中...', 'download')
|
||||||
|
if stype == 'update_status':
|
||||||
|
|
||||||
|
data = public.readFile('tmp/panelExec.log')
|
||||||
|
if data == 'done':
|
||||||
|
return public.returnJson(True, '进度!', 100)
|
||||||
|
else:
|
||||||
|
_data = json.loads(data)
|
||||||
|
return public.returnJson(True, '进度!', _data['pre'])
|
||||||
|
|
||||||
|
if os.path.exists('mdserver-web.zip'):
|
||||||
|
return public.returnJson(True, '进度!', 100)
|
||||||
|
|
||||||
|
if not public.isRestart():
|
||||||
|
return public.returnJson(False, '请等待所有安装任务完成再执行!')
|
||||||
|
if stype == 'check':
|
||||||
|
version_now = config.config().getVersion()
|
||||||
|
version_new_info = self.getServerInfo()
|
||||||
|
if not 'version' in version_new_info:
|
||||||
|
return public.returnJson(False, '服务器数据有问题!')
|
||||||
|
|
||||||
|
diff = self.versionDiff(
|
||||||
|
version_now, version_new_info['version'])
|
||||||
|
if diff == 'new':
|
||||||
|
return public.returnJson(True, '有新版本!', version_new_info['version'])
|
||||||
|
elif diff == 'test':
|
||||||
|
return public.returnJson(True, '有测试版本!', version_new_info['version'])
|
||||||
|
else:
|
||||||
|
return public.returnJson(False, '已经是最新,无需更新!')
|
||||||
|
|
||||||
|
if stype == 'info':
|
||||||
|
version_new_info = self.getServerInfo()
|
||||||
|
version_now = config.config().getVersion()
|
||||||
|
|
||||||
|
if not 'version' in version_new_info:
|
||||||
|
return public.returnJson(False, '服务器数据有问题!')
|
||||||
|
diff = self.versionDiff(
|
||||||
|
version_now, version_new_info['version'])
|
||||||
|
return public.returnJson(True, '更新信息!', version_new_info)
|
||||||
|
|
||||||
|
if stype == 'update':
|
||||||
|
if version == '':
|
||||||
|
return public.returnJson(False, '缺少版本信息!')
|
||||||
|
|
||||||
|
v_new_info = self.getServerInfo()
|
||||||
|
if v_new_info['version'] != version:
|
||||||
|
return public.returnJson(False, '更新失败,请重试!')
|
||||||
|
|
||||||
|
if not 'path' in v_new_info or v_new_info['path'] == '':
|
||||||
|
return public.returnJson(False, '下载地址不存在!')
|
||||||
|
|
||||||
|
execstr = v_new_info['path'] + '|dl|mdserver-web.zip'
|
||||||
|
taskAdd = (None, '下载[mdserver-web-' + v_new_info['version'] + ']',
|
||||||
|
'download', '0', time.strftime('%Y-%m-%d %H:%M:%S'), execstr)
|
||||||
|
|
||||||
|
public.M('tasks').add(
|
||||||
|
'id,name,type,status,addtime, execstr', taskAdd)
|
||||||
|
return public.returnJson(True, '下载中...')
|
||||||
|
|
||||||
|
if stype == 'update_install':
|
||||||
|
public.execShell('unzip -o mdserver-web.zip -d ./')
|
||||||
|
public.execShell('rm -f mdserver-web.zip')
|
||||||
|
return public.returnJson(True, '安装更新成功!')
|
||||||
|
|
||||||
|
return public.returnJson(False, '已经是最新,无需更新!')
|
||||||
|
except Exception as ex:
|
||||||
|
print ex
|
||||||
|
return public.returnJson(False, "连接服务器失败!")
|
||||||
|
|
||||||
|
# 重启面板
|
||||||
|
def reWeb(self, get):
|
||||||
|
if not public.isRestart():
|
||||||
|
public.returnMsg(False, '请等待所有安装任务完成再执行!')
|
||||||
|
|
||||||
|
# public.ExecShell('/etc/init.d/bt restart &')
|
||||||
|
public.returnMsg(True, '执行成功!')
|
||||||
|
|
||||||
|
# 修复面板
|
||||||
|
def repPanel(self, get):
|
||||||
|
vp = ''
|
||||||
|
if public.readFile('/www/server/panel/class/common.py').find('checkSafe') != -1:
|
||||||
|
vp = '_pro'
|
||||||
|
public.ExecShell("wget -O update.sh " + public.get_url() +
|
||||||
|
"/install/update" + vp + ".sh && bash update.sh")
|
||||||
|
if hasattr(web.ctx.session, 'getCloudPlugin'):
|
||||||
|
del(web.ctx.session['getCloudPlugin'])
|
||||||
|
return True
|
||||||
@@ -1,23 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# MW-Linux面板
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# Author: midoks <midoks@163.com>
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# 验证码操作
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||||
|
|
||||||
|
|
||||||
class vieCode:
|
class vieCode:
|
||||||
__fontSize = 20 # 字体大小
|
__fontSize = 20 # 字体大小
|
||||||
__width = 120 # 画布宽度
|
__width = 120 # 画布宽度
|
||||||
@@ -30,7 +19,7 @@ class vieCode:
|
|||||||
__inCurve = True # 是否画干扰线
|
__inCurve = True # 是否画干扰线
|
||||||
__inNoise = True # 是否画干扰点
|
__inNoise = True # 是否画干扰点
|
||||||
__type = 2 # 验证码类型 1、纯字母 2、数字字母混合
|
__type = 2 # 验证码类型 1、纯字母 2、数字字母混合
|
||||||
__fontPatn = 'static/fonts/2.ttf' # 字体
|
__fontPatn = 'class/fonts/2.ttf' # 字体
|
||||||
|
|
||||||
def GetCodeImage(self, size=80, length=4):
|
def GetCodeImage(self, size=80, length=4):
|
||||||
'''获取验证码图片
|
'''获取验证码图片
|
||||||
@@ -86,7 +75,7 @@ class vieCode:
|
|||||||
if not self.__inNoise:
|
if not self.__inNoise:
|
||||||
return
|
return
|
||||||
font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5))
|
font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5))
|
||||||
for i in range(5):
|
for i in xrange(5):
|
||||||
# 杂点颜色
|
# 杂点颜色
|
||||||
noiseColor = (random.randint(150, 200), random.randint(
|
noiseColor = (random.randint(150, 200), random.randint(
|
||||||
150, 200), random.randint(150, 200))
|
150, 200), random.randint(150, 200))
|
||||||
@@ -115,9 +104,9 @@ class vieCode:
|
|||||||
# 画曲线
|
# 画曲线
|
||||||
color = (random.randint(30, 150), random.randint(
|
color = (random.randint(30, 150), random.randint(
|
||||||
30, 150), random.randint(30, 150))
|
30, 150), random.randint(30, 150))
|
||||||
for x in range(xend):
|
for x in xrange(xend):
|
||||||
if w != 0:
|
if w != 0:
|
||||||
for k in range(int(self.__heigth / 10)):
|
for k in xrange(int(self.__heigth / 10)):
|
||||||
y = a * math.sin(w * x + f) + b + self.__heigth / 2
|
y = a * math.sin(w * x + f) + b + self.__heigth / 2
|
||||||
i = int(self.__fontSize / 5)
|
i = int(self.__fontSize / 5)
|
||||||
while i > 0:
|
while i > 0:
|
||||||
@@ -131,7 +120,7 @@ class vieCode:
|
|||||||
font = ImageFont.truetype(self.__fontPatn, self.__fontSize)
|
font = ImageFont.truetype(self.__fontPatn, self.__fontSize)
|
||||||
x = 0
|
x = 0
|
||||||
# 打印字符到画板
|
# 打印字符到画板
|
||||||
for i in range(self.__length):
|
for i in xrange(self.__length):
|
||||||
# 设置字体随机颜色
|
# 设置字体随机颜色
|
||||||
color = (random.randint(30, 150), random.randint(
|
color = (random.randint(30, 150), random.randint(
|
||||||
30, 150), random.randint(30, 150))
|
30, 150), random.randint(30, 150))
|
||||||
@@ -1,8 +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 -print0 | xargs -0 git rm -f --ignore-unmatch
|
|
||||||
find . -name .DS_Store | xargs rm -rf
|
|
||||||
find . -type d -name "*.pyc" | xargs rm -rf
|
|
||||||
@@ -1,107 +1,26 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||||
DIR=$(cd "$(dirname "$0")"; pwd)
|
|
||||||
MDIR=$(dirname "$DIR")
|
|
||||||
|
|
||||||
export LC_ALL="en_US.UTF-8"
|
|
||||||
|
|
||||||
# echo $DIR
|
|
||||||
|
|
||||||
PATH=$PATH:$DIR/bin
|
|
||||||
if [ -f ${DIR}/bin/activate ];then
|
|
||||||
source ${DIR}/bin/activate
|
|
||||||
|
|
||||||
if [ "$?" != "0" ];then
|
|
||||||
echo "load local python env fail!"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
mw_start_task()
|
|
||||||
{
|
|
||||||
isStart=$(ps aux |grep 'panel_task.py'|grep -v grep|awk '{print $2}')
|
|
||||||
if [ "$isStart" = '' ];then
|
|
||||||
echo -e "starting mw-tasks... \c"
|
|
||||||
cd $DIR && python3 panel_task.py >> ${DIR}/logs/panel_task.log 2>&1 &
|
|
||||||
sleep 0.3
|
|
||||||
isStart=$(ps aux |grep 'panel_task.py'|grep -v grep|awk '{print $2}')
|
|
||||||
if [ "$isStart" = '' ];then
|
|
||||||
echo -e "\033[31mfailed\033[0m"
|
|
||||||
echo '------------------------------------------------------'
|
|
||||||
tail -n 20 $DIR/logs/panel_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(){
|
mw_start(){
|
||||||
# 后台任务
|
gunicorn -c setting.py app:app &
|
||||||
mw_start_task
|
python task.py &
|
||||||
|
|
||||||
cd ${DIR}/web && gunicorn -c setting.py app:app
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mw_start_debug(){
|
mw_start_debug(){
|
||||||
if [ ! -f $DIR/logs/panel_task.log ];then
|
# gunicorn -c setting.py app:app
|
||||||
echo '' > $DIR/logs/panel_task.log
|
python task.py &
|
||||||
fi
|
gunicorn -b :7200 app:app
|
||||||
|
# gunicorn -c setting.py app:app
|
||||||
python3 panel_task.py >> $DIR/logs/panel_task.log 2>&1 &
|
|
||||||
port=7200
|
|
||||||
if [ -f /www/server/mdserver-web/data/port.pl ];then
|
|
||||||
port=$(cat /www/server/mdserver-web/data/port.pl)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f ${DIR}/data/port.pl ];then
|
|
||||||
port=$(cat ${DIR}/data/port.pl)
|
|
||||||
fi
|
|
||||||
cd ${DIR}/web && gunicorn -b :${port} -k gthread -w 1 app:app
|
|
||||||
# cd ${DIR}/web && gunicorn -b :${port} -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
|
|
||||||
}
|
|
||||||
|
|
||||||
mw_start_panel(){
|
|
||||||
port=7200
|
|
||||||
if [ -f ${DIR}/data/port.pl ];then
|
|
||||||
port=$(cat ${DIR}/data/port.pl)
|
|
||||||
fi
|
|
||||||
cd ${DIR}/web && gunicorn -b :${port} -k gthread -w 1 app:app
|
|
||||||
# cd ${DIR}/web && gunicorn -b :${port} -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mw_start_bgtask(){
|
|
||||||
cd ${DIR}/web && gunicorn -c setting.py app:app
|
|
||||||
cd ${DIR} && python3 panel_task.py
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
mw_stop()
|
mw_stop()
|
||||||
{
|
{
|
||||||
APP_LIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
|
ps -ef|grep app:app |grep -v grep|awk '{print $2}'|xargs kill -9
|
||||||
APP_LIST=($APP_LIST)
|
ps -ef|grep task.py |grep -v grep|awk '{print $2}'|xargs kill -9
|
||||||
for p in ${APP_LIST[@]}
|
|
||||||
do
|
|
||||||
kill -9 $p > /dev/null 2>&1
|
|
||||||
done
|
|
||||||
|
|
||||||
TASK_LIST=`ps -ef|grep panel_task.py | grep -v grep |awk '{print $2}'`
|
|
||||||
TASK_LIST=($TASK_LIST)
|
|
||||||
for p in ${TASK_LIST[@]}
|
|
||||||
do
|
|
||||||
kill -9 $p > /dev/null 2>&1
|
|
||||||
done
|
|
||||||
|
|
||||||
zzpids=`ps -A -o stat,ppid,pid | grep -e '^[Zz]' | awk '{print $2}'`
|
|
||||||
zzpids=($zzpids)
|
|
||||||
for p in ${zzpids[@]}
|
|
||||||
do
|
|
||||||
kill -9 ${p} > /dev/null 2>&1
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -115,12 +34,4 @@ case "$1" in
|
|||||||
mw_stop
|
mw_stop
|
||||||
mw_start_debug
|
mw_start_debug
|
||||||
;;
|
;;
|
||||||
'panel')
|
|
||||||
mw_stop
|
|
||||||
mw_start_panel
|
|
||||||
;;
|
|
||||||
'task')
|
|
||||||
# mw_stop
|
|
||||||
mw_start_bgtask
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
### 常用命令说明
|
|
||||||
|
|
||||||
|
|
||||||
- 面板相关命令
|
|
||||||
|
|
||||||
```
|
|
||||||
mw start | 启动面板服务器
|
|
||||||
mw stop | 停止面板服务器
|
|
||||||
mw restart | 重启面板服务器
|
|
||||||
mw default | 显示登录信息
|
|
||||||
mw db | 快捷连接MySQL
|
|
||||||
mw redis | 快捷连接Redis
|
|
||||||
mw valkey | 快捷连接valkey
|
|
||||||
mw mongodb | 快捷连接MongoDB
|
|
||||||
mw pgdb | 快捷连接PostgreSQL
|
|
||||||
mw ssh | 快捷连接ssh
|
|
||||||
----------------------------------------
|
|
||||||
mw open | 开启面板
|
|
||||||
mw close | 关闭面板
|
|
||||||
|
|
||||||
mw debug | 开发测试
|
|
||||||
mw venv | 进入虚拟环境
|
|
||||||
mw mirror | 切换镜像
|
|
||||||
mw install_app | 快捷安装常用软件
|
|
||||||
mw update | 更新到正式
|
|
||||||
mw dev/update_dev | 更新到开发
|
|
||||||
|
|
||||||
service mw [start|stop|reload|restart|status]
|
|
||||||
```
|
|
||||||
|
|
||||||
- OpenResty
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
systemctl [start|stop|reload|restart|status] openresty
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
- MySQL
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
systemctl [start|stop|reload|restart|status] mysql
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
- MariaDB
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
systemctl [start|stop|reload|restart|status] mariadb
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
- PHP
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
systemctl [start|stop|reload|restart|status] php[54-81]
|
|
||||||
|
|
||||||
systemctl start php71
|
|
||||||
```
|
|
||||||
|
|
||||||
- Redis
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
systemctl [start|stop|reload|restart|status] redis
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
- Memcached
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
systemctl [start|stop|reload|restart|status] memcached
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
- sphinx
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
systemctl [start|stop|reload|restart|status] sphinx
|
|
||||||
|
|
||||||
```
|
|
||||||
@@ -1,71 +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 |✅ |✅ |
|
|
||||||
| Debian 12.0 |✅ |✅ |
|
|
||||||
| 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 |PHP82 |PHP83 |PHP84 |
|
|
||||||
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
|
|
||||||
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
|
||||||
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
|
||||||
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
|
||||||
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
|
||||||
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
|
||||||
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
|
||||||
| Debian 12 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
|
||||||
| 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 |✅ |✅ |✅ |✅ |
|
|
||||||
| Debian 12 |✅ |✅ |✅ |✅ |
|
|
||||||
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |
|
|
||||||
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |
|
|
||||||
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |
|
|
||||||
| Fedora 31 |✅ |✅ |✅ |✅ |
|
|
||||||
| Fedora 32 |✅ |✅ |✅ |✅ |
|
|
||||||
| AlmaLinux 9 |✅ |✅ |✅ |✅ |
|
|
||||||
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |
|
|
||||||
| Arch Linux |✅ |✅ |✅ |✅ |
|
|
||||||
| openSUSE 15.4 |✅ |✅ |✅ |✅ |
|
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# 自动生成
|
|
||||||
|
|
||||||
certificate.pem - 证书信息
|
|
||||||
privateKey.pem - 私钥
|
|
||||||
Executable
+32
@@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"title":"全部",
|
||||||
|
"type":0,
|
||||||
|
"ps":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title":"运行环境",
|
||||||
|
"type":1,
|
||||||
|
"ps":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title":"数据软件",
|
||||||
|
"type":2,
|
||||||
|
"ps":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title":"代码管理",
|
||||||
|
"type":3,
|
||||||
|
"ps":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title":"系统工具",
|
||||||
|
"type":4,
|
||||||
|
"ps":""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title":"其他插件",
|
||||||
|
"type":5,
|
||||||
|
"ps":""
|
||||||
|
}
|
||||||
|
]
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
7200
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
True
|
||||||
Executable
+132
@@ -0,0 +1,132 @@
|
|||||||
|
|
||||||
|
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 `config` (
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
`webserver` TEXT,
|
||||||
|
`backup_path` TEXT,
|
||||||
|
`sites_path` TEXT,
|
||||||
|
`status` INTEGER,
|
||||||
|
`mysql_root` TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `config` (`id`, `webserver`, `backup_path`, `sites_path`, `status`, `mysql_root`) VALUES
|
||||||
|
(1, 'nginx', '/www/backup', '/www/wwwroot', 0, 'admin');
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `databases` (
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
`pid` INTEGER,
|
||||||
|
`name` TEXT,
|
||||||
|
`username` TEXT,
|
||||||
|
`password` TEXT,
|
||||||
|
`accept` TEXT,
|
||||||
|
`ps` TEXT,
|
||||||
|
`addtime` 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
|
||||||
|
(2, '80', '网站默认端口', '0000-00-00 00:00:00'),
|
||||||
|
(3, '8888', 'WEB面板', '0000-00-00 00:00:00'),
|
||||||
|
(4, '21', 'FTP服务', '0000-00-00 00:00:00'),
|
||||||
|
(5, '22', 'SSH远程管理服务', '0000-00-00 00:00:00');
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ftps` (
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
`pid` INTEGER,
|
||||||
|
`name` TEXT,
|
||||||
|
`password` TEXT,
|
||||||
|
`path` TEXT,
|
||||||
|
`status` TEXT,
|
||||||
|
`ps` TEXT,
|
||||||
|
`addtime` TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
`ps` TEXT,
|
||||||
|
`edate` TEXT,
|
||||||
|
`addtime` 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', '2016-12-10 15:12:56', 0, '287962566@qq.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
|
||||||
|
);
|
||||||
@@ -1,22 +1,20 @@
|
|||||||
CREATE TABLE IF NOT EXISTS `network` (
|
CREATE TABLE IF NOT EXISTS `network` (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`up` TEXT,
|
`up` INTEGER,
|
||||||
`down` TEXT,
|
`down` INTEGER,
|
||||||
`total_up` INTEGER,
|
`total_up` INTEGER,
|
||||||
`total_down` INTEGER,
|
`total_down` INTEGER,
|
||||||
`down_packets` INTEGER,
|
`down_packets` INTEGER,
|
||||||
`up_packets` INTEGER,
|
`up_packets` INTEGER,
|
||||||
`addtime` INTEGER
|
`addtime` INTEGER
|
||||||
);
|
);
|
||||||
CREATE INDEX network_addtime_idx ON network(`addtime`);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `cpuio` (
|
CREATE TABLE IF NOT EXISTS `cpuio` (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`pro` TEXT,
|
`pro` INTEGER,
|
||||||
`mem` TEXT,
|
`mem` INTEGER,
|
||||||
`addtime` INTEGER
|
`addtime` INTEGER
|
||||||
);
|
);
|
||||||
CREATE INDEX cpuio_addtime_idx ON cpuio(`addtime`);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `diskio` (
|
CREATE TABLE IF NOT EXISTS `diskio` (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -28,7 +26,6 @@ CREATE TABLE IF NOT EXISTS `diskio` (
|
|||||||
`write_time` INTEGER,
|
`write_time` INTEGER,
|
||||||
`addtime` INTEGER
|
`addtime` INTEGER
|
||||||
);
|
);
|
||||||
CREATE INDEX diskio_addtime_idx ON diskio(`addtime`);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `load_average` (
|
CREATE TABLE IF NOT EXISTS `load_average` (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -38,4 +35,3 @@ CREATE TABLE IF NOT EXISTS `load_average` (
|
|||||||
`fifteen` REAL,
|
`fifteen` REAL,
|
||||||
`addtime` INTEGER
|
`addtime` INTEGER
|
||||||
);
|
);
|
||||||
CREATE INDEX load_average_addtime_idx ON load_average(`addtime`);
|
|
||||||
@@ -1,29 +1,24 @@
|
|||||||
server
|
server
|
||||||
{
|
{
|
||||||
listen {$PORT};
|
listen {$PORT};
|
||||||
listen [::]:{$PORT};
|
|
||||||
server_name {$SERVER_NAME};
|
server_name {$SERVER_NAME};
|
||||||
index index.php index.html index.htm default.php default.htm default.html;
|
index index.php index.html index.htm default.php default.htm default.html;
|
||||||
root {$ROOT_DIR};
|
root {$ROOT_DIR};
|
||||||
|
|
||||||
#SSL-START
|
#SSL-START %s
|
||||||
#error_page 404/404.html;
|
#error_page 404/404.html;
|
||||||
#SSL-END
|
#SSL-END
|
||||||
|
|
||||||
#301-START
|
#ERROR-PAGE-START %s
|
||||||
|
error_page 404 /404.html;
|
||||||
#PROXY-START
|
error_page 502 /502.html;
|
||||||
|
|
||||||
#ERROR-PAGE-START
|
|
||||||
#error_page 404 /404.html;
|
|
||||||
#error_page 502 /502.html;
|
|
||||||
#ERROR-PAGE-END
|
#ERROR-PAGE-END
|
||||||
|
|
||||||
#PHP-INFO-START
|
#PHP-INFO-START %s
|
||||||
include {$PHP_DIR}/conf/enable-php-{$PHPVER}.conf;
|
include enable-php-{$PHPVER}.conf;
|
||||||
#PHP-INFO-END
|
#PHP-INFO-END
|
||||||
|
|
||||||
#REWRITE-START
|
#REWRITE-START %s
|
||||||
include {$OR_REWRITE}/{$SERVER_NAME}.conf;
|
include {$OR_REWRITE}/{$SERVER_NAME}.conf;
|
||||||
#REWRITE-END
|
#REWRITE-END
|
||||||
|
|
||||||
@@ -38,15 +33,20 @@ server
|
|||||||
allow all;
|
allow all;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css|ttf|woff2)$
|
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
|
||||||
{
|
{
|
||||||
expires 30d;
|
expires 30d;
|
||||||
|
error_log off;
|
||||||
access_log /dev/null;
|
access_log /dev/null;
|
||||||
if ($invalid_referer){
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
access_log {$LOGPATH}/{$SERVER_NAME}.log main;
|
location ~ .*\\.(js|css)?$
|
||||||
|
{
|
||||||
|
expires 12h;
|
||||||
|
error_log off;
|
||||||
|
access_log /dev/null;
|
||||||
|
}
|
||||||
|
|
||||||
|
access_log {$LOGPATH}/{$SERVER_NAME}.log;
|
||||||
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
|
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
|
||||||
}
|
}
|
||||||
@@ -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 && \
|
|
||||||
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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
logs
|
|
||||||
-362
@@ -1,362 +0,0 @@
|
|||||||
# coding: utf-8
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# MW-Linux面板
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# Author: midoks <midoks@163.com>
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# 计划任务
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
import psutil
|
|
||||||
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
os.chdir(web_dir)
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
import thisdb
|
|
||||||
|
|
||||||
from admin import setup
|
|
||||||
setup.init()
|
|
||||||
|
|
||||||
g_log_file = mw.getPanelTaskExecLog()
|
|
||||||
if not os.path.exists(g_log_file):
|
|
||||||
os.system("touch " + g_log_file)
|
|
||||||
|
|
||||||
def execShell(cmdstring, cwd=None, timeout=None, shell=True):
|
|
||||||
cmd = cmdstring + ' > ' + g_log_file + ' 2>&1'
|
|
||||||
return mw.execShell(cmd)
|
|
||||||
|
|
||||||
def writeLogs(data):
|
|
||||||
# 写输出日志
|
|
||||||
try:
|
|
||||||
fp = open(g_log_file, 'w+')
|
|
||||||
fp.write(data)
|
|
||||||
fp.close()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def downloadFile(url, filename):
|
|
||||||
# 下载文件
|
|
||||||
try:
|
|
||||||
import urllib
|
|
||||||
import socket
|
|
||||||
socket.setdefaulttimeout(300)
|
|
||||||
|
|
||||||
headers = ('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36')
|
|
||||||
opener = urllib.request.build_opener()
|
|
||||||
opener.addheaders = [headers]
|
|
||||||
urllib.request.install_opener(opener)
|
|
||||||
|
|
||||||
urllib.request.urlretrieve(url, filename=filename, reporthook=downloadHook)
|
|
||||||
|
|
||||||
if not mw.isAppleSystem():
|
|
||||||
os.system('chown www.www ' + filename)
|
|
||||||
|
|
||||||
writeLogs(filename + ' download success!')
|
|
||||||
except Exception as e:
|
|
||||||
writeLogs(str(e))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def downloadHook(count, blockSize, totalSize):
|
|
||||||
# 下载文件进度回调
|
|
||||||
used = count * blockSize
|
|
||||||
pre = int((100.0 * used / totalSize))
|
|
||||||
speed = {'total': totalSize, 'used': used, 'pre': pre}
|
|
||||||
writeLogs(json.dumps(speed))
|
|
||||||
|
|
||||||
def runPanelTask():
|
|
||||||
# 站点过期检查
|
|
||||||
siteEdateCheck()
|
|
||||||
|
|
||||||
# echo "True" > /www/server/mdserver-web/logs/panel_task.lock
|
|
||||||
lock_file = mw.getTriggerTaskLockFile()
|
|
||||||
try:
|
|
||||||
if os.path.exists(lock_file):
|
|
||||||
bash_list = thisdb.getTaskList(status=-1)
|
|
||||||
for task in bash_list:
|
|
||||||
thisdb.setTaskStatus(task['id'], 0)
|
|
||||||
|
|
||||||
run_list = thisdb.getTaskList(status=0)
|
|
||||||
for run_task in run_list:
|
|
||||||
start = int(time.time())
|
|
||||||
thisdb.setTaskData(run_task['id'], start=start)
|
|
||||||
thisdb.setTaskStatus(run_task['id'], -1)
|
|
||||||
|
|
||||||
if run_task['type'] == 'download':
|
|
||||||
argv = run_task['cmd'].split('|mw|')
|
|
||||||
downloadFile(argv[0], argv[1])
|
|
||||||
elif run_task['type'] == 'execshell':
|
|
||||||
execShell(run_task['cmd'])
|
|
||||||
|
|
||||||
end = int(time.time())
|
|
||||||
thisdb.setTaskData(run_task['id'], end=end)
|
|
||||||
thisdb.setTaskStatus(run_task['id'], 1)
|
|
||||||
|
|
||||||
if thisdb.getTaskUnexecutedCount() < 1:
|
|
||||||
os.remove(lock_file)
|
|
||||||
except Exception as e:
|
|
||||||
print('runPanelTask:',mw.getTracebackInfo())
|
|
||||||
|
|
||||||
# 网站到期处理
|
|
||||||
def siteEdateCheck():
|
|
||||||
try:
|
|
||||||
from utils.site import sites as MwSites
|
|
||||||
website_edate = thisdb.getOption('website_edate', default='0000-00-00')
|
|
||||||
now_time_ymd = time.strftime('%Y-%m-%d', time.localtime())
|
|
||||||
|
|
||||||
if website_edate == now_time_ymd:
|
|
||||||
return False
|
|
||||||
site_list = thisdb.getSitesEdateList(now_time_ymd)
|
|
||||||
for site in site_list:
|
|
||||||
MwSites.instance().stop(site['id'])
|
|
||||||
thisdb.setOption('website_edate', now_time_ymd)
|
|
||||||
except Exception as e:
|
|
||||||
print('siteEdateCheck:',mw.getTracebackInfo())
|
|
||||||
|
|
||||||
# 任务队列
|
|
||||||
def startPanelTask():
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
runPanelTask()
|
|
||||||
time.sleep(5)
|
|
||||||
except Exception as e:
|
|
||||||
print('startPanelTask:',mw.getTracebackInfo())
|
|
||||||
time.sleep(30)
|
|
||||||
startPanelTask()
|
|
||||||
|
|
||||||
def systemTask():
|
|
||||||
# 系统监控任务
|
|
||||||
from utils.system import monitor
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
monitor_status = thisdb.getOption('monitor_status',type='monitor',default='open')
|
|
||||||
if monitor_status == 'open':
|
|
||||||
monitor.instance().run()
|
|
||||||
time.sleep(5)
|
|
||||||
except Exception as ex:
|
|
||||||
print('systemTask:',mw.getTracebackInfo())
|
|
||||||
time.sleep(30)
|
|
||||||
systemTask()
|
|
||||||
|
|
||||||
|
|
||||||
def panelPluginStatusCheck():
|
|
||||||
# 系统监控任务
|
|
||||||
from utils.plugin import plugin
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
# start_t = time.time()
|
|
||||||
plugin.instance().autoCachePluginStatus()
|
|
||||||
# end_t = time.time()
|
|
||||||
time.sleep(60)
|
|
||||||
except Exception as ex:
|
|
||||||
print('panelPluginStatusCheck:',mw.getTracebackInfo())
|
|
||||||
time.sleep(120)
|
|
||||||
panelPluginStatusCheck()
|
|
||||||
|
|
||||||
# -------------------------------------- PHP监控 start --------------------------------------------- #
|
|
||||||
# 502错误检查线程
|
|
||||||
def check502Task():
|
|
||||||
try:
|
|
||||||
check_file = mw.getPanelDir() + '/data/502Task.pl'
|
|
||||||
while True:
|
|
||||||
if os.path.exists(check_file):
|
|
||||||
check502()
|
|
||||||
time.sleep(10)
|
|
||||||
except:
|
|
||||||
time.sleep(30)
|
|
||||||
check502Task()
|
|
||||||
|
|
||||||
|
|
||||||
def check502():
|
|
||||||
try:
|
|
||||||
verlist = [
|
|
||||||
'52', '53', '54', '55', '56', '70',
|
|
||||||
'71', '72', '73', '74', '80', '81',
|
|
||||||
'82', '83', '84', '85'
|
|
||||||
]
|
|
||||||
for ver in verlist:
|
|
||||||
server_dir = mw.getServerDir()
|
|
||||||
php_path = server_dir + '/php/' + ver + '/sbin/php-fpm'
|
|
||||||
if not os.path.exists(php_path):
|
|
||||||
continue
|
|
||||||
if checkPHPVersion(ver):
|
|
||||||
continue
|
|
||||||
if startPHPVersion(ver):
|
|
||||||
print('检测到PHP-' + ver + '处理异常,已自动修复!')
|
|
||||||
mw.writeLog('PHP守护程序', '检测到PHP-' + ver + '处理异常,已自动修复!')
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
mw.writeLog('PHP守护程序', '自动修复异常:'+str(e))
|
|
||||||
|
|
||||||
|
|
||||||
# 处理指定PHP版本
|
|
||||||
def startPHPVersion(version):
|
|
||||||
server_dir = mw.getServerDir()
|
|
||||||
try:
|
|
||||||
# system
|
|
||||||
phpService = mw.systemdCfgDir() + '/php' + version + '.service'
|
|
||||||
if os.path.exists(phpService):
|
|
||||||
mw.execShell("systemctl restart php" + version)
|
|
||||||
if checkPHPVersion(version):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# initd
|
|
||||||
fpm = server_dir + '/php/init.d/php' + version
|
|
||||||
php_path = server_dir + '/php/' + version + '/sbin/php-fpm'
|
|
||||||
if not os.path.exists(php_path):
|
|
||||||
if os.path.exists(fpm):
|
|
||||||
os.remove(fpm)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not os.path.exists(fpm):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 尝试重载服务
|
|
||||||
os.system(fpm + ' reload')
|
|
||||||
if checkPHPVersion(version):
|
|
||||||
return True
|
|
||||||
# 尝试重启服务
|
|
||||||
cgi = '/tmp/php-cgi-' + version + '.sock'
|
|
||||||
pid = server_dir + '/php/' + version + '/var/run/php-fpm.pid'
|
|
||||||
data = mw.execShell("ps -ef | grep php/" + version +" | grep -v grep|grep -v python |awk '{print $2}'")
|
|
||||||
if data[0] != '':
|
|
||||||
os.system("ps -ef | grep php/" + version + " | grep -v grep|grep -v python |awk '{print $2}' | xargs kill ")
|
|
||||||
time.sleep(0.5)
|
|
||||||
if not os.path.exists(cgi):
|
|
||||||
os.system('rm -f ' + cgi)
|
|
||||||
if not os.path.exists(pid):
|
|
||||||
os.system('rm -f ' + pid)
|
|
||||||
os.system(fpm + ' start')
|
|
||||||
if checkPHPVersion(version):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# 检查是否正确启动
|
|
||||||
if os.path.exists(cgi):
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print('startPHPVersion:',mw.getTracebackInfo())
|
|
||||||
mw.writeLog('PHP守护程序', '自动修复异常:'+str(e))
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def checkPHPVersion(version):
|
|
||||||
# 检查指定PHP版本
|
|
||||||
try:
|
|
||||||
sock = mw.getFpmAddress(version)
|
|
||||||
data = mw.requestFcgiPHP(sock, '/phpfpm_status_' + version + '?json')
|
|
||||||
result = str(data, encoding='utf-8')
|
|
||||||
except Exception as e:
|
|
||||||
result = 'Bad Gateway'
|
|
||||||
# 检查openresty
|
|
||||||
if result.find('Bad Gateway') != -1:
|
|
||||||
return False
|
|
||||||
if result.find('HTTP Error 404: Not Found') != -1:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# 检查Web服务是否启动
|
|
||||||
if result.find('Connection refused') != -1:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
# -------------------------------------- PHP监控 end --------------------------------------------- #
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------OpenResty Auto Restart Start --------------------------------------------- #
|
|
||||||
# 解决acme.sh续签后,未起效。
|
|
||||||
def openrestyAutoRestart():
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
# 检查是否安装
|
|
||||||
odir = mw.getServerDir() + '/openresty'
|
|
||||||
if not os.path.exists(odir):
|
|
||||||
time.sleep(86400)
|
|
||||||
continue
|
|
||||||
mw.opWeb('reload')
|
|
||||||
time.sleep(86400)
|
|
||||||
except Exception as e:
|
|
||||||
mw.writeLog('OpenResty检测', '自动修复异常:'+str(e))
|
|
||||||
time.sleep(86400)
|
|
||||||
|
|
||||||
# --------------------------------------OpenResty Auto Restart End --------------------------------------------- #
|
|
||||||
|
|
||||||
# ------------------------------------ OpenResty Restart At Once Start ------------------------------------------ #
|
|
||||||
|
|
||||||
|
|
||||||
def openrestyRestartAtOnce():
|
|
||||||
restart_nginx_tip = mw.getPanelDir()+'/data/restart_nginx.pl'
|
|
||||||
while True:
|
|
||||||
if os.path.exists(restart_nginx_tip):
|
|
||||||
os.remove(restart_nginx_tip)
|
|
||||||
mw.opWeb('reload')
|
|
||||||
time.sleep(1)
|
|
||||||
# ----------------------------------- OpenResty Restart At Once End ------------------------------------------ #
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------Panel Restart Start --------------------------------------------- #
|
|
||||||
def restartPanelService():
|
|
||||||
restart_tip = mw.getPanelDir()+'/data/restart.pl'
|
|
||||||
while True:
|
|
||||||
if os.path.exists(restart_tip):
|
|
||||||
print("restart panel")
|
|
||||||
os.remove(restart_tip)
|
|
||||||
mw.panelCmd('restart_panel')
|
|
||||||
time.sleep(1)
|
|
||||||
# --------------------------------------Panel Restart End --------------------------------------------- #
|
|
||||||
|
|
||||||
|
|
||||||
def setDaemon(t):
|
|
||||||
if sys.version_info.major == 3 and sys.version_info.minor >= 10:
|
|
||||||
t.daemon = True
|
|
||||||
else:
|
|
||||||
t.setDaemon(True)
|
|
||||||
return t
|
|
||||||
|
|
||||||
def run():
|
|
||||||
# 系统监控
|
|
||||||
sysTask = threading.Thread(target=systemTask)
|
|
||||||
sysTask = setDaemon(sysTask)
|
|
||||||
sysTask.start()
|
|
||||||
|
|
||||||
# PHP 502错误检查线程
|
|
||||||
php502 = threading.Thread(target=check502Task)
|
|
||||||
php502 = setDaemon(php502)
|
|
||||||
php502.start()
|
|
||||||
|
|
||||||
# OpenResty Restart At Once Start
|
|
||||||
oraos = threading.Thread(target=openrestyRestartAtOnce)
|
|
||||||
oraos = setDaemon(oraos)
|
|
||||||
oraos.start()
|
|
||||||
|
|
||||||
# OpenResty Auto Restart Start
|
|
||||||
oar = threading.Thread(target=openrestyAutoRestart)
|
|
||||||
oar = setDaemon(oar)
|
|
||||||
oar.start()
|
|
||||||
|
|
||||||
# Panel Plugin Status Check
|
|
||||||
pps = threading.Thread(target=panelPluginStatusCheck)
|
|
||||||
pps = setDaemon(pps)
|
|
||||||
pps.start()
|
|
||||||
|
|
||||||
# Panel Restart Start
|
|
||||||
rps = threading.Thread(target=restartPanelService)
|
|
||||||
rps = setDaemon(rps)
|
|
||||||
rps.start()
|
|
||||||
|
|
||||||
# 面板后台任务
|
|
||||||
startPanelTask()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run()
|
|
||||||
|
|
||||||
-433
@@ -1,433 +0,0 @@
|
|||||||
# coding=utf-8
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# MW-Linux面板
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# Author: midoks <midoks@163.com>
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
# 工具箱
|
|
||||||
# ---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
os.chdir(web_dir)
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
|
|
||||||
from utils.firewall import Firewall as MwFirewall
|
|
||||||
import core.mw as mw
|
|
||||||
import thisdb
|
|
||||||
|
|
||||||
INIT_DIR = "/etc/rc.d/init.d"
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
INIT_DIR = mw.getPanelDir() + "/scripts/init.d"
|
|
||||||
|
|
||||||
INIT_CMD = INIT_DIR + "/mw"
|
|
||||||
|
|
||||||
|
|
||||||
def mw_input_cmd(msg):
|
|
||||||
if sys.version_info[0] == 2:
|
|
||||||
in_val = raw_input(msg)
|
|
||||||
else:
|
|
||||||
in_val = input(msg)
|
|
||||||
return in_val
|
|
||||||
|
|
||||||
def getRemainLen(cmd, max_length=100):
|
|
||||||
cmd_len = len(cmd)
|
|
||||||
cmd_u8_len = len(cmd.encode('utf-8'))
|
|
||||||
return max_length-int((cmd_u8_len - cmd_len)/2+cmd_len)
|
|
||||||
|
|
||||||
def mwcli(mw_input=0):
|
|
||||||
panel_dir = mw.getPanelDir()
|
|
||||||
|
|
||||||
raw_tip = "========================================================================"
|
|
||||||
if not mw_input:
|
|
||||||
print("========================mdserver-web cli tools==========================")
|
|
||||||
cmd_list = [
|
|
||||||
'(1) 重启面板服务',
|
|
||||||
'(2) 停止面板服务',
|
|
||||||
'(3) 启动面板服务',
|
|
||||||
'(4) 重载面板服务',
|
|
||||||
'(5) 修改面板IP',
|
|
||||||
'(6) 修改面板端口',
|
|
||||||
'(7) 关闭安全入口',
|
|
||||||
'(10) 查看面板默认信息',
|
|
||||||
'(11) 修改面板密码',
|
|
||||||
'(12) 修改面板用户名',
|
|
||||||
'(13) 显示面板错误日志',
|
|
||||||
'(14) 关闭面板访问',
|
|
||||||
'(15) 开启面板访问',
|
|
||||||
'(20) 关闭BasicAuth认证',
|
|
||||||
'(21) 解除域名绑定',
|
|
||||||
'(22) 解除面板SSL绑定',
|
|
||||||
'(23) 开启IPV6支持',
|
|
||||||
'(24) 关闭IPV6支持',
|
|
||||||
'(25) 开启防火墙SSH端口',
|
|
||||||
'(26) 关闭二次验证',
|
|
||||||
'(27) 查看防火墙信息',
|
|
||||||
'(28) 自动识别防火墙端口到面板',
|
|
||||||
'(29) 自动识别配置站点信息',
|
|
||||||
'(100) 开启PHP52显示',
|
|
||||||
'(101) 关闭PHP52显示',
|
|
||||||
'(200) 切换Linux系统软件源',
|
|
||||||
'(201) 简单速度测试',
|
|
||||||
'(202) SSH终端管理',
|
|
||||||
'(0) 取消'
|
|
||||||
]
|
|
||||||
cmd_list_num = len(cmd_list)
|
|
||||||
for index in range(cmd_list_num):
|
|
||||||
cmd = cmd_list[index]
|
|
||||||
if index % 2 == 0:
|
|
||||||
if index == (cmd_list_num-1):
|
|
||||||
print(cmd)
|
|
||||||
else:
|
|
||||||
print(cmd + " " * getRemainLen(cmd, 40), end="")
|
|
||||||
if index % 2 == 1:
|
|
||||||
print(cmd)
|
|
||||||
print(raw_tip)
|
|
||||||
try:
|
|
||||||
mw_input = input("请输入命令编号:")
|
|
||||||
if sys.version_info[0] == 3:
|
|
||||||
mw_input = int(mw_input)
|
|
||||||
except:
|
|
||||||
mw_input = 0
|
|
||||||
|
|
||||||
nums = [
|
|
||||||
1, 2, 3, 4, 5, 6, 7,
|
|
||||||
10, 11, 12, 13, 14, 15,
|
|
||||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
|
||||||
100, 101,
|
|
||||||
200, 201, 202
|
|
||||||
]
|
|
||||||
if not mw_input in nums:
|
|
||||||
print(raw_tip)
|
|
||||||
print("已取消!")
|
|
||||||
exit()
|
|
||||||
|
|
||||||
if mw_input == 1:
|
|
||||||
os.system(INIT_CMD + " restart")
|
|
||||||
elif mw_input == 2:
|
|
||||||
os.system(INIT_CMD + " stop")
|
|
||||||
elif mw_input == 3:
|
|
||||||
os.system(INIT_CMD + " start")
|
|
||||||
elif mw_input == 4:
|
|
||||||
os.system(INIT_CMD + " reload")
|
|
||||||
elif mw_input == 5:
|
|
||||||
in_ip = mw_input_cmd("请输入设置的面板IP:")
|
|
||||||
in_ip = in_ip.strip()
|
|
||||||
ip_text = panel_dir + '/data/iplist.txt'
|
|
||||||
if not mw.isVaildIp(in_ip):
|
|
||||||
mw.echoInfo("【"+in_ip+"】: IP不合法")
|
|
||||||
return
|
|
||||||
mw.writeFile(ip_text, in_ip)
|
|
||||||
thisdb.setOption('server_ip', in_ip)
|
|
||||||
mw.echoInfo("设置面板IP: " + in_ip)
|
|
||||||
elif mw_input == 6:
|
|
||||||
in_port = mw_input_cmd("请输入新的面板端口:")
|
|
||||||
in_port_int = int(in_port.strip())
|
|
||||||
if in_port_int < 65536 and in_port_int > 0:
|
|
||||||
MwFirewall.instance().addAcceptPort(in_port, 'WEB面板[TOOLS修改]', 'port')
|
|
||||||
panel_port = panel_dir + '/data/port.pl'
|
|
||||||
mw.writeFile(panel_port, in_port)
|
|
||||||
os.system(INIT_CMD + " restart_panel")
|
|
||||||
os.system(INIT_CMD + " default")
|
|
||||||
else:
|
|
||||||
mw.echoInfo("端口范围在0-65536之间")
|
|
||||||
return
|
|
||||||
elif mw_input == 7:
|
|
||||||
thisdb.setOption('admin_path', '')
|
|
||||||
mw.echoInfo("关闭安全入口成功!")
|
|
||||||
elif mw_input == 10:
|
|
||||||
os.system(INIT_CMD + " default")
|
|
||||||
elif mw_input == 11:
|
|
||||||
input_pwd = mw_input_cmd("请输入新的面板密码:")
|
|
||||||
if len(input_pwd.strip()) < 5:
|
|
||||||
mw.echoInfo("错误,密码长度不能小于5位")
|
|
||||||
return
|
|
||||||
set_panel_pwd(input_pwd.strip(), True)
|
|
||||||
elif mw_input == 12:
|
|
||||||
input_user = mw_input_cmd("请输入新的面板用户名(>=5位):")
|
|
||||||
set_panel_username(input_user.strip())
|
|
||||||
elif mw_input == 13:
|
|
||||||
os.system('tail -100 ' + panel_dir + '/logs/panel_error.log')
|
|
||||||
elif mw_input == 14:
|
|
||||||
admin_close = thisdb.getOption('admin_close')
|
|
||||||
if admin_close == 'no':
|
|
||||||
thisdb.setOption('admin_close', 'yes')
|
|
||||||
mw.echoInfo("关闭面板访问成功!")
|
|
||||||
else:
|
|
||||||
mw.echoInfo("已关闭面板访问!")
|
|
||||||
elif mw_input == 15:
|
|
||||||
admin_close = thisdb.getOption('admin_close')
|
|
||||||
if admin_close == 'yes':
|
|
||||||
thisdb.setOption('admin_close', 'no')
|
|
||||||
mw.echoInfo("开启面板访问成功!")
|
|
||||||
else:
|
|
||||||
mw.echoInfo("已开启面板访问!")
|
|
||||||
elif mw_input == 20:
|
|
||||||
basic_auth = thisdb.getOptionByJson('basic_auth', default={'open':False})
|
|
||||||
if basic_auth['open']:
|
|
||||||
basic_auth['open'] = False
|
|
||||||
thisdb.setOption('basic_auth', json.dumps(basic_auth))
|
|
||||||
os.system(INIT_CMD + " restart")
|
|
||||||
mw.echoInfo("关闭basic_auth成功")
|
|
||||||
elif mw_input == 21:
|
|
||||||
panel_domain = thisdb.getOption('panel_domain', default='')
|
|
||||||
if panel_domain != '':
|
|
||||||
thisdb.setOption('panel_domain', '')
|
|
||||||
os.system(INIT_CMD + " unbind_domain")
|
|
||||||
mw.echoInfo("解除域名绑定成功")
|
|
||||||
else:
|
|
||||||
mw.echoInfo("面板未绑定域名!")
|
|
||||||
elif mw_input == 22:
|
|
||||||
panel_ssl = thisdb.getOptionByJson('panel_ssl', default={'open':False})
|
|
||||||
if panel_ssl['open']:
|
|
||||||
panel_ssl['open'] = False
|
|
||||||
thisdb.setOption('panel_ssl', json.dumps(panel_ssl))
|
|
||||||
os.system(INIT_CMD + " unbind_ssl")
|
|
||||||
mw.echoInfo("解除面板SSL绑定成功")
|
|
||||||
elif mw_input == 23:
|
|
||||||
listen_ipv6 = panel_dir + '/data/ipv6.pl'
|
|
||||||
if not os.path.exists(listen_ipv6):
|
|
||||||
mw.writeFile(listen_ipv6, 'True')
|
|
||||||
os.system(INIT_CMD + " restart")
|
|
||||||
mw.echoInfo("开启IPv6支持了")
|
|
||||||
else:
|
|
||||||
mw.echoInfo("已开启IPv6支持!")
|
|
||||||
elif mw_input == 24:
|
|
||||||
listen_ipv6 = panel_dir + '/data/ipv6.pl'
|
|
||||||
if not os.path.exists(listen_ipv6):
|
|
||||||
mw.echoInfo("已关闭IPv6支持!")
|
|
||||||
else:
|
|
||||||
os.remove(listen_ipv6)
|
|
||||||
os.system(INIT_CMD + " restart")
|
|
||||||
mw.echoInfo("关闭IPv6支持了")
|
|
||||||
elif mw_input == 25:
|
|
||||||
open_ssh_port()
|
|
||||||
mw.echoInfo("已开启!")
|
|
||||||
elif mw_input == 26:
|
|
||||||
two_step_verification = thisdb.getOptionByJson('two_step_verification', default={'open':False})
|
|
||||||
if two_step_verification['open']:
|
|
||||||
two_step_verification['open'] = False
|
|
||||||
thisdb.setOption('two_step_verification', json.dumps(two_step_verification))
|
|
||||||
mw.echoInfo("关闭二次验证成功!")
|
|
||||||
else:
|
|
||||||
mw.echoInfo("二次验证已关闭!")
|
|
||||||
elif mw_input == 27:
|
|
||||||
cmd = 'which ufw'
|
|
||||||
run_cmd = False
|
|
||||||
find_cmd = mw.execShell(cmd)
|
|
||||||
if find_cmd[0].strip() != '':
|
|
||||||
run_cmd = True
|
|
||||||
os.system('ufw status')
|
|
||||||
|
|
||||||
cmd = 'which firewall-cmd'
|
|
||||||
find_cmd = mw.execShell(cmd)
|
|
||||||
if find_cmd[0].strip() != '':
|
|
||||||
run_cmd = True
|
|
||||||
os.system('firewall-cmd --list-all')
|
|
||||||
if not run_cmd:
|
|
||||||
mw.echoInfo("未检测到防火墙!")
|
|
||||||
elif mw_input == 28:
|
|
||||||
MwFirewall.instance().aIF()
|
|
||||||
mw.echoInfo("执行自动识别防火墙端口到面板成功!")
|
|
||||||
elif mw_input == 29:
|
|
||||||
from utils.site_reflect import parse as MwParse
|
|
||||||
MwParse()
|
|
||||||
mw.echoInfo("自动识别配置站点信息成功!")
|
|
||||||
elif mw_input == 100:
|
|
||||||
php_conf = panel_dir + '/plugins/php/info.json'
|
|
||||||
if os.path.exists(php_conf):
|
|
||||||
cont = mw.readFile(php_conf)
|
|
||||||
cont = re.sub("\"53\"", "\"52\",\"53\"", cont)
|
|
||||||
cont = re.sub("\"5.3.29\"", "\"5.2.17\",\"5.3.29\"", cont)
|
|
||||||
mw.writeFile(php_conf, cont)
|
|
||||||
mw.echoInfo("执行PHP52显示成功!")
|
|
||||||
elif mw_input == 101:
|
|
||||||
php_conf = panel_dir + '/plugins/php/info.json'
|
|
||||||
if os.path.exists(php_conf):
|
|
||||||
cont = mw.readFile(php_conf)
|
|
||||||
cont = re.sub("\"52\",", "", cont)
|
|
||||||
cont = re.sub("\"5.2.17\",", cont)
|
|
||||||
mw.writeFile(php_conf, cont)
|
|
||||||
mw.echoInfo("执行PHP52隐藏成功!")
|
|
||||||
elif mw_input == 200:
|
|
||||||
os.system("bash <(curl -sSL https://linuxmirrors.cn/main.sh)")
|
|
||||||
# os.system(INIT_CMD + " mirror")
|
|
||||||
elif mw_input == 201:
|
|
||||||
os.system('curl -Lso- bench.sh | bash')
|
|
||||||
elif mw_input == 202:
|
|
||||||
package = mw.getPanelDir()+'/plugins'
|
|
||||||
|
|
||||||
dst_plugin = mw.getServerDir() + "/webssh"
|
|
||||||
if not os.path.exists(dst_plugin):
|
|
||||||
mw.echoInfo("未安装!")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if not package in sys.path:
|
|
||||||
sys.path.append(package)
|
|
||||||
from webssh.index import App
|
|
||||||
|
|
||||||
obj = App()
|
|
||||||
data = obj.get_server_list()
|
|
||||||
data = json.loads(data)
|
|
||||||
|
|
||||||
if data['status']:
|
|
||||||
wlist = data['data']
|
|
||||||
wlist_len = len(wlist)
|
|
||||||
if wlist_len == 0:
|
|
||||||
mw.echoInfo("SSH终端管理,数据为空!")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if len(sys.argv) == 4:
|
|
||||||
pos = int(sys.argv[3])
|
|
||||||
if pos >= wlist_len:
|
|
||||||
mw.echoInfo("SSH终端管理,超过限制!")
|
|
||||||
exit(1)
|
|
||||||
dst_data = wlist[pos]
|
|
||||||
tmp_host = dst_data["host"]
|
|
||||||
info = obj.get_server_by_host_data(tmp_host)
|
|
||||||
pp_info = tmp_host+"|"+info["port"]+"|"+info['username']+"|"+info['password']+""
|
|
||||||
print(pp_info)
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
mw.echoInfo("请选择:")
|
|
||||||
for x in range(wlist_len):
|
|
||||||
dst_data = wlist[x]
|
|
||||||
tag = dst_data['host']
|
|
||||||
if dst_data['ps'] != "":
|
|
||||||
tag = dst_data['ps']
|
|
||||||
print(str(x) +") " + tag)
|
|
||||||
|
|
||||||
def open_ssh_port():
|
|
||||||
|
|
||||||
find_ssh_port_cmd = "cat /etc/ssh/sshd_config | grep '^Port \\d*' | tail -1"
|
|
||||||
cmd_data = mw.execShell(find_ssh_port_cmd)
|
|
||||||
ssh_port = cmd_data[0].replace("Port ", '').strip()
|
|
||||||
if ssh_port == '':
|
|
||||||
ssh_port = '22'
|
|
||||||
|
|
||||||
mw.echoInfo("SSH端口: "+ str(ssh_port))
|
|
||||||
MwFirewall.instance().addAcceptPort(ssh_port, 'SSH远程管理服务', 'port')
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def set_panel_pwd(password, ncli=False):
|
|
||||||
info = thisdb.getUserByRoot()
|
|
||||||
thisdb.setUserByRoot(password=password)
|
|
||||||
if ncli:
|
|
||||||
mw.echoInfo("username: " + info['name'])
|
|
||||||
mw.echoInfo("password: " + password)
|
|
||||||
else:
|
|
||||||
print(username)
|
|
||||||
|
|
||||||
|
|
||||||
def show_panel_pwd():
|
|
||||||
# 面板密码展示
|
|
||||||
info = thisdb.getUserByRoot()
|
|
||||||
defailt_pwd_file = mw.getPanelDir()+'/data/default.pl'
|
|
||||||
pwd = ''
|
|
||||||
if os.path.exists(defailt_pwd_file):
|
|
||||||
pwd = mw.readFile(defailt_pwd_file).strip()
|
|
||||||
|
|
||||||
if mw.md5(pwd) == info['password']:
|
|
||||||
mw.echoInfo('password: ' + pwd)
|
|
||||||
return
|
|
||||||
print("*-password has been changed!")
|
|
||||||
|
|
||||||
def show_panel_adminpath():
|
|
||||||
admin_path = thisdb.getOption('admin_path')
|
|
||||||
if admin_path == '':
|
|
||||||
print('/login')
|
|
||||||
else:
|
|
||||||
print('/'+admin_path)
|
|
||||||
|
|
||||||
|
|
||||||
def set_panel_username(username=None):
|
|
||||||
# 随机面板用户名
|
|
||||||
if username:
|
|
||||||
if len(username) < 5:
|
|
||||||
mw.echoInfo("错误,用户名长度不能少于5位")
|
|
||||||
return
|
|
||||||
if username in ['admin', 'root']:
|
|
||||||
mw.echoInfo("错误,不能使用过于简单的用户名")
|
|
||||||
return
|
|
||||||
|
|
||||||
thisdb.setUserByRoot(name=username)
|
|
||||||
mw.echoInfo("username: %s" % username)
|
|
||||||
return
|
|
||||||
|
|
||||||
info = thisdb.getUserByRoot()
|
|
||||||
if info['name'] == 'admin':
|
|
||||||
username = mw.getRandomString(8).lower()
|
|
||||||
thisdb.setUserByRoot(name=username)
|
|
||||||
mw.echoInfo('username: ' + info['name'])
|
|
||||||
|
|
||||||
|
|
||||||
def getServerIp():
|
|
||||||
version = sys.argv[2]
|
|
||||||
# ip = mw.execShell(
|
|
||||||
# "curl --insecure -{} -sS --connect-timeout 5 -m 60 https://v6r.ipip.net/?format=text".format(version))
|
|
||||||
ip = mw.execShell(
|
|
||||||
"curl --insecure -{} -sS --connect-timeout 5 -m 60 https://ip.cachecha.com/?format=text".format(version))
|
|
||||||
# print(ip[0])
|
|
||||||
return ip[0]
|
|
||||||
|
|
||||||
|
|
||||||
def getPanelSslType():
|
|
||||||
scheme = 'http'
|
|
||||||
panel_ssl = thisdb.getOptionByJson('panel_ssl', default={'open':False})
|
|
||||||
if panel_ssl['open']:
|
|
||||||
scheme = 'https'
|
|
||||||
return scheme
|
|
||||||
|
|
||||||
def getPanelBindDomain():
|
|
||||||
return thisdb.getOption('panel_domain', default='')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
print('ERROR: Parameter error!')
|
|
||||||
exit(-2)
|
|
||||||
method = sys.argv[1]
|
|
||||||
if method == 'panel':
|
|
||||||
set_panel_pwd(sys.argv[2])
|
|
||||||
elif method == 'username':
|
|
||||||
if len(sys.argv) > 2:
|
|
||||||
set_panel_username(sys.argv[2])
|
|
||||||
else:
|
|
||||||
set_panel_username()
|
|
||||||
elif method == 'password':
|
|
||||||
show_panel_pwd()
|
|
||||||
elif method == 'test':
|
|
||||||
thisdb.getOption('admin_path')
|
|
||||||
elif method == 'admin_path':
|
|
||||||
show_panel_adminpath()
|
|
||||||
elif method == 'getServerIp':
|
|
||||||
print(getServerIp())
|
|
||||||
elif method == 'panel_ssl_type':
|
|
||||||
print(getPanelSslType())
|
|
||||||
elif method == 'panel_bind_domain':
|
|
||||||
print(getPanelBindDomain())
|
|
||||||
elif method == "cli":
|
|
||||||
clinum = 0
|
|
||||||
try:
|
|
||||||
if len(sys.argv) > 2:
|
|
||||||
clinum = int(sys.argv[2]) if sys.argv[2][:6] else sys.argv[2]
|
|
||||||
except:
|
|
||||||
clinum = sys.argv[2]
|
|
||||||
mwcli(clinum)
|
|
||||||
else:
|
|
||||||
print('ERROR: Parameter error')
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 181 B |
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
<div class="bt-form">
|
||||||
|
<div class="bt-w-main">
|
||||||
|
<div class="bt-w-menu">
|
||||||
|
<p class="bgw" onclick="pluginService('abkill');">服务</p>
|
||||||
|
<p onclick="pluginInitD('abkill');">自启动</p>
|
||||||
|
<p onclick="pluginConfig('abkill');">黑名单</p>
|
||||||
|
<p onclick="pluginConfig('abkill');">异常日志</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=abkill&f=js/abkill.js");
|
||||||
|
</script>
|
||||||
Executable
+172
@@ -0,0 +1,172 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import os
|
||||||
|
import urllib
|
||||||
|
import binascii
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
sys.path.append(os.getcwd() + "/class/core")
|
||||||
|
import public
|
||||||
|
|
||||||
|
|
||||||
|
app_debug = False
|
||||||
|
if public.getOs() == 'darwin':
|
||||||
|
app_debug = True
|
||||||
|
|
||||||
|
|
||||||
|
def getPluginName():
|
||||||
|
return 'abkill'
|
||||||
|
|
||||||
|
|
||||||
|
def getPluginDir():
|
||||||
|
return public.getPluginDir() + '/' + getPluginName()
|
||||||
|
|
||||||
|
|
||||||
|
def getServerDir():
|
||||||
|
return public.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(':')
|
||||||
|
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 initDreplace():
|
||||||
|
initd_file = getInitDFile()
|
||||||
|
|
||||||
|
if not os.path.exists(initd_file):
|
||||||
|
return getServerDir()
|
||||||
|
|
||||||
|
return initd_file
|
||||||
|
|
||||||
|
|
||||||
|
def status():
|
||||||
|
data = public.execShell(
|
||||||
|
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
|
||||||
|
if data[0] == '':
|
||||||
|
return 'stop'
|
||||||
|
return 'start'
|
||||||
|
|
||||||
|
|
||||||
|
def csvnOp(method):
|
||||||
|
|
||||||
|
if app_debug:
|
||||||
|
os_name = public.getOs()
|
||||||
|
if os_name == 'darwin':
|
||||||
|
return "Apple Computer does not support"
|
||||||
|
|
||||||
|
_initd_csvn = '/etc/init.d/csvn'
|
||||||
|
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
|
||||||
|
#_csvn = getServerDir() + '/bin/csvn'
|
||||||
|
#_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
|
||||||
|
|
||||||
|
ret_csvn_httpd = public.execShell(_initd_csvn_httpd + ' ' + method)
|
||||||
|
# ret_csvn = public.execShell(_initd_csvn + ' ' + method)
|
||||||
|
subprocess.Popen(_initd_csvn + ' ' + method,
|
||||||
|
stdout=subprocess.PIPE, shell=True)
|
||||||
|
if ret_csvn_httpd[1] == '':
|
||||||
|
return 'ok'
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
|
|
||||||
|
def start():
|
||||||
|
return csvnOp('start')
|
||||||
|
|
||||||
|
|
||||||
|
def stop():
|
||||||
|
return csvnOp('stop')
|
||||||
|
|
||||||
|
|
||||||
|
def restart():
|
||||||
|
return csvnOp('restart')
|
||||||
|
|
||||||
|
|
||||||
|
def reload():
|
||||||
|
return csvnOp('reload')
|
||||||
|
|
||||||
|
|
||||||
|
def initdStatus():
|
||||||
|
if not app_debug:
|
||||||
|
if public.getOs() == 'darwin':
|
||||||
|
return "Apple Computer does not support"
|
||||||
|
|
||||||
|
_initd_csvn = '/etc/init.d/csvn'
|
||||||
|
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
|
||||||
|
|
||||||
|
if os.path.exists(_initd_csvn) and os.path.exists(_initd_csvn_httpd):
|
||||||
|
return 'ok'
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
|
|
||||||
|
def initdInstall():
|
||||||
|
import shutil
|
||||||
|
if not app_debug:
|
||||||
|
if public.getOs() == 'darwin':
|
||||||
|
return "Apple Computer does not support"
|
||||||
|
|
||||||
|
_csvn = getServerDir() + '/bin/csvn'
|
||||||
|
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
|
||||||
|
|
||||||
|
ret_csvn = public.execShell(_csvn + ' install')
|
||||||
|
ret_csvn_httpd = public.execShell(_csvn_httpd + ' install')
|
||||||
|
if ret_csvn[1] == '' and ret_csvn_httpd[1] == '':
|
||||||
|
return 'ok'
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
|
|
||||||
|
def initdUinstall():
|
||||||
|
if not app_debug:
|
||||||
|
if public.getOs() == 'darwin':
|
||||||
|
return "Apple Computer does not support"
|
||||||
|
|
||||||
|
_csvn = getServerDir() + '/bin/csvn'
|
||||||
|
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
|
||||||
|
|
||||||
|
ret_csvn = public.execShell(_csvn + ' remove')
|
||||||
|
ret_csvn_httpd = public.execShell(_csvn_httpd + ' remove')
|
||||||
|
return 'ok'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
func = sys.argv[1]
|
||||||
|
if func == 'status':
|
||||||
|
print status()
|
||||||
|
elif func == 'start':
|
||||||
|
print start()
|
||||||
|
elif func == 'stop':
|
||||||
|
print stop()
|
||||||
|
elif func == 'restart':
|
||||||
|
print restart()
|
||||||
|
elif func == 'reload':
|
||||||
|
print reload()
|
||||||
|
elif func == 'initd_status':
|
||||||
|
print initdStatus()
|
||||||
|
elif func == 'initd_install':
|
||||||
|
print initdInstall()
|
||||||
|
elif func == 'initd_uninstall':
|
||||||
|
print initdUinstall()
|
||||||
|
else:
|
||||||
|
print 'fail'
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"sort": 7,
|
||||||
|
"ps": "异常程序监控和KILL",
|
||||||
|
"shell": "install.sh",
|
||||||
|
"name": "abkill",
|
||||||
|
"title": "异常程序监控",
|
||||||
|
"versions": "0.1",
|
||||||
|
"updates":"0.1",
|
||||||
|
"tip": "soft",
|
||||||
|
"checks": "server/abkill",
|
||||||
|
"author": "midoks",
|
||||||
|
"date": "201-04-01",
|
||||||
|
"home": "https://www.collab.net",
|
||||||
|
"type": "异常程序监控和KILL",
|
||||||
|
"pid": "4"
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||||
|
|
||||||
|
ak_path={$SERVER_PATH}/abkill
|
||||||
|
|
||||||
|
ak_start(){
|
||||||
|
isStart=$(ps aux |grep 'abkill.py'|grep -v grep|awk '{print $2}')
|
||||||
|
if [ "$isStart" == '' ];then
|
||||||
|
echo -e "Starting abkill... \c"
|
||||||
|
cd $ak_path && nohup python abkill.py >> $ak_path/task.log 2>&1 &
|
||||||
|
sleep 0.3
|
||||||
|
isStart=$(ps aux |grep 'abkill.py'|grep -v grep|awk '{print $2}')
|
||||||
|
if [ "$isStart" == '' ];then
|
||||||
|
echo -e "\033[31mfailed\033[0m"
|
||||||
|
echo '------------------------------------------------------'
|
||||||
|
tail -n 20 $ak_path/task.log
|
||||||
|
echo '------------------------------------------------------'
|
||||||
|
echo -e "\033[31mError: abkill service startup failed.\033[0m"
|
||||||
|
return;
|
||||||
|
fi
|
||||||
|
echo -e "\033[32mdone\033[0m"
|
||||||
|
else
|
||||||
|
echo "Starting abkill(pid $isStart) already running"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ak_stop()
|
||||||
|
{
|
||||||
|
echo -e "Stopping abkill... \c";
|
||||||
|
pids=$(ps aux | grep 'abkill.py' | grep -v grep|awk '{print $2}')
|
||||||
|
arr=($pids)
|
||||||
|
|
||||||
|
for p in ${arr[@]}
|
||||||
|
do
|
||||||
|
kill -9 $p
|
||||||
|
done
|
||||||
|
echo -e "\033[32mdone\033[0m"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ak_status()
|
||||||
|
{
|
||||||
|
isStart=$(ps aux|grep 'abkill.py'|grep -v grep|awk '{print $2}')
|
||||||
|
if [ "$isStart" != '' ];then
|
||||||
|
echo -e "\033[32mabkill (pid $(echo $isStart)) already running\033[0m"
|
||||||
|
else
|
||||||
|
echo -e "\033[31mabkill not running\033[0m"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ak_reload()
|
||||||
|
{
|
||||||
|
isStart=$(ps aux|grep 'abkill.py'|grep -v grep|awk '{print $2}')
|
||||||
|
|
||||||
|
if [ "$isStart" != '' ];then
|
||||||
|
ak_stop
|
||||||
|
ak_start
|
||||||
|
else
|
||||||
|
echo -e "\033[31mmw not running\033[0m"
|
||||||
|
mw_start
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
'start') ak_start;;
|
||||||
|
'stop') ak_stop;;
|
||||||
|
'reload') ak_reload;;
|
||||||
|
'restart')
|
||||||
|
ak_stop
|
||||||
|
sleep 0.3
|
||||||
|
ak_start;;
|
||||||
|
'status') ak_status;;
|
||||||
|
esac
|
||||||
Executable
+32
@@ -0,0 +1,32 @@
|
|||||||
|
#!/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/bt_install.pl
|
||||||
|
|
||||||
|
Install_abkill()
|
||||||
|
{
|
||||||
|
echo '正在安装脚本文件...' > $install_tmp
|
||||||
|
mkdir -p $serverPath/abkill
|
||||||
|
echo '0.1' > $serverPath/abkill/version.pl
|
||||||
|
echo '安装完成' > $install_tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
Uninstall_abkill()
|
||||||
|
{
|
||||||
|
rm -f $serverPath/abkill
|
||||||
|
echo "卸载完成" > $install_tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
action=$1
|
||||||
|
if [ "${1}" == 'install' ];then
|
||||||
|
Install_abkill
|
||||||
|
else
|
||||||
|
Uninstall_abkill
|
||||||
|
fi
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
pluginService('abkill');
|
||||||
Executable
+85
@@ -0,0 +1,85 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# 使用示例:
|
||||||
|
# 1、将此文件重命名为btkill.py , 然后上传到服务器/root目录
|
||||||
|
# 2、执行 python /root/btkill.py
|
||||||
|
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
sys.path.append("/usr/local/lib/python2.7/site-packages")
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
|
||||||
|
class btkill:
|
||||||
|
__limit = 10 # Cpu使用率触发上限
|
||||||
|
__vmsize = 1048576 / 4 # 虚拟内存触发上限(字节)
|
||||||
|
|
||||||
|
def checkMain(self):
|
||||||
|
pids = psutil.pids()
|
||||||
|
print pids
|
||||||
|
num = 0
|
||||||
|
for pid in pids:
|
||||||
|
try:
|
||||||
|
p = psutil.Process(pid)
|
||||||
|
if p.exe() == "":
|
||||||
|
continue
|
||||||
|
name = p.name()
|
||||||
|
if self.whiteList(name):
|
||||||
|
continue
|
||||||
|
cputimes = p.cpu_times()
|
||||||
|
if cputimes.user < 0.1:
|
||||||
|
continue
|
||||||
|
print p
|
||||||
|
percent = p.cpu_percent(interval=1)
|
||||||
|
vm = p.memory_info().vms
|
||||||
|
if percent > self.__limit or vm > self.__vmsize:
|
||||||
|
log = time.strftime('%Y-%m-%d %X', time.localtime()) + " (PID=" + str(
|
||||||
|
pid) + ", NAME=" + name + ", VMS=" + str(vm) + ", PERCENT=" + str(percent) + "%)"
|
||||||
|
# p.kill()
|
||||||
|
num += 1
|
||||||
|
print log + " >> killed\n"
|
||||||
|
except Exception as ex:
|
||||||
|
print str(ex)
|
||||||
|
return num
|
||||||
|
|
||||||
|
# 检查白名单
|
||||||
|
def whiteList(self, name):
|
||||||
|
wlist = ['yum', 'apt-get', 'apt', 'redis-cli', 'memcached', 'sshd', 'vm', 'vim', 'htop', 'top', 'sh', 'bash', 'zip', 'gzip', 'rsync',
|
||||||
|
'tar', 'unzip', 'php', 'composer', 'pkill', 'mongo', 'mongod', 'php-fpm', 'nginx', 'httpd', 'lsof', 'ps', 'redis-server',
|
||||||
|
'mysqld', 'mysqld_safe', 'mysql', 'pure-ftpd', 'sparse_dd', 'stunnel', 'squeezed', 'vncterm', 'awk', 'ruby', 'postgres',
|
||||||
|
'mpathalert', 'vncterm', 'multipathd', 'fe', 'elasticsyslog', 'syslogd', 'v6d', 'xapi', 'screen', 'runsvdir', 'svlogd',
|
||||||
|
'java', 'udevd', 'ntpd', 'irqbalance', 'qmgr', 'wpa_supplicant', 'mysqld_safe', 'sftp-server', 'lvmetad', 'gitlab-web',
|
||||||
|
'pure-ftpd', 'auditd', 'master', 'dbus-daemon', 'tapdisk', 'sshd', 'init', 'ksoftirqd', 'kworker', 'kmpathd',
|
||||||
|
'kmpath_handlerd', 'python', 'kdmflush', 'bioset', 'crond', 'kthreadd', 'migration', 'rcu_sched', 'kjournald',
|
||||||
|
'gcc', 'gcc++', 'nginx', 'mysqld', 'php-cgi', 'login', 'firewalld', 'iptables', 'systemd', 'network', 'dhclient',
|
||||||
|
'systemd-journald', 'NetworkManager', 'systemd-logind', 'systemd-udevd', 'polkitd', 'tuned', 'rsyslogd', 'AliYunDunUpdate', 'AliYunDun', 'sendmail']
|
||||||
|
wslist = ['vif', 'qemu', 'scsi_eh', 'xcp',
|
||||||
|
'xen', 'docker', 'yunsuo', 'aliyun', 'PM2']
|
||||||
|
|
||||||
|
for key in wlist:
|
||||||
|
if key == name:
|
||||||
|
return True
|
||||||
|
|
||||||
|
for key in wslist:
|
||||||
|
if name.find(key) != -1:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 开始处理
|
||||||
|
def start(self):
|
||||||
|
num = 0
|
||||||
|
while True:
|
||||||
|
num += self.checkMain()
|
||||||
|
print "查杀完成, 共查杀[" + str(num) + "]个异常进程!"
|
||||||
|
time.sleep(3)
|
||||||
|
print '======================================='
|
||||||
|
print "查杀完成, 共查杀[" + str(num) + "]个异常进程!"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print "正在检测异常进程..."
|
||||||
|
print '======================================='
|
||||||
|
c = btkill()
|
||||||
|
c.start()
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS `dnsapi` (
|
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
`name` TEXT,
|
|
||||||
`type` TEXT,
|
|
||||||
`val` TEXT,
|
|
||||||
`remark` TEXT,
|
|
||||||
`addtime` TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `email` (
|
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
`addr` TEXT,
|
|
||||||
`remark` TEXT,
|
|
||||||
`addtime` TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `domain` (
|
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
`domain` TEXT,
|
|
||||||
`dnsapi_id` TEXT,
|
|
||||||
`email` TEXT,
|
|
||||||
`remark` TEXT,
|
|
||||||
`effective_date` TEXT default '',
|
|
||||||
`expiration_date` TEXT default '',
|
|
||||||
`error` TEXT,
|
|
||||||
`status` INTEGER default '0',
|
|
||||||
`addtime` TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
-- ALTER TABLE `domain` ADD COLUMN `effective_date` TEXT DEFAULT '';
|
|
||||||
-- ALTER TABLE `domain` ADD COLUMN `expiration_date` TEXT DEFAULT '';
|
|
||||||
-- ALTER TABLE `domain` ADD COLUMN `error` TEXT DEFAULT '';
|
|
||||||
-- ALTER TABLE `domain` ADD COLUMN `status` INTEGER DEFAULT '0';
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
import base64
|
|
||||||
|
|
||||||
|
|
||||||
# 8001 / 7788
|
|
||||||
goedge_addr = 'http://127.0.0.2:8009'
|
|
||||||
access_keyid = "xxx"
|
|
||||||
access_key = "xxx"
|
|
||||||
|
|
||||||
# 指定用户
|
|
||||||
userId = 1
|
|
||||||
|
|
||||||
if sys.platform != "darwin":
|
|
||||||
os.chdir("/www/server/mdserver-web")
|
|
||||||
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
|
|
||||||
domain = sys.argv[1]
|
|
||||||
ssl_path = sys.argv[2]
|
|
||||||
|
|
||||||
|
|
||||||
def getToken():
|
|
||||||
api_url = goedge_addr+'/APIAccessTokenService/getAPIAccessToken'
|
|
||||||
post_data = {
|
|
||||||
"type": "admin",
|
|
||||||
"accessKeyId": access_keyid,
|
|
||||||
"accessKey": access_key
|
|
||||||
}
|
|
||||||
data = requests.post(api_url,json=post_data)
|
|
||||||
data_obj = data.json()
|
|
||||||
|
|
||||||
return data_obj['data']['token']
|
|
||||||
|
|
||||||
token = getToken()
|
|
||||||
|
|
||||||
def commonReq(url, data):
|
|
||||||
headers = {
|
|
||||||
'X-Edge-Access-Token': token
|
|
||||||
}
|
|
||||||
api_url = goedge_addr+url
|
|
||||||
resp_data = requests.post(api_url,json=data, headers=headers)
|
|
||||||
return resp_data.json()
|
|
||||||
|
|
||||||
def listSSLCerts(domain):
|
|
||||||
request_data = {
|
|
||||||
"userId":userId,
|
|
||||||
"isCA":False,
|
|
||||||
"keyword": "ACME泛域名自动上传",
|
|
||||||
"domains":[domain,"*."+domain],
|
|
||||||
"size":1
|
|
||||||
}
|
|
||||||
response_data = commonReq('/SSLCertService/listSSLCerts', request_data)
|
|
||||||
|
|
||||||
data = response_data['data']['sslCertsJSON']
|
|
||||||
data = mw.base64StrDecode(data)
|
|
||||||
data = mw.getObjectByJson(data)
|
|
||||||
# print(data)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# createSSLCert(domain)
|
|
||||||
def createSSLCert(domain, did=0):
|
|
||||||
|
|
||||||
ssl_cer_file = ssl_path + '/'+domain+'.cer'
|
|
||||||
|
|
||||||
if not os.path.exists(ssl_cer_file):
|
|
||||||
print("没有有效证书!")
|
|
||||||
return ''
|
|
||||||
# print(ssl_cer_file)
|
|
||||||
ssl_info = mw.getCertName(ssl_cer_file)
|
|
||||||
cer_data = mw.readFile(ssl_cer_file)
|
|
||||||
cer_data = mw.base64StrEncode(cer_data)
|
|
||||||
# print('cer',cer_data)
|
|
||||||
|
|
||||||
ssl_key_file = ssl_path + '/'+domain+'.key'
|
|
||||||
key_data = mw.readFile(ssl_key_file)
|
|
||||||
key_data = mw.base64StrEncode(key_data)
|
|
||||||
# print('ssl_info',ssl_info)
|
|
||||||
|
|
||||||
timeBeginAt = int(time.mktime(time.strptime(ssl_info['notBefore'], "%Y-%m-%d")))
|
|
||||||
timeEndAt = int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")))
|
|
||||||
|
|
||||||
request_data = {
|
|
||||||
"isOn":True,
|
|
||||||
"userId":userId,
|
|
||||||
"name": "ACME泛域名自动上传",
|
|
||||||
"isCA":False,
|
|
||||||
"description":domain,
|
|
||||||
"serverName":domain,
|
|
||||||
"certData":cer_data,
|
|
||||||
"keyData":key_data,
|
|
||||||
"timeBeginAt":timeBeginAt,
|
|
||||||
"timeEndAt": timeEndAt,
|
|
||||||
"dnsNames":[domain,"*."+domain],
|
|
||||||
"commonNames":[ssl_info['issuer']]
|
|
||||||
}
|
|
||||||
|
|
||||||
if did>0:
|
|
||||||
request_data['sslCertId'] = did
|
|
||||||
# print(request_data)
|
|
||||||
response_data = commonReq('/SSLCertService/updateSSLCert', request_data)
|
|
||||||
print('更新成功',domain,response_data)
|
|
||||||
return response_data
|
|
||||||
else:
|
|
||||||
# print(request_data)
|
|
||||||
response_data = commonReq('/SSLCertService/createSSLCert', request_data)
|
|
||||||
print('创建成功',domain,response_data)
|
|
||||||
return response_data
|
|
||||||
return response_data
|
|
||||||
|
|
||||||
def autoSyncDomain(domain):
|
|
||||||
data = listSSLCerts(domain)
|
|
||||||
if len(data) > 0 :
|
|
||||||
did = data[0]['id']
|
|
||||||
createSSLCert(domain,did)
|
|
||||||
else:
|
|
||||||
createSSLCert(domain)
|
|
||||||
print(data)
|
|
||||||
|
|
||||||
|
|
||||||
autoSyncDomain(domain)
|
|
||||||
print(domain,ssl_path)
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
|
|
||||||
domain = sys.argv[1]
|
|
||||||
path = sys.argv[2]
|
|
||||||
|
|
||||||
print(domain,path)
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -1,34 +0,0 @@
|
|||||||
<style>
|
|
||||||
.overflow_hide {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="bt-form">
|
|
||||||
<div class='plugin_version'></div>
|
|
||||||
<div class="bt-w-main">
|
|
||||||
<div class="bt-w-menu">
|
|
||||||
<p class="bgw" onclick="pluginService('acme_pandominassl_apply');">服务</p>
|
|
||||||
<p onclick="dnsapiList();">DNSAPI *</p>
|
|
||||||
<p onclick="emailList();">邮件地址 </p>
|
|
||||||
<p onclick="domainList()">域名SSL *</p>
|
|
||||||
<p onclick="pluginConfigTpl('acme_pandominassl_apply',$('.plugin_version').attr('version'));">HOOK</p>
|
|
||||||
<p onclick="pluginLogs('acme_pandominassl_apply','','run_log');">日志</p>
|
|
||||||
<p onclick="apaReadme();">相关说明</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="bt-w-con pd15">
|
|
||||||
<div class="soft-man-con"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
resetPluginWinWidth(1000);
|
|
||||||
resetPluginWinHeight(550);
|
|
||||||
$.getScript( "/plugins/file?name=acme_pandominassl_apply&f=js/common.js", function(){
|
|
||||||
pluginService('acme_pandominassl_apply', $('.plugin_version').attr('version'));
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,863 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
|
|
||||||
app_debug = False
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
app_debug = True
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginName():
|
|
||||||
return 'acme_pandominassl_apply'
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginDir():
|
|
||||||
return mw.getPluginDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getInitDFile():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return '/tmp/' + getPluginName()
|
|
||||||
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
return '/etc/rc.d/' + getPluginName()
|
|
||||||
|
|
||||||
return '/etc/init.d/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getConf():
|
|
||||||
path = getServerDir() + "/hook.py"
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def getInitDTpl():
|
|
||||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
|
||||||
return path
|
|
||||||
|
|
||||||
def runLog():
|
|
||||||
return getServerDir() + '/hook.log'
|
|
||||||
|
|
||||||
def getArgs():
|
|
||||||
args = sys.argv[3:]
|
|
||||||
# print(args)
|
|
||||||
tmp = {}
|
|
||||||
args_len = len(args)
|
|
||||||
|
|
||||||
if args_len == 1:
|
|
||||||
t = args[0].strip('{').strip('}')
|
|
||||||
if t.strip() == '':
|
|
||||||
tmp = []
|
|
||||||
else:
|
|
||||||
t = t.split(':')
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
elif args_len > 1:
|
|
||||||
for i in range(len(args)):
|
|
||||||
t = args[i].split(':')
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
return tmp
|
|
||||||
|
|
||||||
def checkArgs(data, ck=[]):
|
|
||||||
for i in range(len(ck)):
|
|
||||||
if not ck[i] in data:
|
|
||||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
|
||||||
return (True, mw.returnJson(True, 'ok'))
|
|
||||||
|
|
||||||
|
|
||||||
def 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'
|
|
||||||
|
|
||||||
def configTpl():
|
|
||||||
path = getPluginDir() + '/hooks'
|
|
||||||
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 getPidFile():
|
|
||||||
file = getConf()
|
|
||||||
content = mw.readFile(file)
|
|
||||||
rep = r'pidfile\s*(.*)'
|
|
||||||
tmp = re.search(rep, content)
|
|
||||||
return tmp.groups()[0].strip()
|
|
||||||
|
|
||||||
def status():
|
|
||||||
return 'start'
|
|
||||||
|
|
||||||
def contentReplace(content):
|
|
||||||
service_path = mw.getServerDir()
|
|
||||||
content = content.replace('{$ROOT_PATH}', mw.getFatherDir())
|
|
||||||
content = content.replace('{$SERVER_PATH}', service_path)
|
|
||||||
content = content.replace('{$SERVER_APP}', service_path + '/redis')
|
|
||||||
content = content.replace('{$REDIS_PASS}', mw.getRandomString(10))
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def pSqliteDb(dbname='dnsapi'):
|
|
||||||
file = getServerDir() + '/acme.db'
|
|
||||||
name = 'acme'
|
|
||||||
|
|
||||||
import_sql = mw.readFile(getPluginDir() + '/conf/acme.sql')
|
|
||||||
md5_sql = mw.md5(import_sql)
|
|
||||||
|
|
||||||
import_sign = False
|
|
||||||
save_md5_file = getServerDir() + '/acme.md5'
|
|
||||||
if os.path.exists(save_md5_file):
|
|
||||||
save_md5_sql = mw.readFile(save_md5_file)
|
|
||||||
if save_md5_sql != md5_sql:
|
|
||||||
import_sign = True
|
|
||||||
mw.writeFile(save_md5_file, md5_sql)
|
|
||||||
else:
|
|
||||||
mw.writeFile(save_md5_file, md5_sql)
|
|
||||||
|
|
||||||
if not os.path.exists(file) or import_sql:
|
|
||||||
conn = mw.M(dbname).dbPos(getServerDir(), name)
|
|
||||||
csql_list = import_sql.split(';')
|
|
||||||
for index in range(len(csql_list)):
|
|
||||||
conn.execute(csql_list[index], ())
|
|
||||||
|
|
||||||
conn = mw.M(dbname).dbPos(getServerDir(), name)
|
|
||||||
return conn
|
|
||||||
|
|
||||||
def initDreplace():
|
|
||||||
|
|
||||||
file_tpl = getInitDTpl()
|
|
||||||
|
|
||||||
initD_path = getServerDir() + '/init.d'
|
|
||||||
if not os.path.exists(initD_path):
|
|
||||||
os.mkdir(initD_path)
|
|
||||||
file_bin = initD_path + '/' + getPluginName()
|
|
||||||
|
|
||||||
run_log_file = runLog()
|
|
||||||
if not os.path.exists(run_log_file):
|
|
||||||
mw.writeFile(run_log_file,'')
|
|
||||||
|
|
||||||
hook_file = getConf()
|
|
||||||
if not os.path.exists(hook_file):
|
|
||||||
mw.writeFile(hook_file,'')
|
|
||||||
|
|
||||||
return file_bin
|
|
||||||
|
|
||||||
|
|
||||||
def apaOp(method):
|
|
||||||
file = initDreplace()
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
# current_os = mw.getOs()
|
|
||||||
# if current_os == "darwin":
|
|
||||||
# data = mw.execShell(file + ' ' + method)
|
|
||||||
# if data[1] == '':
|
|
||||||
# return 'ok'
|
|
||||||
# return data[1]
|
|
||||||
|
|
||||||
# if current_os.startswith("freebsd"):
|
|
||||||
# data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
|
||||||
# if data[1] == '':
|
|
||||||
# return 'ok'
|
|
||||||
# return data[1]
|
|
||||||
|
|
||||||
# data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
|
||||||
# if data[1] == '':
|
|
||||||
# return 'ok'
|
|
||||||
# return data[1]
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
|
||||||
import tool_cron
|
|
||||||
tool_cron.createBgTask()
|
|
||||||
|
|
||||||
return apaOp('start')
|
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
|
||||||
import tool_cron
|
|
||||||
tool_cron.removeBgTask()
|
|
||||||
return apaOp('stop')
|
|
||||||
|
|
||||||
|
|
||||||
def restart():
|
|
||||||
status = apaOp('restart')
|
|
||||||
return status
|
|
||||||
|
|
||||||
|
|
||||||
def reload():
|
|
||||||
return apaOp('reload')
|
|
||||||
|
|
||||||
|
|
||||||
def dnsapiAdd():
|
|
||||||
conn = pSqliteDb('dnsapi')
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args,['id','name', 'type', 'remark'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
name = args['name'].strip()
|
|
||||||
remark = args['remark'].strip()
|
|
||||||
stype = args['type'].strip()
|
|
||||||
val = args['val'].strip()
|
|
||||||
sid = args['id'].strip()
|
|
||||||
|
|
||||||
if name == '':
|
|
||||||
return mw.returnJson(False, '名称不能为空!')
|
|
||||||
|
|
||||||
if sid != '0' : #修改操作
|
|
||||||
conn.where("id=?", (sid,)).update({
|
|
||||||
'name':name,
|
|
||||||
'type':stype,
|
|
||||||
'val':val,
|
|
||||||
'remark':remark,
|
|
||||||
})
|
|
||||||
return mw.returnJson(True, '修改成功!')
|
|
||||||
|
|
||||||
if conn.where("name=?", (name,)).count():
|
|
||||||
return mw.returnJson(False, name+'已存在!')
|
|
||||||
|
|
||||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
|
||||||
err = conn.add('name,type,val,remark,addtime', (name, stype, val,remark, addTime))
|
|
||||||
# print(err)
|
|
||||||
return mw.returnJson(True, '添加成功!')
|
|
||||||
|
|
||||||
def dnsapiDel():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['id', 'name'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
conn = pSqliteDb('dnsapi')
|
|
||||||
try:
|
|
||||||
sid = args['id']
|
|
||||||
name = args['name']
|
|
||||||
conn.where("id=?", (sid,)).delete()
|
|
||||||
return mw.returnJson(True, '删除成功!')
|
|
||||||
except Exception as ex:
|
|
||||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
|
||||||
|
|
||||||
def dnsapiList():
|
|
||||||
args = getArgs()
|
|
||||||
page = 1
|
|
||||||
page_size = 10
|
|
||||||
search = ''
|
|
||||||
data = {}
|
|
||||||
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']
|
|
||||||
|
|
||||||
conn = pSqliteDb('dnsapi')
|
|
||||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
|
||||||
condition = ''
|
|
||||||
if not search == '':
|
|
||||||
condition = "name like '%" + search + "%'"
|
|
||||||
field = 'id,name,type,val,remark,addtime'
|
|
||||||
clist = conn.where(condition, ()).field(
|
|
||||||
field).limit(limit).order('id desc').select()
|
|
||||||
|
|
||||||
count = conn.where(condition, ()).count()
|
|
||||||
_page = {}
|
|
||||||
_page['count'] = count
|
|
||||||
_page['p'] = page
|
|
||||||
_page['row'] = page_size
|
|
||||||
_page['tojs'] = 'dbList'
|
|
||||||
data['page'] = mw.getPage(_page)
|
|
||||||
data['data'] = clist
|
|
||||||
|
|
||||||
return mw.getJson(data)
|
|
||||||
|
|
||||||
def dnsapiListAll():
|
|
||||||
conn = pSqliteDb('dnsapi')
|
|
||||||
field = 'id,name,type,val,remark,addtime'
|
|
||||||
data = conn.field(field).limit('1000').select()
|
|
||||||
return mw.getJson(data)
|
|
||||||
|
|
||||||
def emailList():
|
|
||||||
args = getArgs()
|
|
||||||
page = 1
|
|
||||||
page_size = 10
|
|
||||||
search = ''
|
|
||||||
data = {}
|
|
||||||
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']
|
|
||||||
|
|
||||||
conn = pSqliteDb('email')
|
|
||||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
|
||||||
condition = ''
|
|
||||||
if not search == '':
|
|
||||||
condition = "addr like '%" + search + "%'"
|
|
||||||
field = 'id,addr,remark,addtime'
|
|
||||||
clist = conn.where(condition, ()).field(
|
|
||||||
field).limit(limit).order('id desc').select()
|
|
||||||
|
|
||||||
count = conn.where(condition, ()).count()
|
|
||||||
_page = {}
|
|
||||||
_page['count'] = count
|
|
||||||
_page['p'] = page
|
|
||||||
_page['row'] = page_size
|
|
||||||
_page['tojs'] = 'dbList'
|
|
||||||
data['page'] = mw.getPage(_page)
|
|
||||||
data['data'] = clist
|
|
||||||
|
|
||||||
return mw.getJson(data)
|
|
||||||
|
|
||||||
def emailAdd():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args,['addr', 'remark'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
addr = args['addr'].strip()
|
|
||||||
remark = args['remark'].strip()
|
|
||||||
|
|
||||||
if addr == '':
|
|
||||||
return mw.returnJson(False, '邮件地址不能为空!')
|
|
||||||
|
|
||||||
conn = pSqliteDb('email')
|
|
||||||
|
|
||||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
|
||||||
conn.add('addr,remark,addtime', (addr, remark, addTime))
|
|
||||||
return mw.returnJson(True, '添加成功!')
|
|
||||||
|
|
||||||
def emailDel():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['id', 'name'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
conn = pSqliteDb('email')
|
|
||||||
try:
|
|
||||||
sid = args['id']
|
|
||||||
name = args['name']
|
|
||||||
conn.where("id=?", (sid,)).delete()
|
|
||||||
return mw.returnJson(True, '删除成功!')
|
|
||||||
except Exception as ex:
|
|
||||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
|
||||||
|
|
||||||
def domainAdd():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args,['id','domain', 'dnsapi_id','email','remark'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
sid = args['id'].strip()
|
|
||||||
domain = args['domain'].strip()
|
|
||||||
remark = args['remark'].strip()
|
|
||||||
email = args['email'].strip()
|
|
||||||
dnsapi_id = args['dnsapi_id'].strip()
|
|
||||||
|
|
||||||
if domain == '':
|
|
||||||
return mw.returnJson(False, '域名不能为空!')
|
|
||||||
if email == '':
|
|
||||||
return mw.returnJson(False, '邮件不能为空!')
|
|
||||||
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
|
|
||||||
if sid != '0' : #修改操作
|
|
||||||
conn.where("id=?", (sid,)).update({
|
|
||||||
'domain':domain,
|
|
||||||
'dnsapi_id':dnsapi_id,
|
|
||||||
'email':email,
|
|
||||||
'remark':remark,
|
|
||||||
})
|
|
||||||
return mw.returnJson(True, '修改成功!')
|
|
||||||
|
|
||||||
if conn.where("domain=?", (domain,)).count():
|
|
||||||
return mw.returnJson(False, domain+'已存在!')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
|
||||||
conn.add('domain,dnsapi_id,email,remark,addtime', (domain, dnsapi_id,email,remark, addTime))
|
|
||||||
return mw.returnJson(True, '添加成功!')
|
|
||||||
|
|
||||||
def domainDel():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['id', 'name'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
try:
|
|
||||||
sid = args['id']
|
|
||||||
name = args['name']
|
|
||||||
conn.where("id=?", (sid,)).delete()
|
|
||||||
return mw.returnJson(True, '删除成功!')
|
|
||||||
except Exception as ex:
|
|
||||||
return mw.returnJson(False, '删除失败!' + str(ex))
|
|
||||||
|
|
||||||
def domainStatusToggle():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['id'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
|
|
||||||
field = 'id,status'
|
|
||||||
fdata = conn.field(field).where('id=?',(args['id'],)).find()
|
|
||||||
|
|
||||||
fstatus = fdata['status']
|
|
||||||
if fstatus == 0:
|
|
||||||
fstatus = 1
|
|
||||||
else:
|
|
||||||
fstatus = 0
|
|
||||||
# print(fdata['status'],fstatus)
|
|
||||||
conn.where("id=?", (args['id'],)).update({
|
|
||||||
'status':fstatus,
|
|
||||||
})
|
|
||||||
return mw.returnJson(True, '切换成功!')
|
|
||||||
|
|
||||||
def domainList():
|
|
||||||
args = getArgs()
|
|
||||||
page = 1
|
|
||||||
page_size = 10
|
|
||||||
search = ''
|
|
||||||
data = {}
|
|
||||||
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']
|
|
||||||
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
conn_dnsapi = pSqliteDb('dnsapi')
|
|
||||||
limit = str((page - 1) * page_size) + ',' + str(page_size)
|
|
||||||
condition = ''
|
|
||||||
if not search == '':
|
|
||||||
condition = "domain like '%" + search + "%'"
|
|
||||||
field = 'id,domain,dnsapi_id,email,status,effective_date,expiration_date,remark,addtime'
|
|
||||||
clist = conn.where(condition, ()).field(
|
|
||||||
field).limit(limit).order('id desc').select()
|
|
||||||
|
|
||||||
for i in range(len(clist)):
|
|
||||||
tdata = conn_dnsapi.field('id,name').where('id=?',(clist[i]['dnsapi_id'],)).select()
|
|
||||||
if len(tdata) > 0:
|
|
||||||
# print(tdata[0]['name'])
|
|
||||||
clist[i]['dnsapi_id_alias'] = clist[i]['dnsapi_id']+'('+ tdata[0]['name'] +')'
|
|
||||||
else:
|
|
||||||
clist[i]['dnsapi_id_alias'] = clist[i]['dnsapi_id']+' (无)'
|
|
||||||
|
|
||||||
count = conn.where(condition, ()).count()
|
|
||||||
_page = {}
|
|
||||||
_page['count'] = count
|
|
||||||
_page['p'] = page
|
|
||||||
_page['row'] = page_size
|
|
||||||
_page['tojs'] = 'dbList'
|
|
||||||
data['page'] = mw.getPage(_page)
|
|
||||||
data['data'] = clist
|
|
||||||
|
|
||||||
return mw.getJson(data)
|
|
||||||
|
|
||||||
def getDnsapiData(dnsapi_id):
|
|
||||||
if dnsapi_id == '0':
|
|
||||||
return {}
|
|
||||||
conn_dnsapi = pSqliteDb('dnsapi')
|
|
||||||
tdata = conn_dnsapi.field('id,name,type,val').where('id=?',(dnsapi_id,)).select()
|
|
||||||
|
|
||||||
if len(tdata)>0:
|
|
||||||
return tdata[0]
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def getDnsapiExportVar(val):
|
|
||||||
cmd_list = val.split('~')
|
|
||||||
def_var = ''
|
|
||||||
for x in range(len(cmd_list)):
|
|
||||||
v = cmd_list[x]
|
|
||||||
vlist = v.split('|')
|
|
||||||
def_var += 'export '+vlist[0]+'="'+vlist[1]+'"\n'
|
|
||||||
return def_var
|
|
||||||
|
|
||||||
def getDnsapiKv(val):
|
|
||||||
cmd_list = val.split('~')
|
|
||||||
def_var = {}
|
|
||||||
for x in range(len(cmd_list)):
|
|
||||||
v = cmd_list[x]
|
|
||||||
vlist = v.split('|')
|
|
||||||
kk = vlist[0]
|
|
||||||
vv = vlist[1]
|
|
||||||
def_var[kk] = vv
|
|
||||||
return def_var
|
|
||||||
|
|
||||||
def domainApplyPathJudge(domain):
|
|
||||||
acme_dir = "/root/.acme.sh"
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
user = getRunUser()
|
|
||||||
acme_dir = "/Users/"+user+"/.acme.sh"
|
|
||||||
|
|
||||||
abs_domain_path = acme_dir+'/'+domain+'_ecc'
|
|
||||||
# print(abs_domain_path)
|
|
||||||
if os.path.exists(abs_domain_path):
|
|
||||||
return True, abs_domain_path
|
|
||||||
|
|
||||||
abs_domain_path = acme_dir+'/'+domain
|
|
||||||
# print(abs_domain_path)
|
|
||||||
if os.path.exists(abs_domain_path):
|
|
||||||
return True, abs_domain_path
|
|
||||||
|
|
||||||
return False,''
|
|
||||||
|
|
||||||
|
|
||||||
def hookWriteLog(line):
|
|
||||||
hook_file = runLog()
|
|
||||||
mdate = time.strftime('%Y-%m-%d %X', time.localtime())
|
|
||||||
log = "["+mdate+"]:"+line
|
|
||||||
print(log)
|
|
||||||
return mw.writeFile(hook_file,log+"\n",'a+')
|
|
||||||
|
|
||||||
def runHookPy(domain,path):
|
|
||||||
# print(domain,path)
|
|
||||||
run_log = runLog()
|
|
||||||
hook_file = getConf()
|
|
||||||
cmd = 'cd '+mw.getPanelDir()
|
|
||||||
cmd += ' && python3 '+hook_file + ' ' + domain + ' ' + path
|
|
||||||
cmd += ' >> '+ run_log
|
|
||||||
print(cmd)
|
|
||||||
return mw.execShell(cmd)
|
|
||||||
|
|
||||||
def autoUpdateSslData(domain, path):
|
|
||||||
ssl_cer_file = path + '/'+domain+'.cer'
|
|
||||||
ssl_info = mw.getCertName(ssl_cer_file)
|
|
||||||
|
|
||||||
time_begin = int(time.mktime(time.strptime(ssl_info['notBefore'], "%Y-%m-%d")))
|
|
||||||
time_end = int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")))
|
|
||||||
# print(ssl_info)
|
|
||||||
# print(time_begin,time_end)
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
conn.where('domain=?', (domain,)).update({
|
|
||||||
'effective_date':str(time_begin),
|
|
||||||
'expiration_date':str(time_end),
|
|
||||||
})
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def runHookDstDomain(row):
|
|
||||||
domain = row['domain']
|
|
||||||
email = str(row['email'])
|
|
||||||
|
|
||||||
if row['effective_date'] != '':
|
|
||||||
effective_date = int(row['effective_date'])
|
|
||||||
now_int = int(time.time())
|
|
||||||
day = (now_int - effective_date)/86400
|
|
||||||
if int(day) < 8:
|
|
||||||
common_log = '【'+domain+'】未过期'
|
|
||||||
hookWriteLog(common_log)
|
|
||||||
return
|
|
||||||
|
|
||||||
hookWriteLog('开始申请【'+domain+'】SSL证书')
|
|
||||||
cmd = "#!/bin/bash\n"
|
|
||||||
cmd += "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin:/root/.acme.sh\n"
|
|
||||||
cmd += "export PATH\n"
|
|
||||||
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
user = getRunUser()
|
|
||||||
cmd += ". /Users/"+user+"/.zshrc\n"
|
|
||||||
|
|
||||||
cmd_data = getDnsapiData(row['dnsapi_id'])
|
|
||||||
# print(cmd_data)
|
|
||||||
export_val = getDnsapiExportVar(cmd_data['val'])
|
|
||||||
cmd += export_val
|
|
||||||
|
|
||||||
# acme.sh --register-account -m my@example.com
|
|
||||||
cmd_register = 'acme.sh --register-account -m '+ email + '\n'
|
|
||||||
cmd += cmd_register
|
|
||||||
|
|
||||||
|
|
||||||
# acme.sh --issue -d "example.com" -d "*.example.com" --dns dns_cf
|
|
||||||
cmd_apply = 'acme.sh --issue --dns '+str(cmd_data['type'])+' -d '+domain+' -d "*.'+domain+'"'
|
|
||||||
if row['effective_date'] != '':
|
|
||||||
effective_date = int(row['effective_date'])
|
|
||||||
now_int = int(time.time())
|
|
||||||
day = (now_int - effective_date)/86400
|
|
||||||
if int(day) > 7:
|
|
||||||
cmd_apply = 'acme.sh --issue --dns '+str(cmd_data['type'])+' -d '+domain+' -d "*.'+domain+'" --force'
|
|
||||||
cmd += cmd_apply
|
|
||||||
|
|
||||||
run_log = runLog()
|
|
||||||
cmd += ' >> '+ run_log
|
|
||||||
print(cmd)
|
|
||||||
os.system(cmd)
|
|
||||||
hookWriteLog('结束申请【'+domain+'】SSL证书')
|
|
||||||
isok, path = domainApplyPathJudge(domain)
|
|
||||||
print(isok,path)
|
|
||||||
if isok:
|
|
||||||
autoUpdateSslData(domain, path)
|
|
||||||
hookWriteLog('开始执行【'+domain+'】Hook脚本')
|
|
||||||
runHookPy(domain,path)
|
|
||||||
hookWriteLog('结束执行【'+domain+'】Hook脚本')
|
|
||||||
|
|
||||||
def getHookIdCmd():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['id'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
cmd = "cd "+mw.getPanelDir()+" "
|
|
||||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_hook_id 1.0 {"id":"'+args['id']+'"}'
|
|
||||||
return mw.returnJson(True, 'ok',cmd)
|
|
||||||
|
|
||||||
def runHookId():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['id'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
field = 'id,domain,dnsapi_id,email,effective_date,expiration_date,remark'
|
|
||||||
row = conn.field(field).where('id=?',(args['id'],)).find()
|
|
||||||
runHookDstDomain(row)
|
|
||||||
return 'run hook '+args['id']+' end'
|
|
||||||
|
|
||||||
def runHookCmd():
|
|
||||||
cmd = "cd "+mw.getPanelDir()+" "
|
|
||||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_hook'
|
|
||||||
return mw.returnJson(True, 'ok',cmd)
|
|
||||||
|
|
||||||
def runHook():
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
|
|
||||||
field = 'id,domain,dnsapi_id,email,effective_date,expiration_date,remark'
|
|
||||||
clist = conn.field(field).where('status=?',(1,)).limit('1000').order('id desc').select()
|
|
||||||
|
|
||||||
for idx in range(len(clist)):
|
|
||||||
row = clist[idx]
|
|
||||||
# print(row)
|
|
||||||
runHookDstDomain(row)
|
|
||||||
time.sleep(1)
|
|
||||||
return 'run hook end'
|
|
||||||
|
|
||||||
def autoSyncDomain(domain, dnsapi_id, email):
|
|
||||||
conn = pSqliteDb('domain')
|
|
||||||
|
|
||||||
field = 'id,domain,dnsapi_id,email,effective_date,expiration_date,remark'
|
|
||||||
fdata = conn.field(field).where('domain=?',(domain,)).select()
|
|
||||||
# print(fdata)
|
|
||||||
mdate = time.strftime('%Y-%m-%d %X', time.localtime())
|
|
||||||
if len(fdata) == 0:
|
|
||||||
conn.add('domain,dnsapi_id,email,remark,addtime', (domain, dnsapi_id, email,"备注", mdate))
|
|
||||||
print(domain+" 同步成功!")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def runSyncCfDataRow(row, page = 1):
|
|
||||||
# print(row, page)
|
|
||||||
|
|
||||||
cf_key = row['kv']['CF_Key']
|
|
||||||
cf_mail = row['kv']['CF_Email']
|
|
||||||
header = {
|
|
||||||
'X-Auth-Email': cf_mail,
|
|
||||||
'X-Auth-Key': cf_key,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
url = "https://api.cloudflare.com/client/v4/zones?status=active&page="+str(page)+"&per_page=20&order=status&direction=desc&match=all"
|
|
||||||
try:
|
|
||||||
r = requests.get(url, timeout=30, headers=header)
|
|
||||||
r.raise_for_status()
|
|
||||||
r.encoding = r.apparent_encoding
|
|
||||||
# print(r.text)
|
|
||||||
jdata = json.loads(r.text)
|
|
||||||
result = jdata['result']
|
|
||||||
result_info = jdata['result_info']
|
|
||||||
|
|
||||||
# print(len(result))
|
|
||||||
for i in result:
|
|
||||||
autoSyncDomain(i['name'], row['id'], cf_mail)
|
|
||||||
|
|
||||||
if result_info['total_pages'] > page:
|
|
||||||
page += 1
|
|
||||||
runSyncCfDataRow(row, page)
|
|
||||||
# print(result)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
# 同步CloudFlare数据
|
|
||||||
def runSyncCfData():
|
|
||||||
print("同步CloudFlare数据开始")
|
|
||||||
conn_dnsapi = pSqliteDb('dnsapi')
|
|
||||||
field = "id,name,type,val"
|
|
||||||
fdata = conn_dnsapi.field(field).where('type=?', ('dns_cf',)).limit('10').select()
|
|
||||||
|
|
||||||
for x in range(len(fdata)):
|
|
||||||
row = fdata[x]
|
|
||||||
dnsapi_kv = getDnsapiKv(row['val'])
|
|
||||||
row['kv'] = dnsapi_kv
|
|
||||||
runSyncCfDataRow(row)
|
|
||||||
|
|
||||||
print("同步CloudFlare数据结束")
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def runSyncCfCmd():
|
|
||||||
cmd = "cd "+mw.getPanelDir()+" "
|
|
||||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_sync_cf_data'
|
|
||||||
return mw.returnJson(True, 'ok',cmd)
|
|
||||||
|
|
||||||
def runSyncDnspodDataRow(row, page = 1):
|
|
||||||
# print(row, page)
|
|
||||||
|
|
||||||
DPI_Id = row['kv']['DPI_Id']
|
|
||||||
DPI_Key = row['kv']['DPI_Key']
|
|
||||||
data = {
|
|
||||||
'login_token': DPI_Id+','+DPI_Key,
|
|
||||||
'length':5,
|
|
||||||
'format':'json',
|
|
||||||
}
|
|
||||||
url = "https://api.dnspod.com/Domain.List"
|
|
||||||
try:
|
|
||||||
r = requests.post(url, timeout=30, data=data)
|
|
||||||
r.raise_for_status()
|
|
||||||
r.encoding = r.apparent_encoding
|
|
||||||
|
|
||||||
# print(r.text)
|
|
||||||
jdata = json.loads(r.text)
|
|
||||||
info = jdata['info']
|
|
||||||
domains = jdata['domains']
|
|
||||||
|
|
||||||
# print(jdata)
|
|
||||||
for i in domains:
|
|
||||||
autoSyncDomain(i['name'], row['id'], i['owner'])
|
|
||||||
|
|
||||||
page_total = int(info['domain_total']/data['length'])
|
|
||||||
if page_total > page:
|
|
||||||
page += 1
|
|
||||||
runSyncDnspodDataRow(row, page)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
# 同步DnsPod数据
|
|
||||||
def runSyncDnsPodData():
|
|
||||||
print("同步DnsPod数据开始")
|
|
||||||
conn_dnsapi = pSqliteDb('dnsapi')
|
|
||||||
field = "id,name,type,val"
|
|
||||||
fdata = conn_dnsapi.field(field).where('type=?', ('dns_dpi',)).limit('10').select()
|
|
||||||
for x in range(len(fdata)):
|
|
||||||
row = fdata[x]
|
|
||||||
dnsapi_kv = getDnsapiKv(row['val'])
|
|
||||||
row['kv'] = dnsapi_kv
|
|
||||||
runSyncDnspodDataRow(row)
|
|
||||||
|
|
||||||
print(fdata)
|
|
||||||
print("同步DnsPod数据结束")
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def runSyncDnsPodCmd():
|
|
||||||
cmd = "cd "+mw.getPanelDir()+" "
|
|
||||||
cmd += '&& python3 plugins/acme_pandominassl_apply/index.py run_sync_dnspod_data'
|
|
||||||
return mw.returnJson(True, 'ok',cmd)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
func = sys.argv[1]
|
|
||||||
# print(func)
|
|
||||||
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 == 'run_info':
|
|
||||||
print(runInfo())
|
|
||||||
elif func == 'conf':
|
|
||||||
print(getConf())
|
|
||||||
elif func == 'run_log':
|
|
||||||
print(runLog())
|
|
||||||
elif func == 'config_tpl':
|
|
||||||
print(configTpl())
|
|
||||||
elif func == 'read_config_tpl':
|
|
||||||
print(readConfigTpl())
|
|
||||||
elif func == 'dnsapi_list':
|
|
||||||
print(dnsapiList())
|
|
||||||
elif func == 'dnsapi_list_all':
|
|
||||||
print(dnsapiListAll())
|
|
||||||
elif func == 'dnsapi_add':
|
|
||||||
print(dnsapiAdd())
|
|
||||||
elif func == 'dnsapi_del':
|
|
||||||
print(dnsapiDel())
|
|
||||||
elif func == 'email_list':
|
|
||||||
print(emailList())
|
|
||||||
elif func == 'email_add':
|
|
||||||
print(emailAdd())
|
|
||||||
elif func == 'email_del':
|
|
||||||
print(emailDel())
|
|
||||||
elif func == 'domain_list':
|
|
||||||
print(domainList())
|
|
||||||
elif func == 'domain_add':
|
|
||||||
print(domainAdd())
|
|
||||||
elif func == 'domain_del':
|
|
||||||
print(domainDel())
|
|
||||||
elif func == 'domain_status_toggle':
|
|
||||||
print(domainStatusToggle())
|
|
||||||
elif func == 'run_hook':
|
|
||||||
print(runHook())
|
|
||||||
elif func == 'run_hook_cmd':
|
|
||||||
print(runHookCmd())
|
|
||||||
elif func == 'get_run_hook_id_cmd':
|
|
||||||
print(getHookIdCmd())
|
|
||||||
elif func == 'run_hook_id':
|
|
||||||
print(runHookId())
|
|
||||||
elif func == 'run_sync_cf_data':
|
|
||||||
print(runSyncCfData())
|
|
||||||
elif func == 'run_sync_cf_cmd':
|
|
||||||
print(runSyncCfCmd())
|
|
||||||
elif func == 'run_sync_dnspod_data':
|
|
||||||
print(runSyncDnsPodData())
|
|
||||||
elif func == 'run_sync_dnspod_cmd':
|
|
||||||
print(runSyncDnsPodCmd())
|
|
||||||
else:
|
|
||||||
print('error')
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"sort": 7,
|
|
||||||
"ps": "ACME泛域名SSL申请/管理",
|
|
||||||
"name": "acme_pandominassl_apply",
|
|
||||||
"title": "ACME泛域名SSL",
|
|
||||||
"shell": "install.sh",
|
|
||||||
"versions":["1.0"],
|
|
||||||
"tip": "soft",
|
|
||||||
"checks": "server/acme_pandominassl_apply",
|
|
||||||
"path": "server/acme_pandominassl_apply",
|
|
||||||
"display": 1,
|
|
||||||
"author": "ACME",
|
|
||||||
"date": "2024-09-12",
|
|
||||||
"home": "https://github.com/acmesh-official/acme.sh",
|
|
||||||
"type": 0,
|
|
||||||
"pid": "5"
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
|
||||||
export PATH
|
|
||||||
|
|
||||||
curPath=`pwd`
|
|
||||||
rootPath=$(dirname "$curPath")
|
|
||||||
rootPath=$(dirname "$rootPath")
|
|
||||||
serverPath=$(dirname "$rootPath")
|
|
||||||
|
|
||||||
VERSION=$2
|
|
||||||
|
|
||||||
# curl https://get.acme.sh | sh
|
|
||||||
# acme.sh --uninstall
|
|
||||||
|
|
||||||
|
|
||||||
# . /Users/xxx/.zshrc
|
|
||||||
|
|
||||||
# https://github.com/acmesh-official/acme.sh/wiki/dnsapi
|
|
||||||
# https://docs.dnspod.com/api-legacy/domains.html#get-the-domain-list
|
|
||||||
|
|
||||||
# cd /www/server/mdserver-web && python3 plugins/acme_pandominassl_apply/index.py run_hook
|
|
||||||
# cd /www/server/mdserver-web && python3 plugins/acme_pandominassl_apply/index.py run_sync_cf_data
|
|
||||||
# cd /www/server/mdserver-web && python3 plugins/acme_pandominassl_apply/index.py run_sync_dnspod_data
|
|
||||||
|
|
||||||
|
|
||||||
if [ -f ${rootPath}/bin/activate ];then
|
|
||||||
. ${rootPath}/bin/activate
|
|
||||||
fi
|
|
||||||
|
|
||||||
# pip install cloudflare
|
|
||||||
Install_App()
|
|
||||||
{
|
|
||||||
echo '正在安装脚本文件...'
|
|
||||||
mkdir -p $serverPath/source
|
|
||||||
mkdir -p $serverPath/acme_pandominassl_apply
|
|
||||||
echo "${VERSION}" > $serverPath/acme_pandominassl_apply/version.pl
|
|
||||||
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/acme_pandominassl_apply/index.py start
|
|
||||||
echo '安装[ACME泛域名SSL]完成'
|
|
||||||
}
|
|
||||||
|
|
||||||
Uninstall_App()
|
|
||||||
{
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/acme_pandominassl_apply/index.py stop
|
|
||||||
rm -rf $serverPath/acme_pandominassl_apply
|
|
||||||
echo "卸载[ACME泛域名SSL]成功"
|
|
||||||
}
|
|
||||||
|
|
||||||
action=$1
|
|
||||||
if [ "${1}" = 'install' ];then
|
|
||||||
Install_App
|
|
||||||
else
|
|
||||||
Uninstall_App
|
|
||||||
fi
|
|
||||||
@@ -1,801 +0,0 @@
|
|||||||
function apaPost(method, args,callback){
|
|
||||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
|
||||||
|
|
||||||
var req_data = {};
|
|
||||||
req_data['name'] = 'acme_pandominassl_apply';
|
|
||||||
req_data['func'] = method;
|
|
||||||
req_data['version'] = $('.plugin_version').attr('version');
|
|
||||||
|
|
||||||
if (typeof(args) == 'string'){
|
|
||||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
|
||||||
} else {
|
|
||||||
req_data['args'] = JSON.stringify(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/plugins/run', req_data, function(data) {
|
|
||||||
layer.close(loadT);
|
|
||||||
if (!data.status){
|
|
||||||
//错误展示10S
|
|
||||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof(callback) == 'function'){
|
|
||||||
callback(data);
|
|
||||||
}
|
|
||||||
},'json');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function apaPostN(method, args,callback){
|
|
||||||
|
|
||||||
var req_data = {};
|
|
||||||
req_data['name'] = 'acme_pandominassl_apply';
|
|
||||||
req_data['func'] = method;
|
|
||||||
req_data['version'] = $('.plugin_version').attr('version');
|
|
||||||
|
|
||||||
if (typeof(args) == 'string'){
|
|
||||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
|
||||||
} else {
|
|
||||||
req_data['args'] = JSON.stringify(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/plugins/run', req_data, function(data) {
|
|
||||||
if (!data.status){
|
|
||||||
//错误展示10S
|
|
||||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof(callback) == 'function'){
|
|
||||||
callback(data);
|
|
||||||
}
|
|
||||||
},'json');
|
|
||||||
}
|
|
||||||
|
|
||||||
function apaPostCallbak(method, version, args,callback){
|
|
||||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
|
||||||
|
|
||||||
var req_data = {};
|
|
||||||
req_data['name'] = 'acme_pandominassl_apply';
|
|
||||||
req_data['func'] = method;
|
|
||||||
args['version'] = version;
|
|
||||||
|
|
||||||
if (typeof(args) == 'string'){
|
|
||||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
|
||||||
} else {
|
|
||||||
req_data['args'] = JSON.stringify(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/plugins/callback', req_data, 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 apaReadme(){
|
|
||||||
var readme = '<ul class="help-info-text c7">';
|
|
||||||
readme += '<li>ACME泛域名SSL申请/管理/HOOK</li>';
|
|
||||||
readme += '<li>通过DNS验证获取SSL证书!</li>';
|
|
||||||
readme += '<li>HOOK: ssl发生变动时调用!</li>';
|
|
||||||
readme += '<li>暂时仅支持1000个域名管理!</li>';
|
|
||||||
readme += '<li>DNSAPI文档: https://github.com/acmesh-official/acme.sh/wiki/dnsapi</li>';
|
|
||||||
readme += '<li>默认7天强制更新!</li>';
|
|
||||||
|
|
||||||
|
|
||||||
readme += '</ul>';
|
|
||||||
$('.soft-man-con').html(readme);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function emailDel(id, name){
|
|
||||||
safeMessage('删除['+name+']','您真的要删除['+name+']吗?',function(){
|
|
||||||
var data='id='+id+'&name='+name;
|
|
||||||
apaPost('email_del', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
emailList();
|
|
||||||
},{icon: rdata.status ? 1 : 2}, 600);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function emailAdd(type){
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
area: '500px',
|
|
||||||
title: '添加邮件地址',
|
|
||||||
closeBtn: 1,
|
|
||||||
shift: 5,
|
|
||||||
shadeClose: true,
|
|
||||||
btn:["提交","关闭"],
|
|
||||||
content: "<form class='bt-form pd20' id='email_add'>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>邮件地址</span>\
|
|
||||||
<div class='info-r'><input name='addr' class='bt-input-text mr5' style='width:100%;' placeholder='邮件地址' type='text'></div>\
|
|
||||||
</div>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>备注</span>\
|
|
||||||
<div class='info-r'><input name='remark' class='bt-input-text mr5' style='width:100%;' placeholder='备注' type='text'></div>\
|
|
||||||
</div>\
|
|
||||||
</form>",
|
|
||||||
success:function(){
|
|
||||||
$("input[name='addr']").keyup(function(){
|
|
||||||
var v = $(this).val();
|
|
||||||
$("input[name='remark']").val(v);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
yes:function(index) {
|
|
||||||
var data = $("#email_add").serialize();
|
|
||||||
data = decodeURIComponent(data);
|
|
||||||
// data = toArrayObject(data);
|
|
||||||
apaPost('email_add', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
if (rdata.status){
|
|
||||||
layer.close(index);
|
|
||||||
emailList();
|
|
||||||
}
|
|
||||||
},{icon: rdata.status ? 1 : 2}, 2000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function emailList(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
apaPost('email_list', _data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
var list = '';
|
|
||||||
for(i in rdata.data){
|
|
||||||
list += '<tr>';
|
|
||||||
list +='<td><input value="'+rdata.data[i]['id']+'" class="check" onclick="checkSelect();" type="checkbox"></td>';
|
|
||||||
list += '<td>' + rdata.data[i]['addr'] +'</td>';
|
|
||||||
list += '<td>' + rdata.data[i]['remark'] +'</td>';
|
|
||||||
list += '<td style="text-align:right">';
|
|
||||||
list += '<a href="javascript:;" class="btlink" onclick="emailDel(\''+rdata.data[i]['id']+'\',\''+rdata.data[i]['addr']+'\')" title="删除">删除</a>' +
|
|
||||||
'</td>';
|
|
||||||
list += '</tr>';
|
|
||||||
}
|
|
||||||
|
|
||||||
var con = '<div class="safe bgw">\
|
|
||||||
<button onclick="emailAdd()" title="添加邮件地址" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">添加邮件地址</button>\
|
|
||||||
<span style="float:right"> \
|
|
||||||
<button batch="true" style="float: right;display: none;margin-left:10px;" onclick="delDbBatch();" title="删除选中项" class="btn btn-default btn-sm">删除选中</button>\
|
|
||||||
</span>\
|
|
||||||
<div class="divtable mtb10">\
|
|
||||||
<div class="tablescroll">\
|
|
||||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
|
||||||
<thead><tr><th width="30"><input class="check" onclick="checkSelect();" type="checkbox"></th>\
|
|
||||||
<th>邮件地址</th>\
|
|
||||||
<th>备注</th>\
|
|
||||||
<th style="text-align:right;">操作</th></tr></thead>\
|
|
||||||
<tbody>'+ list +'</tbody>\
|
|
||||||
</table>\
|
|
||||||
</div>\
|
|
||||||
<div class="dataTables_paginate paging_bootstrap page"></div>\
|
|
||||||
</div>\
|
|
||||||
</div>';
|
|
||||||
|
|
||||||
$(".soft-man-con").html(con);
|
|
||||||
$('.dataTables_paginate').html(rdata.page);
|
|
||||||
|
|
||||||
readerTableChecked();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function dnsapiDel(id, name){
|
|
||||||
safeMessage('删除['+name+']','您真的要删除['+name+']吗?',function(){
|
|
||||||
var data='id='+id+'&name='+name;
|
|
||||||
apaPost('dnsapi_del', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
dnsapiList();
|
|
||||||
},{icon: rdata.status ? 1 : 2}, 600);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var dnsapi_option = [
|
|
||||||
{"name":"dns_cf", "title":'cloudflare', 'key':'CF_Key:CF_Email'},
|
|
||||||
{"name":"dns_dp", "title":'dnspod/国内', 'key':'DP_Id:DP_Key'},
|
|
||||||
{"name":"dns_dpi", "title":'dnspod/国际', 'key':'DPI_Id:DPI_Key'},
|
|
||||||
{"name":"dns_gd", "title":'GoDaddy', 'key':'GD_Key:GD_Secret'},
|
|
||||||
{"name":"dns_pdns", "title":'PowerDNS', 'key':'PDNS_Url:PDNS_ServerId:PDNS_Token:PDNS_Ttl'},
|
|
||||||
{"name":"dns_lua", "title":'LuaDNS', 'key':'LUA_Key:LUA_Email'},
|
|
||||||
{"name":"dns_me", "title":'DNSMadeEasy', 'key':'ME_Key:ME_Secret'},
|
|
||||||
{"name":"dns_aws", "title":'Amazon Route53', 'key':'AWS_ACCESS_KEY_ID:AWS_SECRET_ACCESS_KEY'},
|
|
||||||
{"name":"dns_ali", "title":'Aliyun', 'key':'Ali_Key:Ali_Secret'},
|
|
||||||
{"name":"dns_ispconfig", "title":'ISPConfig', 'key':'ISPC_User:ISPC_Password:ISPC_Api:ISPC_Api_Insecure'},
|
|
||||||
{"name":"dns_ad", "title":'Alwaysdata', 'key':'AD_API_KEY'},
|
|
||||||
{"name":"dns_linode_v4", "title":'Linode', 'key':'LINODE_V4_API_KEY'},
|
|
||||||
{"name":"dns_freedns", "title":'FreeDNS', 'key':'FREEDNS_User:FREEDNS_Password'},
|
|
||||||
{"name":"dns_cyon", "title":'cyon.ch', 'key':'CY_Username:CY_Password:CY_OTP_Secret'},
|
|
||||||
{"name":"dns_gandi_livedns", "title":'LiveDNS', 'key':'GANDI_LIVEDNS_TOKEN'},
|
|
||||||
{"name":"dns_knot", "title":'Knot', 'key':'KNOT_SERVER:KNOT_KEY'},
|
|
||||||
{"name":"dns_dgon", "title":'DigitalOcean', 'key':'DO_API_KEY'},
|
|
||||||
{"name":"dns_cloudns", "title":'ClouDNS.net', 'key':'CLOUDNS_SUB_AUTH_ID:CLOUDNS_AUTH_PASSWORD'},
|
|
||||||
{"name":"dns_namesilo", "title":'Namesilo', 'key':'Namesilo_Key'},
|
|
||||||
{"name":"dns_azure", "title":'Azure', 'key':'AZUREDNS_SUBSCRIPTIONID:AZUREDNS_TENANTID:AZUREDNS_APPID:AZUREDNS_CLIENTSECRET'},
|
|
||||||
{"name":"dns_selectel", "title":'selectel.com', 'key':'SL_Key'},
|
|
||||||
{"name":"dns_zonomi", "title":'zonomi.com', 'key':'ZM_Key'},
|
|
||||||
{"name":"dns_kinghost", "title":'KingHost', 'key':'KINGHOST_Username:KINGHOST_Password'},
|
|
||||||
{"name":"dns_zilore", "title":'Zilore', 'key':'Zilore_Key'},
|
|
||||||
{"name":"dns_gcloud", "title":'Google Cloud DNS', 'key':'CLOUDSDK_ACTIVE_CONFIG_NAME'},
|
|
||||||
{"name":"dns_mydnsjp", "title":'MyDNS.JP', 'key':'MYDNSJP_MasterID:MYDNSJP_Password'},
|
|
||||||
{"name":"dns_doapi", "title":'do.de', 'key':'DO_LETOKEN'},
|
|
||||||
{"name":"dns_online", "title":'Online', 'key':'ONLINE_API_KEY'},
|
|
||||||
{"name":"dns_cn", "title":'Core-Networks', 'key':'CN_User:CN_Password'},
|
|
||||||
{"name":"dns_ultra", "title":'UltraDNS', 'key':'ULTRA_USR:ULTRA_PWD'},
|
|
||||||
{"name":"dns_hetzner", "title":'Hetzner', 'key':'HETZNER_Token'},
|
|
||||||
{"name":"dns_ddnss", "title":'DDNSS.de', 'key':'DDNSS_Token'},
|
|
||||||
];
|
|
||||||
|
|
||||||
function getDnsapiKey(name){
|
|
||||||
for (var i = 0; i < dnsapi_option.length; i++) {
|
|
||||||
if (dnsapi_option[i]['name'] == name){
|
|
||||||
return dnsapi_option[i]['key'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDnsapiTitle(name){
|
|
||||||
for (var i = 0; i < dnsapi_option.length; i++) {
|
|
||||||
if (dnsapi_option[i]['name'] == name){
|
|
||||||
return dnsapi_option[i]['title'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '其他';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function dnsapiAdd(row){
|
|
||||||
// console.log(row);
|
|
||||||
var option_name = '';
|
|
||||||
var option_remark = '';
|
|
||||||
var option_type = 'dns_cf';
|
|
||||||
var option_val = '';
|
|
||||||
var option_id = 0;
|
|
||||||
if (typeof(row) != 'undefined'){
|
|
||||||
option_name = row['name'];
|
|
||||||
option_remark = row['remark'];
|
|
||||||
option_type = row['type'];
|
|
||||||
option_val = row['val'];
|
|
||||||
option_id = row['id'];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderDnsapiOption(name, val){
|
|
||||||
var vlist = {};
|
|
||||||
if (val != ''){
|
|
||||||
var t = val.split('~');
|
|
||||||
for (var i = 0; i < t.length; i++) {
|
|
||||||
var kv = t[i].split('|');
|
|
||||||
if (kv.length == 2){
|
|
||||||
vlist[kv[0]] = kv[1];
|
|
||||||
} else {
|
|
||||||
vlist[kv[0]] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// console.log(vlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var key = getDnsapiKey(name);
|
|
||||||
var klist = key.split(':');
|
|
||||||
var option_html = '';
|
|
||||||
for (var i = 0; i < klist.length; i++) {
|
|
||||||
var klist_val = '';
|
|
||||||
if (klist[i] in vlist){
|
|
||||||
klist_val = vlist[klist[i]];
|
|
||||||
}
|
|
||||||
option_html += "<span class='tname'>"+klist[i]+"</span>\
|
|
||||||
<div class='info-r'>\
|
|
||||||
<input name='"+klist[i]+"' class='bt-input-text mr5' style='width:100%;' value='"+klist_val+"' placeholder='请输入对应值' type='text'>\
|
|
||||||
</div>";
|
|
||||||
}
|
|
||||||
$('#dnsapi_option').html(option_html);
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
area: '500px',
|
|
||||||
title: '添加DNSAPI',
|
|
||||||
closeBtn: 1,
|
|
||||||
shift: 5,
|
|
||||||
shadeClose: true,
|
|
||||||
btn:["提交","关闭"],
|
|
||||||
content: "<form class='bt-form pd20' id='dnsapi_add'>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>名称</span>\
|
|
||||||
<div class='info-r'><input name='name' class='bt-input-text mr5' style='width:100%;' placeholder='名称' value='"+option_name+"' type='text'></div>\
|
|
||||||
</div>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>DNSAPI类型</span>\
|
|
||||||
<div class='info-r'>\
|
|
||||||
<select class='bt-input-text mr5' name='type'>\
|
|
||||||
<option name='cf'>cloudflare</option>\
|
|
||||||
</select>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
<div class='line' id='dnsapi_option'>\
|
|
||||||
<span class='tname'>CF_Key</span>\
|
|
||||||
<div class='info-r'>\
|
|
||||||
<input name='v1' class='bt-input-text mr5' style='width:100%;' placeholder='请输入对应值' type='text'>\
|
|
||||||
</div>\
|
|
||||||
<span class='tname'>CF_Email</span>\
|
|
||||||
<div class='info-r'>\
|
|
||||||
<input name='v2' class='bt-input-text mr5' style='width:100%;' placeholder='请输入对应值' type='text'>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>备注</span>\
|
|
||||||
<div class='info-r'><input name='remark' class='bt-input-text mr5' style='width:100%;' placeholder='备注' value='"+option_remark+"' type='text'></div>\
|
|
||||||
</div>\
|
|
||||||
<input name='id' value='"+option_id+"' type='hidden'>\
|
|
||||||
</form>",
|
|
||||||
success:function(){
|
|
||||||
$("input[name='name']").keyup(function(){
|
|
||||||
var v = $(this).val();
|
|
||||||
$("input[name='remark']").val(v);
|
|
||||||
});
|
|
||||||
|
|
||||||
var option = '';
|
|
||||||
for (var i = 0; i<dnsapi_option.length; i++) {
|
|
||||||
|
|
||||||
if (dnsapi_option[i]['name'] == option_type){
|
|
||||||
option += "<option value='"+dnsapi_option[i]['name']+"' key='"+dnsapi_option[i]['key']+"' selected>"+dnsapi_option[i]['title']+"</option>";
|
|
||||||
} else {
|
|
||||||
option += "<option value='"+dnsapi_option[i]['name']+"' key='"+dnsapi_option[i]['key']+"'>"+dnsapi_option[i]['title']+"</option>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderDnsapiOption(option_type, option_val);
|
|
||||||
$('select[name="type"]').html(option);
|
|
||||||
$('select[name="type"]').change(function(){
|
|
||||||
var name = $(this).val();
|
|
||||||
if (option_type == name){
|
|
||||||
renderDnsapiOption(name, option_val);
|
|
||||||
} else {
|
|
||||||
renderDnsapiOption(name,'');
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
yes:function(index) {
|
|
||||||
var data = $("#dnsapi_add").serialize();
|
|
||||||
data = decodeURIComponent(data);
|
|
||||||
data = toArrayObject(data);
|
|
||||||
|
|
||||||
var key = getDnsapiKey(data['type']);
|
|
||||||
var klist = key.split(':');
|
|
||||||
var val = '';
|
|
||||||
for (var i = 0; i < klist.length; i++) {
|
|
||||||
var k = klist[i];
|
|
||||||
if (k in data){
|
|
||||||
if (klist.length - 1 == i){
|
|
||||||
val += k + '|' + data[k];
|
|
||||||
} else {
|
|
||||||
val += k + '|' + data[k]+'~';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data['val'] = val;
|
|
||||||
apaPost('dnsapi_add', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
if (rdata.status){
|
|
||||||
layer.close(index);
|
|
||||||
dnsapiList();
|
|
||||||
}
|
|
||||||
},{icon: rdata.status ? 1 : 2}, 2000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function dnsapiList(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
apaPost('dnsapi_list', _data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
var list = '';
|
|
||||||
for(i in rdata.data){
|
|
||||||
list += '<tr>';
|
|
||||||
list +='<td><input value="'+rdata.data[i]['id']+'" class="check" onclick="checkSelect();" type="checkbox"></td>';
|
|
||||||
list += '<td>' + rdata.data[i]['name'] +'</td>';
|
|
||||||
list += '<td>' + getDnsapiTitle(rdata.data[i]['type']) +'</td>';
|
|
||||||
list += '<td>' + rdata.data[i]['val'].split('~').join("<br/>") +'</td>';
|
|
||||||
list += '<td>' + rdata.data[i]['remark'] +'</td>';
|
|
||||||
|
|
||||||
list += '<td style="text-align:right">';
|
|
||||||
list += '<a href="javascript:;" index="'+i+'" class="btlink edit" title="编辑">编辑</a> | ';
|
|
||||||
list += '<a href="javascript:;" class="btlink" onclick="dnsapiDel(\''+rdata.data[i]['id']+'\',\''+rdata.data[i]['name']+'\')" title="删除">删除</a>';
|
|
||||||
list += '</td></tr>';
|
|
||||||
}
|
|
||||||
|
|
||||||
var con = '<div class="safe bgw">\
|
|
||||||
<button onclick="dnsapiAdd()" title="DNSAPI" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">添加DNSAPI</button>\
|
|
||||||
<span style="float:right"> \
|
|
||||||
<button batch="true" style="float: right;display: none;margin-left:10px;" onclick="delDbBatch();" title="删除选中项" class="btn btn-default btn-sm">删除选中</button>\
|
|
||||||
</span>\
|
|
||||||
<div class="divtable mtb10">\
|
|
||||||
<div class="tablescroll">\
|
|
||||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
|
||||||
<thead><tr><th width="30"><input class="check" onclick="checkSelect();" type="checkbox"></th>\
|
|
||||||
<th>名称</th>\
|
|
||||||
<th>类型</th>\
|
|
||||||
<th>值</th>\
|
|
||||||
<th>备注</th>\
|
|
||||||
<th style="text-align:right;">操作</th></tr></thead>\
|
|
||||||
<tbody>'+ list +'</tbody>\
|
|
||||||
</table>\
|
|
||||||
</div>\
|
|
||||||
<div class="dataTables_paginate paging_bootstrap page"></div>\
|
|
||||||
</div>\
|
|
||||||
</div>';
|
|
||||||
|
|
||||||
$(".soft-man-con").html(con);
|
|
||||||
$('.dataTables_paginate').html(rdata.page);
|
|
||||||
|
|
||||||
$('.edit').click(function(){
|
|
||||||
var idx = $(this).attr('index');
|
|
||||||
var row = rdata.data[idx];
|
|
||||||
// console.log(row);
|
|
||||||
dnsapiAdd(row);
|
|
||||||
})
|
|
||||||
|
|
||||||
readerTableChecked();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function domainDel(id, name){
|
|
||||||
safeMessage('删除['+name+']','您真的要删除['+name+']吗?',function(){
|
|
||||||
var data='id='+id+'&name='+name;
|
|
||||||
apaPost('domain_del', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
domainList();
|
|
||||||
},{icon: rdata.status ? 1 : 2}, 600);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function domainStatusToggle(id){
|
|
||||||
var data='id='+id;
|
|
||||||
apaPost('domain_status_toggle', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
domainList();
|
|
||||||
},{icon: rdata.status ? 1 : 2}, 600);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function domainIdCmd(id){
|
|
||||||
var data='id='+id;
|
|
||||||
apaPost('get_run_hook_id_cmd', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
// console.log(rdata);
|
|
||||||
layer.open({
|
|
||||||
title: "手动同步命令",
|
|
||||||
area: ['600px', '180px'],
|
|
||||||
type:1,
|
|
||||||
closeBtn: 1,
|
|
||||||
shadeClose: false,
|
|
||||||
btn:["复制","取消"],
|
|
||||||
content: '<div class="pd15">\
|
|
||||||
<div class="divtable">\
|
|
||||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
|
||||||
</div>\
|
|
||||||
</div>',
|
|
||||||
success:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
},
|
|
||||||
yes:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function domainHookCmd(){
|
|
||||||
apaPost('run_hook_cmd', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
layer.open({
|
|
||||||
title: "手动同步全部命令",
|
|
||||||
area: ['600px', '180px'],
|
|
||||||
type:1,
|
|
||||||
closeBtn: 1,
|
|
||||||
shadeClose: false,
|
|
||||||
btn:["复制","取消"],
|
|
||||||
content: '<div class="pd15">\
|
|
||||||
<div class="divtable">\
|
|
||||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
|
||||||
</div>\
|
|
||||||
</div>',
|
|
||||||
success:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
},
|
|
||||||
yes:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncCfCmd(){
|
|
||||||
apaPost('run_sync_cf_cmd', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
layer.open({
|
|
||||||
title: "手动同步CloudFlare全部域名命令",
|
|
||||||
area: ['600px', '180px'],
|
|
||||||
type:1,
|
|
||||||
closeBtn: 1,
|
|
||||||
shadeClose: false,
|
|
||||||
btn:["复制","取消"],
|
|
||||||
content: '<div class="pd15">\
|
|
||||||
<div class="divtable">\
|
|
||||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
|
||||||
</div>\
|
|
||||||
</div>',
|
|
||||||
success:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
},
|
|
||||||
yes:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncDnsPodCmd(){
|
|
||||||
apaPost('run_sync_dnspod_cmd', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
layer.open({
|
|
||||||
title: "手动同步DnsPod全部域名命令",
|
|
||||||
area: ['600px', '180px'],
|
|
||||||
type:1,
|
|
||||||
closeBtn: 1,
|
|
||||||
shadeClose: false,
|
|
||||||
btn:["复制","取消"],
|
|
||||||
content: '<div class="pd15">\
|
|
||||||
<div class="divtable">\
|
|
||||||
<pre class="layui-code">'+rdata.data+'</pre>\
|
|
||||||
</div>\
|
|
||||||
</div>',
|
|
||||||
success:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
},
|
|
||||||
yes:function(){
|
|
||||||
copyText(rdata.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function domainAdd(row){
|
|
||||||
|
|
||||||
var option_domian = '';
|
|
||||||
var option_remark = '备注';
|
|
||||||
var option_email = '';
|
|
||||||
var option_id = 0;
|
|
||||||
var option_dnsapi_id = 0;
|
|
||||||
if (typeof(row) != 'undefined'){
|
|
||||||
option_domian = row['domain'];
|
|
||||||
option_remark = row['remark'];
|
|
||||||
option_email = row['email'];
|
|
||||||
option_id = row['id'];
|
|
||||||
option_dnsapi_id = row['dnsapi_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
area: '500px',
|
|
||||||
title: '添加顶级域名',
|
|
||||||
closeBtn: 1,
|
|
||||||
shift: 5,
|
|
||||||
shadeClose: true,
|
|
||||||
btn:["提交","关闭"],
|
|
||||||
content: "<form class='bt-form pd20' id='domain_add'>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>域名</span>\
|
|
||||||
<div class='info-r'><input name='domain' class='bt-input-text mr5' style='width:100%;' value='"+option_domian+"' placeholder='域名' type='text'></div>\
|
|
||||||
</div>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>DNSAPI</span>\
|
|
||||||
<div class='info-r'>\
|
|
||||||
<select class='bt-input-text mr5' name='dnsapi_id'>\
|
|
||||||
<option name='0'>无设置</option>\
|
|
||||||
</select>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>邮件</span>\
|
|
||||||
<div class='info-r'><input name='email' class='bt-input-text mr5' style='width:100%;' value='"+option_email+"' placeholder='邮件' type='text'></div>\
|
|
||||||
</div>\
|
|
||||||
<div class='line'>\
|
|
||||||
<span class='tname'>备注</span>\
|
|
||||||
<div class='info-r'><input name='remark' class='bt-input-text mr5' style='width:100%;' value='"+option_remark+"' placeholder='备注' type='text'></div>\
|
|
||||||
</div>\
|
|
||||||
<input name='id' value='"+option_id+"' type='hidden'>\
|
|
||||||
</form>",
|
|
||||||
success:function(){
|
|
||||||
// $("input[name='domain']").keyup(function(){
|
|
||||||
// var v = $(this).val();
|
|
||||||
// $("input[name='remark']").val(v);
|
|
||||||
// });
|
|
||||||
|
|
||||||
var dnsapi_id_html = "<option value='0'>无设置</option>";
|
|
||||||
apaPostN('dnsapi_list_all', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
for (var i = 0; i < rdata.length; i++) {
|
|
||||||
if (option_dnsapi_id == rdata[i]['id']){
|
|
||||||
dnsapi_id_html += "<option value='"+rdata[i]['id']+"' val='"+rdata[i]['val']+"' selected>"+rdata[i]['name']+"</option>";
|
|
||||||
} else {
|
|
||||||
dnsapi_id_html += "<option value='"+rdata[i]['id']+"' val='"+rdata[i]['val']+"'>"+rdata[i]['name']+"</option>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$('select[name="dnsapi_id"]').change(function(){
|
|
||||||
var val = $('select[name="dnsapi_id"]').find("option:selected").attr('val');
|
|
||||||
var val_arr = val.split("|");
|
|
||||||
for (var i = 0; i < val_arr.length; i++) {
|
|
||||||
var param = val_arr[i];
|
|
||||||
var strictEmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
||||||
if(strictEmailRegex.test(param)){
|
|
||||||
$('input[name="email"]').val(param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
$('select[name="dnsapi_id"]').html(dnsapi_id_html);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
yes:function(index) {
|
|
||||||
var data = $("#domain_add").serialize();
|
|
||||||
data = decodeURIComponent(data);
|
|
||||||
apaPost('domain_add', data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
if (rdata.status){
|
|
||||||
layer.close(index);
|
|
||||||
domainList();
|
|
||||||
}
|
|
||||||
},{icon: rdata.status ? 1 : 2}, 2000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function domainList(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
apaPost('domain_list', _data, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
// console.log(rdata);
|
|
||||||
var list = '';
|
|
||||||
for(i in rdata.data){
|
|
||||||
list += '<tr>';
|
|
||||||
list +='<td><input value="'+rdata.data[i]['id']+'" class="check" onclick="checkSelect();" type="checkbox"></td>';
|
|
||||||
list += '<td>' + rdata.data[i]['domain'] +'</td>';
|
|
||||||
list += '<td>' + rdata.data[i]['dnsapi_id_alias'] +'</td>';
|
|
||||||
list += '<td>' + rdata.data[i]['email'] +'</td>';
|
|
||||||
list += '<td>' + rdata.data[i]['remark'] +'</td>';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (rdata.data[i]['effective_date'] == ''){
|
|
||||||
list += '<td>空/未申请</td>';
|
|
||||||
} else {
|
|
||||||
list += '<td>'+getFormatTime(rdata.data[i]['effective_date'],'yyyy/MM/dd')+'</td>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rdata.data[i]['expiration_date'] == ''){
|
|
||||||
list += '<td>空/未申请</td>';
|
|
||||||
} else {
|
|
||||||
list += '<td>'+getFormatTime(rdata.data[i]['expiration_date'],'yyyy/MM/dd')+'</td>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rdata.data[i]['status'] == '0'){
|
|
||||||
list += '<td><a href="javascript:;" index="'+i+'" class="btlink status">否</a></td>';
|
|
||||||
} else {
|
|
||||||
list += '<td><a href="javascript:;" index="'+i+'" class="btlink status">是</a></td>';
|
|
||||||
}
|
|
||||||
|
|
||||||
list += '<td style="text-align:right">';
|
|
||||||
list += '<a href="javascript:;" index="'+i+'" class="btlink cmd" title="命令">命令</a> | ';
|
|
||||||
list += '<a href="javascript:;" index="'+i+'" class="btlink edit" title="编辑">编辑</a> | ';
|
|
||||||
list += '<a href="javascript:;" class="btlink" onclick="domainDel(\''+rdata.data[i]['id']+'\',\''+rdata.data[i]['domain']+'\')" title="删除">删除</a>';
|
|
||||||
list += '</td></tr>';
|
|
||||||
}
|
|
||||||
|
|
||||||
var con = '<div class="safe bgw">\
|
|
||||||
<button onclick="domainAdd()" title="添加顶级域名" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">添加域名</button>\
|
|
||||||
<button onclick="domainHookCmd()" title="全部同步命令" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">全部同步命令</button>\
|
|
||||||
<button onclick="syncCfCmd()" title="cloudflare同步命令" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">cloudflare同步命令</button>\
|
|
||||||
<button onclick="syncDnsPodCmd()" title="DnsPod国际同步命令" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">DnsPod国际同步命令</button>\
|
|
||||||
<div class="divtable mtb10">\
|
|
||||||
<div class="tablescroll">\
|
|
||||||
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
|
||||||
<thead><tr><th width="30"><input class="check" onclick="checkSelect();" type="checkbox"></th>\
|
|
||||||
<th>域名</th>\
|
|
||||||
<th>DNSAPI</th>\
|
|
||||||
<th>邮件</th>\
|
|
||||||
<th>备注</th>\
|
|
||||||
<th>开始</th>\
|
|
||||||
<th>结束</th>\
|
|
||||||
<th>同步</th>\
|
|
||||||
<th style="text-align:right;">操作</th></tr></thead>\
|
|
||||||
<tbody>'+ list +'</tbody>\
|
|
||||||
</table>\
|
|
||||||
</div>\
|
|
||||||
<div class="dataTables_paginate paging_bootstrap page"></div>\
|
|
||||||
</div>\
|
|
||||||
</div>';
|
|
||||||
|
|
||||||
$(".soft-man-con").html(con);
|
|
||||||
$('.dataTables_paginate').html(rdata.page);
|
|
||||||
|
|
||||||
$('.edit').click(function(){
|
|
||||||
var idx = $(this).attr('index');
|
|
||||||
var row = rdata.data[idx];
|
|
||||||
domainAdd(row);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.status').click(function(){
|
|
||||||
var idx = $(this).attr('index');
|
|
||||||
var row = rdata.data[idx];
|
|
||||||
domainStatusToggle(row['id']);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.cmd').click(function(){
|
|
||||||
var idx = $(this).attr('index');
|
|
||||||
var row = rdata.data[idx];
|
|
||||||
domainIdCmd(row['id']);
|
|
||||||
});
|
|
||||||
|
|
||||||
readerTableChecked();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
|
|
||||||
# print(sys.platform)
|
|
||||||
if sys.platform != "darwin":
|
|
||||||
os.chdir("/www/server/mdserver-web")
|
|
||||||
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
from utils.crontab import crontab as MwCrontab
|
|
||||||
|
|
||||||
|
|
||||||
app_debug = False
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
app_debug = True
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginName():
|
|
||||||
return 'acme_pandominassl_apply'
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginDir():
|
|
||||||
return mw.getPluginDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getTaskConf():
|
|
||||||
conf = getServerDir() + "/cron_config.json"
|
|
||||||
return conf
|
|
||||||
|
|
||||||
def getTaskDeltaConf():
|
|
||||||
conf = getServerDir() + "/cron_delta_config.json"
|
|
||||||
return conf
|
|
||||||
|
|
||||||
|
|
||||||
def getConfigData():
|
|
||||||
try:
|
|
||||||
return json.loads(mw.readFile(getTaskConf()))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return {
|
|
||||||
"task_id": -1,
|
|
||||||
"period": "day-n",
|
|
||||||
"where1": "1",
|
|
||||||
"hour": "0",
|
|
||||||
"minute": "15",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def createBgTask():
|
|
||||||
removeBgTask()
|
|
||||||
createBgTaskByName(getPluginName())
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def createBgTaskByName(name):
|
|
||||||
args = getConfigData()
|
|
||||||
_name = "[勿删]ACME泛域名SSL[APA]"
|
|
||||||
res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find()
|
|
||||||
if res:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if "task_id" in args and args["task_id"] > 0:
|
|
||||||
res = mw.M("crontab").field("id, name").where(
|
|
||||||
"id=?", (args["task_id"],)).find()
|
|
||||||
if res and res["id"] == args["task_id"]:
|
|
||||||
print("计划任务已经存在!")
|
|
||||||
return True
|
|
||||||
|
|
||||||
mw_dir = mw.getPanelDir()
|
|
||||||
cmd = '''
|
|
||||||
mw_dir=%s
|
|
||||||
rname=%s
|
|
||||||
plugin_path=%s
|
|
||||||
script_path=%s
|
|
||||||
logs_file=$plugin_path/${rname}.log
|
|
||||||
''' % (mw_dir, name, getServerDir(), getPluginDir())
|
|
||||||
cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT★" >> $logs_file' + "\n"
|
|
||||||
cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n"
|
|
||||||
cmd += 'echo "python3 $script_path/index.py run_hook"' + "\n"
|
|
||||||
cmd += 'cd $mw_dir && python3 $script_path/index.py run_hook' + "\n"
|
|
||||||
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
|
|
||||||
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
|
|
||||||
|
|
||||||
params = {
|
|
||||||
'name': _name,
|
|
||||||
'type': args['period'],
|
|
||||||
'week': "",
|
|
||||||
'where1': args['where1'],
|
|
||||||
'hour': args['hour'],
|
|
||||||
'minute': args['minute'],
|
|
||||||
'save': "",
|
|
||||||
'backup_to': "",
|
|
||||||
'stype': "toShell",
|
|
||||||
'sname': '',
|
|
||||||
'sbody': cmd,
|
|
||||||
'url_address': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
task_id = MwCrontab.instance().add(params)
|
|
||||||
if task_id > 0:
|
|
||||||
args["task_id"] = task_id
|
|
||||||
args["name"] = name
|
|
||||||
mw.writeFile(getTaskConf(), json.dumps(args))
|
|
||||||
|
|
||||||
|
|
||||||
def removeBgTask():
|
|
||||||
cfg = getConfigData()
|
|
||||||
if "task_id" in cfg and cfg["task_id"] > 0:
|
|
||||||
res = mw.M("crontab").field("id, name").where(
|
|
||||||
"id=?", (cfg["task_id"],)).find()
|
|
||||||
if res and res["id"] == cfg["task_id"]:
|
|
||||||
import crontab_api
|
|
||||||
api = crontab_api.crontab_api()
|
|
||||||
data = api.delete(cfg["task_id"])
|
|
||||||
if data[0]:
|
|
||||||
cfg["task_id"] = -1
|
|
||||||
mw.writeFile(getTaskConf(), json.dumps(cfg))
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
action = sys.argv[1]
|
|
||||||
if action == "remove":
|
|
||||||
removeBgTask()
|
|
||||||
elif action == "add":
|
|
||||||
createBgTask()
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB |
@@ -1,31 +0,0 @@
|
|||||||
<style>
|
|
||||||
.overflow_hide {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="bt-form">
|
|
||||||
<div class='plugin_version'></div>
|
|
||||||
<div class="bt-w-main">
|
|
||||||
<div class="bt-w-menu">
|
|
||||||
<p class="bgw" onclick="pluginService('alist');">服务</p>
|
|
||||||
<p onclick="pluginInitD('alist');">自启动</p>
|
|
||||||
<p onclick="alistCommonFunc();">常用功能</p>
|
|
||||||
<p onclick="pluginConfigTpl('alist',$('.plugin_version').attr('version'));">配置修改</p>
|
|
||||||
<p onclick="pluginLogs('alist','','run_log');">运行日志</p>
|
|
||||||
<p onclick="alistReadme();">相关说明</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="bt-w-con pd15">
|
|
||||||
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$.getScript( "/plugins/file?name=alist&f=js/alist.js", function(){
|
|
||||||
pluginService('alist', $('.plugin_version').attr('version'));
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,319 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
|
|
||||||
app_debug = False
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
app_debug = True
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginName():
|
|
||||||
return 'alist'
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginDir():
|
|
||||||
return mw.getPluginDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getInitDFile():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return '/tmp/' + getPluginName()
|
|
||||||
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
return '/etc/rc.d/' + getPluginName()
|
|
||||||
|
|
||||||
return '/etc/init.d/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getInitDTpl():
|
|
||||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def getArgs():
|
|
||||||
args = sys.argv[3:]
|
|
||||||
tmp = {}
|
|
||||||
args_len = len(args)
|
|
||||||
|
|
||||||
if args_len == 1:
|
|
||||||
t = args[0].strip('{').strip('}')
|
|
||||||
if t.strip() == '':
|
|
||||||
tmp = []
|
|
||||||
else:
|
|
||||||
t = t.split(':')
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
elif args_len > 1:
|
|
||||||
for i in range(len(args)):
|
|
||||||
t = args[i].split(':')
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
return tmp
|
|
||||||
|
|
||||||
def checkArgs(data, ck=[]):
|
|
||||||
for i in range(len(ck)):
|
|
||||||
if not ck[i] in data:
|
|
||||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
|
||||||
return (True, mw.returnJson(True, 'ok'))
|
|
||||||
|
|
||||||
|
|
||||||
def getConf():
|
|
||||||
path = getServerDir() + "/data/config.json"
|
|
||||||
return path
|
|
||||||
|
|
||||||
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 __release_port(port, ps = '开启端口'):
|
|
||||||
try:
|
|
||||||
from utils.firewall import Firewall as MwFirewall
|
|
||||||
MwFirewall.instance().addAcceptPort(port, ps, 'port')
|
|
||||||
return port
|
|
||||||
except Exception as e:
|
|
||||||
return "Release failed {}".format(e)
|
|
||||||
|
|
||||||
def __delete_port(port):
|
|
||||||
try:
|
|
||||||
from utils.firewall import Firewall as MwFirewall
|
|
||||||
MwFirewall.instance().delAcceptPortCmd(port, 'tcp')
|
|
||||||
return port
|
|
||||||
except Exception as e:
|
|
||||||
return "Delete failed {}".format(e)
|
|
||||||
|
|
||||||
|
|
||||||
def openPort():
|
|
||||||
content = mw.readFile(getConf())
|
|
||||||
data = json.loads(content)
|
|
||||||
http_port = data['scheme']['http_port']
|
|
||||||
__release_port(http_port, 'alist')
|
|
||||||
return True
|
|
||||||
|
|
||||||
def status():
|
|
||||||
cmd = "ps -ef|grep alist |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'"
|
|
||||||
data = mw.execShell(cmd)
|
|
||||||
if data[0] == '':
|
|
||||||
return 'stop'
|
|
||||||
return 'start'
|
|
||||||
|
|
||||||
def contentReplace(content):
|
|
||||||
service_path = mw.getServerDir()
|
|
||||||
content = content.replace('{$ROOT_PATH}', mw.getFatherDir())
|
|
||||||
content = content.replace('{$SERVER_PATH}', service_path)
|
|
||||||
content = content.replace('{$SERVER_APP}', service_path + '/'+getPluginName())
|
|
||||||
return content
|
|
||||||
|
|
||||||
def initDreplace():
|
|
||||||
|
|
||||||
file_tpl = getInitDTpl()
|
|
||||||
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()
|
|
||||||
|
|
||||||
# initd replace
|
|
||||||
if not os.path.exists(file_bin):
|
|
||||||
content = mw.readFile(file_tpl)
|
|
||||||
content = content.replace('{$SERVER_PATH}', service_path)
|
|
||||||
mw.writeFile(file_bin, content)
|
|
||||||
mw.execShell('chmod +x ' + file_bin)
|
|
||||||
|
|
||||||
|
|
||||||
# systemd
|
|
||||||
systemDir = mw.systemdCfgDir()
|
|
||||||
systemService = systemDir + '/' + getPluginName() + '.service'
|
|
||||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
|
||||||
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
|
|
||||||
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')
|
|
||||||
time.sleep(1)
|
|
||||||
return file_bin
|
|
||||||
|
|
||||||
|
|
||||||
def alistOp(method):
|
|
||||||
file = initDreplace()
|
|
||||||
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == "darwin":
|
|
||||||
data = mw.execShell(file + ' ' + method)
|
|
||||||
if data[1] == '':
|
|
||||||
return 'ok'
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
if current_os.startswith("freebsd"):
|
|
||||||
data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
|
||||||
if data[1] == '':
|
|
||||||
return 'ok'
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
|
||||||
if data[1] == '':
|
|
||||||
return 'ok'
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
|
||||||
return alistOp('start')
|
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
|
||||||
return alistOp('stop')
|
|
||||||
|
|
||||||
|
|
||||||
def restart():
|
|
||||||
status = alistOp('restart')
|
|
||||||
return status
|
|
||||||
|
|
||||||
|
|
||||||
def reload():
|
|
||||||
return alistOp('reload')
|
|
||||||
|
|
||||||
|
|
||||||
def initdStatus():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return "Apple Computer does not support"
|
|
||||||
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
initd_bin = getInitDFile()
|
|
||||||
if os.path.exists(initd_bin):
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
shell_cmd = 'systemctl status ' + \
|
|
||||||
getPluginName() + ' | grep loaded | grep "enabled;"'
|
|
||||||
data = mw.execShell(shell_cmd)
|
|
||||||
if data[0] == '':
|
|
||||||
return 'fail'
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
def initdInstall():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return "Apple Computer does not support"
|
|
||||||
|
|
||||||
# freebsd initd install
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
import shutil
|
|
||||||
source_bin = initDreplace()
|
|
||||||
initd_bin = getInitDFile()
|
|
||||||
shutil.copyfile(source_bin, initd_bin)
|
|
||||||
mw.execShell('chmod +x ' + initd_bin)
|
|
||||||
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
mw.execShell('systemctl enable ' + getPluginName())
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
def initdUinstall():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return "Apple Computer does not support"
|
|
||||||
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
initd_bin = getInitDFile()
|
|
||||||
os.remove(initd_bin)
|
|
||||||
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
mw.execShell('systemctl disable ' + getPluginName())
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
def runLog():
|
|
||||||
return getServerDir() + '/data/log/log.log'
|
|
||||||
|
|
||||||
def pSqliteDb(dbname='databases'):
|
|
||||||
pos_file = getServerDir() + '/data/'
|
|
||||||
file = pos_file + '/data.db'
|
|
||||||
name = 'data'
|
|
||||||
conn = mw.M(dbname).dbPos(pos_file, name)
|
|
||||||
return conn
|
|
||||||
|
|
||||||
def clearCopyTask():
|
|
||||||
conn = pSqliteDb('x_task_items')
|
|
||||||
conn.where('key=?', ('copy',)).setField('persist_data','[]')
|
|
||||||
restart()
|
|
||||||
return mw.returnJson(True, '清空成功并重启服务!')
|
|
||||||
|
|
||||||
def homePage():
|
|
||||||
content = mw.readFile(getConf())
|
|
||||||
data = json.loads(content)
|
|
||||||
http_port = data['scheme']['http_port']
|
|
||||||
ip = mw.getLocalIp()
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
ip = '127.0.0.1'
|
|
||||||
url = 'http://'+ip+":"+str(http_port)
|
|
||||||
# print(url)
|
|
||||||
return mw.returnJson(True, 'ok!', url)
|
|
||||||
|
|
||||||
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 == 'run_log':
|
|
||||||
print(runLog())
|
|
||||||
elif func == 'config_tpl':
|
|
||||||
print(configTpl())
|
|
||||||
elif func == 'read_config_tpl':
|
|
||||||
print(readConfigTpl())
|
|
||||||
elif func == 'clear_copy_task':
|
|
||||||
print(clearCopyTask())
|
|
||||||
elif func == 'home_page':
|
|
||||||
print(homePage())
|
|
||||||
else:
|
|
||||||
print('error')
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"sort": 7,
|
|
||||||
"ps": "一个支持多种存储的文件列表程序",
|
|
||||||
"name": "alist",
|
|
||||||
"title": "Alist",
|
|
||||||
"shell": "install.sh",
|
|
||||||
"versions":["3.37.4","3.38.0","3.45.0"],
|
|
||||||
"tip": "soft",
|
|
||||||
"checks": "server/alist",
|
|
||||||
"path": "server/alist",
|
|
||||||
"display": 1,
|
|
||||||
"author": "alist",
|
|
||||||
"date": "2022-10-09",
|
|
||||||
"home": "https://alist.nn.ci",
|
|
||||||
"type": 0,
|
|
||||||
"pid": "5"
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=A file list program that supports multiple storage
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory={$SERVER_PATH}/alist
|
|
||||||
ExecStart={$SERVER_PATH}/alist/alist server
|
|
||||||
ExecReload=/bin/kill -USR2 $MAINPID
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# chkconfig: 2345 55 25
|
|
||||||
# description: alist Service
|
|
||||||
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: alist
|
|
||||||
# Required-Start: $all
|
|
||||||
# Required-Stop: $all
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: starts alist
|
|
||||||
# Description: starts the MDW-Web
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
# Simple alist init.d script conceived to work on Linux systems
|
|
||||||
# as it does use of the /proc filesystem.
|
|
||||||
|
|
||||||
app_start(){
|
|
||||||
echo "Starting alist server..."
|
|
||||||
cd {$SERVER_PATH}/alist
|
|
||||||
./alist server >> {$SERVER_PATH}/alist/logs.pl 2>&1 &
|
|
||||||
}
|
|
||||||
|
|
||||||
app_stop(){
|
|
||||||
echo "dztasks stopped"
|
|
||||||
ps -ef| grep alist | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'| xargs kill -9
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
app_start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
app_stop
|
|
||||||
;;
|
|
||||||
restart|reload)
|
|
||||||
app_stop
|
|
||||||
sleep 0.3
|
|
||||||
app_start
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Please use start or stop as first argument"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
|
||||||
export PATH
|
|
||||||
|
|
||||||
curPath=`pwd`
|
|
||||||
rootPath=$(dirname "$curPath")
|
|
||||||
rootPath=$(dirname "$rootPath")
|
|
||||||
serverPath=$(dirname "$rootPath")
|
|
||||||
|
|
||||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/alist && bash install.sh install 3.37.4
|
|
||||||
# cd /www/server/mdserver-web/plugins/alist && bash install.sh install 3.45.0
|
|
||||||
|
|
||||||
VERSION=$2
|
|
||||||
|
|
||||||
sysArch=`arch`
|
|
||||||
sysName=`uname`
|
|
||||||
|
|
||||||
ALIST_ARCH_NAME=amd64
|
|
||||||
if [ "$sysArch" = "arm64" ];then
|
|
||||||
ALIST_ARCH_NAME=arm64
|
|
||||||
elif [ "$sysArch" = "x86_64" ]; then
|
|
||||||
ALIST_ARCH_NAME=amd64
|
|
||||||
elif [ "$sysArch" = "aarch64" ]; then
|
|
||||||
ALIST_ARCH_NAME=arm64
|
|
||||||
fi
|
|
||||||
|
|
||||||
ALIST_NAME=linux
|
|
||||||
if [ "$sysName" = "Darwin" ];then
|
|
||||||
ALIST_NAME=darwin
|
|
||||||
fi
|
|
||||||
|
|
||||||
Install_App()
|
|
||||||
{
|
|
||||||
echo '正在安装脚本文件...'
|
|
||||||
|
|
||||||
mkdir -p $serverPath/source
|
|
||||||
mkdir -p $serverPath/source/alist
|
|
||||||
|
|
||||||
FILE_TGZ=alist-${ALIST_NAME}-${ALIST_ARCH_NAME}.tar.gz
|
|
||||||
|
|
||||||
ALIST_DIR=$serverPath/source/alist
|
|
||||||
|
|
||||||
if [ ! -f $ALIST_DIR/${FILE_TGZ} ];then
|
|
||||||
wget --no-check-certificate -O $ALIST_DIR/${FILE_TGZ} https://github.com/alist-org/alist/releases/download/v${VERSION}/${FILE_TGZ}
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p $serverPath/alist
|
|
||||||
|
|
||||||
cd $ALIST_DIR && tar -zxvf ${FILE_TGZ} -C $serverPath/alist
|
|
||||||
echo "${VERSION}" > $serverPath/alist/version.pl
|
|
||||||
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/alist/index.py start
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/alist/index.py initd_install
|
|
||||||
|
|
||||||
cd $serverPath/alist && ./alist admin set admin
|
|
||||||
# cd /www/server/alist && ./alist admin set admin
|
|
||||||
|
|
||||||
echo '安装完成'
|
|
||||||
}
|
|
||||||
|
|
||||||
Uninstall_App()
|
|
||||||
{
|
|
||||||
if [ -f /usr/lib/systemd/system/alist.service ];then
|
|
||||||
systemctl stop alist
|
|
||||||
systemctl disable alist
|
|
||||||
rm -rf /usr/lib/systemd/system/alist.service
|
|
||||||
systemctl daemon-reload
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f /lib/systemd/system/alist.service ];then
|
|
||||||
systemctl stop alist
|
|
||||||
systemctl disable alist
|
|
||||||
rm -rf /lib/systemd/system/alist.service
|
|
||||||
systemctl daemon-reload
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f $serverPath/alist/initd/alist ];then
|
|
||||||
$serverPath/alist/initd/alist stop
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d $serverPath/alist ];then
|
|
||||||
rm -rf $serverPath/alist
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "卸载alist成功"
|
|
||||||
}
|
|
||||||
|
|
||||||
action=$1
|
|
||||||
if [ "${1}" = 'install' ];then
|
|
||||||
Install_App
|
|
||||||
else
|
|
||||||
Uninstall_App
|
|
||||||
fi
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
function alistPost(method, version, args,callback){
|
|
||||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
|
||||||
|
|
||||||
var req_data = {};
|
|
||||||
req_data['name'] = 'alist';
|
|
||||||
req_data['func'] = method;
|
|
||||||
req_data['version'] = version;
|
|
||||||
|
|
||||||
if (typeof(args) == 'string'){
|
|
||||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
|
||||||
} else {
|
|
||||||
req_data['args'] = JSON.stringify(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/plugins/run', req_data, function(data) {
|
|
||||||
layer.close(loadT);
|
|
||||||
if (!data.status){
|
|
||||||
//错误展示10S
|
|
||||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof(callback) == 'function'){
|
|
||||||
callback(data);
|
|
||||||
}
|
|
||||||
},'json');
|
|
||||||
}
|
|
||||||
|
|
||||||
function alistPostCallbak(method, version, args,callback){
|
|
||||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
|
||||||
|
|
||||||
var req_data = {};
|
|
||||||
req_data['name'] = 'alist';
|
|
||||||
req_data['func'] = method;
|
|
||||||
args['version'] = version;
|
|
||||||
|
|
||||||
if (typeof(args) == 'string'){
|
|
||||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
|
||||||
} else {
|
|
||||||
req_data['args'] = JSON.stringify(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
$.post('/plugins/callback', req_data, 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 clearTaskCopy(){
|
|
||||||
layer.confirm('您真的要清空复制任务吗?', { icon: 3, closeBtn: 2 }, function() {
|
|
||||||
alistPost('clear_copy_task', '', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
showMsg(rdata.msg, function(){},{ icon: rdata.status ? 1 : 2 });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function commonHomePage(){
|
|
||||||
alistPost('home_page', '', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
window.open(rdata.data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function alistCommonFunc(){
|
|
||||||
var con = '';
|
|
||||||
con += '<hr/><p class="conf_p" style="text-align:center;">\
|
|
||||||
<button class="btn btn-default btn-sm" onclick="commonHomePage()">主页</button>\
|
|
||||||
<button class="btn btn-default btn-sm" onclick="clearTaskCopy()">清空复制任务</button>\
|
|
||||||
</p>';
|
|
||||||
|
|
||||||
$(".soft-man-con").html(con);
|
|
||||||
}
|
|
||||||
|
|
||||||
function alistReadme(){
|
|
||||||
|
|
||||||
|
|
||||||
var readme = '<ul class="help-info-text c7">';
|
|
||||||
readme += '<li>手动开启默认端口:5244</li>';
|
|
||||||
readme += '<li>默认admin:admin</li>';
|
|
||||||
readme += '<li>手动改密码: cd /www/server/alist && ./alist admin set NEW_PASSWORD</li>';
|
|
||||||
readme += '</ul>';
|
|
||||||
|
|
||||||
$('.soft-man-con').html(readme);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
|
||||||
export PATH
|
|
||||||
|
|
||||||
# OpenResty服务名称
|
|
||||||
service_name="openresty"
|
|
||||||
|
|
||||||
# 检查OpenResty是否正在运行
|
|
||||||
if systemctl is-active --quiet "$service_name"; then
|
|
||||||
# 检查是否存在僵尸进程
|
|
||||||
zombie_processes=$(ps -ef | grep -i openresty | grep -v grep | awk '{print $2}' | xargs ps -o state= -p 2>/dev/null | grep -c Z)
|
|
||||||
if [ "$zombie_processes" -gt 0 ]; then
|
|
||||||
echo "kill nginx 僵尸进程"
|
|
||||||
ps -ef|grep nginx| grep -v grep| awk '{print $2}' | xargs kill -9
|
|
||||||
echo "检测到OpenResty僵尸进程,正在重启服务..."
|
|
||||||
systemctl restart "$service_name"
|
|
||||||
echo "服务已重启"
|
|
||||||
else
|
|
||||||
echo "OpenResty运行正常"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "kill nginx"
|
|
||||||
ps -ef|grep nginx| grep -v grep| awk '{print $2}' | xargs kill -9
|
|
||||||
echo "OpenResty未运行,正在启动服务..."
|
|
||||||
systemctl start "$service_name"
|
|
||||||
echo "服务已启动"
|
|
||||||
fi
|
|
||||||
|
|
||||||
NGINX_IDS=`ps -ef|grep nginx | grep -v grep| awk '{print $2}'`
|
|
||||||
if [ "$NGINX_IDS" = "" ];then
|
|
||||||
ps -ef|grep nginx| grep -v grep| awk '{print $2}' | xargs kill -9
|
|
||||||
systemctl start "$service_name"
|
|
||||||
echo "OpenResty未运行,正在启动服务..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
<IfModule !mpm_netware_module>
|
|
||||||
PidFile "logs/httpd.pid"
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mpm_prefork_module>
|
|
||||||
StartServers 5
|
|
||||||
MinSpareServers 5
|
|
||||||
MaxSpareServers 10
|
|
||||||
MaxRequestWorkers 250
|
|
||||||
MaxConnectionsPerChild 0
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mpm_worker_module>
|
|
||||||
StartServers 3
|
|
||||||
MinSpareThreads 75
|
|
||||||
MaxSpareThreads 250
|
|
||||||
ThreadsPerChild 25
|
|
||||||
MaxRequestWorkers 400
|
|
||||||
MaxConnectionsPerChild 0
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mpm_event_module>
|
|
||||||
StartServers 3
|
|
||||||
MinSpareThreads 75
|
|
||||||
MaxSpareThreads 250
|
|
||||||
ThreadsPerChild 25
|
|
||||||
MaxRequestWorkers 400
|
|
||||||
MaxConnectionsPerChild 0
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mpm_netware_module>
|
|
||||||
ThreadStackSize 65536
|
|
||||||
StartThreads 250
|
|
||||||
MinSpareThreads 25
|
|
||||||
MaxSpareThreads 250
|
|
||||||
MaxThreads 1000
|
|
||||||
MaxConnectionsPerChild 0
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mpm_mpmt_os2_module>
|
|
||||||
StartServers 2
|
|
||||||
MinSpareThreads 5
|
|
||||||
MaxSpareThreads 10
|
|
||||||
MaxConnectionsPerChild 0
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mpm_winnt_module>
|
|
||||||
ThreadsPerChild 150
|
|
||||||
MaxConnectionsPerChild 0
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule !mpm_netware_module>
|
|
||||||
MaxMemFree 2048
|
|
||||||
</IfModule>
|
|
||||||
<IfModule mpm_netware_module>
|
|
||||||
MaxMemFree 100
|
|
||||||
</IfModule>
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
ServerRoot "{$SERVER_PATH}/apache/httpd"
|
|
||||||
Listen 8280
|
|
||||||
|
|
||||||
LoadModule authn_file_module modules/mod_authn_file.so
|
|
||||||
LoadModule authn_core_module modules/mod_authn_core.so
|
|
||||||
LoadModule authz_host_module modules/mod_authz_host.so
|
|
||||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
|
||||||
LoadModule authz_user_module modules/mod_authz_user.so
|
|
||||||
LoadModule authz_core_module modules/mod_authz_core.so
|
|
||||||
LoadModule access_compat_module modules/mod_access_compat.so
|
|
||||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
|
||||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
|
||||||
LoadModule filter_module modules/mod_filter.so
|
|
||||||
LoadModule brotli_module modules/mod_brotli.so
|
|
||||||
LoadModule mime_module modules/mod_mime.so
|
|
||||||
LoadModule log_config_module modules/mod_log_config.so
|
|
||||||
LoadModule env_module modules/mod_env.so
|
|
||||||
LoadModule expires_module modules/mod_expires.so
|
|
||||||
LoadModule headers_module modules/mod_headers.so
|
|
||||||
LoadModule unique_id_module modules/mod_unique_id.so
|
|
||||||
LoadModule setenvif_module modules/mod_setenvif.so
|
|
||||||
LoadModule version_module modules/mod_version.so
|
|
||||||
LoadModule unixd_module modules/mod_unixd.so
|
|
||||||
LoadModule status_module modules/mod_status.so
|
|
||||||
LoadModule dir_module modules/mod_dir.so
|
|
||||||
LoadModule alias_module modules/mod_alias.so
|
|
||||||
LoadModule rewrite_module modules/mod_rewrite.so
|
|
||||||
|
|
||||||
<IfModule unixd_module>
|
|
||||||
User daemon
|
|
||||||
Group daemon
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
ServerAdmin you@example.com
|
|
||||||
ServerName localhost:8280
|
|
||||||
|
|
||||||
<Directory />
|
|
||||||
AllowOverride none
|
|
||||||
Require all denied
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
DocumentRoot "{$SERVER_PATH}/apache/httpd/htdocs"
|
|
||||||
<Directory "{$SERVER_PATH}/apache/httpd/htdocs">
|
|
||||||
Options Indexes FollowSymLinks
|
|
||||||
AllowOverride None
|
|
||||||
Require all granted
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
<IfModule dir_module>
|
|
||||||
DirectoryIndex index.html
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<Files ".ht*">
|
|
||||||
Require all denied
|
|
||||||
</Files>
|
|
||||||
|
|
||||||
ErrorLog "logs/error.log"
|
|
||||||
LogLevel warn
|
|
||||||
|
|
||||||
<IfModule log_config_module>
|
|
||||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
|
||||||
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
|
||||||
|
|
||||||
<IfModule logio_module>
|
|
||||||
# You need to enable mod_logio.c to use %I and %O
|
|
||||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
CustomLog "logs/access.log" common
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule alias_module>
|
|
||||||
ScriptAlias /cgi-bin/ "{$SERVER_PATH}/apache/httpd/cgi-bin/"
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule cgid_module>
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<Directory "{$SERVER_PATH}/apache/httpd/cgi-bin">
|
|
||||||
AllowOverride None
|
|
||||||
Options None
|
|
||||||
Require all granted
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
<IfModule headers_module>
|
|
||||||
RequestHeader unset Proxy early
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mime_module>
|
|
||||||
AddType application/x-compress .Z
|
|
||||||
AddType application/x-gzip .gz .tgz
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
EnableSendfile on
|
|
||||||
|
|
||||||
Include conf/extra/httpd-info.conf
|
|
||||||
Include conf/extra/httpd-mpm.conf
|
|
||||||
|
|
||||||
<IfModule ssl_module>
|
|
||||||
SSLRandomSeed startup builtin
|
|
||||||
SSLRandomSeed connect builtin
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,506 +0,0 @@
|
|||||||
#
|
|
||||||
# This is the main Apache HTTP server configuration file. It contains the
|
|
||||||
# configuration directives that give the server its instructions.
|
|
||||||
# See <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
|
|
||||||
# In particular, see
|
|
||||||
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
|
|
||||||
# for a discussion of each configuration directive.
|
|
||||||
#
|
|
||||||
# Do NOT simply read the instructions in here without understanding
|
|
||||||
# what they do. They're here only as hints or reminders. If you are unsure
|
|
||||||
# consult the online docs. You have been warned.
|
|
||||||
#
|
|
||||||
# Configuration and logfile names: If the filenames you specify for many
|
|
||||||
# of the server's control files begin with "/" (or "drive:/" for Win32), the
|
|
||||||
# server will use that explicit path. If the filenames do *not* begin
|
|
||||||
# with "/", the value of ServerRoot is prepended -- so "logs/access_log"
|
|
||||||
# with ServerRoot set to "/usr/local/apache2" will be interpreted by the
|
|
||||||
# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log"
|
|
||||||
# will be interpreted as '/logs/access_log'.
|
|
||||||
|
|
||||||
#
|
|
||||||
# ServerRoot: The top of the directory tree under which the server's
|
|
||||||
# configuration, error, and log files are kept.
|
|
||||||
#
|
|
||||||
# Do not add a slash at the end of the directory path. If you point
|
|
||||||
# ServerRoot at a non-local disk, be sure to specify a local disk on the
|
|
||||||
# Mutex directive, if file-based mutexes are used. If you wish to share the
|
|
||||||
# same ServerRoot for multiple httpd daemons, you will need to change at
|
|
||||||
# least PidFile.
|
|
||||||
#
|
|
||||||
ServerRoot "/Users/midoks/Desktop/mwdev/server/apache/httpd"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Mutex: Allows you to set the mutex mechanism and mutex file directory
|
|
||||||
# for individual mutexes, or change the global defaults
|
|
||||||
#
|
|
||||||
# Uncomment and change the directory if mutexes are file-based and the default
|
|
||||||
# mutex file directory is not on a local disk or is not appropriate for some
|
|
||||||
# other reason.
|
|
||||||
#
|
|
||||||
# Mutex default:logs
|
|
||||||
|
|
||||||
#
|
|
||||||
# Listen: Allows you to bind Apache to specific IP addresses and/or
|
|
||||||
# ports, instead of the default. See also the <VirtualHost>
|
|
||||||
# directive.
|
|
||||||
#
|
|
||||||
# Change this to Listen on specific IP addresses as shown below to
|
|
||||||
# prevent Apache from glomming onto all bound IP addresses.
|
|
||||||
#
|
|
||||||
#Listen 12.34.56.78:80
|
|
||||||
Listen 80
|
|
||||||
|
|
||||||
#
|
|
||||||
# Dynamic Shared Object (DSO) Support
|
|
||||||
#
|
|
||||||
# To be able to use the functionality of a module which was built as a DSO you
|
|
||||||
# have to place corresponding `LoadModule' lines at this location so the
|
|
||||||
# directives contained in it are actually available _before_ they are used.
|
|
||||||
# Statically compiled modules (those listed by `httpd -l') do not need
|
|
||||||
# to be loaded here.
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# LoadModule foo_module modules/mod_foo.so
|
|
||||||
#
|
|
||||||
LoadModule authn_file_module modules/mod_authn_file.so
|
|
||||||
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
|
|
||||||
#LoadModule authn_anon_module modules/mod_authn_anon.so
|
|
||||||
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
|
|
||||||
#LoadModule authn_socache_module modules/mod_authn_socache.so
|
|
||||||
LoadModule authn_core_module modules/mod_authn_core.so
|
|
||||||
LoadModule authz_host_module modules/mod_authz_host.so
|
|
||||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
|
||||||
LoadModule authz_user_module modules/mod_authz_user.so
|
|
||||||
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
|
|
||||||
#LoadModule authz_owner_module modules/mod_authz_owner.so
|
|
||||||
#LoadModule authz_dbd_module modules/mod_authz_dbd.so
|
|
||||||
LoadModule authz_core_module modules/mod_authz_core.so
|
|
||||||
LoadModule access_compat_module modules/mod_access_compat.so
|
|
||||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
|
||||||
#LoadModule auth_form_module modules/mod_auth_form.so
|
|
||||||
#LoadModule auth_digest_module modules/mod_auth_digest.so
|
|
||||||
#LoadModule allowmethods_module modules/mod_allowmethods.so
|
|
||||||
#LoadModule file_cache_module modules/mod_file_cache.so
|
|
||||||
#LoadModule cache_module modules/mod_cache.so
|
|
||||||
#LoadModule cache_disk_module modules/mod_cache_disk.so
|
|
||||||
#LoadModule cache_socache_module modules/mod_cache_socache.so
|
|
||||||
#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
|
|
||||||
#LoadModule socache_dbm_module modules/mod_socache_dbm.so
|
|
||||||
#LoadModule socache_memcache_module modules/mod_socache_memcache.so
|
|
||||||
#LoadModule socache_redis_module modules/mod_socache_redis.so
|
|
||||||
#LoadModule watchdog_module modules/mod_watchdog.so
|
|
||||||
#LoadModule macro_module modules/mod_macro.so
|
|
||||||
#LoadModule dbd_module modules/mod_dbd.so
|
|
||||||
#LoadModule dumpio_module modules/mod_dumpio.so
|
|
||||||
#LoadModule buffer_module modules/mod_buffer.so
|
|
||||||
#LoadModule ratelimit_module modules/mod_ratelimit.so
|
|
||||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
|
||||||
#LoadModule ext_filter_module modules/mod_ext_filter.so
|
|
||||||
#LoadModule request_module modules/mod_request.so
|
|
||||||
#LoadModule include_module modules/mod_include.so
|
|
||||||
LoadModule filter_module modules/mod_filter.so
|
|
||||||
#LoadModule substitute_module modules/mod_substitute.so
|
|
||||||
#LoadModule sed_module modules/mod_sed.so
|
|
||||||
#LoadModule brotli_module modules/mod_brotli.so
|
|
||||||
LoadModule mime_module modules/mod_mime.so
|
|
||||||
LoadModule log_config_module modules/mod_log_config.so
|
|
||||||
#LoadModule log_debug_module modules/mod_log_debug.so
|
|
||||||
#LoadModule logio_module modules/mod_logio.so
|
|
||||||
LoadModule env_module modules/mod_env.so
|
|
||||||
#LoadModule expires_module modules/mod_expires.so
|
|
||||||
LoadModule headers_module modules/mod_headers.so
|
|
||||||
#LoadModule unique_id_module modules/mod_unique_id.so
|
|
||||||
LoadModule setenvif_module modules/mod_setenvif.so
|
|
||||||
LoadModule version_module modules/mod_version.so
|
|
||||||
#LoadModule remoteip_module modules/mod_remoteip.so
|
|
||||||
#LoadModule proxy_module modules/mod_proxy.so
|
|
||||||
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
|
|
||||||
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
|
|
||||||
#LoadModule proxy_http_module modules/mod_proxy_http.so
|
|
||||||
#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
|
|
||||||
#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
|
|
||||||
#LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
|
|
||||||
#LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
|
|
||||||
#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
|
|
||||||
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
|
|
||||||
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
|
|
||||||
#LoadModule proxy_express_module modules/mod_proxy_express.so
|
|
||||||
#LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
|
|
||||||
#LoadModule session_module modules/mod_session.so
|
|
||||||
#LoadModule session_cookie_module modules/mod_session_cookie.so
|
|
||||||
#LoadModule session_dbd_module modules/mod_session_dbd.so
|
|
||||||
#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
|
|
||||||
#LoadModule ssl_module modules/mod_ssl.so
|
|
||||||
#LoadModule http2_module modules/mod_http2.so
|
|
||||||
#LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
|
|
||||||
#LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
|
|
||||||
#LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
|
|
||||||
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
|
|
||||||
LoadModule unixd_module modules/mod_unixd.so
|
|
||||||
#LoadModule dav_module modules/mod_dav.so
|
|
||||||
LoadModule status_module modules/mod_status.so
|
|
||||||
LoadModule autoindex_module modules/mod_autoindex.so
|
|
||||||
#LoadModule info_module modules/mod_info.so
|
|
||||||
#LoadModule cgid_module modules/mod_cgid.so
|
|
||||||
#LoadModule dav_fs_module modules/mod_dav_fs.so
|
|
||||||
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
|
|
||||||
#LoadModule negotiation_module modules/mod_negotiation.so
|
|
||||||
LoadModule dir_module modules/mod_dir.so
|
|
||||||
#LoadModule actions_module modules/mod_actions.so
|
|
||||||
#LoadModule speling_module modules/mod_speling.so
|
|
||||||
#LoadModule userdir_module modules/mod_userdir.so
|
|
||||||
LoadModule alias_module modules/mod_alias.so
|
|
||||||
#LoadModule rewrite_module modules/mod_rewrite.so
|
|
||||||
|
|
||||||
<IfModule unixd_module>
|
|
||||||
#
|
|
||||||
# If you wish httpd to run as a different user or group, you must run
|
|
||||||
# httpd as root initially and it will switch.
|
|
||||||
#
|
|
||||||
# User/Group: The name (or #number) of the user/group to run httpd as.
|
|
||||||
# It is usually good practice to create a dedicated user and group for
|
|
||||||
# running httpd, as with most system services.
|
|
||||||
#
|
|
||||||
User daemon
|
|
||||||
Group daemon
|
|
||||||
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
# 'Main' server configuration
|
|
||||||
#
|
|
||||||
# The directives in this section set up the values used by the 'main'
|
|
||||||
# server, which responds to any requests that aren't handled by a
|
|
||||||
# <VirtualHost> definition. These values also provide defaults for
|
|
||||||
# any <VirtualHost> containers you may define later in the file.
|
|
||||||
#
|
|
||||||
# All of these directives may appear inside <VirtualHost> containers,
|
|
||||||
# in which case these default settings will be overridden for the
|
|
||||||
# virtual host being defined.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# ServerAdmin: Your address, where problems with the server should be
|
|
||||||
# e-mailed. This address appears on some server-generated pages, such
|
|
||||||
# as error documents. e.g. admin@your-domain.com
|
|
||||||
#
|
|
||||||
ServerAdmin you@example.com
|
|
||||||
|
|
||||||
#
|
|
||||||
# ServerName gives the name and port that the server uses to identify itself.
|
|
||||||
# This can often be determined automatically, but we recommend you specify
|
|
||||||
# it explicitly to prevent problems during startup.
|
|
||||||
#
|
|
||||||
# If your host doesn't have a registered DNS name, enter its IP address here.
|
|
||||||
#
|
|
||||||
#ServerName www.example.com:80
|
|
||||||
|
|
||||||
#
|
|
||||||
# Deny access to the entirety of your server's filesystem. You must
|
|
||||||
# explicitly permit access to web content directories in other
|
|
||||||
# <Directory> blocks below.
|
|
||||||
#
|
|
||||||
<Directory />
|
|
||||||
AllowOverride none
|
|
||||||
Require all denied
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
#
|
|
||||||
# Note that from this point forward you must specifically allow
|
|
||||||
# particular features to be enabled - so if something's not working as
|
|
||||||
# you might expect, make sure that you have specifically enabled it
|
|
||||||
# below.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# DocumentRoot: The directory out of which you will serve your
|
|
||||||
# documents. By default, all requests are taken from this directory, but
|
|
||||||
# symbolic links and aliases may be used to point to other locations.
|
|
||||||
#
|
|
||||||
DocumentRoot "/Users/midoks/Desktop/mwdev/server/apache/httpd/htdocs"
|
|
||||||
<Directory "/Users/midoks/Desktop/mwdev/server/apache/httpd/htdocs">
|
|
||||||
#
|
|
||||||
# Possible values for the Options directive are "None", "All",
|
|
||||||
# or any combination of:
|
|
||||||
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
|
|
||||||
#
|
|
||||||
# Note that "MultiViews" must be named *explicitly* --- "Options All"
|
|
||||||
# doesn't give it to you.
|
|
||||||
#
|
|
||||||
# The Options directive is both complicated and important. Please see
|
|
||||||
# http://httpd.apache.org/docs/2.4/mod/core.html#options
|
|
||||||
# for more information.
|
|
||||||
#
|
|
||||||
Options Indexes FollowSymLinks
|
|
||||||
|
|
||||||
#
|
|
||||||
# AllowOverride controls what directives may be placed in .htaccess files.
|
|
||||||
# It can be "All", "None", or any combination of the keywords:
|
|
||||||
# AllowOverride FileInfo AuthConfig Limit
|
|
||||||
#
|
|
||||||
AllowOverride None
|
|
||||||
|
|
||||||
#
|
|
||||||
# Controls who can get stuff from this server.
|
|
||||||
#
|
|
||||||
Require all granted
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
#
|
|
||||||
# DirectoryIndex: sets the file that Apache will serve if a directory
|
|
||||||
# is requested.
|
|
||||||
#
|
|
||||||
<IfModule dir_module>
|
|
||||||
DirectoryIndex index.html
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
#
|
|
||||||
# The following lines prevent .htaccess and .htpasswd files from being
|
|
||||||
# viewed by Web clients.
|
|
||||||
#
|
|
||||||
<Files ".ht*">
|
|
||||||
Require all denied
|
|
||||||
</Files>
|
|
||||||
|
|
||||||
#
|
|
||||||
# ErrorLog: The location of the error log file.
|
|
||||||
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
|
||||||
# container, error messages relating to that virtual host will be
|
|
||||||
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
|
||||||
# container, that host's errors will be logged there and not here.
|
|
||||||
#
|
|
||||||
ErrorLog "logs/error_log"
|
|
||||||
|
|
||||||
#
|
|
||||||
# LogLevel: Control the number of messages logged to the error_log.
|
|
||||||
# Possible values include: debug, info, notice, warn, error, crit,
|
|
||||||
# alert, emerg.
|
|
||||||
#
|
|
||||||
LogLevel warn
|
|
||||||
|
|
||||||
<IfModule log_config_module>
|
|
||||||
#
|
|
||||||
# The following directives define some format nicknames for use with
|
|
||||||
# a CustomLog directive (see below).
|
|
||||||
#
|
|
||||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
|
||||||
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
|
||||||
|
|
||||||
<IfModule logio_module>
|
|
||||||
# You need to enable mod_logio.c to use %I and %O
|
|
||||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
#
|
|
||||||
# The location and format of the access logfile (Common Logfile Format).
|
|
||||||
# If you do not define any access logfiles within a <VirtualHost>
|
|
||||||
# container, they will be logged here. Contrariwise, if you *do*
|
|
||||||
# define per-<VirtualHost> access logfiles, transactions will be
|
|
||||||
# logged therein and *not* in this file.
|
|
||||||
#
|
|
||||||
CustomLog "logs/access_log" common
|
|
||||||
|
|
||||||
#
|
|
||||||
# If you prefer a logfile with access, agent, and referer information
|
|
||||||
# (Combined Logfile Format) you can use the following directive.
|
|
||||||
#
|
|
||||||
#CustomLog "logs/access_log" combined
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule alias_module>
|
|
||||||
#
|
|
||||||
# Redirect: Allows you to tell clients about documents that used to
|
|
||||||
# exist in your server's namespace, but do not anymore. The client
|
|
||||||
# will make a new request for the document at its new location.
|
|
||||||
# Example:
|
|
||||||
# Redirect permanent /foo http://www.example.com/bar
|
|
||||||
|
|
||||||
#
|
|
||||||
# Alias: Maps web paths into filesystem paths and is used to
|
|
||||||
# access content that does not live under the DocumentRoot.
|
|
||||||
# Example:
|
|
||||||
# Alias /webpath /full/filesystem/path
|
|
||||||
#
|
|
||||||
# If you include a trailing / on /webpath then the server will
|
|
||||||
# require it to be present in the URL. You will also likely
|
|
||||||
# need to provide a <Directory> section to allow access to
|
|
||||||
# the filesystem path.
|
|
||||||
|
|
||||||
#
|
|
||||||
# ScriptAlias: This controls which directories contain server scripts.
|
|
||||||
# ScriptAliases are essentially the same as Aliases, except that
|
|
||||||
# documents in the target directory are treated as applications and
|
|
||||||
# run by the server when requested rather than as documents sent to the
|
|
||||||
# client. The same rules about trailing "/" apply to ScriptAlias
|
|
||||||
# directives as to Alias.
|
|
||||||
#
|
|
||||||
ScriptAlias /cgi-bin/ "/Users/midoks/Desktop/mwdev/server/apache/httpd/cgi-bin/"
|
|
||||||
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule cgid_module>
|
|
||||||
#
|
|
||||||
# ScriptSock: On threaded servers, designate the path to the UNIX
|
|
||||||
# socket used to communicate with the CGI daemon of mod_cgid.
|
|
||||||
#
|
|
||||||
#Scriptsock cgisock
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
#
|
|
||||||
# "/Users/midoks/Desktop/mwdev/server/apache/httpd/cgi-bin" should be changed to whatever your ScriptAliased
|
|
||||||
# CGI directory exists, if you have that configured.
|
|
||||||
#
|
|
||||||
<Directory "/Users/midoks/Desktop/mwdev/server/apache/httpd/cgi-bin">
|
|
||||||
AllowOverride None
|
|
||||||
Options None
|
|
||||||
Require all granted
|
|
||||||
</Directory>
|
|
||||||
|
|
||||||
<IfModule headers_module>
|
|
||||||
#
|
|
||||||
# Avoid passing HTTP_PROXY environment to CGI's on this or any proxied
|
|
||||||
# backend servers which have lingering "httpoxy" defects.
|
|
||||||
# 'Proxy' request header is undefined by the IETF, not listed by IANA
|
|
||||||
#
|
|
||||||
RequestHeader unset Proxy early
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mime_module>
|
|
||||||
#
|
|
||||||
# TypesConfig points to the file containing the list of mappings from
|
|
||||||
# filename extension to MIME-type.
|
|
||||||
#
|
|
||||||
TypesConfig conf/mime.types
|
|
||||||
|
|
||||||
#
|
|
||||||
# AddType allows you to add to or override the MIME configuration
|
|
||||||
# file specified in TypesConfig for specific file types.
|
|
||||||
#
|
|
||||||
#AddType application/x-gzip .tgz
|
|
||||||
#
|
|
||||||
# AddEncoding allows you to have certain browsers uncompress
|
|
||||||
# information on the fly. Note: Not all browsers support this.
|
|
||||||
#
|
|
||||||
#AddEncoding x-compress .Z
|
|
||||||
#AddEncoding x-gzip .gz .tgz
|
|
||||||
#
|
|
||||||
# If the AddEncoding directives above are commented-out, then you
|
|
||||||
# probably should define those extensions to indicate media types:
|
|
||||||
#
|
|
||||||
AddType application/x-compress .Z
|
|
||||||
AddType application/x-gzip .gz .tgz
|
|
||||||
|
|
||||||
#
|
|
||||||
# AddHandler allows you to map certain file extensions to "handlers":
|
|
||||||
# actions unrelated to filetype. These can be either built into the server
|
|
||||||
# or added with the Action directive (see below)
|
|
||||||
#
|
|
||||||
# To use CGI scripts outside of ScriptAliased directories:
|
|
||||||
# (You will also need to add "ExecCGI" to the "Options" directive.)
|
|
||||||
#
|
|
||||||
#AddHandler cgi-script .cgi
|
|
||||||
|
|
||||||
# For type maps (negotiated resources):
|
|
||||||
#AddHandler type-map var
|
|
||||||
|
|
||||||
#
|
|
||||||
# Filters allow you to process content before it is sent to the client.
|
|
||||||
#
|
|
||||||
# To parse .shtml files for server-side includes (SSI):
|
|
||||||
# (You will also need to add "Includes" to the "Options" directive.)
|
|
||||||
#
|
|
||||||
#AddType text/html .shtml
|
|
||||||
#AddOutputFilter INCLUDES .shtml
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
#
|
|
||||||
# The mod_mime_magic module allows the server to use various hints from the
|
|
||||||
# contents of the file itself to determine its type. The MIMEMagicFile
|
|
||||||
# directive tells the module where the hint definitions are located.
|
|
||||||
#
|
|
||||||
#MIMEMagicFile conf/magic
|
|
||||||
|
|
||||||
#
|
|
||||||
# Customizable error responses come in three flavors:
|
|
||||||
# 1) plain text 2) local redirects 3) external redirects
|
|
||||||
#
|
|
||||||
# Some examples:
|
|
||||||
#ErrorDocument 500 "The server made a boo boo."
|
|
||||||
#ErrorDocument 404 /missing.html
|
|
||||||
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
|
|
||||||
#ErrorDocument 402 http://www.example.com/subscription_info.html
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# MaxRanges: Maximum number of Ranges in a request before
|
|
||||||
# returning the entire resource, or one of the special
|
|
||||||
# values 'default', 'none' or 'unlimited'.
|
|
||||||
# Default setting is to accept 200 Ranges.
|
|
||||||
#MaxRanges unlimited
|
|
||||||
|
|
||||||
#
|
|
||||||
# EnableMMAP and EnableSendfile: On systems that support it,
|
|
||||||
# memory-mapping or the sendfile syscall may be used to deliver
|
|
||||||
# files. This usually improves server performance, but must
|
|
||||||
# be turned off when serving from networked-mounted
|
|
||||||
# filesystems or if support for these functions is otherwise
|
|
||||||
# broken on your system.
|
|
||||||
# Defaults: EnableMMAP On, EnableSendfile Off
|
|
||||||
#
|
|
||||||
#EnableMMAP off
|
|
||||||
#EnableSendfile on
|
|
||||||
|
|
||||||
# Supplemental configuration
|
|
||||||
#
|
|
||||||
# The configuration files in the conf/extra/ directory can be
|
|
||||||
# included to add extra features or to modify the default configuration of
|
|
||||||
# the server, or you may simply copy their contents here and change as
|
|
||||||
# necessary.
|
|
||||||
|
|
||||||
# Server-pool management (MPM specific)
|
|
||||||
#Include conf/extra/httpd-mpm.conf
|
|
||||||
|
|
||||||
# Multi-language error messages
|
|
||||||
#Include conf/extra/httpd-multilang-errordoc.conf
|
|
||||||
|
|
||||||
# Fancy directory listings
|
|
||||||
#Include conf/extra/httpd-autoindex.conf
|
|
||||||
|
|
||||||
# Language settings
|
|
||||||
#Include conf/extra/httpd-languages.conf
|
|
||||||
|
|
||||||
# User home directories
|
|
||||||
#Include conf/extra/httpd-userdir.conf
|
|
||||||
|
|
||||||
# Real-time info on requests and configuration
|
|
||||||
#Include conf/extra/httpd-info.conf
|
|
||||||
|
|
||||||
# Virtual hosts
|
|
||||||
#Include conf/extra/httpd-vhosts.conf
|
|
||||||
|
|
||||||
# Local access to the Apache HTTP Server Manual
|
|
||||||
#Include conf/extra/httpd-manual.conf
|
|
||||||
|
|
||||||
# Distributed authoring and versioning (WebDAV)
|
|
||||||
#Include conf/extra/httpd-dav.conf
|
|
||||||
|
|
||||||
# Various default settings
|
|
||||||
#Include conf/extra/httpd-default.conf
|
|
||||||
|
|
||||||
# Configure mod_proxy_html to understand HTML4/XHTML1
|
|
||||||
<IfModule proxy_html_module>
|
|
||||||
Include conf/extra/proxy-html.conf
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
# Secure (SSL/TLS) connections
|
|
||||||
#Include conf/extra/httpd-ssl.conf
|
|
||||||
#
|
|
||||||
# Note: The following must must be present to support
|
|
||||||
# starting without SSL on platforms with no /dev/random equivalent
|
|
||||||
# but a statically compiled-in mod_ssl.
|
|
||||||
#
|
|
||||||
<IfModule ssl_module>
|
|
||||||
SSLRandomSeed startup builtin
|
|
||||||
SSLRandomSeed connect builtin
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,25 +0,0 @@
|
|||||||
<div class="bt-form">
|
|
||||||
<!-- <div class='plugin_version'></div> -->
|
|
||||||
<div class="bt-w-main">
|
|
||||||
<div class="bt-w-menu">
|
|
||||||
<p class="bgw" onclick="httpPluginService('apache',$('.plugin_version').attr('version'));">服务</p>
|
|
||||||
<p onclick="pluginInitD('apache', $('.plugin_version').attr('version'));">自启动</p>
|
|
||||||
<p onclick="pluginConfig('apache');">配置修改</p>
|
|
||||||
<p onclick="getHttpdStatus();">负载状态</p>
|
|
||||||
<p onclick="setOpCfg();">MPM性能调整</p>
|
|
||||||
<p onclick="pluginLogs('apache');">错误日志</p>
|
|
||||||
<p onclick="otherFunc();">维护功能</p>
|
|
||||||
</div>
|
|
||||||
<div class="bt-w-con pd15">
|
|
||||||
<div class="soft-man-con" style="height: 500px; overflow-y: auto;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
// resetPluginWinHeight(600);
|
|
||||||
$.getScript( "/plugins/file?name=apache&f=js/httpd.js", function(){
|
|
||||||
httpPluginService('apache');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,593 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
|
|
||||||
app_debug = False
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
app_debug = True
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginName():
|
|
||||||
return 'apache'
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginDir():
|
|
||||||
return mw.getPluginDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getInitDFile():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return '/tmp/' + getPluginName()
|
|
||||||
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
return '/etc/rc.d/' + getPluginName()
|
|
||||||
|
|
||||||
return '/etc/init.d/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getArgs():
|
|
||||||
args = sys.argv[2:]
|
|
||||||
# print(args)
|
|
||||||
tmp = {}
|
|
||||||
args_len = len(args)
|
|
||||||
|
|
||||||
if args_len == 1:
|
|
||||||
t = args[0].strip('{').strip('}')
|
|
||||||
t = t.split(':',2)
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
elif args_len > 1:
|
|
||||||
for i in range(len(args)):
|
|
||||||
t = args[i].split(':',2)
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
# print(tmp)
|
|
||||||
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 clearTemp():
|
|
||||||
path_bin = getServerDir() + "/httpd"
|
|
||||||
|
|
||||||
|
|
||||||
def getConf():
|
|
||||||
path = getServerDir() + "/httpd/conf/httpd.conf"
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def getConfMpm():
|
|
||||||
path = getServerDir() + "/httpd/conf/extra/httpd-mpm.conf"
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def getConfTpl():
|
|
||||||
path = getPluginDir() + '/conf/httpd.conf'
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def getOs():
|
|
||||||
data = {}
|
|
||||||
data['os'] = mw.getOs()
|
|
||||||
data['auth'] = True
|
|
||||||
return mw.getJson(data)
|
|
||||||
|
|
||||||
|
|
||||||
def getInitDTpl():
|
|
||||||
path = getPluginDir() + "/init.d/httpd.tpl"
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def getPidFile():
|
|
||||||
file = getConf()
|
|
||||||
content = mw.readFile(file)
|
|
||||||
rep = r'pid\s*(.*);'
|
|
||||||
tmp = re.search(rep, content)
|
|
||||||
return tmp.groups()[0].strip()
|
|
||||||
|
|
||||||
|
|
||||||
def getFileOwner(filename):
|
|
||||||
import pwd
|
|
||||||
stat = os.lstat(filename)
|
|
||||||
uid = stat.st_uid
|
|
||||||
pw = pwd.getpwuid(uid)
|
|
||||||
return pw.pw_name
|
|
||||||
|
|
||||||
|
|
||||||
def checkAuthEq(file, owner='root'):
|
|
||||||
fowner = getFileOwner(file)
|
|
||||||
if (fowner == owner):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def confReplace():
|
|
||||||
service_path = mw.getServerDir()
|
|
||||||
content = mw.readFile(getConfTpl())
|
|
||||||
content = content.replace('{$SERVER_PATH}', service_path)
|
|
||||||
|
|
||||||
# 主配置文件
|
|
||||||
nconf = getServerDir() + '/httpd/conf/httpd.conf'
|
|
||||||
mw.writeFile(nconf, content)
|
|
||||||
|
|
||||||
|
|
||||||
def initDreplace():
|
|
||||||
|
|
||||||
file_tpl = getInitDTpl()
|
|
||||||
service_path = mw.getServerDir()
|
|
||||||
|
|
||||||
initD_path = getServerDir() + '/init.d'
|
|
||||||
|
|
||||||
# OpenResty is not installed
|
|
||||||
if not os.path.exists(getServerDir()):
|
|
||||||
print("ok")
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
# init.d
|
|
||||||
file_bin = initD_path + '/' + getPluginName()
|
|
||||||
if not os.path.exists(initD_path):
|
|
||||||
os.mkdir(initD_path)
|
|
||||||
|
|
||||||
# initd replace
|
|
||||||
content = mw.readFile(file_tpl)
|
|
||||||
content = content.replace('{$SERVER_PATH}', service_path)
|
|
||||||
mw.writeFile(file_bin, content)
|
|
||||||
mw.execShell('chmod +x ' + file_bin)
|
|
||||||
|
|
||||||
# config replace
|
|
||||||
confReplace()
|
|
||||||
|
|
||||||
# systemd
|
|
||||||
# /usr/lib/systemd/system
|
|
||||||
systemDir = mw.systemdCfgDir()
|
|
||||||
systemService = systemDir + '/httpd.service'
|
|
||||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
|
||||||
systemServiceTpl = getPluginDir() + '/init.d/httpd.service.tpl'
|
|
||||||
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 status():
|
|
||||||
cmd = "ps -ef|grep 'httpd' |grep -v grep | grep -v python | awk '{print $2}'"
|
|
||||||
data = mw.execShell(cmd)
|
|
||||||
if data[0] == '':
|
|
||||||
return 'stop'
|
|
||||||
return 'start'
|
|
||||||
|
|
||||||
|
|
||||||
def restyOp(method):
|
|
||||||
file = initDreplace()
|
|
||||||
|
|
||||||
# 启动时,先检查一下配置文件
|
|
||||||
check = getServerDir() + "/httpd/bin/httpd -t"
|
|
||||||
check_data = mw.execShell(check)
|
|
||||||
if not check_data[1].find('Syntax OK') > -1:
|
|
||||||
return check_data[1]
|
|
||||||
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == "darwin":
|
|
||||||
data = mw.execShell(file + ' ' + method)
|
|
||||||
if data[1] == '':
|
|
||||||
return 'ok'
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
if current_os.startswith("freebsd"):
|
|
||||||
mw.execShell('service httpd '+method)
|
|
||||||
if data[1] == '':
|
|
||||||
return 'ok'
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
data = mw.execShell('systemctl ' + method + ' httpd')
|
|
||||||
if data[1] == '':
|
|
||||||
return 'ok'
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
|
|
||||||
def op_submit_systemctl_restart():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os.startswith("freebsd"):
|
|
||||||
mw.execShell('service httpd restart')
|
|
||||||
return True
|
|
||||||
|
|
||||||
mw.execShell('systemctl restart httpd')
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def op_submit_init_restart(file):
|
|
||||||
mw.execShell(file + ' restart')
|
|
||||||
|
|
||||||
|
|
||||||
def restyOp_restart():
|
|
||||||
file = initDreplace()
|
|
||||||
|
|
||||||
# 启动时,先检查一下配置文件
|
|
||||||
check = getServerDir() + "/httpd/bin/httpd -t"
|
|
||||||
check_data = mw.execShell(check)
|
|
||||||
if not check_data[1].find('Syntax OK') > -1:
|
|
||||||
return 'ERROR: 配置出错<br><a style="color:red;">' + check_data[1].replace("\n", '<br>') + '</a>'
|
|
||||||
|
|
||||||
if not mw.isAppleSystem():
|
|
||||||
threading.Timer(2, op_submit_systemctl_restart).start()
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
threading.Timer(2, op_submit_init_restart, args=(file,)).start()
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
|
||||||
return restyOp('start')
|
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
|
||||||
r = restyOp('stop')
|
|
||||||
|
|
||||||
mw.execShell("ps -ef|grep httpd | grep -v grep | awk '{print $2}'|xargs -r kill")
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def restart():
|
|
||||||
return restyOp_restart()
|
|
||||||
|
|
||||||
|
|
||||||
def reload():
|
|
||||||
confReplace()
|
|
||||||
return restyOp('reload')
|
|
||||||
|
|
||||||
|
|
||||||
def initdStatus():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return "Apple Computer does not support"
|
|
||||||
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
initd_bin = getInitDFile()
|
|
||||||
if os.path.exists(initd_bin):
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
shell_cmd = 'systemctl status httpd | grep loaded | grep "enabled;"'
|
|
||||||
data = mw.execShell(shell_cmd)
|
|
||||||
if data[0] == '':
|
|
||||||
return 'fail'
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
def initdInstall():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return "Apple Computer does not support"
|
|
||||||
|
|
||||||
# freebsd initd install
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
import shutil
|
|
||||||
source_bin = initDreplace()
|
|
||||||
initd_bin = getInitDFile()
|
|
||||||
shutil.copyfile(source_bin, initd_bin)
|
|
||||||
mw.execShell('chmod +x ' + initd_bin)
|
|
||||||
mw.execShell('sysrc httpd_enable="YES"')
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
mw.execShell('systemctl enable httpd')
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
def initdUinstall():
|
|
||||||
current_os = mw.getOs()
|
|
||||||
if current_os == 'darwin':
|
|
||||||
return "Apple Computer does not support"
|
|
||||||
|
|
||||||
if current_os.startswith('freebsd'):
|
|
||||||
initd_bin = getInitDFile()
|
|
||||||
os.remove(initd_bin)
|
|
||||||
mw.execShell('sysrc httpd_enable="NO"')
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
mw.execShell('systemctl disable httpd')
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
def getHttpdStatusPort():
|
|
||||||
conf = mw.getServerDir() + '/apache/httpd/conf/httpd.conf'
|
|
||||||
content = mw.readFile(conf)
|
|
||||||
if not content:
|
|
||||||
return None
|
|
||||||
rep = r'^\s*Listen\s*(?:\d+\.\d+\.\d+\.\d+:)?(\d+)' # 匹配非注释行的 Listen 指令,忽略大小写
|
|
||||||
tmp = re.search(rep, content, re.IGNORECASE | re.MULTILINE)
|
|
||||||
if tmp:
|
|
||||||
port = tmp.groups()[0].strip()
|
|
||||||
return port
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def runInfoDone(data):
|
|
||||||
result = {}
|
|
||||||
if not data:
|
|
||||||
return result
|
|
||||||
|
|
||||||
# 解析服务器状态数据
|
|
||||||
lines = data.strip().split('\n')
|
|
||||||
for line in lines:
|
|
||||||
if ':' in line:
|
|
||||||
key, value = line.split(':', 1)
|
|
||||||
key = key.strip()
|
|
||||||
value = value.strip()
|
|
||||||
result[key] = value
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def runInfo():
|
|
||||||
op_status = status()
|
|
||||||
if op_status == 'stop':
|
|
||||||
return mw.returnJson(False, "未启动!")
|
|
||||||
|
|
||||||
port = getHttpdStatusPort()
|
|
||||||
if not port:
|
|
||||||
return mw.returnJson(False, "无法获取端口信息!")
|
|
||||||
|
|
||||||
# 取Openresty负载状态
|
|
||||||
try:
|
|
||||||
url = 'http://127.0.0.1:%s/server-status?auto' % port
|
|
||||||
result = mw.httpGet(url, timeout=3)
|
|
||||||
data = runInfoDone(result)
|
|
||||||
return mw.getJson(data)
|
|
||||||
except Exception as e:
|
|
||||||
try:
|
|
||||||
url = 'http://' + mw.getHostAddr() + ':%s/server-status?auto' % port
|
|
||||||
result = mw.httpGet(url)
|
|
||||||
data = runInfoDone(result)
|
|
||||||
return mw.getJson(data)
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, "apache异常!")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, "apache not started!")
|
|
||||||
|
|
||||||
|
|
||||||
def errorLogPath():
|
|
||||||
return getServerDir() + '/httpd/logs/error.log'
|
|
||||||
|
|
||||||
|
|
||||||
def getCfg():
|
|
||||||
cfg = getConfMpm()
|
|
||||||
content = mw.readFile(cfg)
|
|
||||||
|
|
||||||
unitrep = "[kmgKMG]"
|
|
||||||
|
|
||||||
# 获取当前 MPM 模块
|
|
||||||
mpm_module = ""
|
|
||||||
mpm_match = re.search(r"mpm_(\w+)_module", content)
|
|
||||||
if mpm_match:
|
|
||||||
mpm_module = mpm_match.group(1)
|
|
||||||
|
|
||||||
# MPM 配置参数
|
|
||||||
mpm_cfg_args = {
|
|
||||||
"prefork": [
|
|
||||||
{"name": "StartServers", "ps": "服务器进程启动数量", 'type': 2},
|
|
||||||
{"name": "MinSpareServers", "ps": "保持空闲的最小服务器进程数", 'type': 2},
|
|
||||||
{"name": "MaxSpareServers", "ps": "保持空闲的最大服务器进程数", 'type': 2},
|
|
||||||
{"name": "MaxRequestWorkers", "ps": "允许启动的最大服务器进程数", 'type': 2},
|
|
||||||
{"name": "MaxConnectionsPerChild", "ps": "服务器进程服务的最大连接数", 'type': 2},
|
|
||||||
],
|
|
||||||
"worker": [
|
|
||||||
{"name": "StartServers", "ps": "初始服务器进程数", 'type': 2},
|
|
||||||
{"name": "MinSpareThreads", "ps": "保持空闲的最小工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxSpareThreads", "ps": "保持空闲的最大工作线程数", 'type': 2},
|
|
||||||
{"name": "ThreadsPerChild", "ps": "每个服务器进程的工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxRequestWorkers", "ps": "最大工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxConnectionsPerChild", "ps": "服务器进程服务的最大连接数", 'type': 2},
|
|
||||||
],
|
|
||||||
"event": [
|
|
||||||
{"name": "StartServers", "ps": "初始服务器进程数", 'type': 2},
|
|
||||||
{"name": "MinSpareThreads", "ps": "保持空闲的最小工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxSpareThreads", "ps": "保持空闲的最大工作线程数", 'type': 2},
|
|
||||||
{"name": "ThreadsPerChild", "ps": "每个服务器进程的工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxRequestWorkers", "ps": "最大工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxConnectionsPerChild", "ps": "服务器进程服务的最大连接数", 'type': 2},
|
|
||||||
],
|
|
||||||
"netware": [
|
|
||||||
{"name": "ThreadStackSize", "ps": "每个工作线程分配的堆栈大小", 'type': 2},
|
|
||||||
{"name": "StartThreads", "ps": "服务器启动时启动的工作线程数", 'type': 2},
|
|
||||||
{"name": "MinSpareThreads", "ps": "保持空闲的最小线程数", 'type': 2},
|
|
||||||
{"name": "MaxSpareThreads", "ps": "保持空闲的最大线程数", 'type': 2},
|
|
||||||
{"name": "MaxThreads", "ps": "同时活跃的最大工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxConnectionsPerChild", "ps": "线程服务的最大连接数", 'type': 2},
|
|
||||||
],
|
|
||||||
"mpmt_os2": [
|
|
||||||
{"name": "StartServers", "ps": "维护的服务器进程数", 'type': 2},
|
|
||||||
{"name": "MinSpareThreads", "ps": "每个进程的最小空闲线程数", 'type': 2},
|
|
||||||
{"name": "MaxSpareThreads", "ps": "每个进程的最大空闲线程数", 'type': 2},
|
|
||||||
{"name": "MaxConnectionsPerChild", "ps": "每个服务器进程的最大连接数", 'type': 2},
|
|
||||||
],
|
|
||||||
"winnt": [
|
|
||||||
{"name": "ThreadsPerChild", "ps": "服务器进程中的工作线程数", 'type': 2},
|
|
||||||
{"name": "MaxConnectionsPerChild", "ps": "服务器进程服务的最大连接数", 'type': 2},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# 通用配置参数
|
|
||||||
common_cfg_args = [
|
|
||||||
{"name": "MaxMemFree", "ps": "每个分配器允许持有的最大空闲KB数", 'type': 2},
|
|
||||||
]
|
|
||||||
|
|
||||||
# 合并配置参数
|
|
||||||
cfg_args = []
|
|
||||||
if mpm_module in mpm_cfg_args:
|
|
||||||
cfg_args.extend(mpm_cfg_args[mpm_module])
|
|
||||||
cfg_args.extend(common_cfg_args)
|
|
||||||
|
|
||||||
rdata = []
|
|
||||||
for i in cfg_args:
|
|
||||||
# 匹配 MPM 特定配置
|
|
||||||
rep = r"<IfModule mpm_%s_module>.*?(%s)\s+(\w+).*?</IfModule>" % (mpm_module, i["name"])
|
|
||||||
k = re.search(rep, content, re.DOTALL)
|
|
||||||
|
|
||||||
# 如果没有找到 MPM 特定配置,尝试匹配通用配置
|
|
||||||
if not k:
|
|
||||||
rep = r"(%s)\s+(\w+)" % i["name"]
|
|
||||||
k = re.search(rep, content)
|
|
||||||
|
|
||||||
if not k:
|
|
||||||
continue
|
|
||||||
|
|
||||||
key = k.group(1)
|
|
||||||
v = k.group(2) if len(k.groups()) > 1 else ""
|
|
||||||
|
|
||||||
if re.search(unitrep, v):
|
|
||||||
u = str.upper(v[-1])
|
|
||||||
v = v[:-1]
|
|
||||||
if len(u) == 1:
|
|
||||||
psstr = u + "B," + i["ps"]
|
|
||||||
else:
|
|
||||||
psstr = u + "," + i["ps"]
|
|
||||||
else:
|
|
||||||
u = ""
|
|
||||||
|
|
||||||
kv = {"name": key, "value": v, "unit": u,
|
|
||||||
"ps": i["ps"], "type": i["type"]}
|
|
||||||
rdata.append(kv)
|
|
||||||
return mw.returnJson(True, "ok", rdata)
|
|
||||||
|
|
||||||
def replaceChar(value, index, new_char):
|
|
||||||
return value[:index] + new_char + value[index+1:]
|
|
||||||
|
|
||||||
def setCfg():
|
|
||||||
args = getArgs()
|
|
||||||
|
|
||||||
# 检查参数,允许动态参数
|
|
||||||
cfg = getConfMpm()
|
|
||||||
mw.backFile(cfg)
|
|
||||||
content = mw.readFile(cfg)
|
|
||||||
|
|
||||||
# 获取当前 MPM 模块
|
|
||||||
mpm_module = ""
|
|
||||||
mpm_match = re.search(r"mpm_(\w+)_module", content)
|
|
||||||
if mpm_match:
|
|
||||||
mpm_module = mpm_match.group(1)
|
|
||||||
|
|
||||||
# 验证参数值
|
|
||||||
for k, v in args.items():
|
|
||||||
# 检查是否为数字参数
|
|
||||||
if not re.search(r"\d+", v):
|
|
||||||
return mw.returnJson(False, '参数值错误,请输入数字整数')
|
|
||||||
|
|
||||||
# 替换 MPM 特定配置
|
|
||||||
if mpm_module:
|
|
||||||
def replace_mpm_config(match):
|
|
||||||
return match.group(1) + k + match.group(2) + v + match.group(3)
|
|
||||||
rep = r"(<IfModule mpm_%s_module>.*?)%s(\s+)\d+(.*?</IfModule>)" % (mpm_module, k)
|
|
||||||
if re.search(rep, content, re.DOTALL):
|
|
||||||
content = re.sub(rep, replace_mpm_config, content, flags=re.DOTALL)
|
|
||||||
|
|
||||||
# 替换通用配置
|
|
||||||
def replace_common_config(match):
|
|
||||||
return k + match.group(1) + v
|
|
||||||
rep = r"%s(\s+)\d+" % k
|
|
||||||
if re.search(rep, content):
|
|
||||||
content = re.sub(rep, replace_common_config, content)
|
|
||||||
|
|
||||||
mw.writeFile(cfg, content)
|
|
||||||
isError = mw.checkHttpdConfig()
|
|
||||||
if (isError != True):
|
|
||||||
mw.restoreFile(cfg)
|
|
||||||
return mw.returnJson(False, 'ERROR: 配置出错<br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
|
|
||||||
|
|
||||||
mw.restartWeb()
|
|
||||||
return mw.returnJson(True, '设置成功')
|
|
||||||
|
|
||||||
|
|
||||||
def cronAddCheck():
|
|
||||||
try:
|
|
||||||
import tool_task
|
|
||||||
tool_task.createBgTask()
|
|
||||||
return mw.returnJson(True, '添加检查任务成功')
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, '添加检查任务失败:'+str(e))
|
|
||||||
|
|
||||||
def cronDelCheck():
|
|
||||||
try:
|
|
||||||
import tool_task
|
|
||||||
tool_task.removeBgTask()
|
|
||||||
return mw.returnJson(True, '删除检查任务成功')
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, '删除检查任务失败:'+str(e))
|
|
||||||
|
|
||||||
def cronCheck():
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
def installPreInspection():
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
version = '2.4'
|
|
||||||
version_pl = getServerDir() + "/version.pl"
|
|
||||||
if os.path.exists(version_pl):
|
|
||||||
version = mw.readFile(version_pl)
|
|
||||||
|
|
||||||
|
|
||||||
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 == 'install_pre_inspection':
|
|
||||||
print(installPreInspection())
|
|
||||||
elif func == 'conf':
|
|
||||||
print(getConf())
|
|
||||||
elif func == 'get_os':
|
|
||||||
print(getOs())
|
|
||||||
elif func == 'run_info':
|
|
||||||
print(runInfo())
|
|
||||||
elif func == 'error_log':
|
|
||||||
print(errorLogPath())
|
|
||||||
elif func == 'get_cfg':
|
|
||||||
print(getCfg())
|
|
||||||
elif func == 'set_cfg':
|
|
||||||
print(setCfg())
|
|
||||||
elif func == 'check':
|
|
||||||
print(cronCheck())
|
|
||||||
elif func == 'cron_add_check':
|
|
||||||
print(cronAddCheck())
|
|
||||||
elif func == 'cron_del_check':
|
|
||||||
print(cronDelCheck())
|
|
||||||
else:
|
|
||||||
print('error')
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"sort": 0,
|
|
||||||
"title":"apache",
|
|
||||||
"tip":"soft",
|
|
||||||
"name":"apache",
|
|
||||||
"type":"其他插件",
|
|
||||||
"ps":"世界排名第一,快速、可靠并且可通过简单的API扩充",
|
|
||||||
"shell":"install.sh",
|
|
||||||
"install_pre_inspection":true,
|
|
||||||
"checks":"server/apache",
|
|
||||||
"path":"server/apache",
|
|
||||||
"author":"apache",
|
|
||||||
"home":"https://downloads.apache.org/httpd/",
|
|
||||||
"date":"2026-04-11",
|
|
||||||
"pid": "1",
|
|
||||||
"versions": ["2.4"],
|
|
||||||
"updates": ["2.4:66"]
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Apache Web Server
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
Environment=LANG=C
|
|
||||||
ExecStart={$SERVER_PATH}/apache/httpd/bin/httpd $OPTIONS -DFOREGROUND
|
|
||||||
ExecReload={$SERVER_PATH}/apache/httpd/bin/httpd $OPTIONS -k graceful
|
|
||||||
KillSignal=SIGWINCH
|
|
||||||
|
|
||||||
KillMode=mixed
|
|
||||||
PrivateTmp=true
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Apache Web Server
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=forking
|
|
||||||
PIDFile={$SERVER_PATH}/apache/httpd/logs/httpd.pid
|
|
||||||
ExecStart={$SERVER_PATH}/apache/httpd/bin/apachectl start
|
|
||||||
ExecReload={$SERVER_PATH}/apache/httpd/bin/apachectl graceful
|
|
||||||
ExecStop={$SERVER_PATH}/apache/httpd/bin/apachectl stop
|
|
||||||
PrivateTmp=true
|
|
||||||
User=www
|
|
||||||
Group=www
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# chkconfig: 345 85 15
|
|
||||||
# description: Apache Server
|
|
||||||
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: apache
|
|
||||||
# Required-Start: $network
|
|
||||||
# Required-Stop: $network
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Description: Apache Server
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
|
|
||||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/homebrew/bin
|
|
||||||
# Apache 可执行文件的路径
|
|
||||||
DAEMON={$SERVER_PATH}/apache/httpd/bin/httpd
|
|
||||||
# 进程的 PID 文件路径
|
|
||||||
PIDFILE={$SERVER_PATH}/apache/httpd/logs/httpd.pid
|
|
||||||
|
|
||||||
# 根据传入的参数执行不同操作
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
echo "Starting Apache..."
|
|
||||||
$DAEMON -k start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
echo "Stopping Apache..."
|
|
||||||
$DAEMON -k stop
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
echo "Restarting Apache..."
|
|
||||||
$DAEMON -k restart
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
if [ -f $PIDFILE ]; then
|
|
||||||
echo "Apache is running."
|
|
||||||
else
|
|
||||||
echo "Apache is not running."
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 {start|stop|restart|status}"
|
|
||||||
exit 1
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
|
||||||
export PATH
|
|
||||||
|
|
||||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/apache && bash install.sh install 2.4
|
|
||||||
# cd /www/server/mdserver-web/plugins/apache && bash install.sh install 2.4
|
|
||||||
# cd /www/server/mdserver-web/plugins/apache && bash install.sh upgrade 2.4
|
|
||||||
|
|
||||||
# curl -I -H "Accept-Encoding: br" http://localhost
|
|
||||||
# curl -I -H "Accept-Encoding: zstd" http://localhost
|
|
||||||
# curl --http3 -v https://www.xxx.com
|
|
||||||
|
|
||||||
# apt install ncat -y
|
|
||||||
# nc -u -v www.xx.com 443
|
|
||||||
|
|
||||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/apache && python3 plugins/apache/index.py start
|
|
||||||
# cd /www/server/mdserver-web && python3 plugins/apache/index.py start
|
|
||||||
# cd /www/server/mdserver-web && python3 plugins/apache/index.py run_info
|
|
||||||
# ps -ef|grep httpd | grep -v grep | awk '{print $2}'|xargs kill
|
|
||||||
|
|
||||||
curPath=`pwd`
|
|
||||||
rootPath=$(dirname "$curPath")
|
|
||||||
rootPath=$(dirname "$rootPath")
|
|
||||||
serverPath=$(dirname "$rootPath")
|
|
||||||
|
|
||||||
sysName=`uname`
|
|
||||||
action=$1
|
|
||||||
type=$2
|
|
||||||
|
|
||||||
VERSION=$2
|
|
||||||
openrestyDir=${serverPath}/source/apache
|
|
||||||
|
|
||||||
if id www &> /dev/null ;then
|
|
||||||
echo "www uid is `id -u www`"
|
|
||||||
echo "www shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
|
|
||||||
else
|
|
||||||
groupadd www
|
|
||||||
useradd -g www -s /bin/bash www
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${action}" = "upgrade" ];then
|
|
||||||
sh -x $curPath/versions/$2/install.sh $1
|
|
||||||
|
|
||||||
echo "${VERSION}" > $serverPath/apache/version.pl
|
|
||||||
|
|
||||||
mkdir -p $serverPath/web_conf/php/conf
|
|
||||||
echo 'set $PHP_ENV 0;' > $serverPath/web_conf/php/conf/enable-php-00.conf
|
|
||||||
|
|
||||||
#初始化
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/apache/index.py start
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/apache/index.py initd_install
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ "${2}" = "" ];then
|
|
||||||
echo '缺少安装脚本版本...'
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${action}" = "uninstall" ];then
|
|
||||||
if [ -f /usr/lib/systemd/system/httpd.service ] || [ -f /lib/systemd/system/httpd.service ];then
|
|
||||||
systemctl stop httpd
|
|
||||||
rm -rf /usr/systemd/system/httpd.service
|
|
||||||
rm -rf /lib/systemd/system/httpd.service
|
|
||||||
systemctl daemon-reload
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f $serverPath/apache/init.d/httpd ];then
|
|
||||||
$serverPath/apache/init.d/httpd stop
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -rf $serverPath/apache
|
|
||||||
fi
|
|
||||||
|
|
||||||
sh -x $curPath/versions/$2/install.sh $1
|
|
||||||
|
|
||||||
if [ "${action}" = "install" ] && [ -d $serverPath/apache ];then
|
|
||||||
echo "${VERSION}" > $serverPath/apache/version.pl
|
|
||||||
|
|
||||||
mkdir -p $serverPath/web_conf/php/conf
|
|
||||||
echo 'set $PHP_ENV 0;' > $serverPath/web_conf/php/conf/enable-php-00.conf
|
|
||||||
|
|
||||||
#初始化
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/apache/index.py start
|
|
||||||
cd ${rootPath} && python3 ${rootPath}/plugins/apache/index.py initd_install
|
|
||||||
fi
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
function httpPost(method, args, callback){
|
|
||||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
|
||||||
$.post('/plugins/run', {name:'apache', func:method, args:JSON.stringify(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 httpPluginService(_name, version){
|
|
||||||
var data = {name:_name, func:'status'}
|
|
||||||
if ( typeof(version) != 'undefined' ){
|
|
||||||
data['version'] = version;
|
|
||||||
} else {
|
|
||||||
version = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
httpPost('status', data, function(data){
|
|
||||||
if (data.data == 'start'){
|
|
||||||
orPluginSetService(_name, true, version);
|
|
||||||
} else {
|
|
||||||
orPluginSetService(_name, false, version);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function orPluginSetService(_name ,status, version){
|
|
||||||
var serviceCon ='<p class="status">当前状态:<span>'+(status ? '开启' : '关闭' )+
|
|
||||||
'</span><span style="color: '+
|
|
||||||
(status?'#20a53a;':'red;')+
|
|
||||||
' margin-left: 3px;" class="glyphicon ' + (status?'glyphicon glyphicon-play':'glyphicon-pause')+'"></span></p><div class="sfm-opt">\
|
|
||||||
<button class="btn btn-default btn-sm" onclick="orPluginOpService(\''+_name+'\',\''+(status?'stop':'start')+'\',\''+version+'\')">'+(status?'停止':'启动')+'</button>\
|
|
||||||
<button class="btn btn-default btn-sm" onclick="orPluginOpService(\''+_name+'\',\'restart\',\''+version+'\',\'yes\')">重启</button>\
|
|
||||||
<button class="btn btn-default btn-sm" onclick="orPluginOpService(\''+_name+'\',\'reload\',\''+version+'\')">重载配置</button>\
|
|
||||||
</div>';
|
|
||||||
$(".soft-man-con").html(serviceCon);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function orPluginOpService(a, b, v,request_callback) {
|
|
||||||
|
|
||||||
var c = "name=" + a + "&func=" + b;
|
|
||||||
if(v != ''){
|
|
||||||
c = c + '&version='+v;
|
|
||||||
}
|
|
||||||
|
|
||||||
var d = "";
|
|
||||||
|
|
||||||
switch(b) {
|
|
||||||
case "stop":d = '停止';break;
|
|
||||||
case "start":d = '启动';break;
|
|
||||||
case "restart":d = '重启';break;
|
|
||||||
case "reload":d = '重载';break;
|
|
||||||
}
|
|
||||||
layer.confirm( msgTpl('您真的要{1}{2}{3}服务吗?', [d,a,v]), {icon:3,closeBtn: 2}, function() {
|
|
||||||
httpPost('get_os',{},function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
if (!rdata['auth']){
|
|
||||||
layer.prompt({title: '检查到权限不足,需要输入密码!', formType: 1},function(pwd, index){
|
|
||||||
|
|
||||||
layer.close(index);
|
|
||||||
var data = {'pwd':pwd};
|
|
||||||
c += '&args='+JSON.stringify(data);
|
|
||||||
orPluginOpServiceOp(a,b,c,d,a,v,request_callback);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
orPluginOpServiceOp(a,b,c,d,a,v,request_callback);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function orPluginOpServiceOp(a,b,c,d,a,v,request_callback){
|
|
||||||
|
|
||||||
var request_path = "/plugins/run";
|
|
||||||
if (request_callback == 'yes'){
|
|
||||||
request_path = "/plugins/callback";
|
|
||||||
}
|
|
||||||
|
|
||||||
var e = layer.msg(msgTpl('正在{1}{2}{3}服务,请稍候...',[d,a,v]), {icon: 16,time: 0});
|
|
||||||
$.post(request_path, c, function(g) {
|
|
||||||
layer.close(e);
|
|
||||||
|
|
||||||
var f = g.data == 'ok' ? msgTpl('{1}{2}服务已{3}',[a,v,d]) : msgTpl('{1}{2}服务{3}失败!',[a,v,d]);
|
|
||||||
layer.msg(f, {icon: g.data == 'ok' ? 1 : 2});
|
|
||||||
|
|
||||||
if( b != "reload" && g.data == 'ok' ) {
|
|
||||||
if ( b == 'start' ) {
|
|
||||||
orPluginSetService(a, true, v);
|
|
||||||
} else if ( b == 'stop' ){
|
|
||||||
orPluginSetService(a, false, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( g.status && g.data != 'ok' ) {
|
|
||||||
layer.msg(g.data, {icon: 2,time: 10000,shade: 0.3});
|
|
||||||
}
|
|
||||||
|
|
||||||
},'json').error(function() {
|
|
||||||
layer.close(e);
|
|
||||||
layer.msg('操作异常!', {icon: 2});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 定时器变量
|
|
||||||
var httpdStatusTimer = null;
|
|
||||||
|
|
||||||
//查看Apache负载状态
|
|
||||||
function getHttpdStatus() {
|
|
||||||
$.post('/plugins/run', {name:'apache', func:'run_info'}, function(data) {
|
|
||||||
try {
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
|
|
||||||
console.log(rdata);
|
|
||||||
if ('status' in rdata && !rdata.status){
|
|
||||||
showMsg(rdata.msg, function(){}, null,3000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var con = "<div><table class='table table-hover table-bordered'>\
|
|
||||||
<tr><th>服务器版本(ServerVersion)</th><td>" + (rdata.ServerVersion || '-') + "</td></tr>\
|
|
||||||
<tr><th>服务器MPM(ServerMPM)</th><td>" + (rdata.ServerMPM || '-') + "</td></tr>\
|
|
||||||
<tr><th>服务器构建时间(Server Built)</th><td>" + (rdata['Server Built'] || '-') + "</td></tr>\
|
|
||||||
<tr><th>当前时间(CurrentTime)</th><td>" + (rdata.CurrentTime || '-') + "</td></tr>\
|
|
||||||
<tr><th>重启时间(RestartTime)</th><td>" + (rdata.RestartTime || '-') + "</td></tr>\
|
|
||||||
<tr><th>服务器运行时间(ServerUptime)</th><td>" + (rdata.ServerUptime || '-') + "</td></tr>\
|
|
||||||
<tr><th>服务器运行秒数(ServerUptimeSeconds)</th><td>" + (rdata.ServerUptimeSeconds || '-') + "</td></tr>\
|
|
||||||
<tr><th>1分钟负载(Load1)</th><td>" + (rdata.Load1 || '-') + "</td></tr>\
|
|
||||||
<tr><th>5分钟负载(Load5)</th><td>" + (rdata.Load5 || '-') + "</td></tr>\
|
|
||||||
<tr><th>15分钟负载(Load15)</th><td>" + (rdata.Load15 || '-') + "</td></tr>\
|
|
||||||
<tr><th>总访问次数(Total Accesses)</th><td>" + (rdata['Total Accesses'] || '-') + "</td></tr>\
|
|
||||||
<tr><th>总流量(Total kBytes)</th><td>" + (rdata['Total kBytes'] || '-') + " KB</td></tr>\
|
|
||||||
<tr><th>总请求时间(Total Duration)</th><td>" + (rdata['Total Duration'] || '-') + "</td></tr>\
|
|
||||||
<tr><th>CPU用户时间(CPUUser)</th><td>" + (rdata.CPUUser || '-') + "</td></tr>\
|
|
||||||
<tr><th>CPU系统时间(CPUSystem)</th><td>" + (rdata.CPUSystem || '-') + "</td></tr>\
|
|
||||||
<tr><th>CPU负载(CPULoad)</th><td>" + (rdata.CPULoad || '-') + "</td></tr>\
|
|
||||||
<tr><th>每秒请求数(ReqPerSec)</th><td>" + (rdata.ReqPerSec || '-') + "</td></tr>\
|
|
||||||
<tr><th>每秒流量(BytesPerSec)</th><td>" + (rdata.BytesPerSec || '-') + "</td></tr>\
|
|
||||||
<tr><th>每请求流量(BytesPerReq)</th><td>" + (rdata.BytesPerReq || '-') + "</td></tr>\
|
|
||||||
<tr><th>每请求时间(DurationPerReq)</th><td>" + (rdata.DurationPerReq || '-') + "</td></tr>\
|
|
||||||
<tr><th>活动工作进程(BusyWorkers)</th><td>" + (rdata.BusyWorkers || '-') + "</td></tr>\
|
|
||||||
<tr><th>优雅关闭进程(GracefulWorkers)</th><td>" + (rdata.GracefulWorkers || '-') + "</td></tr>\
|
|
||||||
<tr><th>空闲工作进程(IdleWorkers)</th><td>" + (rdata.IdleWorkers || '-') + "</td></tr>\
|
|
||||||
<tr><th>进程数(Processes)</th><td>" + (rdata.Processes || '-') + "</td></tr>\
|
|
||||||
<tr><th>总连接数(ConnsTotal)</th><td>" + (rdata.ConnsTotal || '-') + "</td></tr>\
|
|
||||||
</table></div>";
|
|
||||||
$(".soft-man-con").html(con);
|
|
||||||
}catch(err){
|
|
||||||
showMsg(data.data, function(){}, null,3000);
|
|
||||||
}
|
|
||||||
},'json');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 启动自动刷新
|
|
||||||
function startHttpdStatusAutoRefresh() {
|
|
||||||
// 先清除现有的定时器
|
|
||||||
if (httpdStatusTimer) {
|
|
||||||
clearInterval(httpdStatusTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 立即执行一次
|
|
||||||
getHttpdStatus();
|
|
||||||
|
|
||||||
// 设置定时器,每5秒刷新一次
|
|
||||||
httpdStatusTimer = setInterval(getHttpdStatus, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 停止自动刷新
|
|
||||||
function stopHttpdStatusAutoRefresh() {
|
|
||||||
if (httpdStatusTimer) {
|
|
||||||
clearInterval(httpdStatusTimer);
|
|
||||||
httpdStatusTimer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function setOpCfg(){
|
|
||||||
httpPost('get_cfg', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
var rdata = rdata.data;
|
|
||||||
// console.log(rdata);
|
|
||||||
|
|
||||||
var mlist = '';
|
|
||||||
for (var i = 0; i < rdata.length; i++) {
|
|
||||||
var w = '70'
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
mlist += '<p style="margin-top:15px;"><span>' + rdata[i].name + '</span>' + ibody + "<b class='unit c9'>"+rdata[i].unit+"</b>" +', <font class="c9">' + rdata[i].ps + '</font></p>';
|
|
||||||
}
|
|
||||||
var con = '<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="setOpCfg()">刷新</button>\
|
|
||||||
<button class="btn btn-success btn-sm" onclick="submitConf()">保存</button>\
|
|
||||||
</div>\
|
|
||||||
</div>'
|
|
||||||
$(".soft-man-con").html(con);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitConf() {
|
|
||||||
var data = {};
|
|
||||||
|
|
||||||
// 收集所有配置参数
|
|
||||||
$("input[name]").each(function() {
|
|
||||||
data[$(this).attr('name')] = $(this).val();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("select[name]").each(function() {
|
|
||||||
data[$(this).attr('name')] = $(this).val() || 'on';
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log(data);
|
|
||||||
httpPost('set_cfg', data, function(rdata){
|
|
||||||
var rdata = $.parseJSON(rdata.data);
|
|
||||||
// console.log(rdata);
|
|
||||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function otherFunc(){
|
|
||||||
var con = '<p class="conf_p" style="text-align:center;">\
|
|
||||||
<button class="btn btn-default btn-sm" onclick="cronAddCheck()">添加检查任务</button> \
|
|
||||||
<button class="btn btn-default btn-sm" onclick="cronDelCheck()">删除检查任务</button>\
|
|
||||||
</p>';
|
|
||||||
$(".soft-man-con").html(con);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cronAddCheck(){
|
|
||||||
httpPost('cron_add_check', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cronDelCheck(){
|
|
||||||
httpPost('cron_del_check', {}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
from utils.crontab import crontab as MwCrontab
|
|
||||||
|
|
||||||
|
|
||||||
app_debug = False
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
app_debug = True
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginName():
|
|
||||||
return 'apache'
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginDir():
|
|
||||||
return mw.getPluginDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
def getTaskConf():
|
|
||||||
conf = getServerDir() + "/task_config.json"
|
|
||||||
return conf
|
|
||||||
|
|
||||||
|
|
||||||
def getConfigData():
|
|
||||||
conf = getTaskConf()
|
|
||||||
if os.path.exists(conf):
|
|
||||||
return json.loads(mw.readFile(getTaskConf()))
|
|
||||||
return {
|
|
||||||
"task_id": -1,
|
|
||||||
"period": "minute-n",
|
|
||||||
"where1": "3",
|
|
||||||
"hour": "0",
|
|
||||||
"minute": "0",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def createBgTask():
|
|
||||||
removeBgTask()
|
|
||||||
createBgTaskByName(getPluginName())
|
|
||||||
|
|
||||||
|
|
||||||
def createBgTaskByName(name):
|
|
||||||
args = getConfigData()
|
|
||||||
_name = "[apache]检查任务"
|
|
||||||
res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find()
|
|
||||||
if res:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if "task_id" in args and args["task_id"] > 0:
|
|
||||||
res = mw.M("crontab").field("id, name").where(
|
|
||||||
"id=?", (args["task_id"],)).find()
|
|
||||||
if res and res["id"] == args["task_id"]:
|
|
||||||
print("计划任务已经存在!")
|
|
||||||
return True
|
|
||||||
|
|
||||||
mw_dir = mw.getPanelDir()
|
|
||||||
cmd = '''
|
|
||||||
mw_dir=%s
|
|
||||||
rname=%s
|
|
||||||
plugin_path=%s
|
|
||||||
script_path=%s
|
|
||||||
''' % (mw_dir, name, getServerDir(), getPluginDir())
|
|
||||||
cmd += 'echo "bash $script_path/check.sh"' + "\n"
|
|
||||||
cmd += 'cd $mw_dir && bash $script_path/check.sh' + "\n"
|
|
||||||
|
|
||||||
params = {
|
|
||||||
'name': _name,
|
|
||||||
'type': args['period'],
|
|
||||||
'week': "",
|
|
||||||
'where1': args['where1'],
|
|
||||||
'hour': args['hour'],
|
|
||||||
'minute': args['minute'],
|
|
||||||
'save': "",
|
|
||||||
'backup_to': "",
|
|
||||||
'stype': "toShell",
|
|
||||||
'sname': '',
|
|
||||||
'sbody': cmd,
|
|
||||||
'url_address': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
task_id = MwCrontab.instance().add(params)
|
|
||||||
if task_id > 0:
|
|
||||||
args["task_id"] = task_id
|
|
||||||
args["name"] = name
|
|
||||||
mw.writeFile(getTaskConf(), json.dumps(args))
|
|
||||||
|
|
||||||
|
|
||||||
def removeBgTask():
|
|
||||||
cfg = getConfigData()
|
|
||||||
if "task_id" in cfg and cfg["task_id"] > 0:
|
|
||||||
res = mw.M("crontab").field("id, name").where(
|
|
||||||
"id=?", (cfg["task_id"],)).find()
|
|
||||||
if res and res["id"] == cfg["task_id"]:
|
|
||||||
data = MwCrontab.instance().delete(cfg["task_id"])
|
|
||||||
if data["status"]:
|
|
||||||
cfg["task_id"] = -1
|
|
||||||
mw.writeFile(getTaskConf(), json.dumps(cfg))
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
action = sys.argv[1]
|
|
||||||
if action == "remove":
|
|
||||||
removeBgTask()
|
|
||||||
elif action == "add":
|
|
||||||
createBgTask()
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
|
||||||
export PATH
|
|
||||||
|
|
||||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/apache && bash install.sh install 2.4
|
|
||||||
# cd /www/server/mdserver-web/plugins/apache && bash install.sh install 2.4
|
|
||||||
|
|
||||||
curPath=`pwd`
|
|
||||||
rootPath=$(dirname "$curPath")
|
|
||||||
rootPath=$(dirname "$rootPath")
|
|
||||||
serverPath=$(dirname "$rootPath")
|
|
||||||
|
|
||||||
sysName=`uname`
|
|
||||||
action=$1
|
|
||||||
type=$2
|
|
||||||
|
|
||||||
VERSION=2.4.68
|
|
||||||
apacheDir=${serverPath}/source/apache
|
|
||||||
|
|
||||||
Install_App()
|
|
||||||
{
|
|
||||||
if [ "${action}" = "install" ];then
|
|
||||||
if [ -d $serverPath/apache ];then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ----- cpu start ------
|
|
||||||
if [ -z "${cpuCore}" ]; then
|
|
||||||
cpuCore="1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f /proc/cpuinfo ];then
|
|
||||||
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
|
|
||||||
fi
|
|
||||||
|
|
||||||
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
|
|
||||||
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
|
|
||||||
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
|
|
||||||
cpuCore="${MEM_INFO}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
cpuCore="1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$cpuCore" -gt "2" ];then
|
|
||||||
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
|
|
||||||
else
|
|
||||||
cpuCore="1"
|
|
||||||
fi
|
|
||||||
# ----- cpu end ------
|
|
||||||
|
|
||||||
mkdir -p ${apacheDir}
|
|
||||||
echo 'install script ...'
|
|
||||||
OPTIONS=''
|
|
||||||
|
|
||||||
# 安装 APR 和 APR-util
|
|
||||||
APR_VERSION=1.7.6
|
|
||||||
APR_UTIL_VERSION=1.6.3
|
|
||||||
|
|
||||||
if [ ! -f ${apacheDir}/apr-${APR_VERSION}.tar.bz2 ];then
|
|
||||||
wget --no-check-certificate -O ${apacheDir}/apr-${APR_VERSION}.tar.bz2 https://downloads.apache.org/apr/apr-${APR_VERSION}.tar.bz2 -T 3
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f ${apacheDir}/apr-util-${APR_UTIL_VERSION}.tar.bz2 ];then
|
|
||||||
wget --no-check-certificate -O ${apacheDir}/apr-util-${APR_UTIL_VERSION}.tar.bz2 https://downloads.apache.org/apr/apr-util-${APR_UTIL_VERSION}.tar.bz2 -T 3
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 安装 APR
|
|
||||||
if [ ! -d ${serverPath}/apache/apr ];then
|
|
||||||
cd ${apacheDir} && tar -jxf apr-${APR_VERSION}.tar.bz2
|
|
||||||
cd ${apacheDir}/apr-${APR_VERSION} && ./configure --prefix=${serverPath}/apache/apr
|
|
||||||
make -j${cpuCore} && make install
|
|
||||||
if [ "$?" = "0" ];then
|
|
||||||
# 检查 APR 配置文件
|
|
||||||
APR_CONFIG=$(find ${serverPath}/apache/apr -name "apr-*config" | head -1)
|
|
||||||
if [ -z "$APR_CONFIG" ];then
|
|
||||||
echo "APR installation failed: apr-config not found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "APR installed successfully: $APR_CONFIG"
|
|
||||||
else
|
|
||||||
echo "APR configure failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 安装 APR-util
|
|
||||||
if [ ! -d ${serverPath}/apache/apr-util ];then
|
|
||||||
cd ${apacheDir} && tar -jxf apr-util-${APR_UTIL_VERSION}.tar.bz2
|
|
||||||
cd ${apacheDir}/apr-util-${APR_UTIL_VERSION} && ./configure --prefix=${serverPath}/apache/apr-util --with-apr=${serverPath}/apache/apr
|
|
||||||
make -j${cpuCore} && make install
|
|
||||||
if [ "$?" = "0" ];then
|
|
||||||
# 检查 APR-util 配置文件
|
|
||||||
APU_CONFIG=$(find ${serverPath}/apache/apr-util -name "apu-*config" | head -1)
|
|
||||||
if [ -z "$APU_CONFIG" ];then
|
|
||||||
echo "APR-util installation failed: apu-config not found"
|
|
||||||
find ${serverPath}/apache/apr-util -name "apu-*config"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "APR-util installed successfully: $APU_CONFIG"
|
|
||||||
else
|
|
||||||
echo "APR-util configure failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f ${apacheDir}/httpd-${VERSION}.tar.bz2 ];then
|
|
||||||
wget --no-check-certificate -O ${apacheDir}/httpd-${VERSION}.tar.bz2 https://downloads.apache.org/httpd/httpd-${VERSION}.tar.bz2 -T 3
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d ${apacheDir}/httpd-${VERSION} ];then
|
|
||||||
cd ${apacheDir} && tar -jxf ${apacheDir}/httpd-${VERSION}.tar.bz2
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# 检查 APR 和 APR-util 可执行文件
|
|
||||||
APR_CONFIG=$(find ${serverPath}/apache/apr -name "apr-*config" | head -1)
|
|
||||||
APU_CONFIG=$(find ${serverPath}/apache/apr-util -name "apu-*config" | head -1)
|
|
||||||
|
|
||||||
if [ -z "$APR_CONFIG" ];then
|
|
||||||
echo "APR config not found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$APU_CONFIG" ];then
|
|
||||||
echo "APR-util config not found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
OPTIONS="${OPTIONS} --with-apr=$APR_CONFIG"
|
|
||||||
OPTIONS="${OPTIONS} --with-apr-util=$APU_CONFIG"
|
|
||||||
|
|
||||||
# if [ "$sysName" != "Darwin" ];then
|
|
||||||
# OPTIONS="${OPTIONS} --enable-systemd"
|
|
||||||
# fi
|
|
||||||
# echo "cd ${apacheDir}/httpd-${VERSION} && ./configure --prefix=$serverPath/apache $OPTIONS"
|
|
||||||
cd ${apacheDir}/httpd-${VERSION} && ./configure \
|
|
||||||
--prefix=$serverPath/apache/httpd \
|
|
||||||
$OPTIONS
|
|
||||||
|
|
||||||
make -j${cpuCore} && make install && make clean
|
|
||||||
|
|
||||||
|
|
||||||
if [ -d ${apacheDir}/apr-${APR_VERSION} ];then
|
|
||||||
rm -rf ${apacheDir}/apr-${APR_VERSION}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d ${apacheDir}/apr-util-${APR_UTIL_VERSION} ];then
|
|
||||||
rm -rf ${apacheDir}/apr-util-${APR_UTIL_VERSION}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d ${apacheDir}/httpd-${APR_UTIL_VERSION} ];then
|
|
||||||
rm -rf ${apacheDir}/httpd-${APR_UTIL_VERSION}
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo 'installation of apache completed'
|
|
||||||
}
|
|
||||||
|
|
||||||
Uninstall_App()
|
|
||||||
{
|
|
||||||
echo 'uninstalling apache completed'
|
|
||||||
}
|
|
||||||
|
|
||||||
action=$1
|
|
||||||
if [ "${1}" = "install" ];then
|
|
||||||
Install_App
|
|
||||||
elif [ "${1}" = "upgrade" ];then
|
|
||||||
Install_App
|
|
||||||
else
|
|
||||||
Uninstall_App
|
|
||||||
fi
|
|
||||||
@@ -1,424 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
'''
|
|
||||||
doc: https://docs.python.org/zh-cn/3/library/ftplib.html
|
|
||||||
'''
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
|
|
||||||
import paramiko
|
|
||||||
import ftplib
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
|
|
||||||
DEBUG = True
|
|
||||||
BLOCK_SIZE = 1024 * 1024 * 2
|
|
||||||
# BLOCK_SIZE = 50
|
|
||||||
PROGRESS_FILE_NAME = "PROGRESS_FILE_NAME"
|
|
||||||
|
|
||||||
"""
|
|
||||||
=============自定义异常===================
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class OsError(Exception):
|
|
||||||
"""OS端异常"""
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectNotFound(OsError):
|
|
||||||
"""对象不存在时抛出的异常"""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
message = "文件对象不存在。"
|
|
||||||
super(ObjectNotFound, self).__init__(message, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class APIError(Exception):
|
|
||||||
"""API参数错误异常"""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
_api_error_msg = 'API资料校验失败,请核实!'
|
|
||||||
super(APIError, self).__init__(_api_error_msg, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class FtpPSClient:
|
|
||||||
_title = "FTP"
|
|
||||||
_name = "ftp"
|
|
||||||
__host = None
|
|
||||||
__port = None
|
|
||||||
__user = None
|
|
||||||
__password = None
|
|
||||||
default_port = 21
|
|
||||||
default_backup_path = "/backup/"
|
|
||||||
config_file = "cfg.json"
|
|
||||||
|
|
||||||
def __init__(self, load_config=True, timeout=600):
|
|
||||||
self.timeout = timeout
|
|
||||||
if load_config:
|
|
||||||
data = self.get_config()
|
|
||||||
self.injection_config(data)
|
|
||||||
|
|
||||||
def get_config(self):
|
|
||||||
default_config = {
|
|
||||||
"ftp_host": '',
|
|
||||||
"ftp_user": '',
|
|
||||||
"ftp_pass": '',
|
|
||||||
"backup_path": self.default_backup_path
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg = mw.getServerDir() + "/backup_ftp/" + self.config_file
|
|
||||||
if os.path.exists(cfg):
|
|
||||||
data = mw.readFile(cfg)
|
|
||||||
return json.loads(data)
|
|
||||||
else:
|
|
||||||
return default_config
|
|
||||||
|
|
||||||
def injection_config(self, data):
|
|
||||||
self.__host = host = data["ftp_host"].strip()
|
|
||||||
if host.find(':') == -1:
|
|
||||||
self.__port = self.default_port
|
|
||||||
else:
|
|
||||||
self.__host = host.split(':')[0]
|
|
||||||
self.__port = host.split(':')[1]
|
|
||||||
|
|
||||||
self.__user = data['ftp_user'].strip()
|
|
||||||
self.__password = data['ftp_pass'].strip()
|
|
||||||
bp = data['backup_path'].strip()
|
|
||||||
if bp:
|
|
||||||
self.backup_path = self.getPath(bp)
|
|
||||||
else:
|
|
||||||
self.backup_path = self.getPath(self.default_backup_path)
|
|
||||||
|
|
||||||
def authorize(self):
|
|
||||||
try:
|
|
||||||
if self.timeout is not None:
|
|
||||||
ftp = ftplib.FTP(timeout=self.timeout)
|
|
||||||
else:
|
|
||||||
ftp = ftplib.FTP()
|
|
||||||
|
|
||||||
debuglevel = 0
|
|
||||||
# if DEBUG:
|
|
||||||
# debuglevel = 3
|
|
||||||
ftp.set_debuglevel(debuglevel)
|
|
||||||
# ftp.set_pasv(True)
|
|
||||||
ftp.connect(self.__host, int(self.__port))
|
|
||||||
ftp.login(self.__user, self.__password)
|
|
||||||
return ftp
|
|
||||||
except Exception as e:
|
|
||||||
raise OsError("无法连接FTP客户端,请检查配置参数是否正确!")
|
|
||||||
|
|
||||||
# 取目录路径
|
|
||||||
def getPath(self, path):
|
|
||||||
if path[-1:] != '/':
|
|
||||||
path += '/'
|
|
||||||
if path[:1] != '/':
|
|
||||||
path = '/' + path
|
|
||||||
return path.replace('//', '/')
|
|
||||||
|
|
||||||
def generateDownloadUrl(self, object_name):
|
|
||||||
|
|
||||||
return 'ftp://' + \
|
|
||||||
self.__user + ':' + \
|
|
||||||
self.__password + '@' + \
|
|
||||||
self.__host + ':' + \
|
|
||||||
"/" + object_name
|
|
||||||
|
|
||||||
def buildDirName(self, data_type, file_name):
|
|
||||||
import re
|
|
||||||
prefix_dict = {
|
|
||||||
"site": "web",
|
|
||||||
"database": "db",
|
|
||||||
"path": "path",
|
|
||||||
}
|
|
||||||
file_regx = prefix_dict.get(data_type) + r"_(.+)_20\d+_\d+\."
|
|
||||||
sub_search = re.search(file_regx, file_name)
|
|
||||||
sub_path_name = ""
|
|
||||||
if sub_search:
|
|
||||||
sub_path_name = sub_search.groups()[0]
|
|
||||||
sub_path_name += '/'
|
|
||||||
|
|
||||||
# 构建OS存储路径
|
|
||||||
object_name = self.backup_path + \
|
|
||||||
data_type + '/' + \
|
|
||||||
sub_path_name + \
|
|
||||||
file_name
|
|
||||||
return object_name
|
|
||||||
|
|
||||||
def uploadFile(self, filename, data_type=None, *args, **kwargs):
|
|
||||||
|
|
||||||
client = self.authorize()
|
|
||||||
|
|
||||||
local_file_name = filename
|
|
||||||
filename = os.path.abspath(filename)
|
|
||||||
dirname = os.path.dirname(filename)
|
|
||||||
temp_name = os.path.split(filename)[1]
|
|
||||||
|
|
||||||
object_name = self.buildDirName(data_type, temp_name)
|
|
||||||
|
|
||||||
upload_tmp_dir = os.path.join(dirname, ".upload_tmp")
|
|
||||||
if not os.path.exists(upload_tmp_dir):
|
|
||||||
os.mkdir(upload_tmp_dir)
|
|
||||||
|
|
||||||
print("|-正在上传文件到 {}".format(object_name))
|
|
||||||
|
|
||||||
total_bytes = os.path.getsize(filename)
|
|
||||||
object_md5_name = mw.md5(object_name)
|
|
||||||
pg_file = os.path.join(upload_tmp_dir, object_md5_name + ".pl")
|
|
||||||
|
|
||||||
block_size = BLOCK_SIZE
|
|
||||||
if kwargs.get("block_size"):
|
|
||||||
try:
|
|
||||||
block_size = float(kwargs.get("block_size"))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
remote_file_size = None
|
|
||||||
if not os.path.exists(pg_file):
|
|
||||||
# import uuid
|
|
||||||
# uid = str(uuid.uuid1())
|
|
||||||
progress_info = {
|
|
||||||
"filename": local_file_name,
|
|
||||||
"total_bytes": total_bytes,
|
|
||||||
"uploaded_bytes": 0,
|
|
||||||
}
|
|
||||||
mw.writeFile(pg_file, json.dumps(progress_info))
|
|
||||||
else:
|
|
||||||
progress_info = json.loads(mw.readFile(pg_file))
|
|
||||||
if total_bytes == progress_info.get("total_bytes"):
|
|
||||||
# 取远程文件大小
|
|
||||||
_max_loop = 10
|
|
||||||
while _max_loop > 0:
|
|
||||||
try:
|
|
||||||
time.sleep(1)
|
|
||||||
remote_file_size = client.size(object_name)
|
|
||||||
if remote_file_size > total_bytes:
|
|
||||||
remote_file_size = None
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
if DEBUG:
|
|
||||||
print(type(e))
|
|
||||||
print(e)
|
|
||||||
_max_loop -= 1
|
|
||||||
else:
|
|
||||||
remote_file_size = None
|
|
||||||
|
|
||||||
uploaded_bytes = 0 if remote_file_size is None else remote_file_size
|
|
||||||
|
|
||||||
dir_name = os.path.split(object_name)[0]
|
|
||||||
if dir_name:
|
|
||||||
self.createDirP(dir_name)
|
|
||||||
|
|
||||||
upload_start = time.time()
|
|
||||||
|
|
||||||
try:
|
|
||||||
if total_bytes > 1024 * 1024 * 1024:
|
|
||||||
with open(local_file_name, 'rb') as file_handler:
|
|
||||||
if remote_file_size is not None:
|
|
||||||
file_handler.seek(remote_file_size)
|
|
||||||
|
|
||||||
client.voidcmd("TYPE I")
|
|
||||||
datasock = ''
|
|
||||||
esize = ''
|
|
||||||
|
|
||||||
datasock, esize = client.ntransfercmd(
|
|
||||||
"STOR " + object_name, remote_file_size)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
buf = file_handler.read(block_size)
|
|
||||||
if not len(buf):
|
|
||||||
break
|
|
||||||
datasock.sendall(buf)
|
|
||||||
uploaded_bytes += len(buf)
|
|
||||||
if DEBUG:
|
|
||||||
print('\ruploading %.2f%%' %
|
|
||||||
(float(uploaded_bytes) / total_bytes * 100))
|
|
||||||
|
|
||||||
print("uploaded_bytes", uploaded_bytes)
|
|
||||||
if uploaded_bytes == total_bytes:
|
|
||||||
break
|
|
||||||
datasock.close()
|
|
||||||
|
|
||||||
if DEBUG:
|
|
||||||
print('close data handle')
|
|
||||||
try:
|
|
||||||
client.voidcmd('NOOP')
|
|
||||||
except Exception as e:
|
|
||||||
if DEBUG:
|
|
||||||
print("Send NOOP command error:")
|
|
||||||
print(e)
|
|
||||||
else:
|
|
||||||
if DEBUG:
|
|
||||||
print('keep alive cmd success')
|
|
||||||
client.voidresp()
|
|
||||||
if DEBUG:
|
|
||||||
print('No loop cmd')
|
|
||||||
else:
|
|
||||||
# 小于1G文件直接上传
|
|
||||||
file_handler = open(local_file_name, "rb")
|
|
||||||
client.storbinary('STOR %s' % object_name,
|
|
||||||
file_handler, blocksize=block_size)
|
|
||||||
file_handler.close()
|
|
||||||
except Exception as e:
|
|
||||||
print(str(e))
|
|
||||||
|
|
||||||
completed_file_size = None
|
|
||||||
_max_loop = 10
|
|
||||||
while _max_loop > 0:
|
|
||||||
try:
|
|
||||||
time.sleep(1)
|
|
||||||
completed_file_size = client.size(object_name)
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
_max_loop -= 1
|
|
||||||
if DEBUG:
|
|
||||||
print("size error:" + str(e))
|
|
||||||
|
|
||||||
# 上传完成
|
|
||||||
if completed_file_size == total_bytes:
|
|
||||||
if DEBUG:
|
|
||||||
upload_completed = time.time()
|
|
||||||
upload_diff = upload_completed - upload_start
|
|
||||||
print("文件上传成功, 耗时: {}s。".format(upload_diff))
|
|
||||||
if os.path.exists(pg_file):
|
|
||||||
os.remove(pg_file)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
if os.path.exists(pg_file):
|
|
||||||
os.remove(pg_file)
|
|
||||||
print("文件上传后大小不一致!")
|
|
||||||
|
|
||||||
print("completed_file_size:" + str(completed_file_size))
|
|
||||||
print("total_bytes:", total_bytes)
|
|
||||||
print("object_md5_name:", object_md5_name)
|
|
||||||
print("pg_file:", pg_file)
|
|
||||||
print("filename:", filename)
|
|
||||||
print("dirname:", dirname)
|
|
||||||
print("object_name:", object_name)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def createDirP(self, dir_name):
|
|
||||||
"""创建远程目录
|
|
||||||
|
|
||||||
:param dir_name: 目录名称
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
dirnames = dir_name.split('/')
|
|
||||||
ftp = self.authorize()
|
|
||||||
# ftp.cwd(get.path);
|
|
||||||
for dirname in dirnames:
|
|
||||||
if not dirname or not dirname.strip():
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
flist = ftp.nlst()
|
|
||||||
if not dirname in flist:
|
|
||||||
ftp.mkd(dirname)
|
|
||||||
except:
|
|
||||||
# print("mlsd mode.")
|
|
||||||
try:
|
|
||||||
flist = list(ftp.mlsd())[1:]
|
|
||||||
for f in flist:
|
|
||||||
if dirname == f[0]:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
ftp.mkd(dirname)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
ftp.cwd(dirname)
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def createDir(self, path, name):
|
|
||||||
ftp = self.authorize()
|
|
||||||
path = self.getPath(path)
|
|
||||||
ftp.cwd(path)
|
|
||||||
try:
|
|
||||||
ftp.mkd(name)
|
|
||||||
ftp.close()
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(str(e))
|
|
||||||
ftp.close()
|
|
||||||
return False
|
|
||||||
|
|
||||||
def deleteDir(self, path, dir_name):
|
|
||||||
try:
|
|
||||||
ftp = self.authorize()
|
|
||||||
ftp.rmd(dir_name)
|
|
||||||
return True
|
|
||||||
except ftplib.error_perm as e:
|
|
||||||
print("deleteDir:" + str(e) + ":" + dir_name)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def deleteFile(self, filename):
|
|
||||||
try:
|
|
||||||
ftp = self.authorize()
|
|
||||||
ftp.delete(filename)
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(str(e))
|
|
||||||
return False
|
|
||||||
|
|
||||||
def getList(self, path="/"):
|
|
||||||
ftp = self.authorize()
|
|
||||||
path = self.getPath(path)
|
|
||||||
ftp.cwd(path)
|
|
||||||
mlsd = False
|
|
||||||
try:
|
|
||||||
files = list(ftp.mlsd())
|
|
||||||
mlsd = True
|
|
||||||
except:
|
|
||||||
try:
|
|
||||||
files = ftp.nlst(path)
|
|
||||||
mlsd = False
|
|
||||||
except:
|
|
||||||
raise RuntimeError("FTP服务器数据返回异常!")
|
|
||||||
ftp.close()
|
|
||||||
# print(files)
|
|
||||||
f_list = []
|
|
||||||
dirs = []
|
|
||||||
data = []
|
|
||||||
default_time = '1971/01/01 01:01:01'
|
|
||||||
for dt in files:
|
|
||||||
# print(dt)
|
|
||||||
if mlsd:
|
|
||||||
dt_name = dt[0]
|
|
||||||
dt_info = dt[1]
|
|
||||||
else:
|
|
||||||
if dt.find("/") >= 0:
|
|
||||||
dt = dt.split("/")[-1]
|
|
||||||
tmp = {}
|
|
||||||
tmp['name'] = dt_name
|
|
||||||
if dt_name == '.' or dt_name == '..':
|
|
||||||
continue
|
|
||||||
|
|
||||||
tmp['time'] = dt_info['modify']
|
|
||||||
try:
|
|
||||||
tmp['size'] = dt_info['size']
|
|
||||||
tmp['type'] = "File"
|
|
||||||
tmp['download'] = self.generateDownloadUrl(path + dt_name)
|
|
||||||
f_list.append(tmp)
|
|
||||||
except:
|
|
||||||
tmp['size'] = dt_info['sizd']
|
|
||||||
tmp['type'] = None
|
|
||||||
tmp['download'] = ''
|
|
||||||
dirs.append(tmp)
|
|
||||||
data = dirs + f_list
|
|
||||||
|
|
||||||
mlist = {}
|
|
||||||
mlist['path'] = path
|
|
||||||
mlist['list'] = data
|
|
||||||
return mlist
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,101 +0,0 @@
|
|||||||
<style>
|
|
||||||
.upyunCon {
|
|
||||||
height: 428px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.up-place {
|
|
||||||
height: 62px;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.up-place .btn {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.up-place .place-input {
|
|
||||||
background-color: #f3f3f3;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
height: 30px;
|
|
||||||
line-height: 28px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 1px 0 0 -1px;
|
|
||||||
width: 340px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.place-input ul {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.place-input ul li {
|
|
||||||
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
|
|
||||||
float: left;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.place-input ul li a {
|
|
||||||
height: 28px;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upyunlist {
|
|
||||||
height: 516px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.up-bottom {
|
|
||||||
background-color: #fafafa;
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
bottom: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.up-use {
|
|
||||||
line-height: 50px
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-list .cursor span {
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-title {
|
|
||||||
margin-top: 1px
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip {
|
|
||||||
font-size: 10px;
|
|
||||||
font-style: oblique;
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="upyunCon">
|
|
||||||
<div class="up-place pd15">
|
|
||||||
<button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退"></button>
|
|
||||||
<input id="myPath" style="display:none;" type="text" value="">
|
|
||||||
<div class="place-input pull-left">
|
|
||||||
<div style="width:1400px;height:28px"><ul></ul></div>
|
|
||||||
</div>
|
|
||||||
<button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" style="margin-left:-1px;"></button>
|
|
||||||
<button class="btn btn-default btn-sm pull-right btn-title" onclick="upyunApi()">帐户设置</button>
|
|
||||||
<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="createDir()">新建文件夹</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="upyunlist pd15">
|
|
||||||
<div class="divtable" style="margin-bottom:15px">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>
|
|
||||||
<tbody class="list-list"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$.getScript( "/plugins/file?name=backup_ftp&f=js/backup_ftp.js", function(){
|
|
||||||
osList('/');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,311 +0,0 @@
|
|||||||
# coding:utf-8
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
|
|
||||||
# print(sys.platform)
|
|
||||||
if sys.platform != "darwin":
|
|
||||||
os.chdir("/www/server/mdserver-web")
|
|
||||||
|
|
||||||
|
|
||||||
web_dir = os.getcwd() + "/web"
|
|
||||||
if os.path.exists(web_dir):
|
|
||||||
sys.path.append(web_dir)
|
|
||||||
os.chdir(web_dir)
|
|
||||||
|
|
||||||
import core.mw as mw
|
|
||||||
import core.db as db
|
|
||||||
|
|
||||||
app_debug = False
|
|
||||||
if mw.isAppleSystem():
|
|
||||||
app_debug = True
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginName():
|
|
||||||
return 'backup_ftp'
|
|
||||||
|
|
||||||
|
|
||||||
def getPluginDir():
|
|
||||||
return mw.getPluginDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
sys.path.append(getPluginDir() + "/class")
|
|
||||||
from ftp_client import FtpPSClient
|
|
||||||
|
|
||||||
|
|
||||||
def getServerDir():
|
|
||||||
return mw.getServerDir() + '/' + getPluginName()
|
|
||||||
|
|
||||||
|
|
||||||
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(':', 1)
|
|
||||||
tmp[t[0]] = t[1]
|
|
||||||
return tmp
|
|
||||||
|
|
||||||
|
|
||||||
def checkArgs(data, ck=[]):
|
|
||||||
for i in range(len(ck)):
|
|
||||||
if not ck[i] in data:
|
|
||||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
|
||||||
return (True, mw.returnJson(True, 'ok'))
|
|
||||||
|
|
||||||
|
|
||||||
def status():
|
|
||||||
return 'start'
|
|
||||||
|
|
||||||
|
|
||||||
def getConf():
|
|
||||||
cfg = getServerDir() + "/cfg.json"
|
|
||||||
if not os.path.exists(cfg):
|
|
||||||
rdata = {
|
|
||||||
'use_sftp':False,
|
|
||||||
}
|
|
||||||
return mw.returnJson(False, "未配置", rdata)
|
|
||||||
data = mw.readFile(cfg)
|
|
||||||
data = json.loads(data)
|
|
||||||
return mw.returnJson(True, "OK", data)
|
|
||||||
|
|
||||||
|
|
||||||
def setConf():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['use_sftp', 'ftp_user',
|
|
||||||
'ftp_pass', 'ftp_host', 'backup_path'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
cfg = getServerDir() + "/cfg.json"
|
|
||||||
|
|
||||||
values = ['ftp_user',
|
|
||||||
'ftp_pass',
|
|
||||||
'ftp_host']
|
|
||||||
for v in values:
|
|
||||||
if args[v] == '':
|
|
||||||
return mw.returnJson(False, '必填资料不能为空,请核实!', [])
|
|
||||||
|
|
||||||
if args['backup_path'] == '':
|
|
||||||
args['backup_path'] = "/backup"
|
|
||||||
|
|
||||||
try:
|
|
||||||
ftp = FtpPSClient(load_config=False)
|
|
||||||
ftp.injection_config(args)
|
|
||||||
data = ftp.getList("/")
|
|
||||||
if data:
|
|
||||||
mw.writeFile(cfg, mw.getJson(args))
|
|
||||||
return mw.returnJson(True, '设置成功', [])
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, "FTP校验失败,请核实!\n" + str(e), [])
|
|
||||||
|
|
||||||
|
|
||||||
def getList():
|
|
||||||
cfg = getServerDir() + "/cfg.json"
|
|
||||||
if not os.path.exists(cfg):
|
|
||||||
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
|
|
||||||
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['path'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
try:
|
|
||||||
ftp = FtpPSClient()
|
|
||||||
flist = ftp.getList(args['path'])
|
|
||||||
return mw.returnJson(True, "ok", flist)
|
|
||||||
except Exception as e:
|
|
||||||
return mw.returnJson(False, str(e), [])
|
|
||||||
|
|
||||||
|
|
||||||
def createDir():
|
|
||||||
cfg = getServerDir() + "/cfg.json"
|
|
||||||
if not os.path.exists(cfg):
|
|
||||||
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
|
|
||||||
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['path', 'name'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
ftp = FtpPSClient()
|
|
||||||
isok = ftp.createDir(args['path'], args['name'])
|
|
||||||
if isok:
|
|
||||||
return mw.returnJson(True, "创建成功")
|
|
||||||
return mw.returnJson(False, "创建失败")
|
|
||||||
|
|
||||||
|
|
||||||
def deleteDir():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['dir_name', 'path'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
ftp = FtpPSClient()
|
|
||||||
isok = ftp.deleteDir(args['path'], args['dir_name'])
|
|
||||||
if isok:
|
|
||||||
return mw.returnJson(True, "删除成功")
|
|
||||||
return mw.returnJson(False, "删除失败")
|
|
||||||
|
|
||||||
|
|
||||||
def deleteFile():
|
|
||||||
args = getArgs()
|
|
||||||
data = checkArgs(args, ['path', 'filename'])
|
|
||||||
if not data[0]:
|
|
||||||
return data[1]
|
|
||||||
|
|
||||||
ftp = FtpPSClient()
|
|
||||||
isok = ftp.deleteFile(args['path'] + "/" + args['filename'])
|
|
||||||
if isok:
|
|
||||||
return mw.returnJson(True, "删除成功")
|
|
||||||
return mw.returnJson(False, "删除失败")
|
|
||||||
|
|
||||||
def findPathName(path, filename):
|
|
||||||
f = os.scandir(path)
|
|
||||||
l = []
|
|
||||||
for ff in f:
|
|
||||||
t = {}
|
|
||||||
if ff.name.find(filename) > -1:
|
|
||||||
t['filename'] = path + '/' + ff.name
|
|
||||||
l.append(t)
|
|
||||||
return l
|
|
||||||
|
|
||||||
def backupAllFunc(stype):
|
|
||||||
|
|
||||||
name = sys.argv[2]
|
|
||||||
num = sys.argv[3]
|
|
||||||
|
|
||||||
prefix_dict = {
|
|
||||||
"site": "web",
|
|
||||||
"database": "db",
|
|
||||||
"path": "path",
|
|
||||||
}
|
|
||||||
|
|
||||||
backups = []
|
|
||||||
# print("stype:", stype)
|
|
||||||
# 提前获取-清理多余备份
|
|
||||||
if stype == 'site':
|
|
||||||
pid = mw.M('sites').where('name=?', (name,)).getField('id')
|
|
||||||
backups = mw.M('backup').where('type=? and pid=?', ('0', pid)).field('id,filename').select()
|
|
||||||
if stype == 'database':
|
|
||||||
db_path = mw.getServerDir() + '/mysql'
|
|
||||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where('name=?', (name,)).getField('id')
|
|
||||||
backups = mw.M('backup').where('type=? and pid=?', ('1', pid)).field('id,filename').select()
|
|
||||||
if stype == 'path':
|
|
||||||
backup_dir = mw.getBackupDir()
|
|
||||||
backup_path = backup_dir + '/path'
|
|
||||||
_name = 'path_{}'.format(os.path.basename(name))
|
|
||||||
backups = findPathName(backup_path, _name)
|
|
||||||
|
|
||||||
# 其他类型关系性数据库(mysql类的)
|
|
||||||
if stype.find('database_') > -1:
|
|
||||||
plugin_name = stype.replace('database_', '')
|
|
||||||
db_path = mw.getServerDir() + '/' + plugin_name
|
|
||||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where('name=?', (name,)).getField('id')
|
|
||||||
backups = mw.M('backup').where('type=? and pid=?', ('1', pid)).field('id,filename').select()
|
|
||||||
|
|
||||||
args = stype + " " + name + " " + num
|
|
||||||
cmd = 'python3 ' + mw.getPanelDir() + '/scripts/backup.py ' + args
|
|
||||||
if stype.find('database_') > -1:
|
|
||||||
plugin_name = stype.replace('database_', '')
|
|
||||||
args = "database " + name + " " + num
|
|
||||||
cmd = 'python3 ' + mw.getPanelDir() + '/plugins/' + plugin_name + '/scripts/backup.py ' + args
|
|
||||||
|
|
||||||
os.system(cmd)
|
|
||||||
|
|
||||||
# 开始执行上传信息.
|
|
||||||
|
|
||||||
if stype.find('database_') > -1:
|
|
||||||
bk_name = 'database'
|
|
||||||
plugin_name = stype.replace('database_', '')
|
|
||||||
bk_prefix = plugin_name + '/db'
|
|
||||||
stype = 'database'
|
|
||||||
else:
|
|
||||||
bk_prefix = prefix_dict[stype]
|
|
||||||
bk_name = stype
|
|
||||||
|
|
||||||
find_path = mw.getBackupDir() + '/' + bk_name + '/' + bk_prefix + '_' + name
|
|
||||||
if stype == 'path':
|
|
||||||
_name = 'path_{}'.format(os.path.basename(name))
|
|
||||||
find_path = mw.getBackupDir() + '/path/'+_name
|
|
||||||
|
|
||||||
find_new_file = "ls " + find_path + "_* | grep '.gz' | cut -d \\ -f 1 | awk 'END {print}'"
|
|
||||||
|
|
||||||
filename = mw.execShell(find_new_file)[0].strip()
|
|
||||||
if filename == "":
|
|
||||||
mw.echoInfo("not find upload file!")
|
|
||||||
return ''
|
|
||||||
|
|
||||||
mw.echoInfo("准备上传文件 {}".format(filename))
|
|
||||||
ftp = FtpPSClient()
|
|
||||||
ftp.uploadFile(filename, stype)
|
|
||||||
|
|
||||||
# print(backups)
|
|
||||||
backups = sorted(backups, key=lambda x: x['filename'], reverse=False)
|
|
||||||
mw.echoStart('开始删除远程备份')
|
|
||||||
num = int(num)
|
|
||||||
sep = len(backups) - num
|
|
||||||
if sep > -1:
|
|
||||||
for backup in backups:
|
|
||||||
fn = os.path.basename(backup['filename'])
|
|
||||||
object_name = ftp.buildDirName(stype, fn)
|
|
||||||
ftp.deleteFile(object_name)
|
|
||||||
mw.echoInfo("已清理远程过期备份文件:" + object_name)
|
|
||||||
sep -= 1
|
|
||||||
if sep < 0:
|
|
||||||
break
|
|
||||||
mw.echoEnd('结束删除远程备份')
|
|
||||||
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
def in_array(name, arr=[]):
|
|
||||||
for x in arr:
|
|
||||||
if name == x:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def installPreInspection():
|
|
||||||
return 'ok'
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
func = sys.argv[1]
|
|
||||||
if func == 'status':
|
|
||||||
print(status())
|
|
||||||
elif func == 'start':
|
|
||||||
print(start())
|
|
||||||
elif func == 'stop':
|
|
||||||
print(stop())
|
|
||||||
elif func == 'restart':
|
|
||||||
print(restart())
|
|
||||||
elif func == 'reload':
|
|
||||||
print(reload())
|
|
||||||
elif func == 'install_pre_inspection':
|
|
||||||
print(installPreInspection())
|
|
||||||
elif func == 'conf':
|
|
||||||
print(getConf())
|
|
||||||
elif func == 'set_config':
|
|
||||||
print(setConf())
|
|
||||||
elif func == "get_list":
|
|
||||||
print(getList())
|
|
||||||
elif func == "create_dir":
|
|
||||||
print(createDir())
|
|
||||||
elif func == "delete_dir":
|
|
||||||
print(deleteDir())
|
|
||||||
elif func == 'delete_file':
|
|
||||||
print(deleteFile())
|
|
||||||
elif in_array(func, ['site', 'database', 'path']) or func.find('database_') > -1:
|
|
||||||
print(backupAllFunc(func))
|
|
||||||
else:
|
|
||||||
print('error')
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"sort":6,
|
|
||||||
"title":"FTP存储空间",
|
|
||||||
"hook":["backup"],
|
|
||||||
"tip":"soft",
|
|
||||||
"name":"backup_ftp",
|
|
||||||
"type":"运行环境",
|
|
||||||
"ps":"将网站或数据库打包备份到FTP存储空间",
|
|
||||||
"versions":["1.0"],
|
|
||||||
"install_pre_inspection":false,
|
|
||||||
"shell":"install.sh",
|
|
||||||
"checks":"server/backup_ftp",
|
|
||||||
"path": "server/backup_ftp",
|
|
||||||
"author":"midoks",
|
|
||||||
"home":"https://github.com/midoks/mdserver-web",
|
|
||||||
"date":"2022-10-23",
|
|
||||||
"pid": "5"
|
|
||||||
}
|
|
||||||
@@ -1,31 +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")
|
|
||||||
|
|
||||||
sys_os=`uname`
|
|
||||||
|
|
||||||
|
|
||||||
Install_App()
|
|
||||||
{
|
|
||||||
mkdir -p ${serverPath}/backup_ftp
|
|
||||||
echo "${1}" > ${serverPath}/backup_ftp/version.pl
|
|
||||||
echo '安装完成'
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Uninstall_App()
|
|
||||||
{
|
|
||||||
rm -rf ${serverPath}/backup_ftp
|
|
||||||
}
|
|
||||||
|
|
||||||
action=$1
|
|
||||||
if [ "${1}" = 'install' ];then
|
|
||||||
Install_App $2
|
|
||||||
else
|
|
||||||
Uninstall_App $2
|
|
||||||
fi
|
|
||||||
@@ -1,258 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
function bkfPost(method,args,callback){
|
|
||||||
var _args = null;
|
|
||||||
if (typeof(args) == 'string'){
|
|
||||||
_args = JSON.stringify(toArrayObject(args));
|
|
||||||
} else {
|
|
||||||
_args = JSON.stringify(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
|
||||||
$.post('/plugins/run', {name:'backup_ftp', 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 getFtpLocalTime(data){
|
|
||||||
var str = data.slice(0,4)+"/"+data.slice(4,6)+"/"+data.slice(6,8)
|
|
||||||
+ " " + data.slice(8,10)+":"+data.slice(10,12)+":"+data.slice(12,14);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义部分
|
|
||||||
var i = null;
|
|
||||||
//设置API
|
|
||||||
function upyunApi(){
|
|
||||||
|
|
||||||
bkfPost('conf', {}, function(rdata){
|
|
||||||
var rdata = $.parseJSON(rdata.data);
|
|
||||||
var token = rdata.data;
|
|
||||||
var check_status = token.use_sftp;
|
|
||||||
var sftp_checked = check_status === "true" ? " checked=\"checked\"" : "";
|
|
||||||
|
|
||||||
if (typeof(token.ftp_host) == 'undefined'){
|
|
||||||
token.ftp_host = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(token.ftp_user) == 'undefined'){
|
|
||||||
token.ftp_user = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(token.ftp_pass) == 'undefined'){
|
|
||||||
token.ftp_pass = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(token.backup_path) == 'undefined'){
|
|
||||||
token.backup_path = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
var apicon = '<div class="bingfa mtb15" style="padding-bottom:0px;">\
|
|
||||||
<p>\
|
|
||||||
<span class="span_tit">使用SFTP:</span>\ <input style="width: 20px; vertical-align:middle;" type="checkbox" name="use_sftp"'+sftp_checked+'> 是否使用SFTP进行数据传输 \
|
|
||||||
</p>\
|
|
||||||
<p>\
|
|
||||||
<span class="span_tit">Host:</span>\
|
|
||||||
<input placeholder="请输入主机地址" style="width: 200px;" type="text" name="upyun_service" value="'+token.ftp_host+'"> *服务器地址,FTP默认端口21, SFTP默认端口22\
|
|
||||||
</p>\
|
|
||||||
<p>\
|
|
||||||
<span class="span_tit">用户名:</span>\
|
|
||||||
<input style="width: 200px;" type="text" name="ftp_username" value="'+token.ftp_user+'"> *指定用户名\
|
|
||||||
</p>\
|
|
||||||
<p>\
|
|
||||||
<span class="span_tit">密码:</span>\
|
|
||||||
<input style="width: 200px;" type="password" name="ftp_password" value="'+token.ftp_pass+'"> *登录密码\
|
|
||||||
</p>\
|
|
||||||
<p>\
|
|
||||||
<span class="span_tit">存储位置:</span>\
|
|
||||||
<input placeholder="请输入存储位置" style="width: 200px;" type="text" name="backup_path" value="'+token.backup_path+'"> *相对于根目录的路径,默认是/backup\
|
|
||||||
</p>\
|
|
||||||
</div>';
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
area: "600px",
|
|
||||||
title: "FTP/SFTP帐户设置",
|
|
||||||
closeBtn: 1,
|
|
||||||
shift: 5,
|
|
||||||
shadeClose: false,
|
|
||||||
btn: ['确定','取消'],
|
|
||||||
content:apicon,
|
|
||||||
yes:function(index,layero){
|
|
||||||
var data = {
|
|
||||||
use_sftp:$("input[name='use_sftp']").prop('checked'),
|
|
||||||
ftp_user:$("input[name='ftp_username']").val(),
|
|
||||||
ftp_pass:$("input[name='ftp_password']").val(),
|
|
||||||
ftp_host:$("input[name='upyun_service']").val(),
|
|
||||||
backup_path:$("input[name='backup_path']").val()
|
|
||||||
}
|
|
||||||
bkfPost('set_config', data, function(rdata){
|
|
||||||
var rdata = $.parseJSON(rdata.data);
|
|
||||||
if (rdata.status){
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
layer.close(index);
|
|
||||||
osList("/");
|
|
||||||
},{icon:1},2000);
|
|
||||||
} else{
|
|
||||||
layer.msg(rdata.msg,{icon:2});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createDir(){
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
area: "400px",
|
|
||||||
title: "创建目录",
|
|
||||||
closeBtn: 1,
|
|
||||||
shift: 5,
|
|
||||||
shadeClose: false,
|
|
||||||
btn: ['确定','取消'],
|
|
||||||
content:'<div class="bingfa bt-form c6" style="padding-bottom: 10px;">\
|
|
||||||
<p>\
|
|
||||||
<span class="span_tit">目录名称:</span>\
|
|
||||||
<input style="width: 200px;" type="text" name="newPath" value="">\
|
|
||||||
</p>\
|
|
||||||
</div>',
|
|
||||||
success:function(){
|
|
||||||
$("input[name='newPath']").focus().keyup(function(e){
|
|
||||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
yes:function(index,layero){
|
|
||||||
var name = $("input[name='newPath']").val();
|
|
||||||
if(name == ''){
|
|
||||||
layer.msg('目录名称不能为空!',{icon:2});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var path = $("#myPath").val();
|
|
||||||
var dirname = name;
|
|
||||||
// var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
|
|
||||||
bkfPost('create_dir', {path:path,name:dirname}, function(data){
|
|
||||||
var rdata = $.parseJSON(data.data);
|
|
||||||
if(rdata.status) {
|
|
||||||
showMsg(rdata.msg, function(){
|
|
||||||
layer.close(index);
|
|
||||||
osList(path);
|
|
||||||
} ,{icon:1}, 2000);
|
|
||||||
} else{
|
|
||||||
layer.msg(rdata.msg,{icon:2});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//删除文件
|
|
||||||
function deleteFile(name, is_dir){
|
|
||||||
if (is_dir === false){
|
|
||||||
safeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
|
||||||
var path = $("#myPath").val();
|
|
||||||
var filename = name;
|
|
||||||
bkfPost('delete_file', {filename:filename,path:path}, function(rdata){
|
|
||||||
var rdata = $.parseJSON(rdata.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
osList(path);
|
|
||||||
},{icon:rdata.status?1:2},2000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
safeMessage('删除文件夹','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
|
||||||
var path = $("#myPath").val();
|
|
||||||
bkfPost('delete_dir', {dir_name:name,path:path}, function(rdata){
|
|
||||||
var rdata = $.parseJSON(rdata.data);
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
osList(path);
|
|
||||||
},{icon:rdata.status?1:2},2000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function osList(path){
|
|
||||||
bkfPost('get_list', {path:path}, function(rdata){
|
|
||||||
|
|
||||||
var rdata = $.parseJSON(rdata.data);
|
|
||||||
if(rdata.status === false){
|
|
||||||
showMsg(rdata.msg,function(){
|
|
||||||
upyunApi();
|
|
||||||
},{icon:2},2000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mlist = rdata.data;
|
|
||||||
// console.log(mlist);
|
|
||||||
var listBody = ''
|
|
||||||
var listFiles = ''
|
|
||||||
for(var i=0;i<mlist.list.length;i++){
|
|
||||||
if(mlist.list[i].type == null){
|
|
||||||
listBody += '<tr><td class="cursor" onclick="osList(\''+(path+'/'+mlist.list[i].name).replace('//','/')+'\')"><span class="ico ico-folder"></span>\<span>'+mlist.list[i].name+'</span></td>\
|
|
||||||
<td>-</td>\
|
|
||||||
<td>-</td>\
|
|
||||||
<td class="text-right"><a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', true)">删除</a></td></tr>'
|
|
||||||
}else{
|
|
||||||
listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span>\<span>'+mlist.list[i].name+'</span></td>\
|
|
||||||
<td>'+toSize(mlist.list[i].size)+'</td>\
|
|
||||||
<td>'+getFtpLocalTime(mlist.list[i].time)+'</td>\
|
|
||||||
<td class="text-right"><a target="_blank" href="'+mlist.list[i].download+'" class="btlink">下载</a> | <a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', false)">删除</a></td></tr>'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listBody += listFiles;
|
|
||||||
|
|
||||||
var pathLi='';
|
|
||||||
var tmp = path.split('/')
|
|
||||||
var pathname = '';
|
|
||||||
var n = 0;
|
|
||||||
for(var i=0;i<tmp.length;i++){
|
|
||||||
if(n > 0 && tmp[i] == '') continue;
|
|
||||||
var dirname = tmp[i];
|
|
||||||
if(dirname == '') {
|
|
||||||
dirname = '根目录';
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
pathname += '/' + tmp[i];
|
|
||||||
pathname = pathname.replace('//','/');
|
|
||||||
pathLi += '<li><a title="'+pathname+'" onclick="osList(\''+pathname+'\')">'+dirname+'</a></li>';
|
|
||||||
}
|
|
||||||
var um = 1;
|
|
||||||
if(tmp[tmp.length-1] == '') um = 2;
|
|
||||||
var backPath = tmp.slice(0,tmp.length-um).join('/') || '/';
|
|
||||||
$('#myPath').val(path);
|
|
||||||
$(".upyunCon .place-input ul").html(pathLi);
|
|
||||||
$(".upyunlist .list-list").html(listBody);
|
|
||||||
|
|
||||||
upPathLeft();
|
|
||||||
|
|
||||||
$('#backBtn').unbind().click(function() {
|
|
||||||
osList(backPath);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.upyunCon .refreshBtn').unbind().click(function(){
|
|
||||||
osList(path);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//计算当前目录偏移
|
|
||||||
function upPathLeft(){
|
|
||||||
var UlWidth = $(".place-input ul").width();
|
|
||||||
var SpanPathWidth = $(".place-input").width() - 20;
|
|
||||||
var Ml = UlWidth - SpanPathWidth;
|
|
||||||
if(UlWidth > SpanPathWidth ){
|
|
||||||
$(".place-input ul").css("left",-Ml)
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$(".place-input ul").css("left",0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// $('.layui-layer-page').css('height','670px');
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
|
||||||
export PATH
|
|
||||||
|
|
||||||
# OpenResty服务名称
|
|
||||||
service_name="caddy"
|
|
||||||
|
|
||||||
# 检查OpenResty是否正在运行
|
|
||||||
if systemctl is-active --quiet "$service_name"; then
|
|
||||||
# 检查是否存在僵尸进程
|
|
||||||
zombie_processes=$(ps -ef | grep -i caddy | grep -v grep | awk '{print $2}' | xargs ps -o state= -p 2>/dev/null | grep -c Z)
|
|
||||||
if [ "$zombie_processes" -gt 0 ]; then
|
|
||||||
echo "kill caddy 僵尸进程"
|
|
||||||
ps -ef|grep caddy| grep -v grep| awk '{print $2}' | xargs kill -9
|
|
||||||
echo "检测到OpenResty僵尸进程,正在重启服务..."
|
|
||||||
systemctl restart "$service_name"
|
|
||||||
echo "服务已重启"
|
|
||||||
else
|
|
||||||
echo "OpenResty运行正常"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "kill caddy"
|
|
||||||
ps -ef|grep caddy| grep -v grep| awk '{print $2}' | xargs kill -9
|
|
||||||
echo "caddy未运行,正在启动服务..."
|
|
||||||
systemctl start "$service_name"
|
|
||||||
echo "服务已启动"
|
|
||||||
fi
|
|
||||||
|
|
||||||
NGINX_IDS=`ps -ef|grep caddy | grep -v grep| awk '{print $2}'`
|
|
||||||
if [ "$NGINX_IDS" = "" ];then
|
|
||||||
ps -ef|grep caddy| grep -v grep| awk '{print $2}' | xargs kill -9
|
|
||||||
systemctl start "$service_name"
|
|
||||||
echo "caddy未运行,正在启动服务..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
:8080 {
|
|
||||||
# Set this path to your site's directory.
|
|
||||||
root * /tmp
|
|
||||||
|
|
||||||
# Enable the static file server.
|
|
||||||
file_server
|
|
||||||
|
|
||||||
# Another common task is to set up a reverse proxy:
|
|
||||||
# reverse_proxy localhost:8080
|
|
||||||
|
|
||||||
# Or serve a PHP site through php-fpm:
|
|
||||||
# php_fastcgi localhost:9000
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user