mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-25 00:52:26 +02:00
v6.8.4
1. After the update, the software and panel directory permissions will be set to strict mode (it will be restored automatically after modification) 2. Increase the panel comprehensive anti-riot mechanism 3. Enhance the security of the panel session<br> 4. Enhanced panel entry verification mechanism 5. Optimize the terminal 6. Optimize the panel memory release mechanism Note 1: Version 6.8.2/6.9.11 has security issues, please be sure to upgrade to the latest version Note 2: After this update is successful, it will automatically log out and you need to log in again
This commit is contained in:
Generated
+14
@@ -9,6 +9,13 @@
|
||||
</mappings>
|
||||
</serverdata>
|
||||
</paths>
|
||||
<paths name="root@192.168.1.198:22 (1)">
|
||||
<serverdata>
|
||||
<mappings>
|
||||
<mapping local="$PROJECT_DIR$" web="/" />
|
||||
</mappings>
|
||||
</serverdata>
|
||||
</paths>
|
||||
<paths name="root@192.168.1.199:22">
|
||||
<serverdata>
|
||||
<mappings>
|
||||
@@ -16,6 +23,13 @@
|
||||
</mappings>
|
||||
</serverdata>
|
||||
</paths>
|
||||
<paths name="root@192.168.1.46:22">
|
||||
<serverdata>
|
||||
<mappings>
|
||||
<mapping local="$PROJECT_DIR$" web="/" />
|
||||
</mappings>
|
||||
</serverdata>
|
||||
</paths>
|
||||
</serverData>
|
||||
</component>
|
||||
</project>
|
||||
@@ -5,19 +5,22 @@
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: 黄文良 <287962566@qq.com>
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# +-------------------------------------------------------------------
|
||||
from gevent import monkey,__version__ as gevent_version
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
import os,sys,ssl
|
||||
if os.path.exists("/www/server/panel/class/BTPanel"):
|
||||
os.system("rm -rf /www/server/panel/class/BTPanel")
|
||||
os.chdir('/www/server/panel')
|
||||
if not 'class/' in sys.path:
|
||||
sys.path.insert(0,'class/')
|
||||
from BTPanel import app,sys,public
|
||||
|
||||
if __name__ == '__main__':
|
||||
pid = os.fork()
|
||||
if pid: sys.exit(0)
|
||||
|
||||
#os.umask(0)
|
||||
os.setsid()
|
||||
|
||||
_pid = os.fork()
|
||||
@@ -34,9 +37,6 @@ if __name__ == '__main__':
|
||||
if os.path.exists('data/ipv6.pl'):
|
||||
HOST = "0:0:0:0:0:0:0:0"
|
||||
f.close()
|
||||
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
|
||||
is_debug = os.path.exists('data/debug.pl')
|
||||
keyfile = 'ssl/privateKey.pem'
|
||||
@@ -50,11 +50,21 @@ if __name__ == '__main__':
|
||||
os.dup2(err_f.fileno(),sys.stderr.fileno())
|
||||
err_f.close()
|
||||
|
||||
import threading
|
||||
import jobs
|
||||
|
||||
job = threading.Thread(target=jobs.control_init)
|
||||
job.setDaemon(True)
|
||||
job.start()
|
||||
|
||||
if is_debug:
|
||||
ssl_context = None
|
||||
if is_ssl: ssl_context=(certfile,keyfile)
|
||||
app.run(host=HOST,port=PORT,threaded=True,debug=True,ssl_context=ssl_context)
|
||||
else:
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
|
||||
if is_ssl:
|
||||
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
ssl_context.load_cert_chain(certfile=certfile,keyfile=keyfile)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: 黄文良 <287962566@qq.com>
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
import os,sys
|
||||
|
||||
+833
-768
File diff suppressed because it is too large
Load Diff
+530
-1
@@ -960,6 +960,13 @@ html {
|
||||
.menu .menu_set:hover {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAKnAAACpwB9NLfEgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAF0SURBVDiNpdJNiM5RGAXw38ukkJVvMYqZRsqYZmyYDTZWbCxsKLG3pCSaWNmNJU2NmhU7pQjFRhYsJCTWykfJRz5eH8fmefn39lLy1FPn3nPv7Zzz3FYS/1Oz/sItwg3cwuo/HWp1KRjEQtzBTizAfHzCDMbwDk97PTCECXzBWyzGYXzDCXzGGjzHJB6DJJ3ekuRc4R1JNja4VUl2FZ5OsrXDNTO4jRcYx1W8wTEcx1xcwna0cbM7xGXYgxF8LakTuIbLZWVdWevHXixvWniY5ECSkVqfbGBJBpOcKjyc5FCSR90WXjXSnV1hdqqNVuH3eInvTQUDSfYnmUkylmRDkvNJ1icZSjJV+wNJriQ5WKr01avPqtfW3O/hNPaVmrO1N14qp35pa/jclORM4dHqDjevMdYLSTZ3uD6/q405mMYHjOJojewIluJHjfdj51L3Vx7GElzHbqzAXazERWzDazzoZaG7+5PcT/Kkwux5rlvBP9dPgIpDWf6ENxgAAAAASUVORK5CYII=")
|
||||
}
|
||||
.menu .menu_xterm {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAADaSURBVDiNrZO9FYJAEIQ/lAZICaEEDQ2xDrNNNaQEW3BSy9ASpAVKkBLO5EDQE/Fnknv7bmd29vY2cs4BICnjA5hZDRA555B0ARYj+Q2QPJy1mS3naZpmwH6EXAGlL7ABVsAO2FZVdYx7ifULgaRX4ODPrmDs7QCs277eQVICXAFmDxd7SWPtPGHmLXYaQDNBpOMMHPgWzhNFngW+QX8K7WcqgMTMSklFgNNwf/jBFAAMwMxKH59eCORBBz1iG0ch236MwJ/eoFXLJE3ldYs3dZlCqM0sj35d5xuDSFMDX6z07gAAAABJRU5ErkJggg==")
|
||||
}
|
||||
.menu .current .menu_xterm,
|
||||
.menu .menu_xterm:hover{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAACwSURBVDiNpZPRDYJADEAfhgVc4ViFFVzBGRjBGVxFR2AFHEFGeH5YkVwAj/iSpjR3fSmXtFIJEvt4AKCi9m7zXMi9Cmr60dyrJ3VQ28inOEuVmoBhGqmcBDSox48tfqckpp5DZr1EFHMAjrP6CowFkqknn+AB3Asli4Ld1FmdgJb3iF1854wRk2CcHZ4jd5FvK4JmbYIuq6sFAWw84m7qmW3PMn3vFi7TEoNK5Z/r/AIpZQNuvOKqnwAAAABJRU5ErkJggg==")
|
||||
}
|
||||
|
||||
.menu .menu_folder {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAE3SURBVDiNpZO9SgNBFIW/OySiaBCtbCwE8ReUgGDpE9gExNJmd6O+hM8gmGJn3yKxt7WyEARBUUSbIPhTGFAwxyarSwoZ2AO3mjkf98y9Y5IoI1fKDVQA0jRtOOd2B8BRST5Jkk4IwCSRZVkbOAYeACdpD3iX9DrUpQO+gHaz2XwuRnCSLuM4vpU0AnSAvplNmdlkocbNbN3MTrz3de/9WKVA/07TdN85twbcA5/A8AsLuAO6wI6k2UrhoGZmy3EcH4Zk995vAAd5hA9gBXgJMQ+0ZWanOaAH1IGrEGer1TJgxszOckAFWATOQwDVanUO6EVR9JYD5oGJJEmeAtvfBG7gb4xLwEWgGWA1v59PoQs8Zlm2ANg/RgETwLRz7voXIOnIzBrAdgCgBvgoivowWOUyKv0bfwCvBmEVd9ynHgAAAABJRU5ErkJggg==")
|
||||
@@ -4828,7 +4835,7 @@ select[disabled]{
|
||||
}
|
||||
|
||||
#db_tools button {
|
||||
margin-right: 10px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
#db_tools button:last-child{
|
||||
margin-right: 0;
|
||||
@@ -7234,3 +7241,525 @@ select[disabled]{
|
||||
}
|
||||
/*END*/
|
||||
|
||||
/* 终端管理页面 */
|
||||
|
||||
.pd25{
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.quick_links{
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
background-color: #fcfcfc;
|
||||
position: relative;
|
||||
margin-bottom: 15px;
|
||||
display: none;
|
||||
}
|
||||
.quick_links>span.glyphicon{
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 12px;
|
||||
color: #999;
|
||||
}
|
||||
.quick_links_title{
|
||||
height: 35px;
|
||||
line-height: 37px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
padding: 0 0 0 15px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
color: #555;
|
||||
}
|
||||
.quick_links_title span{
|
||||
margin-right: 4px;
|
||||
color: #ffa515;
|
||||
}
|
||||
.term_item_tab{
|
||||
background: #f1f1f1;
|
||||
font-size: 0;
|
||||
}
|
||||
.term_item_tab .list{
|
||||
display: inline-block;
|
||||
webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
/* display: flex; */
|
||||
height: 38px;
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.term_item_tab .list::-webkit-scrollbar{
|
||||
width:8px;
|
||||
height:4px;
|
||||
background-color: transparent;
|
||||
}
|
||||
.term_item_tab .list ::-webkit-scrollbar-thumb{
|
||||
border-radius:0;
|
||||
background:transparent;
|
||||
border-radius: 4px;
|
||||
transition: all 1s;
|
||||
}
|
||||
.term_item_tab .list:hover::-webkit-scrollbar-thumb{
|
||||
background:rgba(1, 3, 18, 0.4);
|
||||
}
|
||||
.term_item_tab .list::-webkit-scrollbar-track{
|
||||
background-color:transparent;
|
||||
}
|
||||
|
||||
.term_item_tab .list>span{
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
text-align: left;
|
||||
padding: 0 25px 0 22px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-right: 1px solid #e2e2e2;
|
||||
cursor: pointer;
|
||||
width: 150px;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.icon-trem-close{
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -8.5px;
|
||||
right: 8px;
|
||||
display: none !important;
|
||||
}
|
||||
.icon-trem-close::after,
|
||||
.icon-trem-close::before{
|
||||
content: '';
|
||||
height: 14px;
|
||||
width: 2px;
|
||||
display: inline-block;
|
||||
background: #fb0000;
|
||||
z-index: 999;
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
top: 1.5px;
|
||||
left: 8px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.icon-trem-close::after{
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.icon-trem-close::before{
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
|
||||
.term_item_tab .list>span.active .icon-trem-close,
|
||||
.term_item_tab .list>span:hover .icon-trem-close{
|
||||
display: inline-block !important;
|
||||
}
|
||||
.term_item_tab .list>span i{
|
||||
transition: all 50ms;
|
||||
}
|
||||
.term_item_tab .list>span .icon{
|
||||
height: 9px;
|
||||
width: 9px;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 50%;
|
||||
margin-top:-4.5px;
|
||||
}
|
||||
.term_item_tab .list>span .icon.icon-sucess{
|
||||
background-color: #10952a;
|
||||
}
|
||||
.term_item_tab .list>span .icon.icon-info{
|
||||
background-color: #fc6d26;
|
||||
}
|
||||
.term_item_tab .list>span .icon.icon-warning{
|
||||
background-color: #ff5d2c;
|
||||
}
|
||||
|
||||
.term_item_tab .list>span:hover{
|
||||
background-color: #dadada;
|
||||
}
|
||||
|
||||
.term_item_tab .list> span.active{
|
||||
background-color: #424242;
|
||||
}
|
||||
|
||||
.term_item_tab .list span.active span{
|
||||
color: #fff;
|
||||
}
|
||||
.term_item_tab .list .content{
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.term_item_tab .item .glyphicon{
|
||||
vertical-align: top;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
font-size: 15px;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
color: #ff7070 !important;
|
||||
display: none;
|
||||
transition: all 500ms;
|
||||
}
|
||||
.term_item_tab .item .glyphicon:hover{
|
||||
color: red;
|
||||
}
|
||||
.term_item_tab .list span span{
|
||||
vertical-align: middle;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
display: inline-block;
|
||||
line-height: 37px;
|
||||
}
|
||||
.term_item_tab .glyphicon{
|
||||
font-size: 15px;
|
||||
margin-left: 8px;
|
||||
vertical-align: middle;
|
||||
transition: all 500ms;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
color: #ea7575;
|
||||
}
|
||||
.term_item_tab span.glyphicon{
|
||||
color: #888;
|
||||
}
|
||||
.term_item_tab .glyphicon:hover{
|
||||
color: red;
|
||||
}
|
||||
|
||||
.term_item_tab .tab_tootls{
|
||||
padding: 0;
|
||||
float:right;
|
||||
padding-right: 15px;
|
||||
/* display: inline-block; */
|
||||
display: none;
|
||||
}
|
||||
.term_item_tab .tab_tootls span{
|
||||
margin-left: 0;
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
height: 19px;
|
||||
color: #bbb;
|
||||
/* vertical-align: bottom; */
|
||||
}
|
||||
|
||||
|
||||
.term_item_tab .addServer{
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
padding:0;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.term_item_tab .addServer span{
|
||||
margin:0;
|
||||
color: #20a53a;
|
||||
}
|
||||
.term_item_tab>span:hover{
|
||||
background-color:#ececec;
|
||||
cursor: pointer;
|
||||
}
|
||||
.term_item_tab .addServer span:hover{
|
||||
color: #4c4c4c;
|
||||
}
|
||||
.term_content_tab .term_item{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: none;
|
||||
}
|
||||
.term_content_tab .term_item.active{
|
||||
display: inline-block;
|
||||
}
|
||||
.term_content_tab{
|
||||
background-color: #000;
|
||||
position: absolute;
|
||||
top: 38px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 10px 5px 10px 10px;
|
||||
}
|
||||
.quick_links_input{
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
padding-left: 5px;
|
||||
border: none;
|
||||
width: 100%;
|
||||
padding-left:70px;
|
||||
border:1px solid #e1e1e1;
|
||||
background-color: #fcfcfc;
|
||||
border-radius: 3px;
|
||||
transition: all 500ms;
|
||||
}
|
||||
.quick_links_input:focus{
|
||||
outline: none;
|
||||
border:1px solid #20a53a;
|
||||
background-color: fff;
|
||||
}
|
||||
.quick_links_input:active{
|
||||
outline: none;
|
||||
}
|
||||
.term_box{
|
||||
height: 100%;
|
||||
border-radius: 3px;
|
||||
margin-right: 260px;
|
||||
position: relative;
|
||||
}
|
||||
.term_tootls{
|
||||
width:250px;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
/* border: 1px solid #ececec; */
|
||||
}
|
||||
.term_tootls .tootls_tab{
|
||||
display: inline-block;
|
||||
/* border: 1px solid #20a53a; */
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.term_tootls .tootls_tab a{
|
||||
display: inline-block;
|
||||
width: 38px;
|
||||
text-align: center;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
position: absolute;
|
||||
right:0;
|
||||
color: #ececec;
|
||||
background-color: #c7c7c71a;
|
||||
}
|
||||
.term_tootls .tootls_tab a:hover{
|
||||
background-color: #8282824d;
|
||||
}
|
||||
.term_tootls .tootls_tab i{
|
||||
font-style: normal;
|
||||
font-size: 12px;
|
||||
color: #ececec;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.main-content .safe{
|
||||
position: relative;
|
||||
}
|
||||
.xterm .xterm-viewport::-webkit-scrollbar{
|
||||
width:8px;
|
||||
height:5px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.xterm .xterm-viewport::-webkit-scrollbar-thumb{
|
||||
border-radius:0;
|
||||
box-shadow:inset 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
background:#666;
|
||||
border-radius: 4px;
|
||||
transition: all 1s;
|
||||
}
|
||||
.xterm .xterm-viewport:hover::-webkit-scrollbar-thumb{
|
||||
background:#aaa;
|
||||
|
||||
}
|
||||
.xterm .xterm-viewport::-webkit-scrollbar-track{
|
||||
box-shadow:inset 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
border-radius:0;
|
||||
background:#222;
|
||||
border-radius: 4px;
|
||||
transition: all 1s;
|
||||
}
|
||||
.xterm .xterm-viewport:hover::-webkit-scrollbar-track{
|
||||
background-color:#444;
|
||||
}
|
||||
|
||||
.tootls_tab>span{
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
}
|
||||
.tootls_tab a span{
|
||||
margin-right: 1px;
|
||||
}
|
||||
.tootls_tab>span.active{
|
||||
background-color: #28903c;
|
||||
color: #fff;
|
||||
padding-left: 15px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
}
|
||||
.tootls_content{
|
||||
position: absolute;
|
||||
top: 38px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-top: 1px solid #ececec;
|
||||
}
|
||||
.tootls_host_list,
|
||||
.tootls_commonly_list{
|
||||
list-style: none;
|
||||
border-top: none;
|
||||
border: 1px solid #ececec;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.tootls_host_list{
|
||||
height: 380px;
|
||||
overflow:auto;
|
||||
/* margin-bottom: 10px; */
|
||||
overflow-x: hidden;
|
||||
font-size: 0;
|
||||
}
|
||||
.tootls_commonly_list li,
|
||||
.tootls_host_list li{
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
color: #444;
|
||||
border-bottom:1px solid #ececec;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.tootls_commonly_list li{
|
||||
padding-left: 15px;
|
||||
}
|
||||
.tootls_commonly_list li:hover,
|
||||
.tootls_host_list li:hover{
|
||||
background-color: #eee;
|
||||
}
|
||||
.tootls_commonly_list li:hover .tootls,
|
||||
.tootls_host_list li:hover .tootls{
|
||||
display: inline-block;
|
||||
}
|
||||
.tootls_host_list li i{
|
||||
display: inline-block;
|
||||
height:100%;
|
||||
width:38px;
|
||||
background-size: 16px;
|
||||
background: url('../img/soft_ico/ico-cmd.png') no-repeat center center;
|
||||
}
|
||||
|
||||
.tootls_commonly_list li>span,
|
||||
.tootls_host_list li>span{
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
.tootls_commonly_list li:hover >span:nth-child(2),
|
||||
.tootls_host_list li:hover >span:nth-child(2){
|
||||
width: 135px;
|
||||
}
|
||||
.tootls_commonly_list li>span:nth-child(2),
|
||||
.tootls_host_list li>span:nth-child(2){
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
max-width: 210px;
|
||||
}
|
||||
/* .tootls_host_list li>span:nth-child(2){
|
||||
margin-left: 35px;
|
||||
} */
|
||||
.tootls_commonly_list li>span:nth-child(2){
|
||||
max-width: 210px;
|
||||
}
|
||||
.tootls_commonly_list li span:nth-child(3),
|
||||
.tootls_host_list li span:nth-child(3){
|
||||
padding-left: 10px;
|
||||
}
|
||||
.tootls_commonly_list li .tootls,
|
||||
.tootls_host_list li .tootls{
|
||||
width: 70px;
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
display: none;
|
||||
}
|
||||
.tootls_commonly_list li .tootls{
|
||||
width: 90px;
|
||||
}
|
||||
.tootls_commonly_list li .tootls span,
|
||||
.tootls_host_list li .tootls span{
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
.tootls_commonly_list li .tootls span:nth-child(1),
|
||||
.tootls_host_list li .tootls span:nth-child(1){
|
||||
color:#888;
|
||||
font-size: 14px;
|
||||
}
|
||||
.tootls_commonly_list li .tootls span:nth-child(2),
|
||||
.tootls_host_list li .tootls span:nth-child(2){
|
||||
color: #ea7575;
|
||||
}
|
||||
.tootls_commonly_list li .tootls span:nth-child(2):hover,
|
||||
.tootls_host_list li .tootls span:nth-child(2):hover{
|
||||
color: red;
|
||||
}
|
||||
.bt-form-2x .tname,
|
||||
.bt-form-2x .bt-input-text{
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
}
|
||||
.bt-form-2x .bt-input-text{
|
||||
padding-left: 8px;
|
||||
}
|
||||
.bt-form-2x .auth_type_checkbox{
|
||||
/* height: 34px;
|
||||
line-height: 34px; */
|
||||
padding: 8px 12px;
|
||||
}
|
||||
.menu_right_list{
|
||||
width: 140px;
|
||||
position: fixed;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(0,0,0,.15);
|
||||
border-radius: 2px;
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
|
||||
box-shadow: 0 6px 12px rgba(0,0,0,.175);
|
||||
z-index: 999999;
|
||||
background: #fff;
|
||||
padding: 6px 0;
|
||||
display: inline-block;
|
||||
webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.menu_right_list li{
|
||||
height: 28px;
|
||||
line-height:28px;
|
||||
|
||||
}
|
||||
.menu_right_list li:hover{
|
||||
background-color: #ececec;
|
||||
transition: all 500ms;
|
||||
cursor: pointer;
|
||||
}
|
||||
.menu_right_list li a{
|
||||
padding-left: 15px;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
transition: all 500ms;
|
||||
text-decoration: none;
|
||||
}
|
||||
.menu_right_list li:hover a{
|
||||
color: #20a532;
|
||||
}
|
||||
.menu_right_list li.split_line{
|
||||
height: 1px;
|
||||
background-color: #ececec;
|
||||
}
|
||||
/* 终端管理页面 结束*/
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
font-feature-settings: "liga" 0;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -821,7 +821,7 @@ function GetPanelApi() {
|
||||
<span class="tname">'+lan.config.int_sk+'</span>\
|
||||
<div class="info-r">\
|
||||
<input readonly="readonly" name="panel_token_value" class="bt-input-text mr5 disable" type="text" style="width: 310px" value="'+rdata.token+'" disable>\
|
||||
<button class="btn btn-xs btn-success btn-sm" style="margin-left: -50px;" onclick="SetPanelApi(1)">'+lan.config.reset+'</button>\
|
||||
<button class="btn btn-xs btn-success btn-sm" style="margin-left: -57px;" onclick="SetPanelApi(1)">'+lan.config.reset+'</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="line ">\
|
||||
@@ -834,7 +834,7 @@ function GetPanelApi() {
|
||||
<ul class="help-info-text c7">\
|
||||
<li>'+lan.config.help1+'</li>\
|
||||
<li>'+lan.config.help2+'</li>\
|
||||
<li>'+lan.config.help3+':<a class="btlink" href="https://www.bt.cn/bbs/thread-20376-1-1.html" target="_blank">https://www.bt.cn/bbs/thread-20376-1-1.html</a></li>\
|
||||
<li>'+lan.config.help3+':<a class="btlink" href="https://forum.aapanel.com/d/482-api-interface-tutorial" target="_blank">https://forum.aapanel.com/d/482-api-interface-tutorial</a></li>\
|
||||
</ul>\
|
||||
</div>'
|
||||
})
|
||||
|
||||
@@ -48,7 +48,7 @@ var database = {
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'opt', width: 280, title: lan.database.operation, align: 'right', templet: function (item) {
|
||||
field: 'opt', width: 300, title: lan.database.operation, align: 'right', templet: function (item) {
|
||||
var option = "<a href=\"javascript:;\" class=\"btlink\" onclick=\"bt.database.open_phpmyadmin('" + item.name + "','" + item.username + "','" + item.password + "')\" title=\""+lan.database.admin_title+"\">"+lan.database.admin+"</a> | ";
|
||||
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"database.rep_tools('" + item.name + "')\" title=\""+lan.database.mysql_tools+"\">"+lan.database.tools+"</a> | ";
|
||||
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"bt.database.set_data_access('" + item.username + "')\" title=\""+lan.database.set_db_auth+"\">"+lan.database.auth+"</a> | ";
|
||||
@@ -76,7 +76,7 @@ var database = {
|
||||
if (!types[rdata.tables[i].type]) continue;
|
||||
tbody += '<tr>\
|
||||
<td><input value="dbtools_' + rdata.tables[i].table_name + '" class="check" onclick="database.selected_tools(null,\'' + db_name + '\');" type="checkbox"></td>\
|
||||
<td><span style="width:220px;"> ' + rdata.tables[i].table_name + '</span></td>\
|
||||
<td><span style="width:150px;"> ' + rdata.tables[i].table_name + '</span></td>\
|
||||
<td>' + rdata.tables[i].type + '</td>\
|
||||
<td><span style="width:90px;"> ' + rdata.tables[i].collation + '</span></td>\
|
||||
<td>' + rdata.tables[i].rows_count + '</td>\
|
||||
@@ -100,7 +100,7 @@ var database = {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: lan.database.mysql_tools_box+"【" + db_name + "】",
|
||||
area: ['824px', '580px'],
|
||||
area: ['850px', '580px'],
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
content: '<div class="plr15 mt10">\
|
||||
|
||||
+58
-24
@@ -3,6 +3,10 @@ var fileDrop = {
|
||||
endTime:0,
|
||||
uploadLength:0, //上传数量
|
||||
splitSize: 1024 * 1024 * 2, //文件上传分片大小
|
||||
splitEndTime: 0,
|
||||
splitStartTime:0,
|
||||
fileSize:0,
|
||||
speedLastTime:0,
|
||||
filesList:[], // 文件列表数组
|
||||
errorLength:0, //上传失败文件数量
|
||||
isUpload:true, //上传状态,是否可以上传
|
||||
@@ -10,6 +14,7 @@ var fileDrop = {
|
||||
isUploadNumber:800,//限制单次上传数量
|
||||
uploadAllSize:0, // 上传文件总大小
|
||||
uploadedSize:0, // 已上传文件大小
|
||||
updateedSizeLast:0,
|
||||
topUploadedSize:0, // 上一次文件上传大小
|
||||
uploadExpectTime:0, // 预计上传时间
|
||||
initTimer:0, // 初始化计时
|
||||
@@ -17,10 +22,14 @@ var fileDrop = {
|
||||
timerSpeed:0, //速度
|
||||
isLayuiDrop:false, //是否是小窗口拖拽
|
||||
uploading:false,
|
||||
is_webkit:(function(){
|
||||
if(navigator.userAgent.indexOf('WebKit') > -1) return true;
|
||||
return false;
|
||||
})(),
|
||||
init:function(){
|
||||
if($('#mask_layer').length == 0) {
|
||||
window.UploadFiles = function(){ fileDrop.dialog_view()};
|
||||
$("body").append($('<div class="mask_layer" id="mask_layer" style="position:fixed;top:0;left:0;right:0;bottom:0; background:rgba(255,255,255,0.6);border:3px #ccc dashed;z-index:99999999;display:none;color:#999;font-size:40px;text-align:center;overflow:hidden;"><span style="position: absolute;top: 50%;left: 50%;margin-left: -200px;margin-top: -40px;">Upload files to the current directory</span></div>'));
|
||||
window.UploadFiles = function(){ fileDrop.dialog_view()};
|
||||
$("body").append($('<div class="mask_layer" id="mask_layer" style="position:fixed;top:0;left:0;right:0;bottom:0; background:rgba(255,255,255,0.6);border:3px #ccc dashed;z-index:99999999;display:none;color:#999;font-size:40px;text-align:center;overflow:hidden;"><span style="position: absolute;top: 50%;left: 50%;margin-left: -300px;margin-top: -40px;">Upload files to the current directory'+ (!this.is_webkit?'<i style="font-size:20px;font-style:normal;display:block;margin-top:15px;color:red;">This browser not support drag upload. Please choose Chrome or WebKit kernel browser.</i>':'') +'</span></div>'));
|
||||
this.event_relation(document.querySelector('#container'),document,document.querySelector('#mask_layer'));
|
||||
}
|
||||
},
|
||||
@@ -36,8 +45,8 @@ var fileDrop = {
|
||||
}
|
||||
}
|
||||
leave.el.addEventListener("dragleave",(leave.callback != null)?leave.callback:function(e){
|
||||
e.preventDefault();
|
||||
if(e.x == 0 && e.y == 0) $('#mask_layer').hide();
|
||||
e.preventDefault();
|
||||
},false);
|
||||
enter.el.addEventListener("dragenter", (enter.callback != null)?enter.callback:function(e){
|
||||
if(e.dataTransfer.items[0].kind == 'string') return false
|
||||
@@ -50,6 +59,10 @@ var fileDrop = {
|
||||
},
|
||||
// 事件触发
|
||||
ev_drop:function(e){
|
||||
if(!this.is_webkit){
|
||||
$('#mask_layer').hide();
|
||||
return false;
|
||||
}
|
||||
e.preventDefault();
|
||||
if(fileDrop.uploading){
|
||||
layer.msg('Uploading, please wait...');
|
||||
@@ -114,24 +127,6 @@ var fileDrop = {
|
||||
}
|
||||
|
||||
},
|
||||
// 获取上传速度
|
||||
get_timer_speed:function(speed){
|
||||
var that = this,num = 0;
|
||||
if(speed == undefined) speed = 1000
|
||||
that.speedInterval = setInterval(function(){
|
||||
if(that.uploadedSize - that.topUploadedSize === 0){
|
||||
that.timerSpeed = that.timerSpeed == 0 ? 0:(parseInt(that.timerSpeed / num));
|
||||
num += 1;
|
||||
}else{
|
||||
that.timerSpeed = that.uploadedSize - that.topUploadedSize;
|
||||
num = 0;
|
||||
}
|
||||
that.topUploadedSize = that.uploadedSize;
|
||||
$('.file_upload_info .uploadSpeed').text(that.to_size(isNaN(that.timerSpeed)?0:that.timerSpeed)+'/s');
|
||||
var estimateTime = that.time(parseInt(((that.uploadAllSize - that.uploadedSize) / that.timerSpeed) * 1000))
|
||||
if(!isNaN(that.timerSpeed)) $('.file_upload_info .uploadEstimate').text(estimateTime.indexOf('NaN') == -1?estimateTime:'0sec');
|
||||
},speed);
|
||||
},
|
||||
// 上传视图
|
||||
dialog_view:function(config){
|
||||
var that = this,html = '';
|
||||
@@ -150,7 +145,7 @@ var fileDrop = {
|
||||
btn:['Start upload','Cancel upload'],
|
||||
title: 'Upload files to【'+ bt.get_cookie('Path') +'】--- Support breakpoint renewal',
|
||||
skin:'file_dir_uploads',
|
||||
content:'<div style="padding:15px 15px 10px 15px;"><div class="upload_btn_groud"><div class="btn-group"><button type="button" class="btn btn-primary btn-sm upload_file_btn">Upload file</button><button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="caret"></span><span class="sr-only">Toggle Dropdown</span></button><ul class="dropdown-menu"><li><a href="#" data-type="file">Upload file</a></li><li><a href="#" data-type="dir">Upload directory</a></li></ul></div><div class="file_upload_info" style="display:none;"><span>Total process <i class="uploadProgress"></i>, Uploading <i class="uploadNumber"></i>,</span><span style="display:none">Upload failed <i class="uploadError"></i></span><span>Upload speed <i class="uploadSpeed">Getting</i>,</span><span>Expect time <i class="uploadEstimate">Getting</i></span><i></i></div></div><div class="upload_file_body '+ (html==''?'active':'') +'">'+ (html!=''?('<ul class="dropUpLoadFileHead" style="padding-right:'+ (is_show?'15':'0') +'px"><li class="fileTitle"><span class="filename">File name</span><span class="filesize">File size</span><span class="fileStatus">File status</span></li></ul><ul class="dropUpLoadFile list-list">'+ html +'</ul>'):'<span>Please drag the file here</span>') +'</div></div>',
|
||||
content:'<div style="padding:15px 15px 10px 15px;"><div class="upload_btn_groud"><div class="btn-group"><button type="button" class="btn btn-primary btn-sm upload_file_btn">Upload file</button><button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="caret"></span><span class="sr-only">Toggle Dropdown</span></button><ul class="dropdown-menu"><li><a href="#" data-type="file">Upload file</a></li><li><a href="#" data-type="dir">Upload directory</a></li></ul></div><div class="file_upload_info" style="display:none;"><span>Total process <i class="uploadProgress"></i>, Uploading <i class="uploadNumber"></i>,</span><span style="display:none">Upload failed <i class="uploadError"></i></span><span>Upload speed <i class="uploadSpeed">Getting</i>,</span><span>Expect time <i class="uploadEstimate">Getting</i></span><i></i></div></div><div class="upload_file_body '+ (html==''?'active':'') +'">'+ (html!=''?('<ul class="dropUpLoadFileHead" style="padding-right:'+ (is_show?'15':'0') +'px"><li class="fileTitle"><span class="filename">File name</span><span class="filesize">File size</span><span class="fileStatus">File status</span></li></ul><ul class="dropUpLoadFile list-list">'+ html +'</ul>'):'<span>Please drag the file here'+ (!that.is_webkit?'<i style="display: block;font-style: normal;margin-top: 10px;color: red;font-size: 17px;">This browser not support drag upload.<br>Please choose Chrome or WebKit kernel browser.</i>':'') +'</span>') +'</div></div>',
|
||||
success:function(){
|
||||
$('#mask_layer').hide();
|
||||
$('.file_dir_uploads .layui-layer-max').hide();
|
||||
@@ -213,7 +208,7 @@ var fileDrop = {
|
||||
that.upload_file();
|
||||
that.initTimer = new Date();
|
||||
that.uploading = true;
|
||||
that.get_timer_speed();
|
||||
//that.get_timer_speed();
|
||||
}
|
||||
},
|
||||
btn2:function (index, layero){
|
||||
@@ -363,9 +358,14 @@ var fileDrop = {
|
||||
return false;
|
||||
}
|
||||
var that = this;
|
||||
that.splitEndTime = new Date().getTime()
|
||||
that.get_timer_speed()
|
||||
|
||||
that.splitStartTime = new Date().getTime()
|
||||
var item = this.filesList[index],fileEnd = '';
|
||||
if(item == undefined) return false;
|
||||
fileEnd = Math.min(item.file.size, fileStart + this.splitSize),
|
||||
that.fileSize = fileEnd - fileStart
|
||||
form = new FormData();
|
||||
if(fileStart == 0){
|
||||
that.startTime = new Date();
|
||||
@@ -417,7 +417,41 @@ var fileDrop = {
|
||||
that.upload_file(fileStart,index)
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
// 获取上传速度
|
||||
// get_timer_speed:function(speed){
|
||||
// var that = this,num = 0;
|
||||
// if(speed == undefined) speed = 1000
|
||||
// that.speedInterval = setInterval(function(){
|
||||
// if(that.uploadedSize - that.topUploadedSize === 0){
|
||||
// that.timerSpeed = that.timerSpeed == 0 ? 0:(parseInt(that.timerSpeed / num));
|
||||
// num += 1;
|
||||
// }else{
|
||||
// that.timerSpeed = that.uploadedSize - that.topUploadedSize;
|
||||
// num = 0;
|
||||
// }
|
||||
// that.topUploadedSize = that.uploadedSize;
|
||||
// $('.file_upload_info .uploadSpeed').text(that.to_size(isNaN(that.timerSpeed)?0:that.timerSpeed)+'/s');
|
||||
// var estimateTime = that.time(parseInt(((that.uploadAllSize - that.uploadedSize) / that.timerSpeed) * 1000))
|
||||
// if(!isNaN(that.timerSpeed)) $('.file_upload_info .uploadEstimate').text(estimateTime.indexOf('NaN') == -1?estimateTime:'0sec');
|
||||
// },speed);
|
||||
// },
|
||||
get_timer_speed:function(speed){
|
||||
var done_time = new Date().getTime()
|
||||
if(done_time - this.speedLastTime > 1000){
|
||||
var that = this,num = 0;
|
||||
if(speed == undefined) speed = 200
|
||||
var s_time = (that.splitEndTime - that.splitStartTime) / 1000;
|
||||
that.timerSpeed = (that.fileSize / s_time).toFixed(2)
|
||||
that.updateedSizeLast = that.uploadedSize
|
||||
if(that.timerSpeed < 2) return;
|
||||
|
||||
$('.file_upload_info .uploadSpeed').text(that.to_size(isNaN(that.timerSpeed)?0:that.timerSpeed)+'/s');
|
||||
var estimateTime = that.time(parseInt(((that.uploadAllSize - that.uploadedSize) / that.timerSpeed) * 1000))
|
||||
if(!isNaN(that.timerSpeed)) $('.file_upload_info .uploadEstimate').text(estimateTime.indexOf('NaN') == -1?estimateTime:'0sec');
|
||||
this.speedLastTime = done_time;
|
||||
}
|
||||
},
|
||||
time:function(date){
|
||||
var hours = Math.floor(date / (60 * 60 * 1000));
|
||||
var minutes = Math.floor(date / (60 * 1000));
|
||||
|
||||
@@ -574,8 +574,14 @@ var index = {
|
||||
});
|
||||
},
|
||||
beta_msg: function () {
|
||||
var new_load = bt.load();
|
||||
bt.send('get_beta_logs', 'ajax/get_beta_logs', {}, function (data) {
|
||||
var my_list = '';
|
||||
new_load.close();
|
||||
if(data.status === false){
|
||||
layer.msg(data.msg,{icon: 2});
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < data.list.length; i++) {
|
||||
my_list += '<div class="item_list">\
|
||||
<span class="index_acive"></span>\
|
||||
|
||||
+213
-102
@@ -3813,7 +3813,36 @@ var Term = {
|
||||
term: null,
|
||||
term_box: null,
|
||||
ssh_info: null,
|
||||
|
||||
last_body:false,
|
||||
last_cd:null,
|
||||
config:{
|
||||
cols:0,
|
||||
rows:0,
|
||||
fontSize:12
|
||||
},
|
||||
|
||||
// 缩放尺寸
|
||||
detectZoom:(function(){
|
||||
var ratio = 0,
|
||||
screen = window.screen,
|
||||
ua = navigator.userAgent.toLowerCase();
|
||||
if (window.devicePixelRatio !== undefined) {
|
||||
ratio = window.devicePixelRatio;
|
||||
}
|
||||
else if (~ua.indexOf('msie')) {
|
||||
if (screen.deviceXDPI && screen.logicalXDPI) {
|
||||
ratio = screen.deviceXDPI / screen.logicalXDPI;
|
||||
}
|
||||
}
|
||||
else if (window.outerWidth !== undefined && window.innerWidth !== undefined) {
|
||||
ratio = window.outerWidth / window.innerWidth;
|
||||
}
|
||||
|
||||
if (ratio){
|
||||
ratio = Math.round(ratio * 100);
|
||||
}
|
||||
return ratio;
|
||||
})(),
|
||||
//连接websocket
|
||||
connect: function() {
|
||||
if (!Term.bws || Term.bws.readyState == 3 || Term.bws.readyState == 2) {
|
||||
@@ -3827,39 +3856,85 @@ var Term = {
|
||||
Term.bws.addEventListener('message', Term.on_message);
|
||||
Term.bws.addEventListener('close', Term.on_close);
|
||||
Term.bws.addEventListener('error', Term.on_error);
|
||||
Term.bws.addEventListener('open',Term.on_open);
|
||||
|
||||
if (Term.ssh_info) Term.send(JSON.stringify(Term.ssh_info))
|
||||
//if (Term.ssh_info) Term.send(JSON.stringify(Term.ssh_info))
|
||||
}
|
||||
},
|
||||
//连接服务器成功
|
||||
on_open:function(ws_event){
|
||||
Term.send(JSON.stringify(Term.ssh_info || {}))
|
||||
Term.term.FitAddon.fit();
|
||||
Term.resize();
|
||||
var f_path = $("#fileInputPath").val();
|
||||
if(f_path){
|
||||
Term.last_cd = "cd " + f_path;
|
||||
Term.send(Term.last_cd + "\n");
|
||||
}
|
||||
},
|
||||
|
||||
//服务器消息事件
|
||||
on_message: function(ws_event) {
|
||||
result = ws_event.data;
|
||||
if (result === "\r'Server connection failed'!\r" || result === "\rWrong user name or password!\r") {
|
||||
show_ssh_login(result);
|
||||
// on_message: function(ws_event) {
|
||||
// result = ws_event.data;
|
||||
// if (result === "\r'Server connection failed'!\r" || result === "\rWrong user name or password!\r") {
|
||||
// show_ssh_login(result);
|
||||
// Term.close();
|
||||
// return;
|
||||
// }
|
||||
// Term.term.write(result);
|
||||
|
||||
// if (result == '\r\n登出\r\n' || result == '登出\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') {
|
||||
// setTimeout(function() {
|
||||
// layer.close(Term.term_box);
|
||||
// }, 500);
|
||||
// Term.close();
|
||||
// Term.bws = null;
|
||||
// }
|
||||
// },
|
||||
on_message: function (ws_event) {
|
||||
result = ws_event.data;
|
||||
if(Term.last_cd){
|
||||
if(result.indexOf(Term.last_cd) != -1 && result.length - Term.last_cd.length < 3) {
|
||||
Term.last_cd = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (result === "\rServer connection failed!\r" || result == "\rWrong user name or password!\r") {
|
||||
Term.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(result.length > 1 && Term.last_body === false){
|
||||
Term.last_body = true;
|
||||
}
|
||||
Term.term.write(result);
|
||||
|
||||
if (result == '\r\n登出\r\n' || result == '登出\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') {
|
||||
setTimeout(function() {
|
||||
layer.close(Term.term_box);
|
||||
if (result == '\r\n登出\r\n' || result == '\r\n注销\r\n' || result == '注销\r\n' || result == '登出\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') {
|
||||
setTimeout(function () {
|
||||
layer.close(Term.term_box);
|
||||
Term.term.dispose();
|
||||
}, 500);
|
||||
Term.close();
|
||||
Term.bws = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
//websocket关闭事件
|
||||
on_close: function(ws_event) {
|
||||
Term.bws = null;
|
||||
},
|
||||
|
||||
//websocket错误事件
|
||||
on_error: function(ws_event) {
|
||||
if(ws_event.target.readyState === 3){
|
||||
var msg = 'Error: unable to create websocket connection, please close 【Developer mode】 on the settings page';
|
||||
layer.msg(msg,{time:5000})
|
||||
// on_error: function(ws_event) {
|
||||
// if(ws_event.target.readyState === 3){
|
||||
// var msg = 'Error: unable to create websocket connection, please close 【Developer mode】 on the settings page';
|
||||
// layer.msg(msg,{time:5000})
|
||||
// if(Term.state === 3) return
|
||||
// Term.term.write(msg)
|
||||
// Term.state = 3;
|
||||
// }else{
|
||||
// console.log(ws_event)
|
||||
// }
|
||||
// },
|
||||
on_error: function (ws_event) {
|
||||
if(ws_event.target.readyState === 3){
|
||||
if(Term.state === 3) return
|
||||
Term.term.write(msg)
|
||||
Term.state = 3;
|
||||
@@ -3869,18 +3944,28 @@ var Term = {
|
||||
},
|
||||
|
||||
//关闭连接
|
||||
close: function() {
|
||||
Term.bws.close();
|
||||
},
|
||||
close: function () {
|
||||
if(Term.bws){
|
||||
Term.bws.close();
|
||||
}
|
||||
},
|
||||
|
||||
resize: function() {
|
||||
var m_width = 100;
|
||||
var m_height = 34;
|
||||
Term.term.resize(m_width, m_height);
|
||||
Term.term.scrollToBottom();
|
||||
Term.term.focus();
|
||||
Term.send('new_terminal');
|
||||
resize: function () {
|
||||
setTimeout(function(){
|
||||
$("#term").height($(".term_box_all .layui-layer-content").height()-18)
|
||||
Term.term.FitAddon.fit()
|
||||
Term.send(JSON.stringify({resize:1,rows:Term.term.rows,cols:Term.term.cols}));
|
||||
Term.term.focus();
|
||||
},200)
|
||||
},
|
||||
// resize: function() {
|
||||
// var m_width = 100;
|
||||
// var m_height = 34;
|
||||
// Term.term.resize(m_width, m_height);
|
||||
// Term.term.scrollToBottom();
|
||||
// Term.term.focus();
|
||||
// Term.send('new_terminal');
|
||||
// },
|
||||
|
||||
//发送数据
|
||||
//@param event 唯一事件名称
|
||||
@@ -3904,86 +3989,112 @@ var Term = {
|
||||
}
|
||||
}
|
||||
},
|
||||
run: function (ssh_info) {
|
||||
var termCols = 100;
|
||||
var termRows = 34;
|
||||
var loadT = layer.msg('It is loading the files required by the terminal. Please wait...', { icon: 16, time: 0, shade: 0.3 });
|
||||
loadScript([
|
||||
"/static/build/xterm.min.js",
|
||||
"/static/build/addons/attach/attach.min.js",
|
||||
"/static/build/addons/fit/fit.min.js",
|
||||
"/static/build/addons/fullscreen/fullscreen.min.js",
|
||||
"/static/build/addons/search/search.min.js",
|
||||
"/static/build/addons/winptyCompat/winptyCompat.js"
|
||||
], function () {
|
||||
layer.close(loadT);
|
||||
Term.term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true });
|
||||
Term.term.setOption('cursorBlink', true);
|
||||
Term.term_box = layer.open({
|
||||
type: 1,
|
||||
title: lan.public.terminal,
|
||||
area: ['920px', '630px'],
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
content: '<link rel="stylesheet" href="/static/build/xterm.min.css" />\
|
||||
<link rel="stylesheet" href="/static/build/addons/fullscreen/fullscreen.min.css" />\
|
||||
<a class="btlink" onclick="show_ssh_login(1)" style="position: fixed;margin-left: 83px;margin-top: -30px;">[' + lan.public.set + ']</a>\
|
||||
<div class="term-box" style="background-color:#000"><div id="term"></div></div>',
|
||||
cancel: function () {
|
||||
Term.term.destroy();
|
||||
},
|
||||
success: function () {
|
||||
Term.term.open(document.getElementById('term'));
|
||||
Term.resize();
|
||||
}
|
||||
});
|
||||
Term.term.on('data', function (data) {
|
||||
try {
|
||||
Term.bws.send(data)
|
||||
} catch (e) {
|
||||
Term.term.write('\r\nThe connection is lost and you are trying to reconnect!\r\n')
|
||||
Term.connect()
|
||||
}
|
||||
});
|
||||
if (ssh_info) Term.ssh_info = ssh_info
|
||||
Term.connect();
|
||||
})
|
||||
|
||||
},
|
||||
// run: function(ssh_info) {
|
||||
// run: function (ssh_info) {
|
||||
// var termCols = 100;
|
||||
// var termRows = 34;
|
||||
// Term.term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true });
|
||||
// Term.term.setOption('cursorBlink', true);
|
||||
// var loadT = layer.msg('It is loading the files required by the terminal. Please wait...', { icon: 16, time: 0, shade: 0.3 });
|
||||
// loadScript([
|
||||
// "/static/build/xterm.min.js",
|
||||
// "/static/build/addons/attach/attach.min.js",
|
||||
// "/static/build/addons/fit/fit.min.js",
|
||||
// "/static/build/addons/fullscreen/fullscreen.min.js",
|
||||
// "/static/build/addons/search/search.min.js",
|
||||
// "/static/build/addons/winptyCompat/winptyCompat.js"
|
||||
// ], function () {
|
||||
// layer.close(loadT);
|
||||
// Term.term = new Terminal({ cols: termCols, rows: termRows, screenKeys: true, useStyle: true });
|
||||
// Term.term.setOption('cursorBlink', true);
|
||||
// Term.term_box = layer.open({
|
||||
// type: 1,
|
||||
// title: lan.public.terminal,
|
||||
// area: ['920px', '630px'],
|
||||
// closeBtn: 2,
|
||||
// shadeClose: false,
|
||||
// content: '<link rel="stylesheet" href="/static/build/xterm.min.css" />\
|
||||
// <link rel="stylesheet" href="/static/build/addons/fullscreen/fullscreen.min.css" />\
|
||||
// <a class="btlink" onclick="show_ssh_login(1)" style="position: fixed;margin-left: 83px;margin-top: -30px;">[' + lan.public.set + ']</a>\
|
||||
// <div class="term-box" style="background-color:#000"><div id="term"></div></div>',
|
||||
// cancel: function () {
|
||||
// Term.term.destroy();
|
||||
// },
|
||||
// success: function () {
|
||||
// Term.term.open(document.getElementById('term'));
|
||||
// Term.resize();
|
||||
// }
|
||||
// });
|
||||
// Term.term.on('data', function (data) {
|
||||
// try {
|
||||
// Term.bws.send(data)
|
||||
// } catch (e) {
|
||||
// Term.term.write('\r\nThe connection is lost and you are trying to reconnect!\r\n')
|
||||
// Term.connect()
|
||||
// }
|
||||
// });
|
||||
// if (ssh_info) Term.ssh_info = ssh_info
|
||||
// Term.connect();
|
||||
// })
|
||||
|
||||
// Term.term_box = layer.open({
|
||||
// type: 1,
|
||||
// title: lan.public.terminal,
|
||||
// area: ['920px', '630px'],
|
||||
// closeBtn: 2,
|
||||
// shadeClose: false,
|
||||
// content: '<a class="btlink" onclick="show_ssh_login(1)" style="position: fixed;margin-left: 140px;margin-top: -30px;">[' + lan.public.set + ']</a><div class="term-box" style="background-color:#000"><div id="term"></div></div>',
|
||||
// cancel: function() {
|
||||
// Term.term.destroy();
|
||||
|
||||
// },
|
||||
// success: function() {
|
||||
// Term.term.open(document.getElementById('term'));
|
||||
// Term.resize();
|
||||
// }
|
||||
// });
|
||||
|
||||
// Term.term.on('data', function(data) {
|
||||
// try {
|
||||
// Term.bws.send(data)
|
||||
// } catch (e) {
|
||||
// Term.term.write('\r\nThe connection is lost and you are trying to reconnect!\r\n')
|
||||
// Term.connect()
|
||||
// }
|
||||
// });
|
||||
// if (ssh_info) Term.ssh_info = ssh_info
|
||||
// Term.connect();
|
||||
// },
|
||||
run: function (ssh_info) {
|
||||
if($("#panel_debug").attr("data") == 'True') {
|
||||
layer.msg('Error: unable to create websocket connection, please close 【Developer mode】 on the settings page!',{icon:2,time:5000});
|
||||
return;
|
||||
}
|
||||
var loadT = layer.msg('It is loading the files required by the terminal. Please wait...', { icon: 16, time: 0, shade: 0.3 });
|
||||
loadScript([
|
||||
"/static/js/xterm.js"
|
||||
],function(){
|
||||
layer.close(loadT);
|
||||
Term.term = new Terminal({
|
||||
rendererType: "canvas",
|
||||
cols: 100,
|
||||
rows: 34,
|
||||
fontSize:15,
|
||||
screenKeys: true,
|
||||
useStyle: true ,
|
||||
});
|
||||
Term.term.setOption('cursorBlink', true);
|
||||
Term.last_body = false;
|
||||
Term.term_box = layer.open({
|
||||
type: 1,
|
||||
title: lan.public.terminal,
|
||||
area: ['920px', '630px'],
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
skin:'term_box_all',
|
||||
content: '<link rel="stylesheet" href="/static/css/xterm.css" />\
|
||||
<div class="term-box" style="background-color:#000" id="term"></div>',
|
||||
cancel: function (index,lay) {
|
||||
bt.confirm({msg:'Closing the SSH session, the command in progress in the current command line session may be aborted. Continute?',title: "Cofirm to close the SSH session?"},function(ix){
|
||||
Term.term.dispose();
|
||||
layer.close(index);
|
||||
layer.close(ix);
|
||||
Term.close();
|
||||
});
|
||||
return false;
|
||||
},
|
||||
success: function () {
|
||||
$('.term_box_all').css('background-color','#000');
|
||||
Term.term.open(document.getElementById('term'));
|
||||
Term.term.FitAddon = new FitAddon.FitAddon();
|
||||
Term.term.loadAddon(Term.term.FitAddon);
|
||||
Term.term.WebLinksAddon = new WebLinksAddon.WebLinksAddon()
|
||||
Term.term.loadAddon(Term.term.WebLinksAddon)
|
||||
}
|
||||
});
|
||||
Term.term.onData(function (data) {
|
||||
try {
|
||||
Term.bws.send(data)
|
||||
} catch (e) {
|
||||
Term.term.write('\r\nThe connection is lost and you are trying to reconnect!\r\n')
|
||||
Term.connect()
|
||||
}
|
||||
});
|
||||
if (ssh_info) Term.ssh_info = ssh_info
|
||||
Term.connect();
|
||||
});
|
||||
|
||||
},
|
||||
reset_login: function() {
|
||||
var ssh_info = {
|
||||
data: JSON.stringify({
|
||||
|
||||
@@ -224,12 +224,20 @@ var bt = {
|
||||
var num = min + Math.round(rand * range); //四舍五入
|
||||
return num;
|
||||
},
|
||||
set_cookie: function(key, val) {
|
||||
var Days = 30;
|
||||
var exp = new Date();
|
||||
exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
|
||||
document.cookie = key + "=" + escape(val) + ";expires=" + exp.toGMTString();
|
||||
},
|
||||
set_cookie : function(key,val,time)
|
||||
{
|
||||
if(time != undefined){
|
||||
var exp = new Date();
|
||||
exp.setTime(exp.getTime() + time);
|
||||
time = exp.toGMTString();
|
||||
}else{
|
||||
var Days = 30;
|
||||
var exp = new Date();
|
||||
exp.setTime(exp.getTime() + Days*24*60*60*1000);
|
||||
time = exp.toGMTString();
|
||||
}
|
||||
document.cookie = key + "="+ escape (val) + ";expires=" + time;
|
||||
},
|
||||
get_cookie: function(key) {
|
||||
var arr, reg = new RegExp("(^| )" + key + "=([^;]*)(;|$)");
|
||||
if (arr = document.cookie.match(reg)) {
|
||||
@@ -645,10 +653,11 @@ var bt = {
|
||||
if (_obj.name) _name = _obj.name;
|
||||
if (_obj.placeholder) _placeholder = _obj.placeholder;
|
||||
if (_obj.title) _html += '<span class=" mr5">' + _obj.title + " ";
|
||||
var _add_class = _obj.add_class ? (' '+_obj.add_class) : "";
|
||||
switch (_obj.type) {
|
||||
case 'select':
|
||||
var _width = _obj.width ? _obj.width : '100px';
|
||||
_html += '<select ' + (_obj.disabled ? 'disabled' : '') + ' class="bt-input-text mr5 ' + _name + bs + '" name="' + _name + '" style="width:' + _width + '">';
|
||||
_html += '<select ' + (_obj.disabled ? 'disabled' : '') + ' class="bt-input-text mr5 ' + _name + bs + _add_class +'" name="' + _name + '" style="width:' + _width + '">';
|
||||
for (var j = 0; j < _obj.items.length; j++) {
|
||||
_html += '<option ' + (_obj.value == _obj.items[j].value ? 'selected' : '') + ' value="' + _obj.items[j].value + '">' + _obj.items[j].title + '</option>';
|
||||
}
|
||||
@@ -657,12 +666,12 @@ var bt = {
|
||||
case 'textarea':
|
||||
var _width = _obj.width ? _obj.width : '330px';
|
||||
var _height = _obj.height ? _obj.height : '100px';
|
||||
_html += '<textarea class="bt-input-text mr20 ' + _name + bs + '" name="' + _name + '" style="width:' + _width + ';height:' + _height + ';line-height:22px">' + (_obj.value ? _obj.value : '') + '</textarea>';
|
||||
_html += '<textarea class="bt-input-text mr20 ' + _name + bs + _add_class +'" name="' + _name + '" style="width:' + _width + ';height:' + _height + ';line-height:22px">' + (_obj.value ? _obj.value : '') + '</textarea>';
|
||||
if (_placeholder) _html += '<div class="placeholder c9" style="top: 15px; left: 15px; display: block;">' + _placeholder + '</div>';
|
||||
break;
|
||||
case 'button':
|
||||
var _width = _obj.width ? _obj.width : '330px';
|
||||
_html += '<button name=\'' + _name + '\' class="btn btn-success btn-sm mr5 ml5 ' + _name + bs + '">' + _obj.text + '</button>';
|
||||
_html += '<button name=\'' + _name + '\' class="btn btn-success btn-sm mr5 ml5 ' + _name + bs + _add_class +'">' + _obj.text + '</button>';
|
||||
break;
|
||||
case 'radio':
|
||||
var _v = _obj.value === true ? 'checked' : ''
|
||||
@@ -674,7 +683,7 @@ var bt = {
|
||||
break;
|
||||
case 'number':
|
||||
var _width = _obj.width ? _obj.width : '330px';
|
||||
_html += "<input name='" + _name + "' " + (_obj.disabled ? 'disabled' : '') + " class='bt-input-text mr5 " + _name + bs + "' " + (_placeholder ? ' placeholder="' + _placeholder + '"' : "") + " type='number' style='width:" + _width + "' value='" + (_obj.value ? _obj.value : '0') + "' />";
|
||||
_html += "<input name='" + _name + "' " + (_obj.disabled ? 'disabled' : '') + " class='bt-input-text mr5 " + _name + bs + _add_class +"' " + (_placeholder ? ' placeholder="' + _placeholder + '"' : "") + " type='number' style='width:" + _width + "' value='" + (_obj.value ? _obj.value : '0') + "' />";
|
||||
_html += _obj.unit ? _obj.unit : '';
|
||||
break;
|
||||
case 'password':
|
||||
@@ -684,7 +693,7 @@ var bt = {
|
||||
case 'div':
|
||||
var _width = _obj.width ? _obj.width : '330px';
|
||||
var _height = _obj.height ? _obj.height : '100px';
|
||||
_html += '<div class="bt-input-text ace_config_editor_scroll mr20 ' + _name + bs + '" name="' + _name + '" style="width:' + _width + ';height:' + _height + ';line-height:22px">' + (_obj.value ? _obj.value : '') + '</div>';
|
||||
_html += '<div class="bt-input-text ace_config_editor_scroll mr20 ' + _name + bs + _add_class +'" name="' + _name + '" style="width:' + _width + ';height:' + _height + ';line-height:22px">' + (_obj.value ? _obj.value : '') + '</div>';
|
||||
if (_placeholder) _html += '<div class="placeholder c9" style="top: 15px; left: 15px; display: block;">' + _placeholder + '</div>';
|
||||
break;
|
||||
case 'switch':
|
||||
@@ -696,7 +705,7 @@ var bt = {
|
||||
default:
|
||||
var _width = _obj.width ? _obj.width : '330px';
|
||||
|
||||
_html += "<input name='" + _name + "' " + (_obj.disabled ? 'disabled' : '') + " class='bt-input-text mr5 " + _name + bs + "' " + (_placeholder ? ' placeholder="' + _placeholder + '"' : "") + " type='text' style='width:" + _width + "' value='" + (_obj.value ? _obj.value : '') + "' />";
|
||||
_html += "<input name='" + _name + "' " + (_obj.disabled ? 'disabled' : '') + " class='bt-input-text mr5 " + _name + bs + _add_class +"' " + (_placeholder ? ' placeholder="' + _placeholder + '"' : "") + " type='text' style='width:" + _width + "' value='" + (_obj.value ? _obj.value : '') + "' />";
|
||||
break;
|
||||
}
|
||||
if (_obj.title) _html += '</span>';
|
||||
@@ -4511,43 +4520,23 @@ bt.database = {
|
||||
bt.msg(rdata);
|
||||
})
|
||||
},
|
||||
// open_phpmyadmin: function(name, username, password) {
|
||||
// if ($("#toPHPMyAdmin").attr('action').indexOf('phpmyadmin') == -1) {
|
||||
// layer.msg(lan.database.phpmyadmin_err, { icon: 2, shade: [0.3, '#000'] })
|
||||
// setTimeout(function() { window.location.href = '/soft'; }, 3000);
|
||||
// return;
|
||||
// }
|
||||
// var murl = $("#toPHPMyAdmin").attr('action');
|
||||
// $("#pma_username").val(username);
|
||||
// $("#pma_password").val(password);
|
||||
// $("#db").val(name);
|
||||
// layer.msg(lan.database.phpmyadmin, { icon: 16, shade: [0.3, '#000'], time: 1000 });
|
||||
// setTimeout(function() {
|
||||
// $("#toPHPMyAdmin").submit();
|
||||
// }, 200);
|
||||
// },
|
||||
open_phpmyadmin:function(name,username,password){
|
||||
|
||||
if($("#toPHPMyAdmin").attr('action').indexOf('phpmyadmin') == -1){
|
||||
layer.msg(lan.database.phpmyadmin_err,{icon:2,shade: [0.3, '#000']})
|
||||
setTimeout(function(){ window.location.href = '/soft'; },3000);
|
||||
layer.msg(lan.database.phpmyadmin_err,{icon:2,shade: [0.3, '#000']})
|
||||
setTimeout(function(){ window.location.href = '/soft'; },3000);
|
||||
return;
|
||||
}
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: "Please select how to access phpMyAdmin",
|
||||
area: '600px',
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
content: '<div class="change-default pd20">\
|
||||
<button class="btn btn-default btn-sm " onclick="bt.database.submit_phpmyadmin(\''+name+'\',\''+username+'\',\''+password+'\',false)">Secure access through panel</button>\
|
||||
<button style="margin-left: 145px;" class="btn btn-default btn-sm" onclick="bt.database.submit_phpmyadmin(\''+name+'\',\''+username+'\',\''+password+'\',true)">Access by Nginx/Apche/OLS</button>\
|
||||
<ul class="help-info-text c7 plr20">\
|
||||
<li>【Secure access by panel】No need to install Nginx/Apache. The security authentication is performed by the panel. Need to log in to the panel to access it</li>\
|
||||
<li>【Access by Nginx/Apche/OLS】Through the web server access, phpMyAdmin for security authentication</li>\
|
||||
<li>If used【Secure access through panel】that some features cannot be used, please try another access method</li>\
|
||||
</ul>\
|
||||
</div>'
|
||||
});
|
||||
$("#toPHPMyAdmin").attr('action',$("#toPHPMyAdmin").attr('public-data'))
|
||||
var murl = $("#toPHPMyAdmin").attr('action');
|
||||
$("#pma_username").val(username);
|
||||
$("#pma_password").val(password);
|
||||
$("#db").val(name);
|
||||
layer.msg(lan.database.phpmyadmin,{icon:16,shade: [0.3, '#000'],time:1000});
|
||||
setTimeout(function(){
|
||||
$("#toPHPMyAdmin").submit();
|
||||
layer.closeAll();
|
||||
},200);
|
||||
},
|
||||
submit_phpmyadmin: function(name,username,password,pub){
|
||||
if(pub === true){
|
||||
|
||||
+44
-30
@@ -1030,7 +1030,7 @@ var site = {
|
||||
columns: [
|
||||
{ field: 'name', title: lan.site.domain, templet: function(item) { return "<a title='" + lan.site.click_access + "' target='_blank' href='http://" + item.name + ":" + item.port + "' class='btlinkbed'>" + item.name + "</a>" } },
|
||||
{ field: 'port', width: '70px', title: lan.site.port },
|
||||
{ field: 'opt', width: '50px', title: lan.site.operate, templet: function(item) { return '<a class="table-btn-del domain_del" href="javascript:;"><span class="glyphicon glyphicon-trash"></span></a>'; } }
|
||||
{ field: 'opt', width: '50px', align: 'center', title: lan.site.operate, templet: function(item) { return '<a class="table-btn-del domain_del" href="javascript:;"><span class="glyphicon glyphicon-trash"></span></a>'; } }
|
||||
],
|
||||
data: rdata
|
||||
})
|
||||
@@ -1224,7 +1224,7 @@ var site = {
|
||||
{
|
||||
title: '',
|
||||
items: [
|
||||
{ name: 'path', title: lan.site.site_menu_2, width: '50%', value: path, event: { css: 'glyphicon-folder-open', callback: function(obj) { bt.select_path(obj); } } },
|
||||
{ name: 'path', title: lan.site.site_menu_2, width: '50%', value: path, add_class: 'ml5', event: { css: 'glyphicon-folder-open', callback: function(obj) { bt.select_path(obj); } } },
|
||||
{
|
||||
name: 'btn_site_path',
|
||||
type: 'button',
|
||||
@@ -1241,7 +1241,7 @@ var site = {
|
||||
{
|
||||
title: '',
|
||||
items: [
|
||||
{ title: lan.site.run_dir, width: '50%', value: rdata.runPath.runPath, name: 'dirName', type: 'select', items: dirs },
|
||||
{ title: lan.site.run_dir, width: '50%', value: rdata.runPath.runPath, name: 'dirName', type: 'select',add_class: 'ml5 mr20', items: dirs },
|
||||
{
|
||||
name: 'btn_run_path',
|
||||
type: 'button',
|
||||
@@ -1263,6 +1263,7 @@ var site = {
|
||||
_html.append($(_form_data.html).addClass('line mtb10'));
|
||||
clicks = clicks.concat(_form_data.clicks);
|
||||
}
|
||||
_html.find('input[name="path"]').parent().css('padding-left','27px');
|
||||
_html.find('input[type="checkbox"]').parent().addClass('label-input-group ptb10');
|
||||
_html.find('button[name="btn_run_path"]').addClass('ml45');
|
||||
_html.find('button[name="btn_site_path"]').addClass('ml33');
|
||||
@@ -1621,7 +1622,7 @@ var site = {
|
||||
_html.find('.info-r').append(_other)
|
||||
clicks = clicks.concat(_form_data.clicks);
|
||||
}
|
||||
_html.append(bt.render_help([lan.site.rewrite_tips, lan.site.edit_rewrite]));
|
||||
_html.append(bt.render_help([lan.site.rewrite_tips_1,lan.site.rewrite_tips_2, lan.site.edit_rewrite]));
|
||||
$('#webedit-con').append(_html);
|
||||
bt.render_clicks(clicks);
|
||||
|
||||
@@ -1673,8 +1674,9 @@ var site = {
|
||||
set_config: function(web) {
|
||||
var con = '<p style="color: #666; margin-bottom: 7px">Tips:Ctrl+F Search keywords,Ctrl+S Save,Ctrl+H Search and replace</p><div class="bt-input-text ace_config_editor_scroll" style="height: 400px; line-height:18px;" id="siteConfigBody"></div>\
|
||||
<button id="OnlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">Save</button>\
|
||||
<ul class="c7 ptb15">\
|
||||
<li>This is primary configuration file of the site, do NOT modify it at will if you do not know configuration rules.</li>\
|
||||
<ul class="help-info-text c7">\
|
||||
<li>This is primary configuration file of the site.</li>\
|
||||
<li>Do not modify it at will if you do not know configuration rules.</li>\
|
||||
</ul>';
|
||||
$("#webedit-con").html(con);
|
||||
var webserve = bt.get_cookie('serverType'),
|
||||
@@ -1684,7 +1686,7 @@ var site = {
|
||||
});
|
||||
},
|
||||
set_ssl: function(web) {
|
||||
$('#webedit-con').html("<div id='ssl_tabs'></div><div class=\"tab-con\" style=\"padding:10px 0px;\"></div>");
|
||||
$('#webedit-con').html("<div id='ssl_tabs'></div><div class=\"tab-con\" style=\"padding:10px 0px;width: 100%;\"></div>");
|
||||
bt.site.get_site_ssl(web.name, function(rdata) {
|
||||
var _tabs = [
|
||||
// {
|
||||
@@ -1803,18 +1805,18 @@ var site = {
|
||||
if (rdata.status && rdata.type == 1) {
|
||||
var cert_info = '';
|
||||
if (rdata.cert_data['notBefore']) {
|
||||
cert_info = '<div style="margin-bottom: 10px;" class="alert alert-success">\
|
||||
cert_info = '<div style="margin-bottom: 10px;padding: 10px;" class="alert alert-success">\
|
||||
<span style="display: inline-block;overflow: hidden;min-width: 49%;text-overflow: ellipsis;white-space: nowrap;max-width: 100%;"><b>' + lan.site.deploy_success_cret + '</b>' + lan.site.try_renew_cret + '</span>\
|
||||
<span style="display: inline-block;overflow: hidden;min-width: 49%;text-overflow: ellipsis;white-space: nowrap;max-width: 100%;">\
|
||||
<b>' + lan.site.cert_brand + '</b>' + rdata.cert_data.issuer + '</span>\
|
||||
<span style="display: inline-block;overflow: hidden;min-width: 49%;text-overflow: ellipsis;white-space: nowrap;max-width: 100%;"><b>' + lan.site.auth_domain + '</b> ' + rdata.cert_data.dns.join('、') + '</span>\
|
||||
<span style="display: inline-block;overflow: hidden;min-width: 49%;text-overflow: ellipsis;white-space: nowrap;max-width: 100%;"><b>' + lan.site.expire_time + '</b> ' + rdata.cert_data.notAfter + '</span></div>'
|
||||
}
|
||||
robj.append('<div>' + cert_info + '<div><span>' + lan.site.ssl_key + '</span><span style="padding-left:175px">' + lan.site.ssl_crt + '</span></div></div>');
|
||||
robj.append('<div>' + cert_info + '<div><span>' + lan.site.ssl_key + '</span><span style="padding-left:190px">' + lan.site.ssl_crt + '</span></div></div>');
|
||||
var datas = [{
|
||||
items: [
|
||||
{ name: 'key', width: '45%', height: '220px', type: 'textarea', value: rdata.key },
|
||||
{ name: 'csr', width: '45%', height: '220px', type: 'textarea', value: rdata.csr }
|
||||
{ name: 'key', width: '48%', height: '220px', type: 'textarea', value: rdata.key },
|
||||
{ name: 'csr', width: '48%', height: '220px', type: 'textarea', value: rdata.csr }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1844,7 +1846,8 @@ var site = {
|
||||
robj.append(_form_data.html);
|
||||
bt.render_clicks(_form_data.clicks);
|
||||
}
|
||||
robj.find('textarea').css('background-color', '#f6f6f6').attr('readonly', true);
|
||||
robj.find('textarea').css({'background-color':'#f6f6f6','resize':'none'}).attr('readonly', true);
|
||||
robj.find('[name=csr]').css('margin-right', '0');
|
||||
var helps = [
|
||||
lan.site.ssl_tips1,
|
||||
lan.site.ssl_tips2,
|
||||
@@ -1923,7 +1926,7 @@ var site = {
|
||||
class: 'checks_line',
|
||||
items: [{
|
||||
name: 'dns_select',
|
||||
width: '120px',
|
||||
width: 'auto',
|
||||
type: 'select',
|
||||
items: arrs_list,
|
||||
callback: function(obj) {
|
||||
@@ -2090,17 +2093,17 @@ var site = {
|
||||
callback: function(robj) {
|
||||
var cert_info = '';
|
||||
if (rdata.cert_data['notBefore']) {
|
||||
cert_info = '<div style="margin-bottom: 10px;" class="alert alert-success">\
|
||||
cert_info = '<div style="margin-bottom: 10px;padding: 10px;" class="alert alert-success">\
|
||||
<span style="display: inline-block;overflow: hidden;min-width: 49%;text-overflow: ellipsis;white-space: nowrap;max-width: 100%;">' + (rdata.status ? lan.site.deploy_success_tips : lan.site.not_deploy_and_save) + '</span>\
|
||||
<span style="display: inline-block;overflow: hidden;min-width: 49%;text-overflow: ellipsis;white-space: nowrap;max-width: 100%;"><b>' + lan.site.cert_brand + '</b>' + rdata.cert_data.issuer + '</span>\
|
||||
<span style="display:inline-block;max-width: 100%;min-width: 49%;overflow:hidden;text-overflow:ellipsis;white-space: nowrap; "><b>' + lan.site.auth_domain + '</b> ' + rdata.cert_data.dns.join('、') + '</span>\
|
||||
<span style="display:inline-block;max-width: 100%;min-width: 49%;overflow:hidden;text-overflow:ellipsis;white-space: nowrap; "><b>' + lan.site.expire_time + '</b> ' + rdata.cert_data.notAfter + '</span></div>'
|
||||
}
|
||||
robj.append('<div>' + cert_info + '<div><span>' + lan.site.ssl_key + '</span><span style="padding-left:171px">' + lan.site.ssl_crt + '</span></div></div>');
|
||||
robj.append('<div>' + cert_info + '<div><span>' + lan.site.ssl_key + '</span><span style="padding-left:190px">' + lan.site.ssl_crt + '</span></div></div>');
|
||||
var datas = [{
|
||||
items: [
|
||||
{ name: 'key', width: '45%', height: '220px', type: 'textarea', value: rdata.key },
|
||||
{ name: 'csr', width: '45%', height: '220px', type: 'textarea', value: rdata.csr }
|
||||
{ name: 'key', width: '48%', height: '220px', type: 'textarea', value: rdata.key },
|
||||
{ name: 'csr', width: '48%', height: '220px', type: 'textarea', value: rdata.csr }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2139,7 +2142,9 @@ var site = {
|
||||
lan.site.ssl_tips5,
|
||||
]
|
||||
robj.append(bt.render_help(helps));
|
||||
|
||||
robj.find(".help-info-text").css('margin-top','0');
|
||||
robj.find('textarea').css('resize','none');
|
||||
robj.find('[name=csr]').css('margin-right', '0');
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -2274,7 +2279,7 @@ var site = {
|
||||
_html.append(bt.render_help([lan.site.switch_php_help1, lan.site.switch_php_help2, lan.site.switch_php_help3]));
|
||||
$('#webedit-con').append(_html);
|
||||
bt.render_clicks(_form_data.clicks);
|
||||
$('#webedit-con').append('<div class="user_pw_tit" style="margin-top: 2px;padding-top: 11px;border-top: #ccc 1px dashed;"><span class="tit">' + lan.site.session_off + '</span><span class="btswitch-p"style="display: inline-flex;"><input class="btswitch btswitch-ios" id="session_switch" type="checkbox"><label class="btswitch-btn session-btn" for="session_switch" ></label></span></div><div class="user_pw" style="margin-top: 10px; display: block;"></div>' + bt.render_help([lan.site.independent_storage]));
|
||||
$('#webedit-con').append('<div class="user_pw_tit" style="margin-top: 2px;padding-top: 11px;border-top: #ccc 1px dashed;"><span class="tit">' + lan.site.session_off + '</span><span class="btswitch-p ml5" style="margin-bottom: 0;display: inline-block;vertical-align: middle;"><input class="btswitch btswitch-ios" id="session_switch" type="checkbox"><label class="btswitch-btn session-btn" for="session_switch" ></label></span></div><div class="user_pw" style="margin-top: 10px; display: block;"></div>' + bt.render_help([lan.site.independent_storage]));
|
||||
|
||||
function get_session_status() {
|
||||
var loading = bt.load('Getting session status...');
|
||||
@@ -2336,7 +2341,7 @@ var site = {
|
||||
"<div class='info-r ml0 mt5' >" +
|
||||
"<input class='btswitch btswitch-ios' id='type' type='checkbox' name='type' " + (obj.type == 1 ? 'checked="checked"' : '') + " /><label class='btswitch-btn phpmyadmin-btn' for='type' style='float:left'></label>" +
|
||||
"<div style='display: inline-block;'>" +
|
||||
"<span class='tname' style='margin-left:10px;position: relative;top: -5px; width:150px;'>" + lan.site.reserve_url + "</span>" +
|
||||
"<span class='tname' style='margin-left:51px;position: relative;top: -5px; width:150px;'>" + lan.site.reserve_url + "</span>" +
|
||||
"<input class='btswitch btswitch-ios' id='holdpath' type='checkbox' name='holdpath' " + (obj.holdpath == 1 ? 'checked="checked"' : '') + " /><label class='btswitch-btn phpmyadmin-btn' for='holdpath' style='float:left'></label>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
@@ -2354,10 +2359,12 @@ var site = {
|
||||
"</div>" +
|
||||
"<div class='line redirectdomain' style='display:" + (obj.domainorpath == 'domain' ? 'block' : 'none') + "'>" +
|
||||
"<span class='tname'>" + lan.site.redirect_domain + "</span>" +
|
||||
"<div class='info-r ml0'>" +
|
||||
"<div class='info-r ml0' style='height: 35px;'>" +
|
||||
"<select id='usertype' name='redirectdomain' data-actions-box='true' class='selectpicker show-tick form-control' multiple data-live-search='false'>" + domain_html + "</select>" +
|
||||
"<span class='tname' style='width:90px'>" + lan.site.target_url + "</span>" +
|
||||
"<input name='tourl' class='bt-input-text mr5' type='text' style='width:200px;padding-left: 9px;' value='" + obj.tourl + "'>" +
|
||||
"</div>" +
|
||||
"<span class='tname'>" + lan.site.target_url + "</span>" +
|
||||
"<div class='info-r ml0'>" +
|
||||
"<input name='tourl' class='bt-input-text mr5' type='text' style='width:200px;padding-left: 9px;' value='" + obj.tourl + "'>"+
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='line redirectpath' style='display:" + (obj.domainorpath == 'path' ? 'block' : 'none') + "'>" +
|
||||
@@ -2739,29 +2746,34 @@ var site = {
|
||||
"<input class='btswitch btswitch-ios' id='openNginx' type='checkbox' name='cache' " + (obj.cache == 1 ? 'checked="checked"' : '') + "'><label class='btswitch-btn phpmyadmin-btn' for='openNginx'></label>" +
|
||||
"</div>" +
|
||||
"<div style='display: inline-block;'>" +
|
||||
"<span class='tname' style='margin-left:10px;position: relative;top: -5px;width:150px;'>" + lan.site.proxy_adv + "</span>" +
|
||||
"<span class='tname' style='position: relative;top: -5px;width:150px;padding-right: 10px;'>" + lan.site.proxy_adv + "</span>" +
|
||||
"<input class='btswitch btswitch-ios' id='openAdvanced' type='checkbox' name='advanced' " + (obj.advanced == 1 ? 'checked="checked"' : '') + "'><label class='btswitch-btn phpmyadmin-btn' for='openAdvanced'></label>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='line' style='clear:both;'>" +
|
||||
"<span class='tname'>" + lan.site.proxy_name + "</span>" +
|
||||
"<div class='info-r ml0'><input name='proxyname'" + (type ? "" : "readonly='readonly'") + " class='bt-input-text mr5 " + (type ? "" : " disabled") + "' type='text' style='width:200px' value='" + obj.proxyname + "'></div>" +
|
||||
"<div class='info-r ml0'><input name='proxyname'" + (type ? "" : "readonly='readonly'") + " class='bt-input-text mr5 " + (type ? "" : " disabled") + "' type='text' style='width:220px' value='" + obj.proxyname + "'></div>" +
|
||||
"</div>" +
|
||||
"<div class='line cachetime' style='display:" + (obj.cache == 1 ? 'block' : 'none') + "'>" +
|
||||
"<span class='tname'>" + lan.site.cache_time + "</span>" +
|
||||
"<div class='info-r ml0'><input name='cachetime'class='bt-input-text mr5' type='text' style='width:200px' value='" + obj.cachetime + "'>" + lan.site.minute + "</div>" +
|
||||
"<div class='info-r ml0'><input name='cachetime'class='bt-input-text mr5' type='text' style='width:220px' value='" + obj.cachetime + "'>" + lan.site.minute + "</div>" +
|
||||
"</div>" +
|
||||
"<div class='line advanced' style='display:" + (obj.advanced == 1 ? 'block' : 'none') + "'>" +
|
||||
"<span class='tname'>" + lan.site.proxy_dir + "</span>" +
|
||||
"<div class='info-r ml0'><input id='proxydir' name='proxydir' class='bt-input-text mr5' type='text' style='width:200px' value='" + obj.proxydir + "'>" +
|
||||
"<div class='info-r ml0'><input id='proxydir' name='proxydir' class='bt-input-text mr5' type='text' style='width:220px' value='" + obj.proxydir + "'>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='line'>" +
|
||||
"<span class='tname'>" + lan.site.target_url + "</span>" +
|
||||
"<div class='info-r ml0'>" +
|
||||
"<input name='proxysite' class='bt-input-text mr10' type='text' style='width:200px' value='" + obj.proxysite + "'>" +
|
||||
"<span class='mlr15'>" + lan.site.proxy_domain + "</span><input name='todomain' class='bt-input-text ml10' type='text' style='width:200px' value='" + obj.todomain + "'>" +
|
||||
"<input name='proxysite' class='bt-input-text mr10' type='text' style='width:220px' value='" + obj.proxysite + "'>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='line'>" +
|
||||
"<span class='tname'>" + lan.site.proxy_domain + "</span>" +
|
||||
"<div class='info-r ml0'>" +
|
||||
"<input name='todomain' class='bt-input-text ml10' type='text' style='width:220px' value='" + obj.todomain + "'>"+
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='line replace_conter' style='display:" + (bt.get_cookie('serverType') == 'nginx' ? 'block' : 'none') + "'>" +
|
||||
@@ -3056,6 +3068,7 @@ var site = {
|
||||
robj.append(_form_data.html);
|
||||
bt.render_clicks(_form_data.clicks);
|
||||
}
|
||||
robj.find("#none").css('margin-top','10px')
|
||||
$("#none").before("</br>");
|
||||
var helps = [lan.site.access_empty_ref_default, lan.site.multi_url, lan.site.trigger_return_404]
|
||||
robj.append(bt.render_help(helps));
|
||||
@@ -3094,9 +3107,10 @@ var site = {
|
||||
get_site_logs: function(web) {
|
||||
bt.site.get_site_logs(web.name, function(rdata) {
|
||||
var robj = $('#webedit-con');
|
||||
var logs = { class: 'bt-logs', items: [{ name: 'site_logs', height: '520px', value: rdata.msg, width: '100%', type: 'textarea' }] };
|
||||
var logs = { class: 'bt-logs', items: [{ name: 'site_logs', height: '592px', value: rdata.msg, width: '100%', type: 'textarea' }] };
|
||||
var _form_data = bt.render_form_line(logs);
|
||||
robj.append(_form_data.html);
|
||||
robj.find('.site_logs').css('resize','none');
|
||||
bt.render_clicks(_form_data.clicks);
|
||||
$('textarea[name="site_logs"]').attr('readonly', true);
|
||||
$('textarea[name="site_logs"]').scrollTop(100000000000)
|
||||
|
||||
@@ -250,7 +250,7 @@ var soft = {
|
||||
},
|
||||
{
|
||||
field: 'opt',
|
||||
width: 180,
|
||||
width: 190,
|
||||
title: lan.soft.operate,
|
||||
align: 'right',
|
||||
templet: function(item) {
|
||||
@@ -1201,7 +1201,7 @@ var soft = {
|
||||
var title11 = ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2);
|
||||
var title12 = ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2);
|
||||
var title14 = ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2);
|
||||
var Con = '<div class="divtable"><table class="table table-hover table-bordered" style="width: 590px;margin-bottom:10px;background-color:#fafafa">\
|
||||
var Con = '<div class="divtable"><table class="table table-hover table-bordered" style="margin-bottom:10px;background-color:#fafafa">\
|
||||
<tbody>\
|
||||
<tr><th>' + lan.soft.mysql_status_title1 + '</th><td>' + getLocalTime(rdata.Run) + '</td><th>' + lan.soft.mysql_status_title5 + '</th><td>' + parseInt(rdata.Questions / rdata.Uptime) + '</td></tr>\
|
||||
<tr><th>' + lan.soft.mysql_status_title2 + '</th><td>' + rdata.Connections + '</td><th>' + lan.soft.mysql_status_title6 + '</th><td>' + parseInt((parseInt(rdata.Com_commit) + parseInt(rdata.Com_rollback)) / rdata.Uptime) + '</td></tr>\
|
||||
@@ -1209,7 +1209,7 @@ var soft = {
|
||||
<tr><th>' + lan.soft.mysql_status_title4 + '</th><td>' + ToSize(rdata.Bytes_received) + '</td><th>' + lan.soft.mysql_status_title8 + '</th><td>' + rdata.Position + '</td></tr>\
|
||||
</tbody>\
|
||||
</table>\
|
||||
<table class="table table-hover table-bordered" style="width: 490px;margin-bottom: 10px;">\
|
||||
<table class="table table-hover table-bordered" style="margin-bottom: 10px;">\
|
||||
<thead style="display:none;"><th></th><th></th><th></th><th></th></thead>\
|
||||
<tbody>\
|
||||
<tr><th>' + lan.soft.mysql_status_title9 + '</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td colspan="2">' + lan.soft.mysql_status_ps1 + '</td></tr>\
|
||||
|
||||
@@ -0,0 +1,962 @@
|
||||
function Terms(el,config){
|
||||
if(typeof config == "undefined") config = {};
|
||||
this.el = el;
|
||||
this.id = config.ssh_info.id || '';
|
||||
this.bws = null; //websocket对象
|
||||
this.route ='/webssh'; // 访问的方法
|
||||
this.term =null; //term对象
|
||||
this.info =null; // 请求数据
|
||||
this.last_body =null;
|
||||
this.fontSize =15; //终端字体大小
|
||||
this.ssh_info = config.ssh_info;
|
||||
this.run();
|
||||
}
|
||||
Terms.prototype = {
|
||||
// websocket持久化连接
|
||||
connect:function(callback){
|
||||
var that = this;
|
||||
// 判断当前websocket连接是否存在
|
||||
if(!this.bws || this.bws.readyState == 3 || this.bws.readyState == 2){
|
||||
this.bws = new WebSocket((window.location.protocol === 'http:' ? 'ws://' : 'wss://') + window.location.host + this.route);
|
||||
this.bws.addEventListener('message',function(ev){that.on_message(ev)});
|
||||
this.bws.addEventListener('close',function(ev){that.on_close(ev)});
|
||||
this.bws.addEventListener('error',function(ev){that.on_error(ev)});
|
||||
this.bws.addEventListener('open',function(ev){that.on_open(ev)});
|
||||
if(callback) callback(this.bws)
|
||||
}
|
||||
},
|
||||
|
||||
//连接服务器成功
|
||||
on_open:function(ws_event){
|
||||
this.send(JSON.stringify(this.ssh_info || {}))
|
||||
this.term.FitAddon.fit();
|
||||
this.resize({cols:this.term.cols, rows:this.term.rows});
|
||||
},
|
||||
//服务器消息事件
|
||||
on_message: function (ws_event){
|
||||
result = ws_event.data;
|
||||
if (result === "\rServer connection failed!\r" || result == "\rWrong user name or password!\r") {
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
if(result.length > 1 && this.last_body === false){
|
||||
this.last_body = true;
|
||||
}
|
||||
this.term.write(result);
|
||||
this.set_term_icon(1);
|
||||
if (result == '\r\nLog out\r\n' || result == 'Log out\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') {
|
||||
// setTimeout(function () {
|
||||
// layer.close(Term.term_box);
|
||||
// }, 500);
|
||||
this.close();
|
||||
this.bws = null;
|
||||
|
||||
}
|
||||
},
|
||||
//websocket关闭事件
|
||||
on_close: function (ws_event) {
|
||||
this.set_term_icon(0);
|
||||
this.bws = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 设置终端标题状态
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {number} status 终端状态
|
||||
* @return void
|
||||
*/
|
||||
set_term_icon:function(status){
|
||||
var icon_list = ['icon-warning','icon-sucess','icon-info'];
|
||||
if(status == 1){
|
||||
if($("[data-id='"+ this.id +"']").attr("class").indexOf('active') == -1){
|
||||
status = 2;
|
||||
}
|
||||
}
|
||||
$("[data-id='"+ this.id +"']").find('.icon').removeAttr('class').addClass(icon_list[status]+' icon');
|
||||
if(status == 2){
|
||||
that = this;
|
||||
setTimeout(function(){
|
||||
$("[data-id='"+ that.id +"']").find('.icon').removeAttr('class').addClass(icon_list[1]+' icon');
|
||||
},200);
|
||||
}
|
||||
},
|
||||
//websocket错误事件
|
||||
on_error: function (ws_event) {
|
||||
if(ws_event.target.readyState === 3){
|
||||
// var msg = '错误: 无法创建WebSocket连接,请在面板设置页面关闭【开发者模式】';
|
||||
// layer.msg(msg,{time:5000})
|
||||
// if(Term.state === 3) return
|
||||
// Term.term.write(msg)
|
||||
// Term.state = 3;
|
||||
}else{
|
||||
console.log(ws_event)
|
||||
}
|
||||
},
|
||||
//发送数据
|
||||
//@param event 唯一事件名称
|
||||
//@param data 发送的数据
|
||||
//@param callback 服务器返回结果时回调的函数,运行完后将被回收
|
||||
send: function (data, num) {
|
||||
var that = this;
|
||||
//如果没有连接,则尝试连接服务器
|
||||
if (!this.bws || this.bws.readyState == 3 || this.bws.readyState == 2) {
|
||||
this.connect();
|
||||
}
|
||||
|
||||
//判断当前连接状态,如果!=1,则100ms后尝试重新发送
|
||||
if (this.bws.readyState === 1) {
|
||||
this.bws.send(data);
|
||||
} else {
|
||||
if(this.state === 3) return;
|
||||
if (!num) num = 0;
|
||||
if (num < 5) {
|
||||
num++;
|
||||
setTimeout(function () { that.send(data, num++); }, 100)
|
||||
}
|
||||
}
|
||||
},
|
||||
//关闭连接
|
||||
close: function () {
|
||||
this.bws.close();
|
||||
this.set_term_icon(0);
|
||||
},
|
||||
resize: function (size){
|
||||
if(this.bws){
|
||||
size['resize'] = 1;
|
||||
this.send(JSON.stringify(size));
|
||||
this.term
|
||||
}
|
||||
|
||||
},
|
||||
run: function (ssh_info) {
|
||||
var that = this;
|
||||
this.term = new Terminal({fontSize:this.fontSize, screenKeys: true, useStyle: true });
|
||||
this.term.setOption('cursorBlink', true);
|
||||
this.last_body = false;
|
||||
this.term.open($(this.el)[0]);
|
||||
|
||||
this.term.FitAddon = new FitAddon.FitAddon();
|
||||
this.term.loadAddon(this.term.FitAddon);
|
||||
this.term.WebLinksAddon = new WebLinksAddon.WebLinksAddon()
|
||||
this.term.loadAddon(this.term.WebLinksAddon)
|
||||
if (ssh_info) this.ssh_info = ssh_info
|
||||
this.connect();
|
||||
that.term.onData(function (data) {
|
||||
try {
|
||||
that.bws.send(data)
|
||||
} catch (e) {
|
||||
that.term.write('\r\nConnection lost, trying to connect again!\r\n')
|
||||
that.connect()
|
||||
}
|
||||
});
|
||||
this.term.focus();
|
||||
}
|
||||
}
|
||||
|
||||
var host_trem = {
|
||||
host_term:{},
|
||||
host_list:[],
|
||||
command_list:[],
|
||||
sort_time:null,
|
||||
command_form:{
|
||||
title:'',
|
||||
shell:'',
|
||||
},
|
||||
host_form:{
|
||||
host:'',
|
||||
port:'22', //默认端口22
|
||||
username:'root',
|
||||
password:'',
|
||||
pkey: '',
|
||||
ps: ''
|
||||
},
|
||||
init:function(){
|
||||
var that = this,isMousemove = true;
|
||||
$(window).resize(function(){
|
||||
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight;
|
||||
$('.main-content .safe').height(win_height - 105);
|
||||
$('#term_box_view,.term_tootls').height(win_height - 105);
|
||||
$('.tootls_commonly_list').height(win_height - 563);
|
||||
var id = $('.term_item_tab .active').data('id');
|
||||
var item_term = that.host_term[id].term;
|
||||
item_term.FitAddon.fit();
|
||||
that.host_term[id].resize({cols:item_term.cols, rows:item_term.rows});
|
||||
});
|
||||
|
||||
$(document).ready(function (e) {
|
||||
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight;
|
||||
$('.main-content .safe').height(win_height - 105);
|
||||
$('#term_box_view,.term_tootls').height(win_height - 105);
|
||||
$('.tootls_commonly_list').height(win_height - 563);
|
||||
that.open_term_view();
|
||||
});
|
||||
|
||||
// 添加服务器信息
|
||||
$('.addServer').on('click',function(){
|
||||
that.editor_host_view();
|
||||
});
|
||||
|
||||
// 切换服务器终端视图
|
||||
$('.term_item_tab .list').on('click','span.item',function(ev){
|
||||
var index = $(this).index(),data = $(this).data();
|
||||
if($(this).hasClass('addServer')){
|
||||
|
||||
}else if($(this).hasClass('tab_tootls')){
|
||||
|
||||
}else{
|
||||
$(this).addClass('active').siblings().removeClass('active');
|
||||
$('.term_content_tab .term_item:eq('+ index +')').addClass('active').siblings().removeClass('active');
|
||||
that.host_term[data.id];
|
||||
var item = that.host_term[data.id];
|
||||
item.term.focus();
|
||||
item.term.FitAddon.fit();
|
||||
item.resize({cols:item.term.cols, rows:item.term.rows});
|
||||
}
|
||||
|
||||
});
|
||||
$('.term_item_tab').on('click','.icon-trem-close',function(){
|
||||
var id = $(this).parent().data('id');
|
||||
that.remove_term_view(id);
|
||||
})
|
||||
|
||||
|
||||
// 服务器列表工具箱
|
||||
$('.tootls_host_list').on('click','li .tootls span',function(ev){
|
||||
var item = $(this).parent().parent(),host = item.data('host'),index = item.data('index');
|
||||
if(!$(this).index()){
|
||||
that.get_host_find(host,function(rdata){
|
||||
if(rdata.status === false){
|
||||
bt.msg(rdata);
|
||||
return false;
|
||||
}
|
||||
that.editor_host_view({
|
||||
form:rdata,
|
||||
config: {btn: 'Save', title: 'Edit server information 【'+ host +'】'}
|
||||
});
|
||||
});
|
||||
}else{
|
||||
bt.confirm({title:'Delete information',msg:'Delete service information 【'+ host +'】, continue?',icon:0},function(index){
|
||||
that.remove_host(host,function(rdata){
|
||||
layer.close(index);
|
||||
that.reader_host_list(function(){
|
||||
bt.msg(rdata);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
ev.stopPropagation();
|
||||
});
|
||||
// 服务器列表工具箱
|
||||
$('.tootls_commonly_list').on('click','li .tootls span',function(ev){
|
||||
var item = $(this).parent().parent(),title = item.data('title'),index = item.data('index');
|
||||
if(!$(this).index()){
|
||||
that.get_command_find(title,function(rdata){
|
||||
if(rdata.status === false){
|
||||
bt.msg(rdata);
|
||||
return false;
|
||||
}
|
||||
that.editor_command_view({
|
||||
form:rdata,
|
||||
config: {btn: 'Save', title: 'Edit command information【'+ title +'】'}
|
||||
});
|
||||
});
|
||||
}else{
|
||||
bt.confirm({title:'Delete command',msg:'Delete service command 【'+ title +'】, continue?',icon:0},function(index){
|
||||
that.remove_command(title,function(rdata){
|
||||
layer.close(index);
|
||||
that.reader_command_list(function(){
|
||||
bt.msg(rdata);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
ev.stopPropagation();
|
||||
});
|
||||
// 右键菜单
|
||||
$('.term_item_tab .list').on('mousedown','.item',function(ev){
|
||||
if(ev.which == 3){
|
||||
that.reader_right_menu({
|
||||
el:$(this),
|
||||
position:[ev.clientX,ev.clientY],
|
||||
list:[
|
||||
[{title:'Copy session',event:function(el,data){
|
||||
that.open_term_view(that.host_term[data.id].ssh_info);
|
||||
}}],
|
||||
[{title:'Close session',event:function(el,data){
|
||||
that.remove_term_view(data.id);
|
||||
}},
|
||||
{title:'Close to right',event:function(el,data){
|
||||
bt.confirm({msg:'After closing the terminal session, the command in progress in the current command line session may be aborted. Continue?',title: "Close the terminal session?"},function(index){
|
||||
that.remove_term_right_view(data.id);
|
||||
layer.close(index);
|
||||
});
|
||||
}},
|
||||
{title:'Close other',event:function(el,data){
|
||||
bt.confirm({msg:'After closing the terminal session, the command in progress in the current command line session may be aborted. Continue?',title: "Close the terminal session?"},function(index){
|
||||
that.remove_term_other_view(data.id);
|
||||
layer.close(index);
|
||||
});
|
||||
}}]
|
||||
]
|
||||
},function(){
|
||||
$(document).unbind('contextmenu');
|
||||
});
|
||||
ev.preventDefault();
|
||||
$(document).contextmenu(function(e){
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 添加服务器和常用秘钥
|
||||
$('.term_tootls .tootls_tab a').click(function(){
|
||||
var type = $(this).data('type');
|
||||
if(type == 'host'){
|
||||
that.editor_host_view();
|
||||
}else{
|
||||
that.editor_command_view();
|
||||
}
|
||||
});
|
||||
// var clientX = null,clientY = null;
|
||||
// $('.tootls_host_list').on('mousedown','li',function(e){
|
||||
// clientX = e.clientX,clientY = e.clientY;
|
||||
// })
|
||||
// 模拟触发服务器列表点击事件
|
||||
// $('.tootls_host_list').on('mouseup','li',function(e){
|
||||
// if(e.button == 0){
|
||||
// if(clientX == e.clientX && clientY == e.clientY){
|
||||
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
$('.tootls_host_list').on('click','li',function(e){
|
||||
var index = $(this).index(),host = $(this).data('host');
|
||||
$(this).find('i').addClass('active');
|
||||
if($('.item[data-host="'+ host +'"]').length > 0){
|
||||
layer.msg('For multi session window, right click the terminal title to copy the session!',{icon:0,time:3000})
|
||||
}else{
|
||||
that.open_term_view(that.host_list[index]);
|
||||
}
|
||||
});
|
||||
// 服务器列表拖动
|
||||
$('.tootls_host_list').dragsort({
|
||||
dragSelector:'li i',
|
||||
dragEnd:function(){
|
||||
clearTimeout(that.sort_time);
|
||||
that.sort_time = setTimeout(function(){
|
||||
var sort_list = {};
|
||||
$('.tootls_host_list li').each(function(index,el){
|
||||
sort_list[$(this).data('host')] = index;
|
||||
});
|
||||
that.set_sort(sort_list,function(rdata){
|
||||
if(!rdata.status){
|
||||
bt.msg(rdata);
|
||||
}
|
||||
});
|
||||
},500);
|
||||
},
|
||||
dragBetween:false,
|
||||
});
|
||||
this.reader_host_list();
|
||||
this.reader_command_list();
|
||||
},
|
||||
|
||||
reader_right_menu:function(config,callback){
|
||||
var menu = $('<ul class="menu_right_list" id="term_title_menu"></ul>').css({'top':config.position[1],'left':config.position[0]}),html = '';
|
||||
bt.each(config.list,function(index,item){
|
||||
bt.each(item,function(indexs,items){
|
||||
(function(items){
|
||||
menu.append($('<li></li>').append($('<a href="javascript:;" title="'+ items.title +'">'+ items.title +'</a>').click(function(e){
|
||||
if(items.event) items.event(config.el,$(config.el).data())
|
||||
menu.remove();
|
||||
if(callback) callback();
|
||||
})));
|
||||
}(items));
|
||||
});
|
||||
if(index != config.list.length - 1){
|
||||
menu.append('<li class="split_line"></li>');
|
||||
}
|
||||
});
|
||||
if(!$('#term_title_menu').length){
|
||||
$('body').append(menu);
|
||||
}else{
|
||||
$('#term_title_menu').replaceWith(menu);
|
||||
}
|
||||
$(document).click(function(e){
|
||||
menu.remove();
|
||||
$(this).unbind('click');
|
||||
if(callback) callback();
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @name 主机信息添加或编辑
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {Objeact} obj 需要编辑的form数据,可以为空,为空则添加
|
||||
* @return void
|
||||
*/
|
||||
editor_host_view:function(obj){
|
||||
var that = this;
|
||||
if (!obj) obj = {form: this.host_form, config: {btn: 'Submit', title: 'Add host information'}}
|
||||
this.render_template({
|
||||
html: host_form_view.innerHTML,
|
||||
data: obj
|
||||
}, function (html) {
|
||||
layer.open({
|
||||
type: 1 //Page层类型
|
||||
,area: '510px'
|
||||
,closeBtn: 2
|
||||
,title: obj.config.title
|
||||
,btn: [obj.config.btn, 'Cancel']
|
||||
,content: html
|
||||
,success: function (layers, index){
|
||||
$('.auth_type_checkbox').click(function(){
|
||||
var index = $(this).index();
|
||||
$(this).addClass('btn-success').removeClass('btn-default').siblings().removeClass('btn-success').addClass('btn-default')
|
||||
switch(index){
|
||||
case 0:
|
||||
$('.c_password_view').addClass('show').removeClass('hidden');
|
||||
$('.c_pkey_view').addClass('hidden').removeClass('show').find('input').val('');
|
||||
break;
|
||||
case 1:
|
||||
$('.c_password_view').addClass('hidden').removeClass('show').find('input').val('');
|
||||
$('.c_pkey_view').addClass('show').removeClass('hidden');
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
$('[name="host"]').on('change',function(){
|
||||
var host_val = $(this).val();
|
||||
if(!host_val) return;
|
||||
|
||||
var s_host,s_port,s_username,s_password;
|
||||
s_host = host_val;
|
||||
if(host_val.indexOf('@') != -1){
|
||||
var tmp = host_val.split('@')
|
||||
s_host = tmp[1]
|
||||
s_username = tmp[0]
|
||||
|
||||
if (s_username.indexOf(':') != -1){
|
||||
var tmp = s_username.split(':')
|
||||
s_username = tmp[0]
|
||||
s_password = tmp[1]
|
||||
}
|
||||
}
|
||||
if(s_host.indexOf(':')!=-1){
|
||||
var tmp = s_host.split(':')
|
||||
s_host = tmp[0]
|
||||
s_port = tmp[1]
|
||||
}
|
||||
|
||||
if(s_host) {
|
||||
$(this).val(s_host);
|
||||
$('[name="ps"]').val(s_host);
|
||||
}
|
||||
if(s_port) $('[name="port"]').val(s_port);
|
||||
if(s_username) $('[name="username"]').val(s_username);
|
||||
if(s_password) $('[name="password"]').val(s_password);
|
||||
});
|
||||
|
||||
$('[name="host"]').on('input',function(){
|
||||
$('[name="ps"]').val($(this).val());
|
||||
});
|
||||
$('[name="password"],[name="ps"]').keyup(function(e){
|
||||
if(e.keyCode === 13){
|
||||
$('#layui-layer'+ index +' .layui-layer-btn0').click();
|
||||
}
|
||||
});
|
||||
},
|
||||
yes:function(indexs,layero){
|
||||
var form = {};
|
||||
$('.bt-form input,.bt-form textarea').each(function(index,el){
|
||||
var name = $(this).attr('name'),value = $(this).val();
|
||||
form[name] = value;
|
||||
switch(name){
|
||||
// case 'host':
|
||||
// if(!bt.check_ip(value)){
|
||||
// bt.msg({status:false,msg:'服务器ip地址格式错误!'});
|
||||
// return false;
|
||||
// }
|
||||
// break;
|
||||
case 'port':
|
||||
if(!bt.check_port(value)){
|
||||
bt.msg({status:false,msg:'Server port format error!'});
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'username':
|
||||
if(value == ''){
|
||||
bt.msg({status:false,msg:'Server user name cannot be empty!'});
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'password':
|
||||
if(value == '' && $('.c_password_view').hasClass('show')){
|
||||
bt.msg({status:false,msg:'Server password cannot be empty!'});
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'pkey':
|
||||
if(value == '' && $('.c_pkey_view').hasClass('show')){
|
||||
bt.msg({status:false,msg:'Server key cannot be empty!'});
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
if(!obj.form.host){
|
||||
delete form.sort;
|
||||
that.create_host(form,function(res){
|
||||
if(res.status){
|
||||
that.open_term_view(form);
|
||||
layer.close(indexs)
|
||||
that.reader_host_list(function(){
|
||||
bt.msg(res);
|
||||
})
|
||||
}
|
||||
});
|
||||
}else{
|
||||
form.new_host = obj.form.host;
|
||||
that.modify_host(form,function(res){
|
||||
if(res.status){
|
||||
layer.close(indexs)
|
||||
that.reader_host_list(function(){
|
||||
bt.msg(res);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 常用信息添加或编辑
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {Objeact} obj 需要编辑的form数据,可以为空,为空则添加
|
||||
* @return void
|
||||
*/
|
||||
editor_command_view:function(obj){
|
||||
var that = this;
|
||||
if (!obj) obj = {form: this.command_form, config: {btn: 'Submit', title: 'Add command information'}};
|
||||
this.render_template({
|
||||
html: shell_form_view.innerHTML,
|
||||
data: obj
|
||||
}, function (html) {
|
||||
layer.open({
|
||||
type: 1 //Page层类型
|
||||
,area: '510px'
|
||||
,closeBtn: 2
|
||||
,title: obj.config.title
|
||||
,btn: [obj.config.btn, 'Cancel']
|
||||
,content: html
|
||||
,yes: function (indexs,layero){
|
||||
var shell = $('[name="shell"]').val(),title = $('[name="title"]').val();
|
||||
if(title == ''){
|
||||
bt.msg({status:false,msg:'Command description cannot be empty!'});
|
||||
return false;
|
||||
}
|
||||
if(shell == ''){
|
||||
bt.msg({status:false,msg:'Command cannot be empty!'});
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!obj.form.title){
|
||||
that.create_command({shell:shell,title:title},function(res){
|
||||
if(res.status){
|
||||
layer.close(indexs);
|
||||
that.reader_command_list(function(){
|
||||
bt.msg(res);
|
||||
});
|
||||
}
|
||||
});
|
||||
}else{
|
||||
that.modify_command({new_title:title,title:obj.form.title,shell:shell},function(res){
|
||||
if(res.status){
|
||||
layer.close(indexs);
|
||||
that.reader_command_list(function(){
|
||||
bt.msg(res);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @name 设置终端标题状态
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {String} id 终端ID
|
||||
* @param {number} status 终端状态
|
||||
* @return void
|
||||
*/
|
||||
set_term_icon:function(id,status){
|
||||
var icon_list = ['icon-warning','icon-sucess','icon-info'];
|
||||
$("[data-id='"+ id +"']").find('.icon').removeAttr('class').addClass(icon_list[status]+' icon');
|
||||
},
|
||||
/**
|
||||
* @name 打开终端显示视图
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {Objeact} info 终端数据 {
|
||||
* ps:已添加的备注,
|
||||
* host:已添加的服务器ip
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
open_term_view:function(info){
|
||||
if(typeof info === "undefined") info = {host:'127.0.0.1',ps:'Local server'}
|
||||
var random = bt.get_random(9),tab_content = $('.term_content_tab'),item_list = $('.term_item_tab .list');
|
||||
tab_content.find('.term_item').removeClass('active').siblings().removeClass('active');
|
||||
tab_content.append('<div class="term_item active" id="'+ random +'" data-host="'+ info.host +'"></div>');
|
||||
item_list.find('.item').removeClass('active');
|
||||
item_list.append('<span class="active item" data-host="'+ info.host +'" data-id="'+ random +'"><i class="icon icon-sucess"></i><div class="content"><span>'+ info.ps +'</span></div><span class="icon-trem-close"></span></span>');
|
||||
this.host_term[random] = new Terms('#'+random,{ssh_info:{host:info.host,ps:info.ps,id:random}});
|
||||
},
|
||||
/**
|
||||
* @name 关闭终端显示视图
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {String} id 终端id
|
||||
* @return void
|
||||
*/
|
||||
remove_term_view:function(id){
|
||||
var item = $('[data-id="'+ id +'"]'),next = item.next(),prev = item.prev();
|
||||
$('#'+id).remove();
|
||||
item.remove();
|
||||
try {
|
||||
this.host_term[id].bws.close();
|
||||
} catch (error) {
|
||||
}
|
||||
delete this.host_term[id];
|
||||
if(item.hasClass('active')){
|
||||
if(next.length > 0){
|
||||
next.click();
|
||||
}else{
|
||||
prev.click();
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @name 关闭选中右侧终端显示视图
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {String} id 终端id
|
||||
* @return void
|
||||
*/
|
||||
remove_term_right_view:function(id){
|
||||
var arry = [],item = $('[data-id="'+ id +'"]'),nextAll = item.nextAll(),that = this;
|
||||
if(!nextAll.length){
|
||||
return false;
|
||||
}
|
||||
nextAll.each(function(index,el){
|
||||
var data = $(this).data();
|
||||
try {
|
||||
that.host_term[data.id].bws.close();
|
||||
} catch (error) {
|
||||
}
|
||||
delete that.host_term[data.id];
|
||||
});
|
||||
nextAll.remove();
|
||||
item.addClass('active');
|
||||
$('#'+id).addClass('active').nextAll().remove();
|
||||
},
|
||||
/**
|
||||
* @name 关闭其他终端显示视图
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {String} id 终端id
|
||||
* @return void
|
||||
*/
|
||||
remove_term_other_view:function(id){
|
||||
var arry = [],item = $('[data-id="'+ id +'"]'),siblings = item.siblings(),that = this;
|
||||
if(!siblings.length){
|
||||
return false;
|
||||
}
|
||||
siblings.each(function(index,el){
|
||||
var data = $(this).data();
|
||||
try {
|
||||
that.host_term[data.id].bws.close();
|
||||
} catch (error) {
|
||||
}
|
||||
delete that.host_term[data.id];
|
||||
});
|
||||
siblings.remove();
|
||||
item.addClass('active');
|
||||
$('#'+id).addClass('active').siblings().remove();
|
||||
},
|
||||
/**
|
||||
* @name 渲染常用命令列表
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {Objeact} callback 回调函数,回调参数1:当前请求内容
|
||||
* @return void
|
||||
*/
|
||||
reader_command_list:function(callback){
|
||||
var that = this,html = '';
|
||||
this.get_command_list(function(rdata){
|
||||
bt.each(rdata,function(index,item){
|
||||
html += '<li data-title="'+ item.title +'" data-index="'+ index +'" data-clipboard-text="'+ item.shell +'"><i></i><span>'+ item.title +'</span><span class="tootls">'+
|
||||
'<span class="glyphicon glyphicon-edit" aria-hidden="true" title="Edit common command information"></span>'+
|
||||
'<span class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete common command information"></span>'+
|
||||
'</span></li>';
|
||||
});
|
||||
$('.tootls_commonly_list').html(html);
|
||||
var clipboard = new ClipboardJS('.tootls_commonly_list li');
|
||||
clipboard.on('success', function(e) {
|
||||
layer.msg('Copy succeeded!',{icon:1});
|
||||
e.clearSelection();
|
||||
});
|
||||
|
||||
clipboard.on('error', function(e) {
|
||||
console.error('Action:', e.action);
|
||||
console.error('Trigger:', e.trigger);
|
||||
});
|
||||
that.command_list = rdata;
|
||||
if(callback) callback(rdata)
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @name 渲染主机视图列表
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {Objeact} callback 回调函数,回调参数1:当前请求内容
|
||||
* @return void
|
||||
*/
|
||||
reader_host_list:function(callback){
|
||||
var that = this,html = '';
|
||||
this.get_host_list(function(rdata){
|
||||
bt.each(rdata,function(index,item){
|
||||
html += '<li data-host="'+ item.host +'" data-index="'+ index +'"><i></i><span>'+ (item.ps == item.host?item.ps:(item.ps +'【'+ item.host +'】')) +'</span><span class="tootls">'+
|
||||
'<span class="glyphicon glyphicon-edit" aria-hidden="true" title="Edit server information"></span>'+
|
||||
'<span class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete server information"></span>'+
|
||||
'</span></li>';
|
||||
});
|
||||
$('.tootls_host_list').html(html);
|
||||
that.host_list = rdata;
|
||||
if(callback) callback()
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @name 获取host列表
|
||||
* @author chudong<2020-08-010>
|
||||
* @param {Objeact} callback 回调函数,回调参数1:当前请求内容
|
||||
* @return void
|
||||
*/
|
||||
get_host_list:function(callback){
|
||||
var loadT = bt.load('Getting server list, please wait...');
|
||||
this.post('get_host_list',{},function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 获取指定host信息
|
||||
* @author hwliang<2020-08-07>
|
||||
* @param host string host地址
|
||||
* @return void
|
||||
*/
|
||||
get_host_find:function(host,callback){
|
||||
var loadT = bt.load('Getting the specified server information, please wait...');
|
||||
this.post('get_host_find',{host:host},function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name 创建新的host信息
|
||||
* @author hwliang<2020-08-07>
|
||||
* @param ssh_info array ssh信息对象 {
|
||||
* host: 主机地址,
|
||||
port: 端口
|
||||
ps: 备注
|
||||
username: 用户名
|
||||
password: 密码
|
||||
pkey: 密钥(如果不为空,将使用密钥连接)
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
create_host:function(ssh_info,callback){
|
||||
var loadT = bt.load('Adding server information, please wait...');
|
||||
this.post('create_host',ssh_info,function(rdata){
|
||||
loadT.close();
|
||||
if(!rdata.status){
|
||||
bt.msg(rdata);
|
||||
return false;
|
||||
}
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 修改host信息
|
||||
* @author hwliang<2020-08-07>
|
||||
* @param ssh_info array ssh信息对象 {
|
||||
* host: 主机地址,
|
||||
port: 端口
|
||||
ps: 备注
|
||||
sort: 排序(可选,默认0)
|
||||
username: 用户名
|
||||
password: 密码
|
||||
pkey: 密钥(如果不为空,将使用密钥连接)
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
modify_host:function(ssh_info,callback){
|
||||
var loadT = bt.load('Modifying the specified server information, please wait...');
|
||||
this.post('modify_host',ssh_info,function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name 删除host信息
|
||||
* @author hwliang<2020-08-07>
|
||||
* @param host string host地址
|
||||
* @return void
|
||||
*/
|
||||
remove_host:function(host,callback){
|
||||
var loadT = bt.load('Deleting specified server information, please wait...');
|
||||
this.post('remove_host',{host:host},function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name 设置host排序(使用降序)
|
||||
* @author hwliang<2020-08-07>
|
||||
* @param sort_list array 排序对象{
|
||||
* "127.0.0.1":3,
|
||||
* "192.168.1.254":2
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
set_sort:function(sort_list,callabck){
|
||||
this.post('set_sort',{sort_list:JSON.stringify(sort_list)},function(rdata){
|
||||
if(callabck) callabck(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name 获取常用命令列表
|
||||
* @author hwliang<2020-08-08>
|
||||
* @return void
|
||||
*/
|
||||
get_command_list: function(callback){
|
||||
var loadT = bt.load('Getting list of frequently used commands, please wait...');
|
||||
this.post('get_command_list',{},function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 创建常用命令
|
||||
* @author hwliang<2020-08-08>
|
||||
* @param {title} string 命令标题
|
||||
* @parma {shell} string 命令文本
|
||||
* @return void
|
||||
*/
|
||||
create_command: function(obj,callback){
|
||||
var loadT = bt.load('Creating common commands, please wait...');
|
||||
this.post('create_command',obj,function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name 获取指定常用命令
|
||||
* @author hwliang<2020-08-08>
|
||||
* @param {title} string 命令标题
|
||||
* @return void
|
||||
*/
|
||||
get_command_find: function(title,callback){
|
||||
var loadT = bt.load('Getting specified common command data, please wait...');
|
||||
this.post('get_command_find',{title:title},function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 修改常用命令
|
||||
* @author hwliang<2020-08-08>
|
||||
* @param {title} string 命令标题
|
||||
* @param {new_title} string 新的命令标题
|
||||
* @parma {shell} string 命令文本
|
||||
* @return void
|
||||
*/
|
||||
modify_command: function(obj,callback){
|
||||
var loadT = bt.load('Modifying specified common commands, please wait...');
|
||||
this.post('modify_command',obj,function(rdata){
|
||||
loadT.close();
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @name 删除指定常用命令
|
||||
* @author hwliang<2020-08-08>
|
||||
* @param {title} string 命令标题
|
||||
* @return void
|
||||
*/
|
||||
remove_command: function(title,callback){
|
||||
var loadT = bt.load('Deleting specified common commands, please wait...');
|
||||
this.post('remove_command',{title:title},function(rdata){
|
||||
loadT.close();
|
||||
// console.log(rdata)
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @name 请求到后端
|
||||
* @author hwliang<2020-08-07>
|
||||
* @param fun_name string 要访问的方法名称
|
||||
* @param pdata array POST数据
|
||||
* @param callback function 回调函数
|
||||
* @return void
|
||||
*/
|
||||
post:function(fun_name,pdata,callback){
|
||||
bt.send(fun_name,'xterm/'+fun_name,pdata,callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* @author chudong<2020-08-08>
|
||||
* @param {Object} obj 需要渲染的配置对象
|
||||
* @param {*} callback 渲染完成的回调方法
|
||||
*/
|
||||
render_template:function(obj, callback) {
|
||||
if (!obj.html) return '缺少模板HTML';
|
||||
var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n',
|
||||
cursor = 0;
|
||||
var add = function (line, js) {
|
||||
js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
|
||||
(code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
|
||||
return add;
|
||||
}
|
||||
while (match = re.exec(obj.html)) {
|
||||
add(obj.html.slice(cursor, match.index))(match[1], true);
|
||||
cursor = match.index + match[0].length;
|
||||
}
|
||||
add(obj.html.substr(cursor, obj.html.length - cursor));
|
||||
code += 'return r.join("");';
|
||||
if (callback) {
|
||||
callback(new Function(code.replace(/[\r\t\n]/g, '')).apply(obj.data));
|
||||
} else {
|
||||
return new Function(code.replace(/[\r\t\n]/g, '')).apply(obj.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
host_trem.init();
|
||||
File diff suppressed because one or more lines are too long
@@ -146,6 +146,14 @@
|
||||
"GET_INFO": "Get Info",
|
||||
"NGINX_LOAD_ERR": "Nginx load status acquisition failed:{1}",
|
||||
"GET_DATA_ERR": "Data acquisition failed!",
|
||||
"PHP_LOAD_ERR": "PHP load status acquisition failed: {1}"
|
||||
|
||||
"PHP_LOAD_ERR": "PHP load status acquisition failed: {1}",
|
||||
"MODIFY_SSH_INFO": "Modify the SSH information of HOST: {1}",
|
||||
"ADD_SSH_INFO": "Add the SSH information of HOST: {1}",
|
||||
"DEL_SSH_INFO": "Delete the SSH information of HOST: {1}",
|
||||
"TYPE_TERMINAL": "aaPanel terminal",
|
||||
"ADD_COMMAND_COMMAND": "Add common commands [{1}]",
|
||||
"EDIT_COMMAND_COMMAND": "Modify common commands [{1}]",
|
||||
"DEL_COMMAND_COMMAND": "Delete common commands [{1}]",
|
||||
"OPEN_FILE": "Open File",
|
||||
"TASK_QUEUE": "Task queue"
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
"DATABASE_NAME_EXISTS":"Database exists!",
|
||||
"DATABASE_NAME_LEN":"Database name cannot be more than 16 characters!",
|
||||
"DATABASE_ERR_CONNECT":"ERROR to connect database, pls check database status!",
|
||||
"DATABASE_ERR_PASS":"Database password is incorrect!",
|
||||
"DATABASE_ERR_PASS":"Mysql root or user password is incorrect, please try to reset!",
|
||||
"DATABASE_ERR_NOT_EXISTS":"Database user does NOT exist!",
|
||||
"DATABASE_USER_NAME_ERR": "Database username is illegal!",
|
||||
"DATABASE_ERR_MYSQLDB":"MySQLdb component is missing! <br>Please enter SSH and run the command: pip install mysql-python",
|
||||
@@ -383,6 +383,7 @@
|
||||
"CHANVE_FAIL": "Failed to change",
|
||||
"DB_NOT_EXIST": "Database does NOT exist!",
|
||||
"DOWNLOAD_FILE": "Download file",
|
||||
"DOWNLOAD_FILE1": "Download file {1}",
|
||||
"FILE_NAME_SPECIAL_CHARACTRES": "File names can NOT contain special characters!",
|
||||
"DIR_NAME_SPECIAL_CHARACTRES": "Directory names cannot contain special characters!",
|
||||
"RENAME_SUCCESS": "Successfully renamed!",
|
||||
@@ -959,5 +960,29 @@
|
||||
"PHPMYADMIN_SSL_ERR2": "Did not detect the port that nginx phpmyadmin listens, please confirm whether the file has been manually modified.",
|
||||
"PHPMYADMIN_SSL_ERR3": "Did not detect the port that apache phpmyadmin listens, please confirm whether the file has been manually modified.",
|
||||
"PHPMYADMIN_SSL_ERR4": "The panel certificate does not exist. Please apply for the panel certificate and try again.",
|
||||
"PHPMYADMIN_SSL_ERR5": "Open successfully, please manually release phpmyadmin ssl port"
|
||||
"PHPMYADMIN_SSL_ERR5": "Open successfully, please manually release phpmyadmin ssl port",
|
||||
"CONCTION_FAILURE": "Connection failure!",
|
||||
"SSH_LOGIN_INFO_ERR": "Password or private key cannot both be empty: {1}:{2}",
|
||||
"SSH_LOGIN_ERR": "Unable to complete the automatic authentication, please add 127.0.0.1 to the server list and set the authentication method to [password authentication]",
|
||||
"SSH_LOGIN_ERR1": "Account or Password incorrect: {1}",
|
||||
"SSH_LOGIN_ERR2": "Unsupported authentication type: {1}",
|
||||
"SSH_LOGIN_ERR3": "The target server actively refused the connection",
|
||||
"SSH_LOGIN_ERR4": "The protocol header response timed out, and the network quality with the target server was too bad: {1}",
|
||||
"SSH_LOGIN_ERR5": "The SSH protocol handshake timed out, and the network quality with the target server is too bad",
|
||||
"SSH_LOGIN_ERR6": "unknown error: {1}",
|
||||
"SSH_LOGIN": "Successfully logged in to the SSH server [{1}:{2}]",
|
||||
"LOGIN_SUCCESS2": "Login success\n",
|
||||
"CONNECTION_SUCCEEDED": "connection succeeded",
|
||||
"RECONNECT_SSH": "The connection is disconnected, press enter to try to reconnect!",
|
||||
"SSH_LOGIN_ERR7": "The specified SSH information does not exist!",
|
||||
"SSH_LOGIN_ERR8": "The specified host address has been added to other SSH information!",
|
||||
"SSH_LOGIN_ERR9": "Please pass in the [sort_list] field",
|
||||
"COMMAND_NAME_EXIST": "The specified command name already exists",
|
||||
"COMMAND_NOTEXIST": "The specified command does not exist",
|
||||
"AUTH_FAILED": "10 consecutive authentication failures are prohibited for 1 hour",
|
||||
"AUTH_FAILED1": "20 consecutive verification failures, prohibited for 1 hour",
|
||||
"UNBOUND_DEVICE": "Unbound device",
|
||||
"KEY_ERR": "Key verification failed",
|
||||
"FORM_DATA_ERR": "No form_data data found",
|
||||
"WRONG_RESPONSE": "Wrong response: {1}"
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@
|
||||
"H1":"Dashboard",
|
||||
"H2":"Site Manager",
|
||||
"SEARCH":"Site search",
|
||||
"PS":"Permission will be allocated to www user when a site is created with aaPanel",
|
||||
"PS":"After the website is created, the file owner will be set to [www], You can add your backup plan in ",
|
||||
"BTN1":"Add site",
|
||||
"BTN2":"Set default page",
|
||||
"BTN3":"Default domain",
|
||||
"BTN2":"Default page",
|
||||
"BTN3":"Default WebSite",
|
||||
"BTN4":"Delete",
|
||||
"BTN5":"Category manager",
|
||||
"TH1":"Domain",
|
||||
@@ -142,9 +142,9 @@
|
||||
"CT11":"Bind BT account",
|
||||
"CT12":"Panel template",
|
||||
"CY1":"Take alias for aaPanel",
|
||||
"CY2":"Suggested range of port: 8888 - 65535",
|
||||
"CY2":"Suggested port: 8888-65535",
|
||||
"CY3":"Binding a access domain to the Panel Warning:If a domain is bound to Panel, you'll have to access panel with Domain ONLY!",
|
||||
"CY4":"Set authorized access IP, split multiple IP with (,) Warning:If authorized IP is set, ONLY the PC with authorized IP can access the panel!",
|
||||
"CY4":"Split multiple IP with (,) Warning:If authorized IP is set, ONLY the PC with authorized IP can access the panel!",
|
||||
"CY5":"New created site will be saved to subdirectory by default!",
|
||||
"CY6":"Directory of site and database backup!",
|
||||
"CY7":"Defualt IP is Internet IP. If you need use local virtual machine to test, please input Intranet IP of virtual machine!",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<button onclick="database.add_database()" title="{{data['lan']['BTNT1']}}" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">{{data['lan']['BTN1']}}</button>
|
||||
<button onclick="bt.database.set_root()" title="{{data['lan']['BTNT2']}}" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">{{data['lan']['BTN2']}}</button>
|
||||
<button onclick="bt.database.open_phpmyadmin('','root','{{data['mysql_root']}}')" title="{{data['lan']['BTNT3']}}" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">{{data['lan']['BTN3']}}</button>
|
||||
<a href="/adminer/index.php" target="_blank" title="Lightweight database management tool that supports remote database management" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">Adminer</a>
|
||||
<!-- <a href="/adminer/index.php" target="_blank" title="Lightweight database management tool that supports remote database management" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">Adminer</a> -->
|
||||
<span style="float:right">
|
||||
<button batch="true" style="float: right;display: none;margin-left:10px;" onclick="database.batch_database('del');" title="{{data['lan']['BTNT4']}}" class="btn btn-default btn-sm">{{data['lan']['BTN4']}}</button>
|
||||
<button onclick="bt.recycle_bin.open_recycle_bin(6)" id="dataRecycle" title="{{data['lan']['BTNT4']}}" class="btn btn-default btn-sm" style="margin-left: 5px;"><span class="glyphicon glyphicon-trash" style="margin-right: 5px;"></span>{{data['lan']['RECYCLE_BIN']}}</button>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div class="bgw mtb15 pd15">
|
||||
<div class="info-title-tips">
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span> {{data['lan']['PS']}}After the site is successfully established, please<a class="btlink" href="/crontab">[Cron]</a>Add scheduled backup tasks to the page!</p>
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span> {{data['lan']['PS']}}<a class="btlink" href="/crontab">[Cron]</a></p>
|
||||
</div>
|
||||
<button onclick="site.add_site()" class="btn btn-success btn-sm btn-title" type="button">{{data['lan']['BTN1']}}</button>
|
||||
<button onclick="site.set_default_page()" class="btn btn-default btn-sm btn-title" type="button">{{data['lan']['BTN2']}}</button>
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="main-content pb55">
|
||||
<div class="container-fluid">
|
||||
<div class="safe bgw mtb15 pd15" style="height: 100%;">
|
||||
<link rel="stylesheet" href="/static/css/xterm.css" />
|
||||
<div class="quick_links">
|
||||
<div class="quick_links_title"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span>SSH://</div>
|
||||
<input type="text" class="quick_links_input" placeholder="root@192.168.1.1:21, support temporary SSH connection.">
|
||||
<span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span>
|
||||
</div>
|
||||
<div class="term_box" id="term_box_view">
|
||||
<div class="term_item_tab">
|
||||
<div class="list"></div>
|
||||
<span class="addServer" title="Add server SSH information">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true" ></span>
|
||||
</span>
|
||||
<span class="tab_tootls">
|
||||
<span class="glyphicon glyphicon-triangle-top" aria-hidden="true"></span>
|
||||
<span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="term_content_tab"></div>
|
||||
</div>
|
||||
<div class="term_tootls">
|
||||
<div class="tootls_tab"><span class="active">Server list</span><a href="javascript:;" data-type="host" title="Add server SSH information"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a></div>
|
||||
<ul class="tootls_host_list"></ul>
|
||||
<div class="tootls_tab"><span class="active">Commands<i>(Click to copy)</i></span><a href="javascript:;" data-type="shell" title="Add common commands"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a></div>
|
||||
<ul class="tootls_commonly_list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/html" id="host_form_view">
|
||||
<div class="bt-form bt-form-2x pd20" id="host_form">
|
||||
<input type="text" name="sort" class="hidden" value="<% this.form.sort %>" />
|
||||
<div class="line input_group">
|
||||
<span class="tname">Server IP</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="host" class="bt-input-text mr5" style="width:240px" value="<% this.form.host %>" placeholder="Enter server IP" val="" autocomplete="off" />
|
||||
<input type="text" name="port" class="bt-input-text mr5" style="width:60px" placeholder="端口" value="<% this.form.port %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<span class="tname">SSH account</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="username" class="bt-input-text mr5" style="width:305px" placeholder="Enter SSH account" value="<% this.form.username %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<span class="tname">Verification</span>
|
||||
<div class="info-r ">
|
||||
<div class="btn-group">
|
||||
<button type="button" tabindex="-1" class="btn btn-sm auth_type_checkbox <% !(this.form.password != '' || this.form.pkey == '' && this.form.password == '')?'btn-default':'btn-success' %>" data-ctype="0">Password</button>
|
||||
<button type="button" tabindex="-1" class="btn btn-sm auth_type_checkbox <% this.form.pkey == ''?'btn-default':'btn-success' %>" data-ctype="1">Private key</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line c_password_view <% (this.form.password != '' || this.form.pkey == '' && this.form.password == '')?'show':'hidden'%>">
|
||||
<span class="tname">Password</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="password" class="bt-input-text mr5" placeholder="Please enter SSH password" style="width:305px;" value="<% this.form.password %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line c_pkey_view <% this.form.pkey != ''?'show':'hidden'%>">
|
||||
<span class="tname">Private key</span>
|
||||
<div class="info-r">
|
||||
<textarea rows="4" name="pkey" class="bt-input-text mr5" placeholder="Please enter SSH Private key" style="width:305px;height: 80px;line-height: 18px;padding-top:10px;"><% this.form.pkey %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<span class="tname">Remarks</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="ps" class="bt-input-text mr5" placeholder="Please enter remarks, can be blank" style="width:305px;" value="<% this.form.ps %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="shell_form_view">
|
||||
<div class="bt-form bt-form-2x pd20" id="host_form">
|
||||
<div class="line">
|
||||
<span class="tname">Name</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="title" class="bt-input-text mr5" style="width:305px" placeholder="Please enter command description, required" value="<% this.form.title %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<span class="tname">Content</span>
|
||||
<div class="info-r">
|
||||
<textarea rows="4" name="shell" class="bt-input-text mr5" placeholder="Please enter command content, required" style="width:305px;height: 150px;line-height: 18px;padding-top:10px;"><% this.form.shell %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/clipboard.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/xterm.js"></script>
|
||||
<script type="text/javascript" src="/static/js/term.js"></script>
|
||||
<script type="text/javascript">
|
||||
if($("#panel_debug").attr("data") == 'True') {
|
||||
layer.msg('The current mode is developer mode. Can not support SSH. Please turn it off in the 【Settings】 page!',{icon:7,shade: [0.3, '#000'],time:0});
|
||||
$(".layui-layer-shade").css("margin-left", "180px");
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from cachelib.base import BaseCache, NullCache
|
||||
from cachelib.simple import SimpleCache
|
||||
from cachelib.file import FileSystemCache
|
||||
from cachelib.memcached import MemcachedCache
|
||||
from cachelib.redis import RedisCache
|
||||
from cachelib.uwsgi import UWSGICache
|
||||
|
||||
__all__ = [
|
||||
'BaseCache',
|
||||
'NullCache',
|
||||
'SimpleCache',
|
||||
'FileSystemCache',
|
||||
'MemcachedCache',
|
||||
'RedisCache',
|
||||
'UWSGICache',
|
||||
]
|
||||
|
||||
__version__ = '0.1'
|
||||
__author__ = 'Pallets Team'
|
||||
@@ -0,0 +1,26 @@
|
||||
# flake8: noqa
|
||||
import sys
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
|
||||
if PY2:
|
||||
text_type = unicode
|
||||
string_types = (str, unicode)
|
||||
integer_types = (int, long)
|
||||
iteritems = lambda d, *args, **kwargs: d.iteritems(*args, **kwargs)
|
||||
|
||||
def to_native(x, charset=sys.getdefaultencoding(), errors='strict'):
|
||||
if x is None or isinstance(x, str):
|
||||
return x
|
||||
return x.encode(charset, errors)
|
||||
|
||||
else:
|
||||
text_type = str
|
||||
string_types = (str, )
|
||||
integer_types = (int, )
|
||||
iteritems = lambda d, *args, **kwargs: iter(d.items(*args, **kwargs))
|
||||
|
||||
def to_native(x, charset=sys.getdefaultencoding(), errors='strict'):
|
||||
if x is None or isinstance(x, str):
|
||||
return x
|
||||
return x.decode(charset, errors)
|
||||
@@ -0,0 +1,198 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from cachelib._compat import iteritems
|
||||
|
||||
|
||||
def _items(mappingorseq):
|
||||
"""Wrapper for efficient iteration over mappings represented by dicts
|
||||
or sequences::
|
||||
|
||||
>>> for k, v in _items((i, i*i) for i in xrange(5)):
|
||||
... assert k*k == v
|
||||
|
||||
>>> for k, v in _items(dict((i, i*i) for i in xrange(5))):
|
||||
... assert k*k == v
|
||||
|
||||
"""
|
||||
if hasattr(mappingorseq, 'items'):
|
||||
return iteritems(mappingorseq)
|
||||
return mappingorseq
|
||||
|
||||
|
||||
class BaseCache(object):
|
||||
|
||||
"""Baseclass for the cache systems. All the cache systems implement this
|
||||
API or a superset of it.
|
||||
|
||||
:param default_timeout: the default timeout (in seconds) that is used if
|
||||
no timeout is specified on :meth:`set`. A timeout
|
||||
of 0 indicates that the cache never expires.
|
||||
"""
|
||||
|
||||
def __init__(self, default_timeout=300):
|
||||
self.default_timeout = default_timeout
|
||||
|
||||
def _normalize_timeout(self, timeout):
|
||||
if timeout is None:
|
||||
timeout = self.default_timeout
|
||||
return timeout
|
||||
|
||||
def get(self, key):
|
||||
"""Look up key in the cache and return the value for it.
|
||||
|
||||
:param key: the key to be looked up.
|
||||
:returns: The value if it exists and is readable, else ``None``.
|
||||
"""
|
||||
return None
|
||||
|
||||
def delete(self, key):
|
||||
"""Delete `key` from the cache.
|
||||
|
||||
:param key: the key to delete.
|
||||
:returns: Whether the key existed and has been deleted.
|
||||
:rtype: boolean
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_many(self, *keys):
|
||||
"""Returns a list of values for the given keys.
|
||||
For each key an item in the list is created::
|
||||
|
||||
foo, bar = cache.get_many("foo", "bar")
|
||||
|
||||
Has the same error handling as :meth:`get`.
|
||||
|
||||
:param keys: The function accepts multiple keys as positional
|
||||
arguments.
|
||||
"""
|
||||
return [self.get(k) for k in keys]
|
||||
|
||||
def get_dict(self, *keys):
|
||||
"""Like :meth:`get_many` but return a dict::
|
||||
|
||||
d = cache.get_dict("foo", "bar")
|
||||
foo = d["foo"]
|
||||
bar = d["bar"]
|
||||
|
||||
:param keys: The function accepts multiple keys as positional
|
||||
arguments.
|
||||
"""
|
||||
return dict(zip(keys, self.get_many(*keys)))
|
||||
|
||||
def set(self, key, value, timeout=None):
|
||||
"""Add a new key/value to the cache (overwrites value, if key already
|
||||
exists in the cache).
|
||||
|
||||
:param key: the key to set
|
||||
:param value: the value for the key
|
||||
:param timeout: the cache timeout for the key in seconds (if not
|
||||
specified, it uses the default timeout). A timeout of
|
||||
0 indicates that the cache never expires.
|
||||
:returns: ``True`` if key has been updated, ``False`` for backend
|
||||
errors. Pickling errors, however, will raise a subclass of
|
||||
``pickle.PickleError``.
|
||||
:rtype: boolean
|
||||
"""
|
||||
return True
|
||||
|
||||
def add(self, key, value, timeout=None):
|
||||
"""Works like :meth:`set` but does not overwrite the values of already
|
||||
existing keys.
|
||||
|
||||
:param key: the key to set
|
||||
:param value: the value for the key
|
||||
:param timeout: the cache timeout for the key in seconds (if not
|
||||
specified, it uses the default timeout). A timeout of
|
||||
0 indicates that the cache never expires.
|
||||
:returns: Same as :meth:`set`, but also ``False`` for already
|
||||
existing keys.
|
||||
:rtype: boolean
|
||||
"""
|
||||
return True
|
||||
|
||||
def set_many(self, mapping, timeout=None):
|
||||
"""Sets multiple keys and values from a mapping.
|
||||
|
||||
:param mapping: a mapping with the keys/values to set.
|
||||
:param timeout: the cache timeout for the key in seconds (if not
|
||||
specified, it uses the default timeout). A timeout of
|
||||
0 indicates that the cache never expires.
|
||||
:returns: Whether all given keys have been set.
|
||||
:rtype: boolean
|
||||
"""
|
||||
rv = True
|
||||
for key, value in _items(mapping):
|
||||
if not self.set(key, value, timeout):
|
||||
rv = False
|
||||
return rv
|
||||
|
||||
def delete_many(self, *keys):
|
||||
"""Deletes multiple keys at once.
|
||||
|
||||
:param keys: The function accepts multiple keys as positional
|
||||
arguments.
|
||||
:returns: Whether all given keys have been deleted.
|
||||
:rtype: boolean
|
||||
"""
|
||||
return all(self.delete(key) for key in keys)
|
||||
|
||||
def has(self, key):
|
||||
"""Checks if a key exists in the cache without returning it. This is a
|
||||
cheap operation that bypasses loading the actual data on the backend.
|
||||
|
||||
This method is optional and may not be implemented on all caches.
|
||||
|
||||
:param key: the key to check
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
'%s doesn\'t have an efficient implementation of `has`. That '
|
||||
'means it is impossible to check whether a key exists without '
|
||||
'fully loading the key\'s data. Consider using `self.get` '
|
||||
'explicitly if you don\'t care about performance.'
|
||||
)
|
||||
|
||||
def clear(self):
|
||||
"""Clears the cache. Keep in mind that not all caches support
|
||||
completely clearing the cache.
|
||||
|
||||
:returns: Whether the cache has been cleared.
|
||||
:rtype: boolean
|
||||
"""
|
||||
return True
|
||||
|
||||
def inc(self, key, delta=1):
|
||||
"""Increments the value of a key by `delta`. If the key does
|
||||
not yet exist it is initialized with `delta`.
|
||||
|
||||
For supporting caches this is an atomic operation.
|
||||
|
||||
:param key: the key to increment.
|
||||
:param delta: the delta to add.
|
||||
:returns: The new value or ``None`` for backend errors.
|
||||
"""
|
||||
value = (self.get(key) or 0) + delta
|
||||
return value if self.set(key, value) else None
|
||||
|
||||
def dec(self, key, delta=1):
|
||||
"""Decrements the value of a key by `delta`. If the key does
|
||||
not yet exist it is initialized with `-delta`.
|
||||
|
||||
For supporting caches this is an atomic operation.
|
||||
|
||||
:param key: the key to increment.
|
||||
:param delta: the delta to subtract.
|
||||
:returns: The new value or `None` for backend errors.
|
||||
"""
|
||||
value = (self.get(key) or 0) - delta
|
||||
return value if self.set(key, value) else None
|
||||
|
||||
|
||||
class NullCache(BaseCache):
|
||||
|
||||
"""A cache that doesn't cache. This can be useful for unit testing.
|
||||
|
||||
:param default_timeout: a dummy parameter that is ignored but exists
|
||||
for API compatibility with other caches.
|
||||
"""
|
||||
|
||||
def has(self, key):
|
||||
return False
|
||||
@@ -0,0 +1,190 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import errno
|
||||
import tempfile
|
||||
from hashlib import md5
|
||||
from time import time
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError: # pragma: no cover
|
||||
import pickle
|
||||
|
||||
from cachelib.base import BaseCache
|
||||
from cachelib._compat import text_type
|
||||
|
||||
|
||||
class FileSystemCache(BaseCache):
|
||||
|
||||
"""A cache that stores the items on the file system. This cache depends
|
||||
on being the only user of the `cache_dir`. Make absolutely sure that
|
||||
nobody but this cache stores files there or otherwise the cache will
|
||||
randomly delete files therein.
|
||||
|
||||
:param cache_dir: the directory where cache files are stored.
|
||||
:param threshold: the maximum number of items the cache stores before
|
||||
it starts deleting some. A threshold value of 0
|
||||
indicates no threshold.
|
||||
:param default_timeout: the default timeout that is used if no timeout is
|
||||
specified on :meth:`~BaseCache.set`. A timeout of
|
||||
0 indicates that the cache never expires.
|
||||
:param mode: the file mode wanted for the cache files, default 0600
|
||||
"""
|
||||
|
||||
#: used for temporary files by the FileSystemCache
|
||||
_fs_transaction_suffix = '.__wz_cache'
|
||||
#: keep amount of files in a cache element
|
||||
_fs_count_file = '__wz_cache_count'
|
||||
|
||||
def __init__(self, cache_dir, threshold=500, default_timeout=300,
|
||||
mode=0o600):
|
||||
BaseCache.__init__(self, default_timeout)
|
||||
self._path = cache_dir
|
||||
self._threshold = threshold
|
||||
self._mode = mode
|
||||
|
||||
try:
|
||||
os.makedirs(self._path)
|
||||
except OSError as ex:
|
||||
if ex.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
# If there are many files and a zero threshold,
|
||||
# the list_dir can slow initialisation massively
|
||||
if self._threshold != 0:
|
||||
self._update_count(value=len(self._list_dir()))
|
||||
|
||||
@property
|
||||
def _file_count(self):
|
||||
return self.get(self._fs_count_file) or 0
|
||||
|
||||
def _update_count(self, delta=None, value=None):
|
||||
# If we have no threshold, don't count files
|
||||
if self._threshold == 0:
|
||||
return
|
||||
|
||||
if delta:
|
||||
new_count = self._file_count + delta
|
||||
else:
|
||||
new_count = value or 0
|
||||
self.set(self._fs_count_file, new_count, mgmt_element=True)
|
||||
|
||||
def _normalize_timeout(self, timeout):
|
||||
timeout = BaseCache._normalize_timeout(self, timeout)
|
||||
if timeout != 0:
|
||||
timeout = time() + timeout
|
||||
return int(timeout)
|
||||
|
||||
def _list_dir(self):
|
||||
"""return a list of (fully qualified) cache filenames
|
||||
"""
|
||||
mgmt_files = [self._get_filename(name).split('/')[-1]
|
||||
for name in (self._fs_count_file,)]
|
||||
return [os.path.join(self._path, fn) for fn in os.listdir(self._path)
|
||||
if not fn.endswith(self._fs_transaction_suffix)
|
||||
and fn not in mgmt_files]
|
||||
|
||||
def _prune(self):
|
||||
if self._threshold == 0 or not self._file_count > self._threshold:
|
||||
return
|
||||
|
||||
entries = self._list_dir()
|
||||
now = time()
|
||||
for idx, fname in enumerate(entries):
|
||||
try:
|
||||
remove = False
|
||||
with open(fname, 'rb') as f:
|
||||
expires = pickle.load(f)
|
||||
remove = (expires != 0 and expires <= now) or idx % 3 == 0
|
||||
|
||||
if remove:
|
||||
os.remove(fname)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
self._update_count(value=len(self._list_dir()))
|
||||
|
||||
def clear(self):
|
||||
for fname in self._list_dir():
|
||||
try:
|
||||
os.remove(fname)
|
||||
except (IOError, OSError):
|
||||
self._update_count(value=len(self._list_dir()))
|
||||
return False
|
||||
self._update_count(value=0)
|
||||
return True
|
||||
|
||||
def _get_filename(self, key):
|
||||
if isinstance(key, text_type):
|
||||
key = key.encode('utf-8') # XXX unicode review
|
||||
hash = md5(key).hexdigest()
|
||||
return os.path.join(self._path, hash)
|
||||
|
||||
def get(self, key):
|
||||
filename = self._get_filename(key)
|
||||
try:
|
||||
with open(filename, 'rb') as f:
|
||||
pickle_time = pickle.load(f)
|
||||
if pickle_time == 0 or pickle_time >= time():
|
||||
return pickle.load(f)
|
||||
else:
|
||||
os.remove(filename)
|
||||
return None
|
||||
except (IOError, OSError, pickle.PickleError):
|
||||
return None
|
||||
|
||||
def add(self, key, value, timeout=None):
|
||||
filename = self._get_filename(key)
|
||||
if not os.path.exists(filename):
|
||||
return self.set(key, value, timeout)
|
||||
return False
|
||||
|
||||
def set(self, key, value, timeout=None, mgmt_element=False):
|
||||
# Management elements have no timeout
|
||||
if mgmt_element:
|
||||
timeout = 0
|
||||
|
||||
# Don't prune on management element update, to avoid loop
|
||||
else:
|
||||
self._prune()
|
||||
|
||||
timeout = self._normalize_timeout(timeout)
|
||||
filename = self._get_filename(key)
|
||||
try:
|
||||
fd, tmp = tempfile.mkstemp(suffix=self._fs_transaction_suffix,
|
||||
dir=self._path)
|
||||
with os.fdopen(fd, 'wb') as f:
|
||||
pickle.dump(timeout, f, 1)
|
||||
pickle.dump(value, f, pickle.HIGHEST_PROTOCOL)
|
||||
|
||||
os.rename(tmp, filename)
|
||||
os.chmod(filename, self._mode)
|
||||
except (IOError, OSError):
|
||||
return False
|
||||
else:
|
||||
# Management elements should not count towards threshold
|
||||
if not mgmt_element:
|
||||
self._update_count(delta=1)
|
||||
return True
|
||||
|
||||
def delete(self, key, mgmt_element=False):
|
||||
try:
|
||||
os.remove(self._get_filename(key))
|
||||
except (IOError, OSError):
|
||||
return False
|
||||
else:
|
||||
# Management elements should not count towards threshold
|
||||
if not mgmt_element:
|
||||
self._update_count(delta=-1)
|
||||
return True
|
||||
|
||||
def has(self, key):
|
||||
filename = self._get_filename(key)
|
||||
try:
|
||||
with open(filename, 'rb') as f:
|
||||
pickle_time = pickle.load(f)
|
||||
if pickle_time == 0 or pickle_time >= time():
|
||||
return True
|
||||
else:
|
||||
os.remove(filename)
|
||||
return False
|
||||
except (IOError, OSError, pickle.PickleError):
|
||||
return False
|
||||
@@ -0,0 +1,186 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
from time import time
|
||||
from cachelib._compat import iteritems, to_native
|
||||
from cachelib.base import BaseCache, _items
|
||||
|
||||
|
||||
_test_memcached_key = re.compile(r'[^\x00-\x21\xff]{1,250}$').match
|
||||
|
||||
|
||||
class MemcachedCache(BaseCache):
|
||||
|
||||
"""A cache that uses memcached as backend.
|
||||
|
||||
The first argument can either be an object that resembles the API of a
|
||||
:class:`memcache.Client` or a tuple/list of server addresses. In the
|
||||
event that a tuple/list is passed, Werkzeug tries to import the best
|
||||
available memcache library.
|
||||
|
||||
This cache looks into the following packages/modules to find bindings for
|
||||
memcached:
|
||||
|
||||
- ``pylibmc``
|
||||
- ``google.appengine.api.memcached``
|
||||
- ``memcached``
|
||||
- ``libmc``
|
||||
|
||||
Implementation notes: This cache backend works around some limitations in
|
||||
memcached to simplify the interface. For example unicode keys are encoded
|
||||
to utf-8 on the fly. Methods such as :meth:`~BaseCache.get_dict` return
|
||||
the keys in the same format as passed. Furthermore all get methods
|
||||
silently ignore key errors to not cause problems when untrusted user data
|
||||
is passed to the get methods which is often the case in web applications.
|
||||
|
||||
:param servers: a list or tuple of server addresses or alternatively
|
||||
a :class:`memcache.Client` or a compatible client.
|
||||
:param default_timeout: the default timeout that is used if no timeout is
|
||||
specified on :meth:`~BaseCache.set`. A timeout of
|
||||
0 indicates that the cache never expires.
|
||||
:param key_prefix: a prefix that is added before all keys. This makes it
|
||||
possible to use the same memcached server for different
|
||||
applications. Keep in mind that
|
||||
:meth:`~BaseCache.clear` will also clear keys with a
|
||||
different prefix.
|
||||
"""
|
||||
|
||||
def __init__(self, servers=None, default_timeout=300, key_prefix=None):
|
||||
BaseCache.__init__(self, default_timeout)
|
||||
if servers is None or isinstance(servers, (list, tuple)):
|
||||
if servers is None:
|
||||
servers = ['127.0.0.1:11211']
|
||||
self._client = self.import_preferred_memcache_lib(servers)
|
||||
if self._client is None:
|
||||
raise RuntimeError('no memcache module found')
|
||||
else:
|
||||
# NOTE: servers is actually an already initialized memcache
|
||||
# client.
|
||||
self._client = servers
|
||||
|
||||
self.key_prefix = to_native(key_prefix)
|
||||
|
||||
def _normalize_key(self, key):
|
||||
key = to_native(key, 'utf-8')
|
||||
if self.key_prefix:
|
||||
key = self.key_prefix + key
|
||||
return key
|
||||
|
||||
def _normalize_timeout(self, timeout):
|
||||
timeout = BaseCache._normalize_timeout(self, timeout)
|
||||
if timeout > 0:
|
||||
timeout = int(time()) + timeout
|
||||
return timeout
|
||||
|
||||
def get(self, key):
|
||||
key = self._normalize_key(key)
|
||||
# memcached doesn't support keys longer than that. Because often
|
||||
# checks for so long keys can occur because it's tested from user
|
||||
# submitted data etc we fail silently for getting.
|
||||
if _test_memcached_key(key):
|
||||
return self._client.get(key)
|
||||
|
||||
def get_dict(self, *keys):
|
||||
key_mapping = {}
|
||||
have_encoded_keys = False
|
||||
for key in keys:
|
||||
encoded_key = self._normalize_key(key)
|
||||
if not isinstance(key, str):
|
||||
have_encoded_keys = True
|
||||
if _test_memcached_key(key):
|
||||
key_mapping[encoded_key] = key
|
||||
_keys = list(key_mapping)
|
||||
d = rv = self._client.get_multi(_keys)
|
||||
if have_encoded_keys or self.key_prefix:
|
||||
rv = {}
|
||||
for key, value in iteritems(d):
|
||||
rv[key_mapping[key]] = value
|
||||
if len(rv) < len(keys):
|
||||
for key in keys:
|
||||
if key not in rv:
|
||||
rv[key] = None
|
||||
return rv
|
||||
|
||||
def add(self, key, value, timeout=None):
|
||||
key = self._normalize_key(key)
|
||||
timeout = self._normalize_timeout(timeout)
|
||||
return self._client.add(key, value, timeout)
|
||||
|
||||
def set(self, key, value, timeout=None):
|
||||
key = self._normalize_key(key)
|
||||
timeout = self._normalize_timeout(timeout)
|
||||
return self._client.set(key, value, timeout)
|
||||
|
||||
def get_many(self, *keys):
|
||||
d = self.get_dict(*keys)
|
||||
return [d[key] for key in keys]
|
||||
|
||||
def set_many(self, mapping, timeout=None):
|
||||
new_mapping = {}
|
||||
for key, value in _items(mapping):
|
||||
key = self._normalize_key(key)
|
||||
new_mapping[key] = value
|
||||
|
||||
timeout = self._normalize_timeout(timeout)
|
||||
failed_keys = self._client.set_multi(new_mapping, timeout)
|
||||
return not failed_keys
|
||||
|
||||
def delete(self, key):
|
||||
key = self._normalize_key(key)
|
||||
if _test_memcached_key(key):
|
||||
return self._client.delete(key)
|
||||
|
||||
def delete_many(self, *keys):
|
||||
new_keys = []
|
||||
for key in keys:
|
||||
key = self._normalize_key(key)
|
||||
if _test_memcached_key(key):
|
||||
new_keys.append(key)
|
||||
return self._client.delete_multi(new_keys)
|
||||
|
||||
def has(self, key):
|
||||
key = self._normalize_key(key)
|
||||
if _test_memcached_key(key):
|
||||
return self._client.append(key, '')
|
||||
return False
|
||||
|
||||
def clear(self):
|
||||
return self._client.flush_all()
|
||||
|
||||
def inc(self, key, delta=1):
|
||||
key = self._normalize_key(key)
|
||||
return self._client.incr(key, delta)
|
||||
|
||||
def dec(self, key, delta=1):
|
||||
key = self._normalize_key(key)
|
||||
return self._client.decr(key, delta)
|
||||
|
||||
def import_preferred_memcache_lib(self, servers):
|
||||
"""Returns an initialized memcache client. Used by the constructor."""
|
||||
try:
|
||||
import pylibmc
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return pylibmc.Client(servers)
|
||||
|
||||
try:
|
||||
from google.appengine.api import memcache
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return memcache.Client()
|
||||
|
||||
try:
|
||||
import memcache
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return memcache.Client(servers)
|
||||
|
||||
try:
|
||||
import libmc
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return libmc.Client(servers)
|
||||
@@ -0,0 +1,154 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError: # pragma: no cover
|
||||
import pickle
|
||||
|
||||
from cachelib.base import BaseCache, _items
|
||||
from cachelib._compat import string_types, integer_types
|
||||
|
||||
|
||||
class RedisCache(BaseCache):
|
||||
"""Uses the Redis key-value store as a cache backend.
|
||||
|
||||
The first argument can be either a string denoting address of the Redis
|
||||
server or an object resembling an instance of a redis.Redis class.
|
||||
|
||||
Note: Python Redis API already takes care of encoding unicode strings on
|
||||
the fly.
|
||||
|
||||
:param host: address of the Redis server or an object which API is
|
||||
compatible with the official Python Redis client (redis-py).
|
||||
:param port: port number on which Redis server listens for connections.
|
||||
:param password: password authentication for the Redis server.
|
||||
:param db: db (zero-based numeric index) on Redis Server to connect.
|
||||
:param default_timeout: the default timeout that is used if no timeout is
|
||||
specified on :meth:`~BaseCache.set`. A timeout of
|
||||
0 indicates that the cache never expires.
|
||||
:param key_prefix: A prefix that should be added to all keys.
|
||||
|
||||
Any additional keyword arguments will be passed to ``redis.Redis``.
|
||||
"""
|
||||
|
||||
def __init__(self, host='localhost', port=6379, password=None,
|
||||
db=0, default_timeout=300, key_prefix=None, **kwargs):
|
||||
BaseCache.__init__(self, default_timeout)
|
||||
if host is None:
|
||||
raise ValueError('RedisCache host parameter may not be None')
|
||||
if isinstance(host, string_types):
|
||||
try:
|
||||
import redis
|
||||
except ImportError:
|
||||
raise RuntimeError('no redis module found')
|
||||
if kwargs.get('decode_responses', None):
|
||||
raise ValueError('decode_responses is not supported by '
|
||||
'RedisCache.')
|
||||
self._client = redis.Redis(host=host, port=port, password=password,
|
||||
db=db, **kwargs)
|
||||
else:
|
||||
self._client = host
|
||||
self.key_prefix = key_prefix or ''
|
||||
|
||||
def _normalize_timeout(self, timeout):
|
||||
timeout = BaseCache._normalize_timeout(self, timeout)
|
||||
if timeout == 0:
|
||||
timeout = -1
|
||||
return timeout
|
||||
|
||||
def dump_object(self, value):
|
||||
"""Dumps an object into a string for redis. By default it serializes
|
||||
integers as regular string and pickle dumps everything else.
|
||||
"""
|
||||
t = type(value)
|
||||
if t in integer_types:
|
||||
return str(value).encode('ascii')
|
||||
return b'!' + pickle.dumps(value)
|
||||
|
||||
def load_object(self, value):
|
||||
"""The reversal of :meth:`dump_object`. This might be called with
|
||||
None.
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
if value.startswith(b'!'):
|
||||
try:
|
||||
return pickle.loads(value[1:])
|
||||
except pickle.PickleError:
|
||||
return None
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError:
|
||||
# before 0.8 we did not have serialization. Still support that.
|
||||
return value
|
||||
|
||||
def get(self, key):
|
||||
return self.load_object(self._client.get(self.key_prefix + key))
|
||||
|
||||
def get_many(self, *keys):
|
||||
if self.key_prefix:
|
||||
keys = [self.key_prefix + key for key in keys]
|
||||
return [self.load_object(x) for x in self._client.mget(keys)]
|
||||
|
||||
def set(self, key, value, timeout=None):
|
||||
timeout = self._normalize_timeout(timeout)
|
||||
dump = self.dump_object(value)
|
||||
if timeout == -1:
|
||||
result = self._client.set(name=self.key_prefix + key,
|
||||
value=dump)
|
||||
else:
|
||||
result = self._client.setex(name=self.key_prefix + key,
|
||||
value=dump, time=timeout)
|
||||
return result
|
||||
|
||||
def add(self, key, value, timeout=None):
|
||||
timeout = self._normalize_timeout(timeout)
|
||||
dump = self.dump_object(value)
|
||||
return (
|
||||
self._client.setnx(name=self.key_prefix + key, value=dump) and
|
||||
self._client.expire(name=self.key_prefix + key, time=timeout)
|
||||
)
|
||||
|
||||
def set_many(self, mapping, timeout=None):
|
||||
timeout = self._normalize_timeout(timeout)
|
||||
# Use transaction=False to batch without calling redis MULTI
|
||||
# which is not supported by twemproxy
|
||||
pipe = self._client.pipeline(transaction=False)
|
||||
|
||||
for key, value in _items(mapping):
|
||||
dump = self.dump_object(value)
|
||||
if timeout == -1:
|
||||
pipe.set(name=self.key_prefix + key, value=dump)
|
||||
else:
|
||||
pipe.setex(name=self.key_prefix + key, value=dump,
|
||||
time=timeout)
|
||||
return pipe.execute()
|
||||
|
||||
def delete(self, key):
|
||||
return self._client.delete(self.key_prefix + key)
|
||||
|
||||
def delete_many(self, *keys):
|
||||
if not keys:
|
||||
return
|
||||
if self.key_prefix:
|
||||
keys = [self.key_prefix + key for key in keys]
|
||||
return self._client.delete(*keys)
|
||||
|
||||
def has(self, key):
|
||||
return self._client.exists(self.key_prefix + key)
|
||||
|
||||
def clear(self):
|
||||
status = False
|
||||
if self.key_prefix:
|
||||
keys = self._client.keys(self.key_prefix + '*')
|
||||
if keys:
|
||||
status = self._client.delete(*keys)
|
||||
else:
|
||||
status = self._client.flushdb()
|
||||
return status
|
||||
|
||||
def inc(self, key, delta=1):
|
||||
return self._client.incr(name=self.key_prefix + key, amount=delta)
|
||||
|
||||
def dec(self, key, delta=1):
|
||||
return self._client.decr(name=self.key_prefix + key, amount=delta)
|
||||
@@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from time import time
|
||||
import os,struct
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError: # pragma: no cover
|
||||
import pickle
|
||||
|
||||
from cachelib.base import BaseCache
|
||||
|
||||
|
||||
class SimpleCache(BaseCache):
|
||||
|
||||
"""Simple memory cache for single process environments. This class exists
|
||||
mainly for the development server and is not 100% thread safe. It tries
|
||||
to use as many atomic operations as possible and no locks for simplicity
|
||||
but it could happen under heavy load that keys are added multiple times.
|
||||
|
||||
:param threshold: the maximum number of items the cache stores before
|
||||
it starts deleting some.
|
||||
:param default_timeout: the default timeout that is used if no timeout is
|
||||
specified on :meth:`~BaseCache.set`. A timeout of
|
||||
0 indicates that the cache never expires.
|
||||
"""
|
||||
__session_key = 'BT_:'
|
||||
__session_basedir = '/www/server/panel/data/session'
|
||||
|
||||
def __init__(self, threshold=500, default_timeout=300):
|
||||
BaseCache.__init__(self, default_timeout)
|
||||
self._cache = {}
|
||||
self.clear = self._cache.clear
|
||||
self._threshold = threshold
|
||||
|
||||
def _prune(self):
|
||||
if len(self._cache) > self._threshold:
|
||||
now = time()
|
||||
toremove = []
|
||||
for idx, (key, (expires, _)) in enumerate(self._cache.items()):
|
||||
if (expires != 0 and expires <= now) or idx % 3 == 0:
|
||||
toremove.append(key)
|
||||
for key in toremove:
|
||||
self._cache.pop(key, None)
|
||||
|
||||
|
||||
def _normalize_timeout(self, timeout):
|
||||
timeout = BaseCache._normalize_timeout(self, timeout)
|
||||
if timeout > 0:
|
||||
timeout = time() + timeout
|
||||
return timeout
|
||||
|
||||
def get(self, key):
|
||||
try:
|
||||
|
||||
expires, value = self._cache[key]
|
||||
if expires == 0 or expires > time():
|
||||
return pickle.loads(value)
|
||||
|
||||
except (KeyError, pickle.PickleError):
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
if not os.path.exists(filename): return None
|
||||
|
||||
with open(filename, 'rb') as fp:
|
||||
_val = fp.read()
|
||||
fp.close()
|
||||
|
||||
expires = struct.unpack('f',_val[:4])[0]
|
||||
if expires == 0 or expires > time():
|
||||
value = _val[4:]
|
||||
|
||||
self._cache[key] = (expires,value)
|
||||
return pickle.loads(value)
|
||||
except :pass
|
||||
return None
|
||||
|
||||
def set(self, key, value, timeout=None):
|
||||
|
||||
expires = self._normalize_timeout(timeout)
|
||||
self._prune()
|
||||
|
||||
_val = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
|
||||
self._cache[key] = (expires,_val)
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
if len(_val) < 256: return True
|
||||
if not os.path.exists(self.__session_basedir): os.makedirs(self.__session_basedir,384)
|
||||
|
||||
expires = struct.pack('f',expires)
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
fp = open(filename, 'wb+')
|
||||
fp.write(expires + _val)
|
||||
fp.close()
|
||||
os.chmod(filename,384)
|
||||
except :pass
|
||||
return True
|
||||
|
||||
def add(self, key, value, timeout=None):
|
||||
expires = self._normalize_timeout(timeout)
|
||||
self._prune()
|
||||
item = (expires, pickle.dumps(value,
|
||||
pickle.HIGHEST_PROTOCOL))
|
||||
if key in self._cache:
|
||||
return False
|
||||
self._cache.setdefault(key, item)
|
||||
return True
|
||||
|
||||
def delete(self, key):
|
||||
result = self._cache.pop(key, None) is not None
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
if os.path.exists(filename): os.remove(filename)
|
||||
except : pass
|
||||
return result
|
||||
|
||||
def has(self, key):
|
||||
try:
|
||||
expires, value = self._cache[key]
|
||||
return expires == 0 or expires > time()
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def md5(self,strings):
|
||||
"""
|
||||
生成MD5
|
||||
@strings 要被处理的字符串
|
||||
return string(32)
|
||||
"""
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
|
||||
m.update(strings.encode('utf-8'))
|
||||
return m.hexdigest()
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import platform
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError: # pragma: no cover
|
||||
import pickle
|
||||
|
||||
from cachelib.base import BaseCache
|
||||
|
||||
|
||||
class UWSGICache(BaseCache):
|
||||
""" Implements the cache using uWSGI's caching framework.
|
||||
|
||||
.. note::
|
||||
This class cannot be used when running under PyPy, because the uWSGI
|
||||
API implementation for PyPy is lacking the needed functionality.
|
||||
|
||||
:param default_timeout: The default timeout in seconds.
|
||||
:param cache: The name of the caching instance to connect to, for
|
||||
example: mycache@localhost:3031, defaults to an empty string, which
|
||||
means uWSGI will cache in the local instance. If the cache is in the
|
||||
same instance as the werkzeug app, you only have to provide the name of
|
||||
the cache.
|
||||
"""
|
||||
def __init__(self, default_timeout=300, cache=''):
|
||||
BaseCache.__init__(self, default_timeout)
|
||||
|
||||
if platform.python_implementation() == 'PyPy':
|
||||
raise RuntimeError("uWSGI caching does not work under PyPy, see "
|
||||
"the docs for more details.")
|
||||
|
||||
try:
|
||||
import uwsgi
|
||||
self._uwsgi = uwsgi
|
||||
except ImportError:
|
||||
raise RuntimeError("uWSGI could not be imported, are you "
|
||||
"running under uWSGI?")
|
||||
|
||||
self.cache = cache
|
||||
|
||||
def get(self, key):
|
||||
rv = self._uwsgi.cache_get(key, self.cache)
|
||||
if rv is None:
|
||||
return
|
||||
return pickle.loads(rv)
|
||||
|
||||
def delete(self, key):
|
||||
return self._uwsgi.cache_del(key, self.cache)
|
||||
|
||||
def set(self, key, value, timeout=None):
|
||||
return self._uwsgi.cache_update(key, pickle.dumps(value),
|
||||
self._normalize_timeout(timeout),
|
||||
self.cache)
|
||||
|
||||
def add(self, key, value, timeout=None):
|
||||
return self._uwsgi.cache_set(key, pickle.dumps(value),
|
||||
self._normalize_timeout(timeout),
|
||||
self.cache)
|
||||
|
||||
def clear(self):
|
||||
return self._uwsgi.cache_clear(self.cache)
|
||||
|
||||
def has(self, key):
|
||||
return self._uwsgi.cache_exists(key, self.cache) is not None
|
||||
+41
-15
@@ -6,8 +6,7 @@
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# +-------------------------------------------------------------------
|
||||
from flask import request, redirect, g
|
||||
from BTPanel import session, cache
|
||||
from BTPanel import session, cache , request, redirect, g
|
||||
from datetime import datetime
|
||||
import os
|
||||
import public
|
||||
@@ -34,10 +33,11 @@ class panelSetup:
|
||||
ua = ua.lower()
|
||||
if ua.find('spider') != -1 or ua.find('bot') != -1:
|
||||
return redirect('https://www.google.com')
|
||||
g.version = '6.8.2'
|
||||
g.version = '6.8.4'
|
||||
g.title = public.GetConfigValue('title')
|
||||
g.uri = request.path
|
||||
g.debug = os.path.exists('data/debug.pl')
|
||||
g.pyversion = sys.version_info[0]
|
||||
if not g.debug:
|
||||
g.cdn_url = public.get_cdn_url()
|
||||
if not g.cdn_url:
|
||||
@@ -50,6 +50,19 @@ class panelSetup:
|
||||
session['version'] = g.version
|
||||
session['title'] = g.title
|
||||
g.is_aes = False
|
||||
|
||||
dirPath = '/www/server/phpmyadmin/pma'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
dirPath = '/www/server/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
dirPath = '/www/server/panel/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -59,6 +72,9 @@ class panelAdmin(panelSetup):
|
||||
# 本地请求
|
||||
def local(self):
|
||||
result = panelSetup().init()
|
||||
if result:
|
||||
return result
|
||||
result = self.check_login()
|
||||
if result:
|
||||
return result
|
||||
result = self.setSession()
|
||||
@@ -68,9 +84,6 @@ class panelAdmin(panelSetup):
|
||||
if result:
|
||||
return result
|
||||
result = self.checkWebType()
|
||||
if result:
|
||||
return result
|
||||
result = self.check_login()
|
||||
if result:
|
||||
return result
|
||||
result = self.checkConfig()
|
||||
@@ -99,7 +112,7 @@ class panelAdmin(panelSetup):
|
||||
if not 'lan' in session:
|
||||
session['lan'] = public.GetLanguage()
|
||||
if not 'home' in session:
|
||||
session['home'] = 'http://www.aapanel.com'
|
||||
session['home'] = 'https://console.aapanel.com'
|
||||
return None
|
||||
|
||||
# 检查Web服务器类型
|
||||
@@ -185,26 +198,37 @@ class panelAdmin(panelSetup):
|
||||
return redirect('/login')
|
||||
from BTPanel import get_input
|
||||
get = get_input()
|
||||
|
||||
|
||||
client_ip = public.GetClientIp()
|
||||
if not 'client_bind_token' in get:
|
||||
if not 'request_token' in get or not 'request_time' in get:
|
||||
return redirect('/login')
|
||||
client_ip = public.GetClientIp()
|
||||
|
||||
num_key = client_ip + '_api'
|
||||
if not public.get_error_num(num_key,20):
|
||||
return public.returnMsg(False,'AUTH_FAILED1')
|
||||
|
||||
|
||||
if not client_ip in api_config['limit_addr']:
|
||||
return public.returnJson(False,'%s[' % public.GetMsg("CHECK_IP_FALSE")+client_ip+']')
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False,'%s[' % public.GetMsg("AUTH_FAILED1")+client_ip+']')
|
||||
else:
|
||||
num_key = client_ip + '_app'
|
||||
if not public.get_error_num(num_key,20):
|
||||
return public.returnMsg(False,'AUTH_FAILED1')
|
||||
a_file = '/dev/shm/' + get.client_bind_token
|
||||
if not os.path.exists(a_file):
|
||||
import panelApi
|
||||
if not panelApi.panelApi().get_app_find(get.client_bind_token):
|
||||
return public.returnMsg(False, 'Unbound device')
|
||||
public.writeFile(a_file, '')
|
||||
public.set_error_num(num_key)
|
||||
return public.returnMsg(False,'UNBOUND_DEVICE')
|
||||
public.writeFile(a_file,'')
|
||||
|
||||
if not 'key' in api_config:
|
||||
return public.returnJson(False, 'Key verification failed')
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False, 'KEY_ERR')
|
||||
if not 'form_data' in get:
|
||||
return public.returnJson(False, 'No form_data data found')
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False, 'FORM_DATA_ERR')
|
||||
|
||||
g.form_data = json.loads(public.aes_decrypt(get.form_data, api_config['key']))
|
||||
|
||||
@@ -215,7 +239,9 @@ class panelAdmin(panelSetup):
|
||||
g.aes_key = api_config['key']
|
||||
request_token = public.md5(get.request_time + api_config['token'])
|
||||
if get.request_token == request_token:
|
||||
public.set_error_num(num_key,True)
|
||||
return False
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False,'SECRET_KEY_CHECK_FALSE')
|
||||
|
||||
# 检查系统配置
|
||||
|
||||
+1
-2
@@ -12,8 +12,7 @@ try:
|
||||
except:
|
||||
public.ExecShell("pip install pyotp &")
|
||||
try:
|
||||
from BTPanel import session,admin_path_checks,g
|
||||
from flask import request
|
||||
from BTPanel import session,admin_path_checks,g,request
|
||||
import send_mail
|
||||
except:pass
|
||||
class config:
|
||||
|
||||
+11
-3
@@ -10,7 +10,8 @@
|
||||
import sqlite3
|
||||
import os,time,sys
|
||||
os.chdir('/www/server/panel')
|
||||
sys.path.insert(0,'class')
|
||||
if not 'class/' in sys.path:
|
||||
sys.path.insert(0,'class/')
|
||||
import public
|
||||
|
||||
class Sql():
|
||||
@@ -29,7 +30,13 @@ class Sql():
|
||||
|
||||
def __init__(self):
|
||||
self.__DB_FILE = 'data/default.db'
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self,exc_type,exc_value,exc_trackback):
|
||||
self.close()
|
||||
|
||||
def __GetConn(self):
|
||||
#取数据库对象
|
||||
try:
|
||||
@@ -306,7 +313,8 @@ class Sql():
|
||||
#写锁
|
||||
def write_lock(self):
|
||||
self.is_lock()
|
||||
open(self.__LOCK,'wb+').close()
|
||||
with open(self.__LOCK,'wb+') as f:
|
||||
f.close()
|
||||
|
||||
#解锁
|
||||
def rm_lock(self):
|
||||
|
||||
+1
-1
@@ -164,7 +164,7 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
# 上传文件
|
||||
def UploadFile(self, get):
|
||||
from werkzeug.utils import secure_filename
|
||||
from flask import request
|
||||
from BTPanel import request
|
||||
if sys.version_info[0] == 2:
|
||||
get.path = get.path.encode('utf-8')
|
||||
if not os.path.exists(get.path):
|
||||
|
||||
+34
-4
@@ -10,7 +10,21 @@ import time,public,db,os,sys,json,re
|
||||
os.chdir('/www/server/panel')
|
||||
|
||||
def control_init():
|
||||
dirPath = '/www/server/phpmyadmin/pma'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
dirPath = '/www/server/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
dirPath = '/www/server/panel/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
sql = db.Sql().dbfile('system')
|
||||
if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'load_average')).count():
|
||||
csql = '''CREATE TABLE IF NOT EXISTS `load_average` (
|
||||
@@ -105,7 +119,7 @@ def control_init():
|
||||
public.ExecShell(c)
|
||||
p_file = 'class/plugin2.so'
|
||||
if os.path.exists(p_file): public.ExecShell("rm -f class/*.so")
|
||||
# public.ExecShell("chmod -R 600 /www/server/panel/data;chmod -R 600 /www/server/panel/config;chmod -R 700 /www/server/cron;chmod -R 600 /www/server/cron/*.log;chown -R root:root /www/server/panel/data;chown -R root:root /www/server/panel/config;chown -R www:www /www/server/phpmyadmin;chmod -R 700 /www/server/phpmyadmin")
|
||||
public.ExecShell("chmod -R 600 /www/server/panel/data;chmod -R 600 /www/server/panel/config;chmod -R 700 /www/server/cron;chmod -R 600 /www/server/cron/*.log;chown -R root:root /www/server/panel/data;chown -R root:root /www/server/panel/config;chown -R root:root /www/server/phpmyadmin;chmod -R 755 /www/server/phpmyadmin")
|
||||
if os.path.exists("/www/server/mysql"):
|
||||
public.ExecShell("chown mysql:mysql /etc/my.cnf;chmod 600 /etc/my.cnf")
|
||||
stop_path = '/www/server/stop'
|
||||
@@ -113,6 +127,14 @@ def control_init():
|
||||
os.makedirs(stop_path)
|
||||
public.ExecShell("chown -R root:root {path};chmod -R 755 {path}".format(path=stop_path))
|
||||
public.ExecShell('chmod 755 /www;chmod 755 /www/server')
|
||||
if os.path.exists('/www/server/phpmyadmin/pma'):
|
||||
public.ExecShell("rm -rf /www/server/phpmyadmin/pma")
|
||||
if os.path.exists("/www/server/adminer"):
|
||||
public.ExecShell("rm -rf /www/server/adminer")
|
||||
if os.path.exists("/www/server/panel/adminer"):
|
||||
public.ExecShell("rm -rf /www/server/panel/adminer")
|
||||
if os.path.exists('/dev/shm/session.db'):
|
||||
os.remove('/dev/shm/session.db')
|
||||
#disable_putenv('putenv')
|
||||
clean_session()
|
||||
#set_crond()
|
||||
@@ -141,7 +163,15 @@ def files_set_mode():
|
||||
["/www/server/speed","/*.lua","root",755,False],
|
||||
["/www/server/speed/total","","www",755,True],
|
||||
["/www/server/btwaf","/*.lua","root",755,False],
|
||||
|
||||
["/www/backup","","root",600,True],
|
||||
["/www/wwwlogs","","www",700,True],
|
||||
["/www/enterprise_backup","","root",600,True],
|
||||
["/www/server/cron","","root",700,True],
|
||||
["/www/server/cron","/*.log","root",600,True],
|
||||
["/www/server/stop","","root",755,True],
|
||||
["/www/server/redis","","redis",700,True],
|
||||
["/www/server/redis/redis.conf","","redis",600,False],
|
||||
["/www/Recycle_bin","","root",600,True],
|
||||
["/www/server/panel/class","","root",600,True],
|
||||
["/www/server/panel/data","","root",600,True],
|
||||
["/www/server/panel/plugin","","root",600,False],
|
||||
@@ -163,8 +193,8 @@ def files_set_mode():
|
||||
["/dev/shm/session.db","","root",600,False],
|
||||
["/dev/shm/session_py3","","root",600,True],
|
||||
["/dev/shm/session_py2","","root",600,True],
|
||||
|
||||
["/www/server/adminer","","www",700,True]
|
||||
["/www/server/phpmyadmin","","root",755,True],
|
||||
["/www/server/coll","","root",700,True]
|
||||
]
|
||||
|
||||
for m in m_paths:
|
||||
|
||||
+280
-270
@@ -12,8 +12,6 @@
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
import json,os,public,time,re,sys
|
||||
if __name__ != "__main__":
|
||||
from BTPanel import request,abort,send_file,Resp,cache
|
||||
import time
|
||||
import fastcgiClient as fcgi_client
|
||||
import struct
|
||||
@@ -57,11 +55,21 @@ class panelPHP:
|
||||
|
||||
#将参数写到文件
|
||||
def __write_args(self,args):
|
||||
from BTPanel import request
|
||||
if os.path.exists(self.__args_tmp): os.remove(self.__args_tmp)
|
||||
self.__clean_args_file()
|
||||
data = {}
|
||||
data['GET'] = request.args.to_dict()
|
||||
data['POST'] = request.form.to_dict()
|
||||
data['POST'] = {}
|
||||
x_token = request.headers.get('x-http-token')
|
||||
if x_token:
|
||||
aes_pwd = x_token[:8] + x_token[40:48]
|
||||
for key in request.form.keys():
|
||||
data['POST'][key] = str(request.form.get(key,''))
|
||||
if x_token:
|
||||
if len(data['POST'][key]) > 5:
|
||||
if data['POST'][key][:6] == 'BT-CRT':
|
||||
data['POST'][key] = public.aes_decrypt(data['POST'][key][6:],aes_pwd)
|
||||
data['POST']['client_ip'] = public.GetClientIp()
|
||||
data = json.dumps(data)
|
||||
public.writeFile(self.__args_tmp,data)
|
||||
@@ -127,273 +135,275 @@ class panelPHP:
|
||||
break
|
||||
return php_v
|
||||
|
||||
def get_phpmyadmin_phpversion(self):
|
||||
'''
|
||||
@name 获取当前phpmyadmin设置的PHP版本
|
||||
@author hwliang<2020-07-13>
|
||||
@return string
|
||||
'''
|
||||
ikey = 'pma_phpv'
|
||||
phpv = cache.get(ikey)
|
||||
if phpv: return phpv
|
||||
webserver = public.get_webserver()
|
||||
if webserver == 'nginx':
|
||||
filename = public.GetConfigValue('setup_path') + '/nginx/conf/enable-php.conf'
|
||||
conf = public.readFile(filename)
|
||||
if not conf: return None
|
||||
rep = r"php-cgi-(\d+)\.sock"
|
||||
phpv = re.findall(rep,conf)
|
||||
elif webserver == 'openlitespeed':
|
||||
filename = public.GetConfigValue('setup_path') + "/panel/vhost/openlitespeed/detail/phpmyadmin.conf"
|
||||
conf = public.readFile(filename)
|
||||
if not conf: return None
|
||||
rep = r"/usr/local/lsws/lsphp(\d+)/bin/lsphp"
|
||||
phpv = re.findall(rep,conf)
|
||||
else:
|
||||
filename = public.GetConfigValue('setup_path') + '/apache/conf/extra/httpd-vhosts.conf'
|
||||
conf = public.readFile(filename)
|
||||
if not conf: return None
|
||||
rep = r"php-cgi-(\d+)\.sock"
|
||||
phpv = re.findall(rep,conf)
|
||||
# def get_phpmyadmin_phpversion(self):
|
||||
# '''
|
||||
# @name 获取当前phpmyadmin设置的PHP版本
|
||||
# @author hwliang<2020-07-13>
|
||||
# @return string
|
||||
# '''
|
||||
# from BTPanel import cache
|
||||
# ikey = 'pma_phpv'
|
||||
# phpv = cache.get(ikey)
|
||||
# if phpv: return phpv
|
||||
# webserver = public.get_webserver()
|
||||
# if webserver == 'nginx':
|
||||
# filename = public.GetConfigValue('setup_path') + '/nginx/conf/enable-php.conf'
|
||||
# conf = public.readFile(filename)
|
||||
# if not conf: return None
|
||||
# rep = r"php-cgi-(\d+)\.sock"
|
||||
# phpv = re.findall(rep,conf)
|
||||
# elif webserver == 'openlitespeed':
|
||||
# filename = public.GetConfigValue('setup_path') + "/panel/vhost/openlitespeed/detail/phpmyadmin.conf"
|
||||
# conf = public.readFile(filename)
|
||||
# if not conf: return None
|
||||
# rep = r"/usr/local/lsws/lsphp(\d+)/bin/lsphp"
|
||||
# phpv = re.findall(rep,conf)
|
||||
# else:
|
||||
# filename = public.GetConfigValue('setup_path') + '/apache/conf/extra/httpd-vhosts.conf'
|
||||
# conf = public.readFile(filename)
|
||||
# if not conf: return None
|
||||
# rep = r"php-cgi-(\d+)\.sock"
|
||||
# phpv = re.findall(rep,conf)
|
||||
|
||||
if not phpv: return None
|
||||
cache.set(ikey,phpv[0],3)
|
||||
return phpv[0]
|
||||
|
||||
def get_pma_root(self):
|
||||
'''
|
||||
@name 获取phpmyadmin根目录
|
||||
@author hwliang<2020-07-13>
|
||||
@return string
|
||||
'''
|
||||
pma_path = '/www/server/phpmyadmin/'
|
||||
if not os.path.exists(pma_path):
|
||||
os.makedirs(pma_path)
|
||||
for dname in os.listdir(pma_path):
|
||||
if dname.find('phpmyadmin_') != -1:
|
||||
return os.path.join(pma_path,dname)
|
||||
return None
|
||||
|
||||
def check_phpmyadmin_phpversion(self):
|
||||
'''
|
||||
@name 检查当前phpmyadmin版本可用的php版本列表
|
||||
@author hwliang<2020-07-13>
|
||||
@return list
|
||||
'''
|
||||
pma_path = '/www/server/phpmyadmin/'
|
||||
pma_version_f1 = os.path.join(pma_path,'version_check.pl')
|
||||
pma_root = os.path.join(pma_path,'pma')
|
||||
pma_version_f2 = os.path.join(pma_root,'version_check.pl')
|
||||
if not os.path.exists(pma_version_f1):
|
||||
src_vfile = os.path.join(pma_path,'version.pl')
|
||||
if os.path.exists(src_vfile):
|
||||
public.writeFile(pma_version_f1,public.readFile(src_vfile))
|
||||
v_sync = public.readFile(pma_version_f1) == public.readFile(pma_version_f2)
|
||||
|
||||
if not os.path.exists(pma_root + '/index.php') or not v_sync:
|
||||
o_pma_root = self.get_pma_root()
|
||||
|
||||
if o_pma_root:
|
||||
if not os.path.exists(pma_root):
|
||||
os.makedirs(pma_root)
|
||||
public.ExecShell("\cp -arf {}/* {}/".format(o_pma_root,pma_root))
|
||||
public.ExecShell("chown -R www:www {}".format(pma_root))
|
||||
public.ExecShell("chmod -R 700 {}".format(pma_root))
|
||||
public.ExecShell("\cp -arf {} {}".format(pma_version_f1,pma_version_f2))
|
||||
index = public.readFile(pma_root + '/index.php')
|
||||
if index:
|
||||
if index.find("use PhpMyAdmin\\Util") != -1:
|
||||
resp = "use PhpMyAdmin\\Util;\nif(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');"
|
||||
index = index.replace("use PhpMyAdmin\\Util;",resp)
|
||||
elif index.find("use PMA\libraries\LanguageManager;") != -1:
|
||||
resp = "use PMA\libraries\LanguageManager;\nif(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');"
|
||||
index = index.replace("use PMA\libraries\LanguageManager;",resp)
|
||||
elif index.find("require_once 'libraries/common.inc.php';") != -1:
|
||||
resp = "if(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');\nrequire_once 'libraries/common.inc.php';"
|
||||
index = index.replace("require_once 'libraries/common.inc.php';",resp)
|
||||
|
||||
|
||||
public.writeFile(pma_root + '/index.php',index)
|
||||
|
||||
if not os.path.exists(pma_version_f2):
|
||||
return False
|
||||
|
||||
pma_version = public.readFile(pma_version_f2)
|
||||
self.pma_version = pma_version
|
||||
if pma_version:
|
||||
pma_version = pma_version[:3]
|
||||
|
||||
if pma_version == '4.4':
|
||||
return ['53','54','55','56']
|
||||
elif pma_version == '4.0':
|
||||
return ['52','53']
|
||||
elif pma_version == '4.6':
|
||||
return None
|
||||
elif pma_version == '4.7':
|
||||
return ['55','56','70','71','72']
|
||||
elif pma_version in ['4.8','4.9','5.0']:
|
||||
return ['70','71','72','73','74']
|
||||
else:
|
||||
return ['55','56','70','71','72']
|
||||
|
||||
def get_mysql_port(self):
|
||||
'''
|
||||
@name 获取mysql当前端口号
|
||||
@author hwliang<2020-07-13>
|
||||
@return int
|
||||
'''
|
||||
try:
|
||||
myconf = public.readFile('/etc/my.cnf')
|
||||
rep = r"port\s*=\s*([0-9]+)"
|
||||
port = int(re.search(rep,myconf).groups()[0])
|
||||
if not port: port = 3306
|
||||
return port
|
||||
except:
|
||||
return 3306
|
||||
|
||||
def write_pma_passwd(self,username,password):
|
||||
'''
|
||||
@name 写入mysql帐号密码到配置文件
|
||||
@author hwliang<2020-07-13>
|
||||
@param username string(用户名)
|
||||
@param password string(密码)
|
||||
@return bool
|
||||
'''
|
||||
|
||||
self.check_phpmyadmin_phpversion()
|
||||
pconfig = 'cookie'
|
||||
if username:
|
||||
pconfig = 'config'
|
||||
pma_path = '/www/server/phpmyadmin/'
|
||||
pma_config_file = os.path.join(pma_path,'pma/config.inc.php')
|
||||
conf = public.readFile(pma_config_file)
|
||||
if not conf: return False
|
||||
rep = r"/\* Authentication type \*/(.|\n)+/\* Server parameters \*/"
|
||||
rstr = '''/* Authentication type */
|
||||
$cfg['Servers'][$i]['auth_type'] = '{}';
|
||||
$cfg['Servers'][$i]['host'] = 'localhost';
|
||||
$cfg['Servers'][$i]['port'] = '{}';
|
||||
$cfg['Servers'][$i]['user'] = '{}';
|
||||
$cfg['Servers'][$i]['password'] = '{}';
|
||||
/* Server parameters */'''.format(pconfig,self.get_mysql_port(),username,password)
|
||||
conf = re.sub(rep,rstr,conf)
|
||||
public.writeFile(pma_config_file,conf)
|
||||
return True
|
||||
|
||||
def request_php(self,uri):
|
||||
'''
|
||||
@name 发起fastcgi请求到PHP-FPM
|
||||
@author hwliang<2020-07-11>
|
||||
@param puri string(URI地址)
|
||||
@return socket
|
||||
'''
|
||||
php_unix_socket = '/tmp/php-cgi-{}.sock'.format(self.php_version)
|
||||
f = FPM(php_unix_socket,self.document_root,self.last_path)
|
||||
|
||||
if request.full_path.find('?') != -1:
|
||||
uri = request.full_path[request.full_path.find(uri):]
|
||||
if self.re_io:
|
||||
sock = f.load_url(uri,content=self.re_io)
|
||||
else:
|
||||
sock = f.load_url(uri,content=request.stream)
|
||||
return sock
|
||||
|
||||
def start(self,puri,document_root,last_path = ''):
|
||||
'''
|
||||
@name 开始处理PHP请求
|
||||
@author hwliang<2020-07-11>
|
||||
@param puri string(URI地址)
|
||||
@return socket or Response
|
||||
'''
|
||||
if puri in ['/','',None]: puri = 'index.php'
|
||||
if puri[0] == '/': puri = puri[1:]
|
||||
self.document_root = document_root
|
||||
self.last_path = last_path
|
||||
filename = document_root + puri
|
||||
|
||||
|
||||
#如果是PHP文件
|
||||
if puri[-4:] == '.php':
|
||||
if request.path.find('/phpmyadmin/') != -1:
|
||||
ikey = 'pma_php_version'
|
||||
self.php_version = cache.get(ikey)
|
||||
if not self.php_version:
|
||||
php_version = self.get_phpmyadmin_phpversion()
|
||||
php_versions = self.check_phpmyadmin_phpversion()
|
||||
if not php_versions:
|
||||
if php_versions == False:
|
||||
return Resp(
|
||||
'Phpmyadmin is not installed, or support for phpMyAdmin4.6 has been discontinued due to security issues, uninstall and install other secure versions in the software store!')
|
||||
else:
|
||||
return Resp('phpmyadmin is not installed')
|
||||
if not php_version or not php_version in php_versions:
|
||||
php_version = php_versions
|
||||
self.php_version = self.get_php_version(php_version)
|
||||
if not self.php_version:
|
||||
php_version = self.check_phpmyadmin_phpversion()
|
||||
self.php_version = self.get_php_version(php_version)
|
||||
if not php_version:
|
||||
return Resp('No supported PHP version found: {}'.format(php_versions))
|
||||
|
||||
if not self.php_version in php_versions:
|
||||
self.php_version = self.get_php_version(php_versions)
|
||||
|
||||
if not self.php_version:
|
||||
return Resp('No supported PHP version found: {}'.format(php_versions))
|
||||
cache.set(ikey,self.php_version,1)
|
||||
if request.method == 'POST':
|
||||
#登录phpmyadmin
|
||||
if puri in ['index.php','/index.php']:
|
||||
content = public.url_encode(request.form.to_dict())
|
||||
if not isinstance(content,bytes):
|
||||
content = content.encode()
|
||||
self.re_io = StringIO(content)
|
||||
username = request.form.get('pma_username')
|
||||
if username:
|
||||
password = request.form.get('pma_password')
|
||||
if not self.write_pma_passwd(username,password):
|
||||
return Resp('Phpmyadmin is not installed')
|
||||
|
||||
if puri in ['logout.php', '/logout.php']:
|
||||
self.write_pma_passwd(None, None)
|
||||
else:
|
||||
src_path = '/www/server/panel/adminer'
|
||||
dst_path = '/www/server/adminer'
|
||||
if os.path.exists(src_path):
|
||||
if not os.path.exists(dst_path): os.makedirs(dst_path)
|
||||
public.ExecShell("\cp -arf {}/* {}/".format(src_path, dst_path))
|
||||
public.ExecShell("chown -R www:www {}".format(dst_path))
|
||||
public.ExecShell("chmod -R 700 {}".format(dst_path))
|
||||
public.ExecShell("rm -rf {}".format(src_path))
|
||||
|
||||
if not os.path.exists(dst_path + '/index.php'):
|
||||
return Resp("The AdMiner file is missing. Please try again after the [Fix] panel on the first page!")
|
||||
|
||||
ikey = 'aer_php_version'
|
||||
self.php_version = cache.get(ikey)
|
||||
if not self.php_version:
|
||||
self.php_version = self.get_php_version(None)
|
||||
cache.set(ikey, self.php_version, 10)
|
||||
if not self.php_version:
|
||||
return Resp('没有找到可用的PHP版本')
|
||||
|
||||
#文件是否存在?
|
||||
if not os.path.exists(filename):
|
||||
return abort(404)
|
||||
|
||||
#发送到FPM
|
||||
try:
|
||||
return self.request_php(puri)
|
||||
except Exception as ex:
|
||||
if str(ex).find('No such file or directory') != -1:
|
||||
return Resp('Specify PHP version: {}, not started, or unable to connect!'.format(self.php_version))
|
||||
return Resp(str(ex))
|
||||
|
||||
if not os.path.exists(filename):
|
||||
return abort(404)
|
||||
|
||||
#如果是静态文件
|
||||
return send_file(filename)
|
||||
# if not phpv: return None
|
||||
# cache.set(ikey,phpv[0],3)
|
||||
# return phpv[0]
|
||||
#
|
||||
# def get_pma_root(self):
|
||||
# '''
|
||||
# @name 获取phpmyadmin根目录
|
||||
# @author hwliang<2020-07-13>
|
||||
# @return string
|
||||
# '''
|
||||
# pma_path = '/www/server/phpmyadmin/'
|
||||
# if not os.path.exists(pma_path):
|
||||
# os.makedirs(pma_path)
|
||||
# for dname in os.listdir(pma_path):
|
||||
# if dname.find('phpmyadmin_') != -1:
|
||||
# return os.path.join(pma_path,dname)
|
||||
# return None
|
||||
#
|
||||
# def check_phpmyadmin_phpversion(self):
|
||||
# '''
|
||||
# @name 检查当前phpmyadmin版本可用的php版本列表
|
||||
# @author hwliang<2020-07-13>
|
||||
# @return list
|
||||
# '''
|
||||
# return
|
||||
# pma_path = '/www/server/phpmyadmin/'
|
||||
# pma_version_f1 = os.path.join(pma_path,'version_check.pl')
|
||||
# pma_root = os.path.join(pma_path,'pma')
|
||||
# pma_version_f2 = os.path.join(pma_root,'version_check.pl')
|
||||
# if not os.path.exists(pma_version_f1):
|
||||
# src_vfile = os.path.join(pma_path,'version.pl')
|
||||
# if os.path.exists(src_vfile):
|
||||
# public.writeFile(pma_version_f1,public.readFile(src_vfile))
|
||||
# v_sync = public.readFile(pma_version_f1) == public.readFile(pma_version_f2)
|
||||
#
|
||||
# if not os.path.exists(pma_root + '/index.php') or not v_sync:
|
||||
# o_pma_root = self.get_pma_root()
|
||||
#
|
||||
# if o_pma_root:
|
||||
# if not os.path.exists(pma_root):
|
||||
# os.makedirs(pma_root)
|
||||
# public.ExecShell("\cp -arf {}/* {}/".format(o_pma_root,pma_root))
|
||||
# public.ExecShell("chown -R www:www {}".format(pma_root))
|
||||
# public.ExecShell("chmod -R 700 {}".format(pma_root))
|
||||
# public.ExecShell("\cp -arf {} {}".format(pma_version_f1,pma_version_f2))
|
||||
# index = public.readFile(pma_root + '/index.php')
|
||||
# if index:
|
||||
# if index.find("use PhpMyAdmin\\Util") != -1:
|
||||
# resp = "use PhpMyAdmin\\Util;\nif(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');"
|
||||
# index = index.replace("use PhpMyAdmin\\Util;",resp)
|
||||
# elif index.find("use PMA\libraries\LanguageManager;") != -1:
|
||||
# resp = "use PMA\libraries\LanguageManager;\nif(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');"
|
||||
# index = index.replace("use PMA\libraries\LanguageManager;",resp)
|
||||
# elif index.find("require_once 'libraries/common.inc.php';") != -1:
|
||||
# resp = "if(function_exists('opcache_invalidate')) opcache_invalidate('/www/server/phpmyadmin/pma/config.inc.php');\nrequire_once 'libraries/common.inc.php';"
|
||||
# index = index.replace("require_once 'libraries/common.inc.php';",resp)
|
||||
#
|
||||
#
|
||||
# public.writeFile(pma_root + '/index.php',index)
|
||||
#
|
||||
# if not os.path.exists(pma_version_f2):
|
||||
# return False
|
||||
#
|
||||
# pma_version = public.readFile(pma_version_f2)
|
||||
# self.pma_version = pma_version
|
||||
# if pma_version:
|
||||
# pma_version = pma_version[:3]
|
||||
#
|
||||
# if pma_version == '4.4':
|
||||
# return ['53','54','55','56']
|
||||
# elif pma_version == '4.0':
|
||||
# return ['52','53']
|
||||
# elif pma_version == '4.6':
|
||||
# return None
|
||||
# elif pma_version == '4.7':
|
||||
# return ['55','56','70','71','72']
|
||||
# elif pma_version in ['4.8','4.9','5.0']:
|
||||
# return ['70','71','72','73','74']
|
||||
# else:
|
||||
# return ['55','56','70','71','72']
|
||||
#
|
||||
# def get_mysql_port(self):
|
||||
# '''
|
||||
# @name 获取mysql当前端口号
|
||||
# @author hwliang<2020-07-13>
|
||||
# @return int
|
||||
# '''
|
||||
# try:
|
||||
# myconf = public.readFile('/etc/my.cnf')
|
||||
# rep = r"port\s*=\s*([0-9]+)"
|
||||
# port = int(re.search(rep,myconf).groups()[0])
|
||||
# if not port: port = 3306
|
||||
# return port
|
||||
# except:
|
||||
# return 3306
|
||||
#
|
||||
# def write_pma_passwd(self,username,password):
|
||||
# '''
|
||||
# @name 写入mysql帐号密码到配置文件
|
||||
# @author hwliang<2020-07-13>
|
||||
# @param username string(用户名)
|
||||
# @param password string(密码)
|
||||
# @return bool
|
||||
# '''
|
||||
#
|
||||
# self.check_phpmyadmin_phpversion()
|
||||
# pconfig = 'cookie'
|
||||
# if username:
|
||||
# pconfig = 'config'
|
||||
# pma_path = '/www/server/phpmyadmin/'
|
||||
# pma_config_file = os.path.join(pma_path,'pma/config.inc.php')
|
||||
# conf = public.readFile(pma_config_file)
|
||||
# if not conf: return False
|
||||
# rep = r"/\* Authentication type \*/(.|\n)+/\* Server parameters \*/"
|
||||
# rstr = '''/* Authentication type */
|
||||
# $cfg['Servers'][$i]['auth_type'] = '{}';
|
||||
# $cfg['Servers'][$i]['host'] = 'localhost';
|
||||
# $cfg['Servers'][$i]['port'] = '{}';
|
||||
# $cfg['Servers'][$i]['user'] = '{}';
|
||||
# $cfg['Servers'][$i]['password'] = '{}';
|
||||
# /* Server parameters */'''.format(pconfig,self.get_mysql_port(),username,password)
|
||||
# conf = re.sub(rep,rstr,conf)
|
||||
# public.writeFile(pma_config_file,conf)
|
||||
# return True
|
||||
#
|
||||
# def request_php(self,uri):
|
||||
# '''
|
||||
# @name 发起fastcgi请求到PHP-FPM
|
||||
# @author hwliang<2020-07-11>
|
||||
# @param puri string(URI地址)
|
||||
# @return socket
|
||||
# '''
|
||||
# php_unix_socket = '/tmp/php-cgi-{}.sock'.format(self.php_version)
|
||||
# f = FPM(php_unix_socket,self.document_root,self.last_path)
|
||||
#
|
||||
# if request.full_path.find('?') != -1:
|
||||
# uri = request.full_path[request.full_path.find(uri):]
|
||||
# if self.re_io:
|
||||
# sock = f.load_url(uri,content=self.re_io)
|
||||
# else:
|
||||
# sock = f.load_url(uri,content=request.stream)
|
||||
# return sock
|
||||
#
|
||||
# def start(self,puri,document_root,last_path = ''):
|
||||
# '''
|
||||
# @name 开始处理PHP请求
|
||||
# @author hwliang<2020-07-11>
|
||||
# @param puri string(URI地址)
|
||||
# @return socket or Response
|
||||
# '''
|
||||
# if puri in ['/','',None]: puri = 'index.php'
|
||||
# if puri[0] == '/': puri = puri[1:]
|
||||
# self.document_root = document_root
|
||||
# self.last_path = last_path
|
||||
# filename = document_root + puri
|
||||
#
|
||||
#
|
||||
# #如果是PHP文件
|
||||
# if puri[-4:] == '.php':
|
||||
# if request.path.find('/phpmyadmin/') != -1:
|
||||
# ikey = 'pma_php_version'
|
||||
# self.php_version = cache.get(ikey)
|
||||
# if not self.php_version:
|
||||
# php_version = self.get_phpmyadmin_phpversion()
|
||||
# php_versions = self.check_phpmyadmin_phpversion()
|
||||
# if not php_versions:
|
||||
# if php_versions == False:
|
||||
# return Resp(
|
||||
# 'Phpmyadmin is not installed, or support for phpMyAdmin4.6 has been discontinued due to security issues, uninstall and install other secure versions in the software store!')
|
||||
# else:
|
||||
# return Resp('phpmyadmin is not installed')
|
||||
# if not php_version or not php_version in php_versions:
|
||||
# php_version = php_versions
|
||||
# self.php_version = self.get_php_version(php_version)
|
||||
# if not self.php_version:
|
||||
# php_version = self.check_phpmyadmin_phpversion()
|
||||
# self.php_version = self.get_php_version(php_version)
|
||||
# if not php_version:
|
||||
# return Resp('No supported PHP version found: {}'.format(php_versions))
|
||||
#
|
||||
# if not self.php_version in php_versions:
|
||||
# self.php_version = self.get_php_version(php_versions)
|
||||
#
|
||||
# if not self.php_version:
|
||||
# return Resp('No supported PHP version found: {}'.format(php_versions))
|
||||
# cache.set(ikey,self.php_version,1)
|
||||
# if request.method == 'POST':
|
||||
# #登录phpmyadmin
|
||||
# if puri in ['index.php','/index.php']:
|
||||
# content = public.url_encode(request.form.to_dict())
|
||||
# if not isinstance(content,bytes):
|
||||
# content = content.encode()
|
||||
# self.re_io = StringIO(content)
|
||||
# username = request.form.get('pma_username')
|
||||
# if username:
|
||||
# password = request.form.get('pma_password')
|
||||
# if not self.write_pma_passwd(username,password):
|
||||
# return Resp('Phpmyadmin is not installed')
|
||||
#
|
||||
# if puri in ['logout.php', '/logout.php']:
|
||||
# self.write_pma_passwd(None, None)
|
||||
# else:
|
||||
# src_path = '/www/server/panel/adminer'
|
||||
# dst_path = '/www/server/adminer'
|
||||
# if os.path.exists(src_path):
|
||||
# if not os.path.exists(dst_path): os.makedirs(dst_path)
|
||||
# public.ExecShell("\cp -arf {}/* {}/".format(src_path, dst_path))
|
||||
# public.ExecShell("chown -R www:www {}".format(dst_path))
|
||||
# public.ExecShell("chmod -R 700 {}".format(dst_path))
|
||||
# public.ExecShell("rm -rf {}".format(src_path))
|
||||
#
|
||||
# if not os.path.exists(dst_path + '/index.php'):
|
||||
# return Resp("The AdMiner file is missing. Please try again after the [Fix] panel on the first page!")
|
||||
#
|
||||
# ikey = 'aer_php_version'
|
||||
# self.php_version = cache.get(ikey)
|
||||
# if not self.php_version:
|
||||
# self.php_version = self.get_php_version(None)
|
||||
# cache.set(ikey, self.php_version, 10)
|
||||
# if not self.php_version:
|
||||
# return Resp('没有找到可用的PHP版本')
|
||||
#
|
||||
# #文件是否存在?
|
||||
# if not os.path.exists(filename):
|
||||
# return abort(404)
|
||||
#
|
||||
# #发送到FPM
|
||||
# try:
|
||||
# return self.request_php(puri)
|
||||
# except Exception as ex:
|
||||
# if str(ex).find('No such file or directory') != -1:
|
||||
# return Resp('Specify PHP version: {}, not started, or unable to connect!'.format(self.php_version))
|
||||
# return Resp(str(ex))
|
||||
#
|
||||
# if not os.path.exists(filename):
|
||||
# return abort(404)
|
||||
#
|
||||
# #如果是静态文件
|
||||
# return send_file(filename)
|
||||
|
||||
|
||||
|
||||
@@ -529,7 +539,7 @@ class FPM(object):
|
||||
except ValueError:
|
||||
script_name = url
|
||||
query_string = ''
|
||||
|
||||
from BTPanel import request
|
||||
env = {
|
||||
'SCRIPT_FILENAME': '%s%s' % (self.document_root, script_name),
|
||||
'QUERY_STRING': query_string,
|
||||
|
||||
@@ -171,6 +171,8 @@ class panelPlugin:
|
||||
if 'status' in result:
|
||||
if result['status']:
|
||||
public.httpPost(public.GetConfigValue('home') + '/api/panel/plugin_total',{"pid":pluginInfo['id'],'p_name':pluginInfo['name']},3)
|
||||
get.force = 1
|
||||
self.get_cloud_list(get)
|
||||
except:pass
|
||||
return result
|
||||
|
||||
@@ -1891,8 +1893,7 @@ class panelPlugin:
|
||||
return panelPHP.panelPHP(get.name).exec_php_script(get)
|
||||
return public.returnMsg(False,'PLUGIN_INPUT_B')
|
||||
if not self.check_accept(get):return public.returnMsg(False,public.to_string([24744, 26410, 36141, 20080, 91, 37, 115, 93, 25110, 25480, 26435, 24050, 21040, 26399, 33]) % (self.get_title_byname(get),))
|
||||
if not path in sys.path:
|
||||
sys.path.insert(0,path)
|
||||
public.package_path_append(path)
|
||||
plugin_main = __import__(get.name+'_main')
|
||||
try:
|
||||
reload(plugin_main)
|
||||
|
||||
+21
-13
@@ -11,7 +11,10 @@
|
||||
# 网站管理类
|
||||
#------------------------------
|
||||
import io,re,public,os,sys,shutil,json,hashlib,socket,time
|
||||
from BTPanel import session
|
||||
try:
|
||||
from BTPanel import session
|
||||
except:
|
||||
pass
|
||||
from panelRedirect import panelRedirect
|
||||
import site_dir_auth
|
||||
class panelSite(panelRedirect):
|
||||
@@ -93,10 +96,10 @@ class panelSite(panelRedirect):
|
||||
for key in tmp:
|
||||
if key == port: return False
|
||||
|
||||
listen = "\nListen "+tmp[0]
|
||||
listen = "\nListen "+ tmp[0] + "\n"
|
||||
listen_ipv6 = ''
|
||||
#if self.is_ipv6: listen_ipv6 = "\nListen [::]:" + port
|
||||
allConf = allConf.replace(listen,listen + "\nListen " + port + listen_ipv6)
|
||||
allConf = allConf.replace(listen,listen + "Listen " + port + listen_ipv6 + "\n")
|
||||
public.writeFile(filename, allConf)
|
||||
return True
|
||||
|
||||
@@ -633,7 +636,7 @@ include /www/server/panel/vhost/openlitespeed/proxy/BTSITENAME/*.conf
|
||||
public.ExecShell("rm -f " + public.GetConfigValue('logs_path') + '/' + siteName + "-*")
|
||||
|
||||
#删除备份
|
||||
public.ExecShell("rm -f "+session['config']['backup_path']+'/site/'+siteName+'_*')
|
||||
#public.ExecShell("rm -f "+session['config']['backup_path']+'/site/'+siteName+'_*')
|
||||
|
||||
#删除根目录
|
||||
if 'path' in get:
|
||||
@@ -1423,10 +1426,11 @@ listener SSL443 {
|
||||
ssl_certificate /www/server/panel/vhost/cert/%s/fullchain.pem;
|
||||
ssl_certificate_key /www/server/panel/vhost/cert/%s/privkey.pem;
|
||||
ssl_protocols TLSv1.1 TLSv1.2%s;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
|
||||
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
error_page 497 https://$host$request_uri;
|
||||
""" % (get.first_domain, get.first_domain,self.get_tls13())
|
||||
if (conf.find('ssl_certificate') != -1):
|
||||
@@ -1500,7 +1504,7 @@ listener SSL443 {
|
||||
SSLEngine On
|
||||
SSLCertificateFile /www/server/panel/vhost/cert/%s/fullchain.pem
|
||||
SSLCertificateKeyFile /www/server/panel/vhost/cert/%s/privkey.pem
|
||||
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
|
||||
SSLCipherSuite EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5
|
||||
SSLProtocol All -SSLv2 -SSLv3 -TLSv1
|
||||
SSLHonorCipherOrder On
|
||||
%s
|
||||
@@ -1701,7 +1705,6 @@ listener SSL443 {
|
||||
detail_file = self.setupPath + '/panel/vhost/openlitespeed/detail/' + siteName + '.conf'
|
||||
force_https = self.setupPath + '/panel/vhost/openlitespeed/redirect/' + siteName
|
||||
string = 'rm -f {}/force_https.conf*'.format(force_https)
|
||||
public.writeFile("/tmp/2",string)
|
||||
public.ExecShell(string)
|
||||
detail_conf = public.readFile(detail_file)
|
||||
if detail_conf:
|
||||
@@ -1739,6 +1742,7 @@ listener SSL443 {
|
||||
type = 0
|
||||
if os.path.exists(path + '/README'): type = 1
|
||||
if os.path.exists(path + '/partnerOrderId'): type = 2
|
||||
if os.path.exists(path + '/certOrderId'): type = 3
|
||||
csrpath = path + "/fullchain.pem" # 生成证书路径
|
||||
keypath = path + "/privkey.pem" # 密钥文件路径
|
||||
key = public.readFile(keypath)
|
||||
@@ -1792,8 +1796,11 @@ listener SSL443 {
|
||||
if 'dnsapi' in crontab_config[siteName]:
|
||||
auth_type = 'dns'
|
||||
|
||||
|
||||
return {'status': status, 'domain': domains, 'key': key, 'csr': csr, 'type': type, 'httpTohttps': toHttps,'cert_data':cert_data,'email':email,"index":index,'auth_type':auth_type}
|
||||
if os.path.exists(path + '/certOrderId'): type = 3
|
||||
oid = -1
|
||||
if type == 3:
|
||||
oid = int(public.readFile(path + '/certOrderId'))
|
||||
return {'status': status,'oid':oid, 'domain': domains, 'key': key, 'csr': csr, 'type': type, 'httpTohttps': toHttps,'cert_data':cert_data,'email':email,"index":index,'auth_type':auth_type}
|
||||
|
||||
|
||||
#启动站点
|
||||
@@ -2887,7 +2894,7 @@ server
|
||||
if get.todomain:
|
||||
if not re.search(tod,get.todomain):
|
||||
return public.returnMsg(False, 'SENT_DOMAIN_FORMAT', (get.todomain,))
|
||||
else:
|
||||
if public.get_webserver() != 'openlitespeed':
|
||||
get.todomain = "$host"
|
||||
|
||||
# 检测目标URL格式
|
||||
@@ -3085,9 +3092,10 @@ RewriteRule ^%s(.*)$ http://%s/$1 [P,E=Proxy-Host:%s]
|
||||
status = self.SetProxy(get)
|
||||
if not status["status"]:
|
||||
return status
|
||||
get.version = '00'
|
||||
get.siteName = get.sitename
|
||||
self.SetPHPVersion(get)
|
||||
if get.proxydir == '/':
|
||||
get.version = '00'
|
||||
get.siteName = get.sitename
|
||||
self.SetPHPVersion(get)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'ADD_SUCCESS')
|
||||
|
||||
|
||||
+14
-12
@@ -17,15 +17,16 @@ import public
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
sys.path.insert(0, '/www/server/panel/class')
|
||||
os.chdir('/www/server/panel')
|
||||
|
||||
if not 'class/' in sys.path:
|
||||
sys.path.insert(0,'class/')
|
||||
|
||||
class bt_task:
|
||||
__table = 'task_list'
|
||||
__task_tips = '/dev/shm/bt_task_now.pl'
|
||||
__task_path = '/www/server/panel/tmp/'
|
||||
down_log_total_file = '/tmp/download_total.pl'
|
||||
not_web = False
|
||||
def __init__(self):
|
||||
|
||||
# 创建数据表
|
||||
@@ -66,7 +67,7 @@ class bt_task:
|
||||
data = sql.field('id,name,type,shell,other,status,exectime,endtime,addtime').order(
|
||||
'id asc').limit('10').select()
|
||||
if type(data) == str:
|
||||
public.WriteLog('Task queue',data)
|
||||
public.WriteLog('TASK_QUEUE',data)
|
||||
return []
|
||||
if not 'num' in get:
|
||||
get.num = 15
|
||||
@@ -139,7 +140,7 @@ class bt_task:
|
||||
"kill -9 $(ps aux|grep '"+task_info['shell']+"'|grep -v grep|awk '{print $2}')")
|
||||
|
||||
public.ExecShell("/etc/init.d/bt start")
|
||||
return public.returnMsg(True, '任务已取消!')
|
||||
return public.returnMsg(True, 'TASK_CANCEL')
|
||||
|
||||
# 取一条任务
|
||||
def get_task_find(self, id):
|
||||
@@ -219,7 +220,9 @@ class bt_task:
|
||||
log_file = self.__task_path + str(id) + '.log'
|
||||
if not os.path.exists(log_file):
|
||||
data = ''
|
||||
if(task_type == '1'): data = {'name':public.GetMsg("DOWNLOAD_FILE"),'total':0,'used':0,'pre':0,'speed':0}
|
||||
if(task_type == '1'):
|
||||
data = {'name': public.GetMsg("DOWNLOAD_FILE"), 'total': 0, 'used': 0,
|
||||
'pre': 0, 'speed': 0, 'time': 0}
|
||||
return data
|
||||
|
||||
if(task_type == '1'):
|
||||
@@ -245,7 +248,7 @@ class bt_task:
|
||||
speed_total = re.findall(
|
||||
r"([\d\.]+[BbKkMmGg]).+\s+(\d+)%\s+([\d\.]+[KMBGkmbg])\s+(\w+[sS])", speed_tmp)
|
||||
if not speed_total:
|
||||
data = {'name':'download file {}'.format(filename),'total':0,'used':0,'pre':0,'speed':0,'time':0}
|
||||
data = {'name':public.getMsg('DOWNLOAD_FILE1',(filename,)),'total':0,'used':0,'pre':0,'speed':0,'time':0}
|
||||
else:
|
||||
speed_total = speed_total[0]
|
||||
used = speed_total[0]
|
||||
@@ -312,7 +315,7 @@ class bt_task:
|
||||
return public.returnMsg(False,'NOT_SUP_COMP_FORMAT')
|
||||
|
||||
self.set_file_accept(dfile)
|
||||
public.WriteLog("TYPE_FILE", 'ZIP_SUCCESS', (sfiles, dfile))
|
||||
public.WriteLog("TYPE_FILE", 'ZIP_SUCCESS', (sfiles, dfile),not_web = self.not_web)
|
||||
return public.returnMsg(True, 'ZIP_SUCCESS')
|
||||
|
||||
# 文件解压
|
||||
@@ -356,7 +359,7 @@ class bt_task:
|
||||
user = pwd.getpwuid(os.stat(dfile).st_uid).pw_name
|
||||
public.ExecShell("chown %s:%s %s" % (user, user, dfile))
|
||||
|
||||
public.WriteLog("TYPE_FILE", 'UNZIP_SUCCESS', (sfile, dfile))
|
||||
public.WriteLog("TYPE_FILE", 'UNZIP_SUCCESS', (sfile, dfile),not_web = self.not_web)
|
||||
return public.returnMsg(True, 'UNZIP_SUCCESS')
|
||||
|
||||
# 备份网站
|
||||
@@ -378,7 +381,7 @@ class bt_task:
|
||||
|
||||
sql = public.M('backup').add('type,name,pid,filename,size,addtime',
|
||||
(0, fileName, find['id'], zipName, 0, public.getDate()))
|
||||
public.WriteLog('TYPE_SITE', 'SITE_BACKUP_SUCCESS', (find['name'],))
|
||||
public.WriteLog('TYPE_SITE', 'SITE_BACKUP_SUCCESS', (find['name'],),not_web = self.not_web)
|
||||
return public.returnMsg(True, 'BACKUP_SUCCESS')
|
||||
|
||||
# 备份数据库
|
||||
@@ -405,7 +408,7 @@ class bt_task:
|
||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
sql.add('type,name,pid,filename,size,addtime',
|
||||
(1, fileName, id, backupName, 0, addTime))
|
||||
public.WriteLog("TYPE_DATABASE", "DATABASE_BACKUP_SUCCESS", (name,))
|
||||
public.WriteLog("TYPE_DATABASE", "DATABASE_BACKUP_SUCCESS", (name,),not_web = self.not_web)
|
||||
return public.returnMsg(True, 'BACKUP_SUCCESS')
|
||||
|
||||
# 导入数据库
|
||||
@@ -454,7 +457,7 @@ class bt_task:
|
||||
'setup_path') + "/mysql/bin/mysql -uroot -p" + root + " --force \"" + name + "\" < " + file)
|
||||
self.mypass(False, root)
|
||||
|
||||
public.WriteLog("TYPE_DATABASE", 'DATABASE_INPUT_SUCCESS', (name,))
|
||||
public.WriteLog("TYPE_DATABASE", 'DATABASE_INPUT_SUCCESS', (name,),not_web = self.not_web)
|
||||
return public.returnMsg(True, 'DATABASE_INPUT_SUCCESS')
|
||||
|
||||
# 配置
|
||||
@@ -479,7 +482,6 @@ class bt_task:
|
||||
from collections import namedtuple
|
||||
get = namedtuple('get',['path'])
|
||||
get.path = filename
|
||||
public.writeFile('/tmp/2',str(get.path))
|
||||
files.files().fix_permissions(get)
|
||||
|
||||
# 检查敏感目录
|
||||
|
||||
@@ -164,7 +164,8 @@ class panel_restore:
|
||||
result = self._restore_backup(self._local_file, site_info, args)
|
||||
else:
|
||||
return public.ExecShell(False,'Currently only supports restoring local, Google storage and AWS S3 backups')
|
||||
os.remove(self._local_file)
|
||||
if os.path.exists(self._local_file):
|
||||
os.remove(self._local_file)
|
||||
if result:
|
||||
self._progress_rewrite('Recovery failed: {}'.format(str(site_info['site_path'])))
|
||||
return result
|
||||
|
||||
+101
-15
@@ -32,8 +32,9 @@ def M(table):
|
||||
ps: 默认访问data/default.db
|
||||
"""
|
||||
import db
|
||||
sql = db.Sql()
|
||||
return sql.table(table)
|
||||
with db.Sql() as sql:
|
||||
#sql = db.Sql()
|
||||
return sql.table(table)
|
||||
|
||||
def HttpGet(url,timeout = 6,headers = {}):
|
||||
"""
|
||||
@@ -317,7 +318,7 @@ def GetJson(data):
|
||||
try:
|
||||
return dumps(data,ensure_ascii=False)
|
||||
except:
|
||||
return dumps(returnMsg(False,"Wrong response: %s" % str(data)))
|
||||
return dumps(returnMsg(False,"WRONG_RESPONSE", (str(data))))
|
||||
|
||||
def getJson(data):
|
||||
return GetJson(data)
|
||||
@@ -341,10 +342,10 @@ def ReadFile(filename,mode = 'r'):
|
||||
f_body = fp.read()
|
||||
fp.close()
|
||||
except Exception as ex2:
|
||||
WriteLog('Open File',str(ex2))
|
||||
WriteLog('OPEN_FILE',str(ex2))
|
||||
return False
|
||||
else:
|
||||
WriteLog('Open File',str(ex))
|
||||
WriteLog('OPEN_FILE',str(ex))
|
||||
return False
|
||||
return f_body
|
||||
|
||||
@@ -375,19 +376,20 @@ def WriteFile(filename,s_body,mode='w+'):
|
||||
def writeFile(filename,s_body,mode='w+'):
|
||||
return WriteFile(filename,s_body,mode)
|
||||
|
||||
def WriteLog(type,logMsg,args=()):
|
||||
def WriteLog(type,logMsg,args=(),not_web = False):
|
||||
#写日志
|
||||
#try:
|
||||
import time,db,json
|
||||
username = 'system'
|
||||
uid = 1
|
||||
try:
|
||||
from BTPanel import session
|
||||
if 'username' in session:
|
||||
username = session['username']
|
||||
uid = session['uid']
|
||||
except:
|
||||
pass
|
||||
if not not_web:
|
||||
try:
|
||||
from BTPanel import session
|
||||
if 'username' in session:
|
||||
username = session['username']
|
||||
uid = session['uid']
|
||||
except:
|
||||
pass
|
||||
global _LAN_LOG
|
||||
if not _LAN_LOG:
|
||||
_LAN_LOG = json.loads(ReadFile('BTPanel/static/language/' + GetLanguage() + '/log.json'))
|
||||
@@ -624,8 +626,10 @@ def get_url(timeout = 0.5):
|
||||
mnode1 = []
|
||||
mnode2 = []
|
||||
mnode3 = []
|
||||
new_node_list = {}
|
||||
for node in node_list:
|
||||
node['net'],node['ping'] = get_timeout(node['protocol'] + node['address'] + ':' + node['port'] + '/net_test',1)
|
||||
new_node_list[node['address']] = node['ping']
|
||||
if not node['ping']: continue
|
||||
if node['ping'] < 100: #当响应时间<100ms且可用带宽大于1500KB时
|
||||
if node['net'] > 1500:
|
||||
@@ -645,6 +649,16 @@ def get_url(timeout = 0.5):
|
||||
mnode = sorted(mnode2,key= lambda x:x['ping'],reverse=False)
|
||||
|
||||
if not mnode: return 'http://download.bt.cn'
|
||||
|
||||
new_node_keys = new_node_list.keys()
|
||||
for i in range(len(node_list)):
|
||||
if node_list[i]['address'] in new_node_keys:
|
||||
node_list[i]['ping'] = new_node_list[node_list[i]['address']]
|
||||
else:
|
||||
node_list[i]['ping'] = 500
|
||||
|
||||
new_node_list = sorted(node_list,key=lambda x: x['ping'],reverse=False)
|
||||
writeFile(nodeFile,json.dumps(new_node_list))
|
||||
return mnode[0]['protocol'] + mnode[0]['address'] + ':' + mnode[0]['port']
|
||||
except:
|
||||
return 'http://download.bt.cn'
|
||||
@@ -1356,7 +1370,7 @@ def write_request_log(reques = None):
|
||||
log_file = getDate(format='%Y-%m-%d') + '.json'
|
||||
if not os.path.exists(log_path): os.makedirs(log_path)
|
||||
|
||||
from flask import request
|
||||
from BTPanel import request
|
||||
log_data = []
|
||||
log_data.append(getDate())
|
||||
log_data.append(GetClientIp() + ':' + str(request.environ.get('REMOTE_PORT')))
|
||||
@@ -1364,6 +1378,7 @@ def write_request_log(reques = None):
|
||||
log_data.append(request.full_path)
|
||||
log_data.append(request.headers.get('User-Agent'))
|
||||
WriteFile(log_path + '/' + log_file,json.dumps(log_data) + "\n",'a+')
|
||||
rep_sys_path()
|
||||
except: pass
|
||||
|
||||
# 重载模块
|
||||
@@ -1545,6 +1560,7 @@ def auto_backup_panel():
|
||||
shutil.copytree(panel_paeh + '/data',backup_path + '/data')
|
||||
shutil.copytree(panel_paeh + '/config',backup_path + '/config')
|
||||
shutil.copytree(panel_paeh + '/vhost',backup_path + '/vhost')
|
||||
ExecShell("chmod -R 600 {path};chown -R root.root {path}".format(paht=b_path))
|
||||
time_now = time.time() - (86400 * 15)
|
||||
for f in os.listdir(b_path):
|
||||
try:
|
||||
@@ -1723,7 +1739,7 @@ def import_cdn_plugin():
|
||||
try:
|
||||
import static_cdn_main
|
||||
except:
|
||||
sys.path.insert(0,plugin_path)
|
||||
package_path_append(plugin_path)
|
||||
import static_cdn_main
|
||||
|
||||
|
||||
@@ -1737,6 +1753,8 @@ def get_cdn_hosts():
|
||||
|
||||
def get_cdn_url():
|
||||
try:
|
||||
if os.path.exists('plugin/static_cdn/not_open.pl'):
|
||||
return False
|
||||
from BTPanel import cache
|
||||
cdn_url = cache.get('cdn_url')
|
||||
if cdn_url: return cdn_url
|
||||
@@ -1921,6 +1939,74 @@ def restore_file(file, act=None):
|
||||
file_type = "_def"
|
||||
ExecShell("/usr/bin/cp -p {1} {0}".format(file, file + file_type))
|
||||
|
||||
|
||||
def package_path_append(path):
|
||||
if not path in sys.path:
|
||||
sys.path.insert(0, path)
|
||||
|
||||
|
||||
def rep_sys_path():
|
||||
sys_path = []
|
||||
for p in sys.path:
|
||||
if p in sys_path: continue
|
||||
sys_path.append(p)
|
||||
sys.path = sys_path
|
||||
|
||||
|
||||
def get_ssh_port():
|
||||
'''
|
||||
@name 获取本机SSH端口
|
||||
@author hwliang<2020-08-07>
|
||||
@return int
|
||||
'''
|
||||
s_file = '/etc/ssh/sshd_config'
|
||||
conf = readFile(s_file)
|
||||
if not conf: conf = ''
|
||||
rep = r"#*Port\s+([0-9]+)\s*\n"
|
||||
tmp1 = re.search(rep, conf)
|
||||
ssh_port = 22
|
||||
if tmp1:
|
||||
ssh_port = int(tmp1.groups(0)[0])
|
||||
return ssh_port
|
||||
|
||||
def set_error_num(key,empty = False,expire=3600):
|
||||
'''
|
||||
@name 设置失败次数(每调用一次+1)
|
||||
@author hwliang<2020-08-21>
|
||||
@param key<string> 索引
|
||||
@param empty<bool> 是否清空计数
|
||||
@param expire<int> 计数器生命周期(秒)
|
||||
@return bool
|
||||
'''
|
||||
from BTPanel import cache
|
||||
num = cache.get(key)
|
||||
if not num:
|
||||
num = 0
|
||||
else:
|
||||
if empty:
|
||||
cache.delete(key)
|
||||
return True
|
||||
cache.set(key,num + 1,expire)
|
||||
return True
|
||||
|
||||
def get_error_num(key,limit=False):
|
||||
'''
|
||||
@name 获取失败次数
|
||||
@author hwliang<2020-08-21>
|
||||
@param key<string> 索引
|
||||
@param limit<False or int> 如果为False,则直接返回失败次数,否则与失败次数比较,若大于失败次数返回True,否则返回False
|
||||
@return int or bool
|
||||
'''
|
||||
from BTPanel import cache
|
||||
num = cache.get(key)
|
||||
if not num: num = 0
|
||||
if not limit:
|
||||
return num
|
||||
if limit > num:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
#取通用对象
|
||||
class dict_obj:
|
||||
def __contains__(self, key):
|
||||
|
||||
+861
-142
File diff suppressed because it is too large
Load Diff
+17
-11
@@ -12,19 +12,19 @@ try:
|
||||
except:
|
||||
pass
|
||||
class system:
|
||||
setupPath = None;
|
||||
setupPath = None
|
||||
ssh = None
|
||||
shell = None
|
||||
|
||||
def __init__(self):
|
||||
self.setupPath = public.GetConfigValue('setup_path');
|
||||
self.setupPath = public.GetConfigValue('setup_path')
|
||||
|
||||
def GetConcifInfo(self,get=None):
|
||||
#取环境配置信息
|
||||
if not 'config' in session:
|
||||
session['config'] = public.M('config').where("id=?",('1',)).field('webserver,sites_path,backup_path,status,mysql_root').find();
|
||||
session['config'] = public.M('config').where("id=?",('1',)).field('webserver,sites_path,backup_path,status,mysql_root').find()
|
||||
if not 'email' in session['config']:
|
||||
session['config']['email'] = public.M('users').where("id=?",('1',)).getField('email');
|
||||
session['config']['email'] = public.M('users').where("id=?",('1',)).getField('email')
|
||||
data = {}
|
||||
data = session['config']
|
||||
data['webserver'] = session['config']['webserver']
|
||||
@@ -66,8 +66,8 @@ class system:
|
||||
if rtmp:
|
||||
phpport = rtmp.groups()[0]
|
||||
|
||||
if conf.find('AUTH_START') != -1: pauth = True;
|
||||
if conf.find(self.setupPath + '/stop') == -1: pstatus = True;
|
||||
if conf.find('AUTH_START') != -1: pauth = True
|
||||
if conf.find(self.setupPath + '/stop') == -1: pstatus = True
|
||||
configFile = self.setupPath + '/nginx/conf/enable-php.conf'
|
||||
conf = public.readFile(configFile)
|
||||
rep = "php-cgi-([0-9]+)\.sock"
|
||||
@@ -75,7 +75,7 @@ class system:
|
||||
if rtmp:
|
||||
phpversion = rtmp.groups()[0]
|
||||
except:
|
||||
pass;
|
||||
pass
|
||||
|
||||
elif os.path.exists(self.setupPath+'/apache'):
|
||||
data['webserver'] = 'apache'
|
||||
@@ -93,8 +93,8 @@ class system:
|
||||
rtmp = re.search(rep,conf)
|
||||
if rtmp:
|
||||
phpport = rtmp.groups()[0]
|
||||
if conf.find('AUTH_START') != -1: pauth = True;
|
||||
if conf.find(self.setupPath + '/stop') == -1: pstatus = True;
|
||||
if conf.find('AUTH_START') != -1: pauth = True
|
||||
if conf.find(self.setupPath + '/stop') == -1: pstatus = True
|
||||
except:
|
||||
pass
|
||||
elif os.path.exists('/usr/local/lsws/bin/lswsctrl'):
|
||||
@@ -480,10 +480,16 @@ class system:
|
||||
|
||||
ntime = time.time()
|
||||
networkInfo = {}
|
||||
up = cache.get('up')
|
||||
down = cache.get('down')
|
||||
if not up:
|
||||
up = networkIo[0]
|
||||
if not down:
|
||||
down = networkIo[1]
|
||||
networkInfo['upTotal'] = networkIo[0]
|
||||
networkInfo['downTotal'] = networkIo[1]
|
||||
networkInfo['up'] = round(float(networkIo[0] - cache.get("up")) / 1024 / (ntime - otime),2)
|
||||
networkInfo['down'] = round(float(networkIo[1] - cache.get("down")) / 1024 / (ntime - otime),2)
|
||||
networkInfo['up'] = round(float(networkIo[0] - up) / 1024 / (ntime - otime),2)
|
||||
networkInfo['down'] = round(float(networkIo[1] - down) / 1024 / (ntime - otime),2)
|
||||
networkInfo['downPackets'] =networkIo[3]
|
||||
networkInfo['upPackets'] =networkIo[2]
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
["45.32.116.160", "103.224.251.67", "119.188.210.21", "183.60.107.171", "125.88.182.172"]
|
||||
[ "119.147.144.34", "103.224.251.67","45.76.53.20","120.206.184.160","[2001:19f0:7001:54fc:5400:2ff:fe9b:97f9]", "45.32.116.160", "[240e:ff:9000:1100:0:3:0:34]" ]
|
||||
+12
-4
@@ -48,32 +48,40 @@
|
||||
"id": "memuAfiles",
|
||||
"sort": 7
|
||||
},
|
||||
{
|
||||
"title": "Terminal",
|
||||
"href": "/xterm",
|
||||
"class": "menu_xterm",
|
||||
"id": "memuAxterm",
|
||||
"sort": 8
|
||||
},
|
||||
{
|
||||
"title": "Cron",
|
||||
"href": "/crontab",
|
||||
"class": "menu_day",
|
||||
"id": "memuAcrontab",
|
||||
"sort": 8
|
||||
"sort": 9
|
||||
},
|
||||
|
||||
{
|
||||
"title": "App Store",
|
||||
"href": "/soft",
|
||||
"class": "menu_soft",
|
||||
"id": "memuAsoft",
|
||||
"sort": 9
|
||||
"sort": 10
|
||||
},
|
||||
{
|
||||
"title": "Settings",
|
||||
"href": "/config",
|
||||
"class": "menu_set",
|
||||
"id": "memuAconfig",
|
||||
"sort": 10
|
||||
"sort": 11
|
||||
},
|
||||
{
|
||||
"title": "Log out",
|
||||
"href": "/login?dologin=True",
|
||||
"class": "menu_exit",
|
||||
"id": "dologin",
|
||||
"sort": 11
|
||||
"sort": 12
|
||||
}
|
||||
]
|
||||
Binary file not shown.
@@ -29,12 +29,6 @@
|
||||
"port": "80",
|
||||
"ping": 500
|
||||
},
|
||||
{
|
||||
"protocol": "http://",
|
||||
"address": "125.88.182.172",
|
||||
"port": "5880",
|
||||
"ping": 500
|
||||
},
|
||||
{
|
||||
"protocol": "http://",
|
||||
"address": "123.129.198.197",
|
||||
|
||||
@@ -304,6 +304,7 @@ case "$1" in
|
||||
$pythonV $panel_path/tools.py cli $2
|
||||
;;
|
||||
'default')
|
||||
LOCAL_IP=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
|
||||
port=$(cat $panel_path/data/port.pl)
|
||||
password=$(cat $panel_path/default.pl)
|
||||
if [ -f $panel_path/data/domain.conf ];then
|
||||
@@ -322,7 +323,8 @@ case "$1" in
|
||||
echo -e "=================================================================="
|
||||
echo -e "\033[32maaPanel default info!\033[0m"
|
||||
echo -e "=================================================================="
|
||||
echo "Bt-Panel-URL: $pool://$address:$port$auth_path"
|
||||
echo "aaPanel Internet Address: $pool://$address:$port$auth_path"
|
||||
echo "aaPanel Internal Address: $pool://${LOCAL_IP}:$port$auth_path"
|
||||
echo -e `$pythonV $panel_path/tools.py username`
|
||||
echo -e "password: $password"
|
||||
echo -e "\033[33mWarning:\033[0m"
|
||||
|
||||
+43
-15
@@ -21,31 +21,55 @@ if os.path.exists('/www/server/nginx/logs/nginx.pid'): is_nginx = True
|
||||
px = '.log'
|
||||
if not is_nginx: px = '-access_log'
|
||||
|
||||
def split_logs(oldFileName,num):
|
||||
global logsPath
|
||||
if not os.path.exists(oldFileName):
|
||||
print('|---'+oldFileName+'file does not exist!')
|
||||
return
|
||||
def build_errlog(sitename):
|
||||
if is_nginx:
|
||||
log = sitename + '.error.log'
|
||||
elif os.path.exists('/usr/local/lsws/bin/lswsctrl'):
|
||||
log = sitename + '_ols.error_log'
|
||||
else:
|
||||
log = sitename + '-error_log'
|
||||
return log
|
||||
|
||||
logs=sorted(glob.glob(oldFileName+"_*"))
|
||||
def clean_backlog(logname,num):
|
||||
logs=sorted(glob.glob(logname+"_*"))
|
||||
count=len(logs)
|
||||
num=count - num
|
||||
|
||||
for i in range(count):
|
||||
if i>num: break;
|
||||
os.remove(logs[i])
|
||||
print('|---Extra log ['+logs[i]+'] has been deleted!')
|
||||
print('|---The extra log ['+logs[i]+'] has been deleted!')
|
||||
|
||||
def split_logs(oldFileName,num,site_name):
|
||||
global logsPath
|
||||
errlog_name = build_errlog(site_name)
|
||||
old_errlog = logsPath + errlog_name
|
||||
|
||||
if not os.path.exists(oldFileName):
|
||||
print('|---'+oldFileName+'file does not exist!')
|
||||
return
|
||||
|
||||
clean_backlog(oldFileName,num)
|
||||
clean_backlog(old_errlog,num)
|
||||
|
||||
newFileName=oldFileName+'_'+time.strftime("%Y-%m-%d_%H%M%S")+'.log'
|
||||
shutil.move(oldFileName,newFileName)
|
||||
os.system("gzip %s" % newFileName)
|
||||
print('|---The log has been cut to: '+newFileName+'.gz')
|
||||
new_errlog = old_errlog+'_'+time.strftime("%Y-%m-%d_%H%M%S")+'.log'
|
||||
shutil.move(old_errlog, new_errlog)
|
||||
if not os.path.exists('/www/server/panel/data/log_not_gzip.pl'):
|
||||
os.system("gzip %s" % newFileName)
|
||||
os.system("gzip %s" % new_errlog)
|
||||
print('|---The log has been cut to:' + newFileName + '.gz')
|
||||
print('|---The log has been cut to:' + new_errlog + '.gz')
|
||||
else:
|
||||
print('|---The log has been cut to:'+newFileName+'.log')
|
||||
print('|---The log has been cut to:' + new_errlog + '.log')
|
||||
|
||||
def split_all(save):
|
||||
sites = public.M('sites').field('name').select()
|
||||
for site in sites:
|
||||
oldFileName = logsPath + site['name'] + px
|
||||
split_logs(oldFileName,save)
|
||||
split_logs(oldFileName,save,site['name'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
num = int(sys.argv[2])
|
||||
@@ -53,14 +77,18 @@ if __name__ == '__main__':
|
||||
split_all(num)
|
||||
else:
|
||||
siteName = sys.argv[1]
|
||||
if siteName[-4:] == '.log':
|
||||
if siteName[-4:] == '.log':
|
||||
siteName = siteName[:-4]
|
||||
else:
|
||||
elif siteName[-11:] == '-access_log':
|
||||
siteName = siteName.replace("-access_log",'')
|
||||
else:
|
||||
siteName = siteName.replace("_ols.access_log", '')
|
||||
oldFileName = logsPath+sys.argv[1]
|
||||
split_logs(oldFileName,num)
|
||||
split_logs(oldFileName,num,siteName)
|
||||
|
||||
if is_nginx:
|
||||
os.system("kill -USR1 `cat /www/server/nginx/logs/nginx.pid`");
|
||||
os.system("kill -USR1 `cat /www/server/nginx/logs/nginx.pid`")
|
||||
elif os.path.exists('/usr/local/lsws/bin/lswsctl'):
|
||||
os.system('/usr/local/lsws/bin/lswsctl restart')
|
||||
else:
|
||||
os.system('/etc/init.d/httpd reload');
|
||||
os.system('/etc/init.d/httpd reload')
|
||||
+39
-14
@@ -21,13 +21,17 @@ if os.path.exists('/www/server/nginx/logs/nginx.pid'): is_nginx = True
|
||||
px = '.log'
|
||||
if not is_nginx: px = '-access_log'
|
||||
|
||||
def split_logs(oldFileName,num):
|
||||
global logsPath
|
||||
if not os.path.exists(oldFileName):
|
||||
print('|---'+oldFileName+'file does not exist!')
|
||||
return
|
||||
def build_errlog(sitename):
|
||||
if is_nginx:
|
||||
log = sitename + '.error.log'
|
||||
elif os.path.exists('/usr/local/lsws/bin/lswsctl'):
|
||||
log = sitename + '-error_log'
|
||||
else:
|
||||
log = sitename + '_ols.error_log'
|
||||
return log
|
||||
|
||||
logs=sorted(glob.glob(oldFileName+"_*"))
|
||||
def clean_backlog(logname,num):
|
||||
logs=sorted(glob.glob(logname+"_*"))
|
||||
count=len(logs)
|
||||
num=count - num
|
||||
|
||||
@@ -36,16 +40,33 @@ def split_logs(oldFileName,num):
|
||||
os.remove(logs[i])
|
||||
print('|---The extra log ['+logs[i]+'] has been deleted!')
|
||||
|
||||
def split_logs(oldFileName,num,site_name):
|
||||
global logsPath
|
||||
errlog_name = build_errlog(site_name)
|
||||
old_errlog = logsPath + errlog_name
|
||||
if not os.path.exists(oldFileName):
|
||||
print('|---'+oldFileName+'file does not exist!')
|
||||
return
|
||||
|
||||
clean_backlog(oldFileName,num)
|
||||
clean_backlog(old_errlog,num)
|
||||
|
||||
newFileName=oldFileName+'_'+time.strftime("%Y-%m-%d_%H%M%S")+'.log'
|
||||
shutil.move(oldFileName,newFileName)
|
||||
os.system("gzip %s" % newFileName)
|
||||
print('|---The log has been cut to:'+newFileName+'.gz')
|
||||
new_errlog = build_errlog(site_name)+'_'+time.strftime("%Y-%m-%d_%H%M%S")+'.log'
|
||||
shutil.move(old_errlog, newFileName)
|
||||
if not os.path.exists('/www/server/panel/data/log_not_gzip.pl'):
|
||||
os.system("gzip %s" % newFileName)
|
||||
os.system("gzip %s" % new_errlog)
|
||||
print('|---The log has been cut to:' + newFileName + '.gz')
|
||||
else:
|
||||
print('|---The log has been cut to:'+newFileName+'.log')
|
||||
|
||||
def split_all(save):
|
||||
sites = public.M('sites').field('name').select()
|
||||
for site in sites:
|
||||
oldFileName = logsPath + site['name'] + px
|
||||
split_logs(oldFileName,save)
|
||||
split_logs(oldFileName,save,site['name'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
num = int(sys.argv[2])
|
||||
@@ -53,14 +74,18 @@ if __name__ == '__main__':
|
||||
split_all(num)
|
||||
else:
|
||||
siteName = sys.argv[1]
|
||||
if siteName[-4:] == '.log':
|
||||
if siteName[-4:] == '.log':
|
||||
siteName = siteName[:-4]
|
||||
else:
|
||||
elif siteName[-11:] == '-access_log':
|
||||
siteName = siteName.replace("-access_log",'')
|
||||
else:
|
||||
siteName = siteName.replace("_ols.access_log", '')
|
||||
oldFileName = logsPath+sys.argv[1]
|
||||
split_logs(oldFileName,num)
|
||||
split_logs(oldFileName,num,siteName)
|
||||
|
||||
if is_nginx:
|
||||
os.system("kill -USR1 `cat /www/server/nginx/logs/nginx.pid`");
|
||||
os.system("kill -USR1 `cat /www/server/nginx/logs/nginx.pid`")
|
||||
elif os.path.exists('/usr/local/lsws/bin/lswsctl'):
|
||||
os.system('/usr/local/lsws/bin/lswsctl restart')
|
||||
else:
|
||||
os.system('/etc/init.d/httpd reload');
|
||||
os.system('/etc/init.d/httpd reload')
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
from json import dumps,loads
|
||||
from psutil import Process,pids,cpu_count,cpu_percent,net_io_counters,disk_io_counters,virtual_memory
|
||||
sys.path.insert(0,"/www/server/panel/class/")
|
||||
@@ -21,7 +22,6 @@ import db
|
||||
import public
|
||||
import time
|
||||
import panelTask
|
||||
import setPanelLets
|
||||
global pre,timeoutCount,logPath,isTask,oldEdate,isCheck
|
||||
pre = 0
|
||||
timeoutCount = 0
|
||||
@@ -30,29 +30,23 @@ oldEdate = None
|
||||
logPath = '/tmp/panelExec.log'
|
||||
isTask = '/tmp/panelTask.pl'
|
||||
|
||||
class MyBad():
|
||||
_msg = None
|
||||
def __init__(self,msg):
|
||||
self._msg = msg
|
||||
def __repr__(self):
|
||||
return self._msg
|
||||
|
||||
def get_python_bin():
|
||||
bin_file = '/www/server/panel/pyenv/bin/python'
|
||||
if os.path.exists(bin_file):
|
||||
return bin_file
|
||||
return '/usr/bin/python'
|
||||
|
||||
def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
try:
|
||||
global logPath
|
||||
import shlex
|
||||
import datetime
|
||||
import subprocess
|
||||
import time
|
||||
sub = subprocess.Popen(cmdstring+' &> '+logPath, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096)
|
||||
|
||||
while sub.poll() is None:
|
||||
time.sleep(0.1)
|
||||
|
||||
return sub.returncode
|
||||
except:
|
||||
return None
|
||||
def ReadFile(filename,mode = 'r'):
|
||||
"""
|
||||
读取文件内容
|
||||
@filename 文件名
|
||||
return string(bin) 若文件不存在,则返回None
|
||||
"""
|
||||
if not os.path.exists(filename): return False
|
||||
f_body = None
|
||||
with open(filename, mode) as fp:
|
||||
f_body = fp.read()
|
||||
return f_body
|
||||
|
||||
#下载文件
|
||||
def DownloadFile(url,filename):
|
||||
@@ -60,7 +54,7 @@ def DownloadFile(url,filename):
|
||||
import urllib,socket
|
||||
socket.setdefaulttimeout(10)
|
||||
urllib.urlretrieve(url,filename=filename ,reporthook= DownloadHook)
|
||||
public.ExecShell('chown www.www ' + filename)
|
||||
os.system('chown www.www ' + filename)
|
||||
WriteLogs('done')
|
||||
except:
|
||||
WriteLogs('done')
|
||||
@@ -82,41 +76,62 @@ def DownloadHook(count, blockSize, totalSize):
|
||||
def WriteLogs(logMsg):
|
||||
try:
|
||||
global logPath
|
||||
fp = open(logPath,'w+')
|
||||
fp.write(logMsg)
|
||||
fp.close()
|
||||
with open(logPath,'w+') as fp:
|
||||
fp.write(logMsg)
|
||||
fp.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
#任务队列
|
||||
|
||||
def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
try:
|
||||
global logPath
|
||||
import shlex
|
||||
import datetime
|
||||
import subprocess
|
||||
import time
|
||||
sub = subprocess.Popen(cmdstring+' &> '+logPath, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096)
|
||||
|
||||
while sub.poll() is None:
|
||||
time.sleep(0.1)
|
||||
|
||||
return sub.returncode
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
#任务队列
|
||||
def startTask():
|
||||
global isTask
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
if os.path.exists(isTask):
|
||||
sql = db.Sql()
|
||||
sql.table('tasks').where("status=?",('-1',)).setField('status','0')
|
||||
taskArr = sql.table('tasks').where("status=?",('0',)).field('id,type,execstr').order("id asc").select()
|
||||
for value in taskArr:
|
||||
start = int(time.time())
|
||||
if not sql.table('tasks').where("id=?",(value['id'],)).count(): continue
|
||||
sql.table('tasks').where("id=?",(value['id'],)).save('status,start',('-1',start))
|
||||
if value['type'] == 'download':
|
||||
argv = value['execstr'].split('|bt|')
|
||||
DownloadFile(argv[0],argv[1])
|
||||
elif value['type'] == 'execshell':
|
||||
ExecShell(value['execstr'])
|
||||
end = int(time.time())
|
||||
sql.table('tasks').where("id=?",(value['id'],)).save('status,end',('1',end))
|
||||
if(sql.table('tasks').where("status=?",('0')).count() < 1):
|
||||
if os.path.exists(isTask): os.remove(isTask)
|
||||
#ExecShell('rm -f ' + isTask)
|
||||
with db.Sql() as sql:
|
||||
sql.table('tasks').where("status=?",('-1',)).setField('status','0')
|
||||
taskArr = sql.table('tasks').where("status=?",('0',)).field('id,type,execstr').order("id asc").select()
|
||||
for value in taskArr:
|
||||
start = int(time.time())
|
||||
if not sql.table('tasks').where("id=?",(value['id'],)).count(): continue
|
||||
sql.table('tasks').where("id=?",(value['id'],)).save('status,start',('-1',start))
|
||||
if value['type'] == 'download':
|
||||
argv = value['execstr'].split('|bt|')
|
||||
DownloadFile(argv[0],argv[1])
|
||||
elif value['type'] == 'execshell':
|
||||
ExecShell(value['execstr'])
|
||||
end = int(time.time())
|
||||
sql.table('tasks').where("id=?",(value['id'],)).save('status,end',('1',end))
|
||||
if(sql.table('tasks').where("status=?",('0')).count() < 1):
|
||||
if os.path.exists(isTask): os.remove(isTask)
|
||||
#ExecShell('rm -f ' + isTask)
|
||||
sql.close()
|
||||
taskArr = None
|
||||
except:
|
||||
pass
|
||||
siteEdate()
|
||||
time.sleep(2)
|
||||
except:
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
time.sleep(60)
|
||||
startTask()
|
||||
|
||||
@@ -124,22 +139,14 @@ def startTask():
|
||||
def siteEdate():
|
||||
global oldEdate
|
||||
try:
|
||||
if not oldEdate: oldEdate = public.readFile('data/edate.pl')
|
||||
if not oldEdate: oldEdate = ReadFile('data/edate.pl')
|
||||
if not oldEdate: oldEdate = '0000-00-00'
|
||||
mEdate = time.strftime('%Y-%m-%d',time.localtime())
|
||||
if oldEdate == mEdate: return False
|
||||
edateSites = public.M('sites').where('edate>? AND edate<? AND (status=? OR status=?)',('0000-00-00',mEdate,1,u'running')).field('id,name').select()
|
||||
import panelSite
|
||||
siteObject = panelSite.panelSite()
|
||||
for site in edateSites:
|
||||
get = MyBad('')
|
||||
get.id = site['id']
|
||||
get.name = site['name']
|
||||
siteObject.SiteStop(get)
|
||||
oldEdate = mEdate
|
||||
public.writeFile('data/edate.pl',mEdate)
|
||||
except:
|
||||
pass
|
||||
os.system(get_python_bin() + " /www/server/panel/script/site_task.py > /dev/null")
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
pass
|
||||
|
||||
def GetLoadAverage():
|
||||
c = os.getloadavg()
|
||||
@@ -157,8 +164,9 @@ def GetLoadAverage():
|
||||
def systemTask():
|
||||
try:
|
||||
filename = 'data/control.conf'
|
||||
sql = db.Sql().dbfile('system')
|
||||
csql = '''CREATE TABLE IF NOT EXISTS `load_average` (
|
||||
with db.Sql() as sql:
|
||||
sql = sql.dbfile('system')
|
||||
csql = '''CREATE TABLE IF NOT EXISTS `load_average` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`pro` REAL,
|
||||
`one` REAL,
|
||||
@@ -166,7 +174,9 @@ def systemTask():
|
||||
`fifteen` REAL,
|
||||
`addtime` INTEGER
|
||||
)'''
|
||||
sql.execute(csql,())
|
||||
sql.execute(csql,())
|
||||
sql.close()
|
||||
|
||||
count = 0
|
||||
reloadNum=0
|
||||
network_up = network_down = diskio_1 = diskio_2 = networkInfo = cpuInfo = diskInfo = None
|
||||
@@ -177,7 +187,7 @@ def systemTask():
|
||||
|
||||
day = 30
|
||||
try:
|
||||
day = int(public.readFile(filename))
|
||||
day = int(ReadFile(filename))
|
||||
if day < 1:
|
||||
time.sleep(10)
|
||||
continue
|
||||
@@ -243,14 +253,15 @@ def systemTask():
|
||||
diskInfo['write_time'] += tmp['write_time']
|
||||
|
||||
diskio_1 = diskio_2
|
||||
except:disk_ios = False
|
||||
except:
|
||||
logging.info(public.get_error_info())
|
||||
disk_ios = False
|
||||
|
||||
|
||||
#print diskInfo
|
||||
|
||||
if count >= 12:
|
||||
try:
|
||||
sql.close()
|
||||
sql = db.Sql().dbfile('system')
|
||||
addtime = int(time.time())
|
||||
deltime = addtime - (day * 86400)
|
||||
@@ -272,23 +283,26 @@ def systemTask():
|
||||
lpro = round((load_average['one'] / load_average['max']) * 100,2)
|
||||
if lpro > 100: lpro = 100
|
||||
sql.table('load_average').add('pro,one,five,fifteen,addtime',(lpro,load_average['one'],load_average['five'],load_average['fifteen'],addtime))
|
||||
|
||||
sql.close()
|
||||
|
||||
lpro = None
|
||||
load_average = None
|
||||
cpuInfo = None
|
||||
networkInfo = None
|
||||
diskInfo = None
|
||||
data = None
|
||||
count = 0
|
||||
reloadNum += 1
|
||||
if reloadNum > 1440:
|
||||
reloadNum = 0
|
||||
except Exception as ex:
|
||||
print(str(ex))
|
||||
logging.debug(str(ex))
|
||||
del(tmp)
|
||||
|
||||
time.sleep(5)
|
||||
count +=1
|
||||
except:
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
time.sleep(30)
|
||||
systemTask()
|
||||
|
||||
@@ -307,15 +321,15 @@ def GetMemUsed():
|
||||
#检查502错误
|
||||
def check502():
|
||||
try:
|
||||
phpversions = ['53','54','55','56','70','71','72','73','74']
|
||||
phpversions = ['53','54','55','56','70','71','72','73','74','80']
|
||||
for version in phpversions:
|
||||
php_path = '/www/server/php/' + version + '/sbin/php-fpm'
|
||||
if not os.path.exists(php_path): continue
|
||||
if checkPHPVersion(version): continue
|
||||
if startPHPVersion(version):
|
||||
public.WriteLog('PHP守护程序','检测到PHP-' + version + '处理异常,已自动修复!')
|
||||
except:
|
||||
pass
|
||||
public.WriteLog('PHP daemon','PHP-' + version + 'processing exception was detected and has been automatically fixed!',not_web = True)
|
||||
except Exception as ex:
|
||||
logging.info(ex)
|
||||
|
||||
#处理指定PHP版本
|
||||
def startPHPVersion(version):
|
||||
@@ -327,105 +341,44 @@ def startPHPVersion(version):
|
||||
return False
|
||||
|
||||
#尝试重载服务
|
||||
public.ExecShell(fpm + ' reload')
|
||||
os.system(fpm + ' reload')
|
||||
if checkPHPVersion(version): return True
|
||||
|
||||
#尝试重启服务
|
||||
cgi = '/tmp/php-cgi-'+version + '.sock'
|
||||
pid = '/www/server/php/'+version+'/var/run/php-fpm.pid'
|
||||
public.ExecShell('pkill -9 php-fpm-'+version)
|
||||
os.system('pkill -9 php-fpm-'+version)
|
||||
time.sleep(0.5)
|
||||
if not os.path.exists(cgi): public.ExecShell('rm -f ' + cgi)
|
||||
if not os.path.exists(pid): public.ExecShell('rm -f ' + pid)
|
||||
public.ExecShell(fpm + ' start')
|
||||
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:
|
||||
except Exception as ex:
|
||||
logging.debug(ex)
|
||||
return True
|
||||
|
||||
|
||||
#检查指定PHP版本
|
||||
def checkPHPVersion(version):
|
||||
try:
|
||||
url = 'http://127.0.0.1/phpfpm_'+version+'_status'
|
||||
result = HttpGet(url)
|
||||
#检查nginx
|
||||
if result.find('Bad Gateway') != -1: return False
|
||||
#检查Apache
|
||||
if result.find('Service Unavailable') != -1: return False
|
||||
if result.find('Not Found') != -1: CheckPHPINFO()
|
||||
|
||||
#检查Web服务是否启动
|
||||
if result.find('Connection refused') != -1:
|
||||
global isTask
|
||||
if os.path.exists(isTask):
|
||||
isStatus = public.readFile(isTask)
|
||||
if isStatus == 'True': return True
|
||||
filename = '/etc/init.d/nginx'
|
||||
if os.path.exists(filename): public.ExecShell(filename + ' start')
|
||||
filename = '/etc/init.d/httpd'
|
||||
if os.path.exists(filename): public.ExecShell(filename + ' start')
|
||||
|
||||
uri = "/phpfpm_"+version+"_status?json"
|
||||
result = public.request_php(version,uri,'')
|
||||
loads(result)
|
||||
return True
|
||||
except:
|
||||
return True
|
||||
logging.info("PHP-{} unreachable detected".format(version))
|
||||
return False
|
||||
|
||||
|
||||
#检测PHPINFO配置
|
||||
def CheckPHPINFO():
|
||||
php_versions = ['53','54','55','56','70','71','72','73','74']
|
||||
setupPath = '/www/server'
|
||||
path = setupPath +'/panel/vhost/nginx/phpinfo.conf'
|
||||
if not os.path.exists(path):
|
||||
opt = ""
|
||||
for version in php_versions:
|
||||
opt += "\n\tlocation /"+version+" {\n\t\tinclude enable-php-"+version+".conf;\n\t}"
|
||||
|
||||
phpinfoBody = '''server
|
||||
{
|
||||
listen 80;
|
||||
server_name 127.0.0.2;
|
||||
allow 127.0.0.1;
|
||||
index phpinfo.php index.html index.php;
|
||||
root /www/server/phpinfo;
|
||||
%s
|
||||
}''' % (opt,)
|
||||
public.writeFile(path,phpinfoBody)
|
||||
|
||||
|
||||
path = setupPath + '/panel/vhost/apache/phpinfo.conf'
|
||||
if not os.path.exists(path):
|
||||
opt = ""
|
||||
for version in php_versions:
|
||||
opt += """\n<Location /%s>
|
||||
SetHandler "proxy:unix:/tmp/php-cgi-%s.sock|fcgi://localhost"
|
||||
</Location>""" % (version,version)
|
||||
|
||||
phpinfoBody = '''
|
||||
<VirtualHost *:80>
|
||||
DocumentRoot "/www/server/phpinfo"
|
||||
ServerAdmin phpinfo
|
||||
ServerName 127.0.0.2
|
||||
%s
|
||||
<Directory "/www/server/phpinfo">
|
||||
SetOutputFilter DEFLATE
|
||||
Options FollowSymLinks
|
||||
AllowOverride All
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
DirectoryIndex index.php index.html index.htm default.php default.html default.htm
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
''' % (opt,)
|
||||
public.writeFile(path,phpinfoBody)
|
||||
|
||||
#502错误检查线程
|
||||
def check502Task():
|
||||
try:
|
||||
while True:
|
||||
if os.path.exists('/www/server/panel/data/502Task.pl'): check502()
|
||||
sess_expire()
|
||||
time.sleep(600)
|
||||
except:
|
||||
time.sleep(600)
|
||||
@@ -456,7 +409,7 @@ def panel_status():
|
||||
pool = 'http://'
|
||||
if os.path.exists(panel_path + '/data/ssl.pl'): pool = 'https://'
|
||||
port = '8888'
|
||||
if os.path.exists(panel_path + '/data/port.pl'): port = public.readFile(panel_path + '/data/port.pl').strip()
|
||||
if os.path.exists(panel_path + '/data/port.pl'): port = ReadFile(panel_path + '/data/port.pl').strip()
|
||||
panel_url = pool + '127.0.0.1:' + port + '/service_status'
|
||||
panel_pid = get_panel_pid()
|
||||
n = 0
|
||||
@@ -464,7 +417,6 @@ def panel_status():
|
||||
v = 0
|
||||
while True:
|
||||
time.sleep(5)
|
||||
check_session()
|
||||
if not panel_pid: panel_pid = get_panel_pid()
|
||||
if not panel_pid: service_panel('start')
|
||||
|
||||
@@ -496,11 +448,11 @@ def panel_status():
|
||||
if e_body.find('table session') != -1:
|
||||
sess_file = '/dev/shm/session.db'
|
||||
if os.path.exists(sess_file): os.remove(sess_file)
|
||||
public.ExecShell("bash /www/server/panel/init.sh reload &")
|
||||
os.system("bash /www/server/panel/init.sh reload &")
|
||||
time.sleep(10)
|
||||
result = HttpGet(panel_url)
|
||||
if result == 'True':
|
||||
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!')
|
||||
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!',not_web = True)
|
||||
|
||||
if n > 18000:
|
||||
n = 0
|
||||
@@ -511,7 +463,7 @@ def panel_status():
|
||||
update_panel()
|
||||
result = HttpGet(panel_url)
|
||||
if result == 'True':
|
||||
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!')
|
||||
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!',not_web = True)
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
@@ -523,29 +475,7 @@ def service_panel(action = 'reload'):
|
||||
if not os.path.exists('/www/server/panel/init.sh'):
|
||||
update_panel()
|
||||
else:
|
||||
public.ExecShell("bash /www/server/panel/init.sh {} &".format(action))
|
||||
|
||||
|
||||
def check_session():
|
||||
try:
|
||||
session_file = '/dev/shm/session.db'
|
||||
if not os.path.exists(session_file): #如果session文件不存在
|
||||
return False
|
||||
s_size = os.path.getsize(session_file)
|
||||
if s_size < 1024 * 1024 * 2: return False
|
||||
if s_size > 1024 * 1024 * 10:
|
||||
#大于10MB
|
||||
if os.path.exists(session_file): os.remove(session_file)
|
||||
public.ExecShell("bash /www/server/panel/init.sh reload &")
|
||||
else:
|
||||
sql = db.Sql()
|
||||
sql._Sql__DB_FILE = session_file
|
||||
sql.table('session').where('expiry<?',(public.format_date())).delete()
|
||||
sql.table('session').execute('VACUUM',())
|
||||
sql.close()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
os.system("bash /www/server/panel/init.sh {} &".format(action))
|
||||
|
||||
#重启面板服务
|
||||
def restart_panel_service():
|
||||
@@ -562,6 +492,8 @@ def restart_panel_service():
|
||||
|
||||
#取面板pid
|
||||
def get_panel_pid():
|
||||
pid = ReadFile('/www/server/panel/logs/panel.pid')
|
||||
if pid: return int(pid)
|
||||
for pid in pids():
|
||||
try:
|
||||
p = Process(pid)
|
||||
@@ -574,33 +506,42 @@ def get_panel_pid():
|
||||
def HttpGet(url,timeout = 6,headers = {}):
|
||||
if sys.version_info[0] == 2:
|
||||
try:
|
||||
import urllib2,ssl
|
||||
if sys.version_info[0] == 2:
|
||||
reload(urllib2)
|
||||
reload(ssl)
|
||||
try:
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
except:pass
|
||||
import urllib2
|
||||
req = urllib2.Request(url, headers = headers)
|
||||
response = urllib2.urlopen(req,timeout = timeout,)
|
||||
return response.read()
|
||||
except Exception as ex:
|
||||
logging.debug(str(ex))
|
||||
return str(ex)
|
||||
else:
|
||||
try:
|
||||
import urllib.request,ssl
|
||||
try:
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
except:pass
|
||||
import urllib.request
|
||||
req = urllib.request.Request(url,headers = headers)
|
||||
response = urllib.request.urlopen(req,timeout = timeout)
|
||||
result = response.read()
|
||||
if type(result) == bytes: result = result.decode('utf-8')
|
||||
return result
|
||||
except Exception as ex:
|
||||
logging.debug("URL: {} => {}".format(url,ex))
|
||||
return str(ex)
|
||||
|
||||
|
||||
#定时任务去检测邮件信息
|
||||
def send_mail_time():
|
||||
p_path = '/www/server/panel/data/'
|
||||
p_reload = p_path + '/send_to_user.pl'
|
||||
if not os.path.exists(p_path):
|
||||
return
|
||||
while True:
|
||||
try:
|
||||
if os.path.exists(p_reload):
|
||||
os.system(get_python_bin() + " /www/server/panel/script/mail_task.py > /dev/null")
|
||||
os.remove(p_reload)
|
||||
time.sleep(60)
|
||||
except:
|
||||
time.sleep(180)
|
||||
send_mail_time()
|
||||
|
||||
def main():
|
||||
main_pid = 'logs/task.pid'
|
||||
if os.path.exists(main_pid):
|
||||
@@ -619,13 +560,9 @@ def main():
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
task_log_file='logs/task.log'
|
||||
if not os.path.exists(task_log_file):
|
||||
open(task_log_file,'w+').close()
|
||||
|
||||
err_f = open(task_log_file,'a+')
|
||||
os.dup2(err_f.fileno(),sys.stderr.fileno())
|
||||
err_f.close()
|
||||
public.ExecShell('rm -rf /www/server/phpinfo/*')
|
||||
logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s [%(levelname)s] at %(lineno)d: %(message)s',datefmt = '%Y-%m-%d(%a)%H:%M:%S',filename = task_log_file,filemode = 'a+')
|
||||
logging.info('Service started')
|
||||
|
||||
import threading
|
||||
t = threading.Thread(target=systemTask)
|
||||
@@ -648,7 +585,12 @@ def main():
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
|
||||
p = threading.Thread(target=send_mail_time)
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
|
||||
task_obj = panelTask.bt_task()
|
||||
task_obj.not_web = True
|
||||
p = threading.Thread(target=task_obj.start_task)
|
||||
p.setDaemon(True)
|
||||
p.start()
|
||||
|
||||
Reference in New Issue
Block a user