diff --git a/README.md b/README.md index 216375f9d..27a6c7c0b 100644 --- a/README.md +++ b/README.md @@ -100,17 +100,15 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443: ``` -### 版本更新 0.15.1 +### 版本更新 0.15.2 -* 升级功能优化。 -* 域名伪静态保存优化。 -* 自动同步gitee。 -* nezha保存优化。 -* OP防火墙优化(站点配置-状态关闭后,不再防御)-已安装的,需要重载。 -* 修复子目录绑定-伪静态问题。 -* [插件]docker - 添加IP地址池。 -* PHP下载中国优化。 -* 监控页面-自定义时间优化。 +* OpenResty升级到1.21.4.2 +* 计划任务自动脚本运行时间 +* rsyncd添加优化 +* 使用mariadb二进制导入备份文件 +* docker插件-镜像导入导出功能 +* 网站设置反向代理升级功能 +* 优化初始化安装SSH端口识别 ### JSDelivr安装地址 diff --git a/class/core/common.py b/class/core/common.py index d44336015..28f624fc6 100755 --- a/class/core/common.py +++ b/class/core/common.py @@ -33,6 +33,7 @@ from flask import redirect def init(): initDB() + initDBSshPort() initUserInfo() initInitD() initInitTask() @@ -62,6 +63,17 @@ def initDB(): print(str(ex)) +def initDBSshPort(): + # SSH端口必须放开 + import firewall_api + cmd_data = mw.execShell( + "cat /etc/ssh/sshd_config | grep '^Port \d*' | tail -1") + ssh_port = cmd_data[0].replace("Port ", '').strip() + if ssh_port == '': + ssh_port = '22' + firewall_api.firewall_api().addAcceptPortArgs(ssh_port, 'SSH远程管理服务', 'port') + + def doContentReplace(src, dst): content = mw.readFile(src) content = content.replace("{$SERVER_PATH}", mw.getRunDir()) diff --git a/class/core/config_api.py b/class/core/config_api.py index 751a7df54..ea50233dd 100755 --- a/class/core/config_api.py +++ b/class/core/config_api.py @@ -27,7 +27,7 @@ from flask import request class config_api: - __version = '0.15.1' + __version = '0.15.2' __api_addr = 'data/api.json' def __init__(self): diff --git a/class/core/crontab_api.py b/class/core/crontab_api.py index b74a51dcc..facaaba1c 100755 --- a/class/core/crontab_api.py +++ b/class/core/crontab_api.py @@ -508,6 +508,22 @@ class crontab_api: else: head = "#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n" + start_head = ''' +SCRIPT_RUN_TIME="0s" +MW_ToSeconds() +{ + SEC=$1 + if [ $SEC -lt 60 ]; then + SCRIPT_RUN_TIME="${SEC}s" + elif [ $SEC -ge 60 ] && [ $SEC -lt 3600 ];then + SCRIPT_RUN_TIME="$(( SEC / 60 ))m$(( SEC % 60 ))s" + elif [ $SEC -ge 3600 ]; then + SCRIPT_RUN_TIME="$(( SEC / 3600 ))h$(( (SEC % 3600) / 60 ))m$(( (SEC % 3600) % 60 ))s" + fi +} +START_MW_SHELL_TIME=`date +%s` +''' + source_bin_activate = ''' export LANG=en_US.UTF-8 MW_PATH=%s/bin/activate @@ -515,7 +531,7 @@ if [ -f $MW_PATH ];then source $MW_PATH fi''' % (mw.getRunDir(),) - head = head + source_bin_activate + "\n" + head = head + start_head + source_bin_activate + "\n" log = '.log' script_dir = mw.getRunDir() + "/scripts" @@ -557,7 +573,10 @@ fi''' % (mw.getRunDir(),) shell += ''' echo "----------------------------------------------------------------------------" endDate=`date +"%Y-%m-%d %H:%M:%S"` -echo "★[$endDate] Successful" +END_MW_SHELL_TIME=`date +"%s"` +((SHELL_COS_TIME=($END_MW_SHELL_TIME-$START_MW_SHELL_TIME))) +MW_ToSeconds $SHELL_COS_TIME +echo "★[$endDate] Successful | Script Run [$SCRIPT_RUN_TIME] " echo "----------------------------------------------------------------------------" ''' cronPath = mw.getServerDir() + '/cron' diff --git a/class/core/mw.py b/class/core/mw.py index d3fe98cb6..d2d37549d 100755 --- a/class/core/mw.py +++ b/class/core/mw.py @@ -1215,6 +1215,12 @@ def formatDate(format="%Y-%m-%d %H:%M:%S", times=None): return time.strftime(format, time_local) +def strfToTime(sdate): + # 转换时间 + import time + return time.strftime('%Y-%m-%d', time.strptime(sdate, '%b %d %H:%M:%S %Y %Z')) + + def checkIp(ip): # 检查是否为IPv4地址 import re diff --git a/class/core/plugins_api.py b/class/core/plugins_api.py index 97248eba1..936c0b444 100755 --- a/class/core/plugins_api.py +++ b/class/core/plugins_api.py @@ -139,7 +139,7 @@ class plugins_api: def initApi(self): plugin_names = { - 'openresty': '1.21.4.1', + 'openresty': '1.21.4.2', 'php': '56', 'swap': '1.1', 'mysql': '5.7', diff --git a/class/core/site_api.py b/class/core/site_api.py index 42a2bdbf7..12b16d858 100755 --- a/class/core/site_api.py +++ b/class/core/site_api.py @@ -1870,19 +1870,16 @@ class site_api: if _id == '' or _siteName == '': return mw.returnJson(False, "必填项不能为空!") - _old_config = mw.readFile( - "{}/{}/{}.conf".format(self.proxyPath, _siteName, _id)) - if _old_config == False: - return mw.returnJson(False, "非法操作") - - mw.writeFile("{}/{}/{}.conf".format(self.proxyPath, - _siteName, _id), _config) + proxy_file = "{}/{}/{}.conf".format(self.proxyPath, _siteName, _id) + mw.backFile(proxy_file) + mw.writeFile(proxy_file, _config) rule_test = mw.checkWebConfig() if rule_test != True: - mw.writeFile("{}/{}/{}.conf".format(self.proxyPath, - _siteName, _id), _old_config) + mw.restoreFile(proxy_file) + mw.removeBackFile(proxy_file) return mw.returnJson(False, "OpenResty 配置测试不通过, 请重试: {}".format(rule_test)) + mw.removeBackFile(proxy_file) self.operateRedirectConf(_siteName, 'start') mw.restartWeb() return mw.returnJson(True, "ok") @@ -1923,21 +1920,20 @@ class site_api: _from = request.form.get('from', '') _to = request.form.get('to', '') _host = request.form.get('host', '') + _name = request.form.get('name', '') _open_proxy = request.form.get('open_proxy', '') + _open_cache = request.form.get('open_cache', '') + _cache_time = request.form.get('cache_time', '') + _id = request.form.get('id', '') - if _siteName == "" or _from == "" or _to == "" or _host == "": + # print(_name, _siteName, _from, _to, _host) + if _name == "" or _siteName == "" or _from == "" or _to == "" or _host == "": return mw.returnJson(False, "必填项不能为空") - data_path = self.getProxyDataPath(_siteName) - data_content = mw.readFile( - data_path) if os.path.exists(data_path) else "" - data = json.loads(data_content) if data_content != "" else [] - rep = "http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?" if not re.match(rep, _to): return mw.returnJson(False, "错误的目标地址!") - # _to = _to.strip("/") # get host from url try: if _host == "$host": @@ -1946,7 +1942,11 @@ class site_api: except: return mw.returnJson(False, "错误的目标地址") - # location ~* ^{from}(.*)$ { + proxy_site_path = self.getProxyDataPath(_siteName) + data_content = mw.readFile( + proxy_site_path) if os.path.exists(proxy_site_path) else "" + data = json.loads(data_content) if data_content != "" else [] + tpl = "#PROXY-START\n\ location ^~ {from} {\n\ proxy_pass {to};\n\ @@ -1954,12 +1954,29 @@ location ^~ {from} {\n\ proxy_set_header X-Real-IP $remote_addr;\n\ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\ proxy_set_header REMOTE-HOST $remote_addr;\n\ + proxy_set_header Upgrade $http_upgrade;\n\ + proxy_set_header Connection $connection_upgrade;\n\ + proxy_http_version 1.1;\n\ \n\ add_header X-Cache $upstream_cache_status;\n\ - proxy_ignore_headers Set-Cookie Cache-Control expires;\n\ - add_header Cache-Control no-cache;\n\ \n\ - set $static_files_app 0;\n\ + {proxy_cache}\n\ +}\n\ +# PROXY-END" + + tpl_proxy_cache = "\n\ + if ( $uri ~* \"\.(gif|png|jpg|css|js|woff|woff2)$\" )\n\ + {\n\ + expires {cache_time}m;\n\ + }\n\ + proxy_ignore_headers Set-Cookie Cache-Control expires;\n\ + proxy_cache mw_cache;\n\ + proxy_cache_key \"$host$uri$is_args$args\";\n\ + proxy_cache_valid 200 304 301 302 {cache_time}m;\n\ +" + + tpl_proxy_nocache = "\n\ + set $static_files_app 0; \n\ if ( $uri ~* \"\.(gif|png|jpg|css|js|woff|woff2)$\" )\n\ {\n\ set $static_files_app 1;\n\ @@ -1969,8 +1986,7 @@ location ^~ {from} {\n\ {\n\ add_header Cache-Control no-cache;\n\ }\n\ -}\n\ -#PROXY-END" +" # replace if _from[0] != '/': @@ -1978,28 +1994,69 @@ location ^~ {from} {\n\ tpl = tpl.replace("{from}", _from, 999) tpl = tpl.replace("{to}", _to) tpl = tpl.replace("{host}", _host, 999) + tpl = tpl.replace("{cache_time}", _cache_time, 999) - _id = mw.md5("{}+{}+{}".format(_from, _to, _siteName)) - for item in data: - if item["id"] == _id: - return mw.returnJson(False, "已存在该规则!") - if item["from"] == _from: - return mw.returnJson(False, "代理目录已存在!") - data.append({ - "from": _from, - "to": _to, - "host": _host, - "id": _id - }) + if _open_cache == 'on': + tpl_proxy_cache = tpl_proxy_cache.replace( + "{cache_time}", _cache_time, 999) + tpl = tpl.replace("{proxy_cache}", tpl_proxy_cache, 999) + else: + tpl = tpl.replace("{proxy_cache}", tpl_proxy_nocache, 999) + + proxy_action = 'add' + if _id == "": + _id = mw.md5("{}".format(_name)) + else: + proxy_action = 'edit' + + conf_proxy = "{}/{}.conf".format(self.getProxyPath(_siteName), _id) + conf_bk = "{}/{}.conf.txt".format(self.getProxyPath(_siteName), _id) + + mw.writeFile(conf_proxy, tpl) + + rule_test = mw.checkWebConfig() + if rule_test != True: + os.remove(conf_proxy) + return mw.returnJson(False, "OpenResty配置测试不通过, 请重试: {}".format(rule_test)) + + if proxy_action == "add": + # 添加代理 + _id = mw.md5("{}".format(_name)) + for item in data: + if item["name"] == _name: + return mw.returnJson(False, "名称重复!") + if item["from"] == _from: + return mw.returnJson(False, "代理目录已存在!") + data.append({ + "name": _name, + "from": _from, + "to": _to, + "host": _host, + "open_cache": _open_cache, + "open_proxy": _open_proxy, + "cache_time": _cache_time, + "id": _id, + }) + else: + # 修改代理 + dindex = -1 + for x in range(len(data)): + if data[x]["id"] == _id: + dindex = x + break + if dindex < 0: + return mw.returnJson(False, "异常请求") + data[dindex]['from'] = _from + data[dindex]['to'] = _to + data[dindex]['host'] = _host + data[dindex]['open_cache'] = _open_cache + data[dindex]['open_proxy'] = _open_proxy + data[dindex]['cache_time'] = _cache_time - conf_file = "{}/{}.conf".format(self.getProxyPath(_siteName), _id) if _open_proxy != 'on': - conf_file = "{}/{}.conf.txt".format( - self.getProxyPath(_siteName), _id) - - mw.writeFile(data_path, json.dumps(data)) - mw.writeFile(conf_file, tpl) + os.rename(conf_proxy, conf_bk) + mw.writeFile(proxy_site_path, json.dumps(data)) self.operateProxyConf(_siteName, 'start') mw.restartWeb() return mw.returnJson(True, "ok", {"hash": _id}) @@ -2030,10 +2087,10 @@ location ^~ {from} {\n\ self.getProxyPath(_siteName), _id) mw.execShell(cmd) except: - return mw.returnJson(False, "删除失败!") + return mw.returnJson(False, "删除反代失败!") mw.restartWeb() - return mw.returnJson(True, "删除成功!") + return mw.returnJson(True, "删除反代成功!") def getSiteTypesApi(self): # 取网站分类 @@ -2100,7 +2157,7 @@ location ^~ {from} {\n\ ##### ----- end ----- ### - # 域名编码转换 + # 域名编码转换 def toPunycode(self, domain): import re if sys.version_info[0] == 2: @@ -2108,7 +2165,7 @@ location ^~ {from} {\n\ tmp = domain.split('.') newdomain = '' for dkey in tmp: - # 匹配非ascii字符 + # 匹配非ascii字符 match = re.search(u"[\x80-\xff]+", dkey) if not match: newdomain += dkey + '.' @@ -2663,7 +2720,7 @@ location ^~ {from} {\n\ mw.writeLog('TYPE_SITE', '设置成功,站点到期后将自动停止!', (siteName, edate)) return mw.returnJson(True, '设置成功,站点到期后将自动停止!') - # ssl相关方法 start +# ssl相关方法 start def setSslConf(self, siteName): file = self.getHostConf(siteName) conf = mw.readFile(file) @@ -2762,9 +2819,4 @@ location ^~ {from} {\n\ mw.execShell("chattr +i " + filename) return mw.returnJson(True, '已打开防跨站设置!') - - # 转换时间 - def strfToTime(self, sdate): - import time - return time.strftime('%Y-%m-%d', time.strptime(sdate, '%b %d %H:%M:%S %Y %Z')) - # ssl相关方法 end +# ssl相关方法 end diff --git a/data/sql/default.sql b/data/sql/default.sql index 8cdd9bf63..6797e84ba 100755 --- a/data/sql/default.sql +++ b/data/sql/default.sql @@ -46,9 +46,8 @@ CREATE TABLE IF NOT EXISTS `firewall` ( INSERT INTO `firewall` (`id`, `port`, `ps`, `addtime`) VALUES (1, '80', '网站默认端口', '0000-00-00 00:00:00'), -(2, '22', 'SSH远程管理服务', '0000-00-00 00:00:00'), -(3, '443', 'HTTPS', '0000-00-00 00:00:00'), -(4, '888', 'phpMyAdmin默认端口', '0000-00-00 00:00:00'); +(2, '443', 'HTTPS', '0000-00-00 00:00:00'), +(3, '888', 'phpMyAdmin默认端口', '0000-00-00 00:00:00'); diff --git a/data/tpl/nginx.conf b/data/tpl/nginx.conf index b4b0eb1c7..e1a4f2588 100755 --- a/data/tpl/nginx.conf +++ b/data/tpl/nginx.conf @@ -39,20 +39,13 @@ server allow all; } - location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$ + location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf|js|css)$ { expires 30d; - error_log off; + error_log /dev/null; access_log /dev/null; } - location ~ .*\\.(js|css)?$ - { - expires 12h; - error_log off; - access_log /dev/null; - } - access_log {$LOGPATH}/{$SERVER_NAME}.log main; error_log {$LOGPATH}/{$SERVER_NAME}.error.log; } \ No newline at end of file diff --git a/data/tpl/nginx_dirbind.conf b/data/tpl/nginx_dirbind.conf index 30e54725b..129a7ddd1 100755 --- a/data/tpl/nginx_dirbind.conf +++ b/data/tpl/nginx_dirbind.conf @@ -35,18 +35,11 @@ server allow all; } - location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$ + location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf|js|css)$ { - expires 30d; - error_log off; + error_log /dev/null; access_log /dev/null; - } - - location ~ .*\\.(js|css)?$ - { - expires 12h; - error_log off; - access_log /dev/null; + expires 30d; } access_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.log; diff --git a/plugins/docker/index.html b/plugins/docker/index.html index ffcf912a6..fd9647867 100755 --- a/plugins/docker/index.html +++ b/plugins/docker/index.html @@ -40,6 +40,7 @@
自启动
容器列表
镜像列表
+镜像导出
IP地址池
仓库
diff --git a/plugins/docker/index.py b/plugins/docker/index.py index 259f008ed..e528d9ced 100755 --- a/plugins/docker/index.py +++ b/plugins/docker/index.py @@ -429,6 +429,92 @@ def dockerRemoveImage(): return mw.returnJson(False, '删除失败, 当前镜像正在使用!') +def getImageListFunc(dbname=''): + bkDir = mw.getRootDir() + '/backup/docker' + blist = os.listdir(bkDir) + r = [] + + bname = 'db_' + dbname + blen = len(bname) + for x in blist: + fbstr = x[0:blen] + if fbstr == bname: + r.append(x) + return r + + +def dockerImagePickDir(): + bkDir = mw.getRootDir() + '/backup/docker' + return mw.returnJson(True, 'ok', bkDir) + + +def dockerImagePickList(): + + bkDir = mw.getRootDir() + '/backup/docker' + if not os.path.exists(bkDir): + os.mkdir(bkDir) + + r = os.listdir(bkDir) + rr = [] + for x in range(0, len(r)): + p = bkDir + '/' + r[x] + data = {} + data['name'] = r[x] + + rsize = os.path.getsize(p) + data['size'] = mw.toSize(rsize) + + t = os.path.getctime(p) + t = time.localtime(t) + + data['time'] = time.strftime('%Y-%m-%d %H:%M:%S', t) + rr.append(data) + + data['file'] = p + + return mw.returnJson(True, 'ok', rr) + + +def dockerImagePickSave(): + # image 导出 + args = getArgs() + data = checkArgs(args, ['images']) + if not data[0]: + return data[1] + + bkDir = mw.getRootDir() + '/backup/docker/' + images = args['images'] + try: + file_name = bkDir + \ + str(time.strftime('%Y%m%d_%H%M%S', time.localtime())) + '.tar.gz' + mw.execShell('docker image save %s | gzip > %s' % + (images, file_name)) + return mw.returnJson(True, '导出镜像 {} 成功!'.format(file_name)) + except docker.errors.APIError as ex: + return mw.returnJson(False, '操作失败: ' + str(ex)) + + +def dockerImagePickLoad(): + # 镜像文件导入 + args = getArgs() + data = checkArgs(args, ['file']) + if not data[0]: + return data[1] + try: + file_path = args['file'] + if not os.path.exists(file_path): + return mw.returnJson(False, '文件不存在') + if file_path.endswith('.tar'): + mw.execShell('docker image load < %s' % file_path) + elif file_path.endswith('.tar.gz'): + mw.execShell('gunzip -c %s | docker image load' % file_path) + else: + return mw.returnJson(False, '不支持改文件类型!') + return mw.returnJson(True, '导入镜像文件成功!') + except docker.errors.APIError as ex: + return mw.returnJson(False, '操作失败: ' + str(ex)) + + def dockerLoginCheck(user_name, user_pass, registry): # 登陆验证 cmd = 'docker login -u=%s -p %s %s' % (user_name, user_pass, registry) @@ -523,6 +609,45 @@ def __release_port(port): return "Release failed {}".format(e) +def dockerPortCheck(): + args = getArgs() + data = checkArgs(args, ['port']) + if not data[0]: + return data[1] + + port = args['port'] + is_ok = IsPortExists(port) + if is_ok: + return mw.returnJson(True, 'ok') + return mw.returnJson(False, 'fail') + + +def IsPortExists(port): + # 判断端口是否被占用 + ret = __check_dst_port(ip='localhost', port=port) + ret2 = __check_dst_port(ip='0.0.0.0', port=port) + if ret: + return ret + if not ret and ret2: + return ret2 + if not ret and not ret2: + return False + + +def __check_dst_port(ip, port, timeout=3): + # 端口检测 + import socket + ok = True + try: + s = socket.socket() + s.settimeout(timeout) + s.connect((ip, port)) + s.close() + except: + ok = False + return ok + + def dockerCreateCon(): args = getArgs() data = checkArgs(args, ['environments', 'command', @@ -703,6 +828,14 @@ if __name__ == "__main__": print(dockerPullReg()) elif func == 'image_list': print(imageListData()) + elif func == 'image_pick_dir': + print(dockerImagePickDir()) + elif func == 'image_pick_save': + print(dockerImagePickSave()) + elif func == 'image_pick_load': + print(dockerImagePickLoad()) + elif func == 'image_pick_list': + print(dockerImagePickList()) elif func == 'docker_get_iplist': print(getDockerIpList()) elif func == 'docker_del_ip': @@ -715,6 +848,8 @@ if __name__ == "__main__": print(dockerCreateCon()) elif func == 'docker_remove_image': print(dockerRemoveImage()) + elif func == 'docker_port_check': + print(dockerPortCheck()) elif func == 'docker_login': print(dockerLogin()) elif func == 'docker_logout': diff --git a/plugins/docker/info.json b/plugins/docker/info.json index 26949af08..cfc02fb21 100755 --- a/plugins/docker/info.json +++ b/plugins/docker/info.json @@ -1,6 +1,6 @@ { "sort": 7, - "ps": "Docker 是一个开源的应用容器引擎(开发测试中)", + "ps": "Docker是一个开源的应用容器引擎", "name": "docker", "title": "Docker", "shell": "install.sh", diff --git a/plugins/docker/js/docker.js b/plugins/docker/js/docker.js index 4d5cfc98c..d2c35d6f3 100755 --- a/plugins/docker/js/docker.js +++ b/plugins/docker/js/docker.js @@ -1,40 +1,46 @@ -function dPost(method, version, args,callback){ +function dPostOrgin(args, callback) { + $.post('/plugins/run', args, function(data) { + callback(data); + }, 'json'); +} + +function dPost(method, version, args, callback) { var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); var req_data = {}; req_data['name'] = 'docker'; req_data['func'] = method; req_data['version'] = version; - - if (typeof(args) == 'string'){ + + if (typeof(args) == 'string') { req_data['args'] = JSON.stringify(toArrayObject(args)); } else { req_data['args'] = JSON.stringify(args); } - $.post('/plugins/run', req_data, function(data) { + dPostOrgin(req_data, function(data) { layer.close(loadT); - if (!data.status){ + if (!data.status) { //错误展示10S - layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']}); + layer.msg(data.msg, { icon: 0, time: 2000, shade: [10, '#000'] }); return; } - if(typeof(callback) == 'function'){ + if (typeof(callback) == 'function') { callback(data); } - },'json'); + }); } -function dPostCallbak(method, version, args,callback){ +function dPostCallbak(method, version, args, callback) { var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); var req_data = {}; req_data['name'] = 'docker'; req_data['func'] = method; args['version'] = version; - - if (typeof(args) == 'string'){ + + if (typeof(args) == 'string') { req_data['args'] = JSON.stringify(toArrayObject(args)); } else { req_data['args'] = JSON.stringify(args); @@ -42,115 +48,115 @@ function dPostCallbak(method, version, args,callback){ $.post('/plugins/callback', req_data, function(data) { layer.close(loadT); - if (!data.status){ - layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + if (!data.status) { + layer.msg(data.msg, { icon: 0, time: 2000, shade: [0.3, '#000'] }); return; } - if(typeof(callback) == 'function'){ + if (typeof(callback) == 'function') { callback(data); } - },'json'); + }, 'json'); } -function logsCon(id){ - dPost('docker_con_log','',{Hostname:id},function(rdata){ +function logsCon(id) { + dPost('docker_con_log', '', { Hostname: id }, function(rdata) { var rdata = $.parseJSON(rdata.data); - if(!rdata.status) { - layer.msg(rdata.msg,{icon:2}); + if (!rdata.status) { + layer.msg(rdata.msg, { icon: 2 }); return; }; layer.open({ - type:1, - title:'Docker日志', + type: 1, + title: 'Docker日志', area: '600px', closeBtn: 2, - content:'' + + ''+ (rdata.msg == '' ? 'No logs':rdata.msg) +'' - +'
', { icon: 16, time: 0, shade: [0.3, "#000"] });
+ dPost('docker_port_check', '',{port:port}, function(rdata){
layer.close(loadT);
- if(rdata !== false){
- layer.msg('Port ['+name2+'] is already in the mapping list!',{icon:2});
+ var rdata = $.parseJSON(rdata.data);
+ if (rdata.status){
+ layer.msg('端口 [' + name2 + ']已在映射列表中!', { icon: 2 });
return;
}
+
var selecttype = $(".type-port select").val();
- var portable= '| \ + | 名称 | \ +版本 | \ +大小 | \ +
|---|
| 名称 | \ +大小 | \ +时间 | \ +操作 |
|---|
| ' + period +' | ' + '\
同步\
- | 日志\
+ | 手动日志\
| 过滤器\
| 编辑\
| 删除\
@@ -562,7 +562,7 @@ function rsyncdConf(){
}
function rsyncdLog(){
- pluginStandAloneLogs("rsyncd","","run_log");
+ pluginRollingLogs("rsyncd","","run_log");
}
diff --git a/plugins/tgbot/startup/extend/init_cmd.py b/plugins/tgbot/startup/extend/init_cmd.py
index 26958d6fa..b5192f95c 100644
--- a/plugins/tgbot/startup/extend/init_cmd.py
+++ b/plugins/tgbot/startup/extend/init_cmd.py
@@ -22,6 +22,6 @@ def init(bot):
bot.set_my_commands(
commands=[
telebot.types.BotCommand("start", "查看帮助信息"),
- telebot.types.BotCommand("faq", "查看bbs帖子主题【不要忘记:冒号】"),
+ telebot.types.BotCommand("faq", "查看bbs帖子主题【?:】"),
],
)
diff --git a/plugins/tgbot/startup/extend/receive_faq.py b/plugins/tgbot/startup/extend/receive_faq.py
index 0a9e7ab23..6b619af86 100644
--- a/plugins/tgbot/startup/extend/receive_faq.py
+++ b/plugins/tgbot/startup/extend/receive_faq.py
@@ -189,26 +189,22 @@ def run(bot, message):
return bot
# print(text_body)
- if isThisCmd('/faq:', text_body):
- cmd_text = getReadCmd('/faq:', text_body)
+ if isThisCmd('/?:', text_body):
+ cmd_text = getReadCmd('/?:', text_body)
return searchFaq(bot, message, cmd_text)
- # if isThisCmd('/debug', text_body):
- # cmd_text = getReadCmd('/debug', text_body)
- # return searchDebug(bot, message, cmd_text)
+ # if text_body.find('?') > -1 or text_body.find('?') > -1:
+ # return_msg = "你似乎在寻找【" + text_body + "】答案:\n"
+ # return_msg += "/faq:开始寻找你的问题\n"
+ # keyboard = [
+ # [
+ # types.InlineKeyboardButton(
+ # text="如未找到,可以在论坛补充你的提问!", url='https://bbs.midoks.me'),
+ # ]
- if text_body.find('?') > -1 or text_body.find('?') > -1:
- return_msg = "你似乎在寻找【" + text_body + "】答案:\n"
- return_msg += "/faq:开始寻找你的问题\n"
- keyboard = [
- [
- types.InlineKeyboardButton(
- text="如未找到,可以在论坛补充你的提问!", url='https://bbs.midoks.me'),
- ]
-
- ]
- markup = types.InlineKeyboardMarkup(keyboard)
- bot.reply_to(message, return_msg, reply_markup=markup)
+ # ]
+ # markup = types.InlineKeyboardMarkup(keyboard)
+ # bot.reply_to(message, return_msg, reply_markup=markup)
return bot
diff --git a/route/static/app/files.js b/route/static/app/files.js
index 840ebc205..9ec2d36f4 100755
--- a/route/static/app/files.js
+++ b/route/static/app/files.js
@@ -789,18 +789,15 @@ function batchPasteTo(data,path){
function getSuffixName(fileName){
var extArr = fileName.split(".");
- var exts = ['folder','folder-unempty','sql','c','cpp','cs','flv','css','js',
+ var exts = ['folder-unempty','sql','c','cpp','cs','flv','css','js',
'htm','html','java','log','mht','url','xml','ai','bmp','cdr','gif','ico',
- 'jpeg','jpg','JPG','png','psd','webp','ape','avi','flv','mkv','mov','mp3','mp4',
+ 'jpeg','jpg','JPG','png','psd','webp','ape','avi','mkv','mov','mp3','mp4',
'mpeg','mpg','rm','rmvb','swf','wav','webm','wma','wmv','rtf','docx','fdf','potm',
'pptx','txt','xlsb','xlsx','7z','cab','iso','rar','zip','gz','bt','file','apk','bookfolder',
- 'folder','folder-empty','folder-unempty','fromchromefolder','documentfolder','fromphonefolder',
- 'mix','musicfolder','picturefolder','videofolder','sefolder','access','mdb','accdb','sql','c',
- 'cpp','cs','js','fla','flv','htm','html','java','mht','url','xml','ai','bmp','cdr',
- 'gif','ico','jpeg','jpg','JPG','png','psd','webp','ape','avi','flv','mkv','mov','mp3','mp4','mpeg',
- 'mpg','rm','rmvb','swf','wav','webm','wma','wmv','doc','docm','dotx','dotm','dot','rtf','docx','pdf',
- 'fdf','ppt','pptm','pot','potm','pptx','txt','xls','csv','xlsm','xlsb','xlsx','7z','gz','cab','iso',
- 'rar','zip','bt','file','apk','css','scss','svg','pl','py','php','md','json','sh'];
+ 'folder','folder-empty','fromchromefolder','documentfolder','fromphonefolder',
+ 'mix','musicfolder','picturefolder','videofolder','sefolder','access','mdb','accdb',
+ 'fla','doc','docm','dotx','dotm','dot','pdf',
+ 'ppt','pptm','pot','xls','csv','xlsm','scss','svg','pl','py','php','md','json','sh','conf'];
var extLastName = extArr[extArr.length - 1];
for(var i=0; i " +
- '开启代理'+
- " " +
- "" +
- "" +
- " " +
- ""+
- "代理目录" +
- " " +
- "" +
- "" +
- " " +
- "" +
- "目标URL" +
- " " +
- "" +
- "" +
- "发送域名" +
- "" +
- " " +
- "" +
- " " +
- "",
- yes:function(){
- var data = $('#form_redirect').serializeArray();
+ content: "",
+ success:function(){
+
+ if (typeof(obj) != 'undefined'){
+ // console.log(obj);
+ $('input[name="name"]').val(obj['name']).attr('readonly','readonly').addClass('disabled');
+ if (obj['open_cache'] == 'on'){
+ $("input[name='open_cache']").prop("checked",true);
+ $('#cache_time').show();
+ }
+
+ $('input[name="from"]').val(obj['from']);
+ $('input[name="to"]').val(obj['to']);
+
+ var url = obj['to'];
+ var ip_reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
+ url = url.replace(/^http[s]?:\/\//, '');
+ url = url.replace(/(:|\?|\/|\\)(.*)$/, '');
+ if (ip_reg.test(url)) {
+ $("[name='host']").val('$host');
+ } else {
+ $("[name='host']").val(url);
+ }
+
+ $('input[name="id"]').val(obj['id']);
+ $('input[name="cache_time"]').val(obj['cache_time']);
+ }
+
+
+ $('input[name="to"]').on('keyup', function(){
+ var url = $(this).val();
+ var ip_reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
+ url = url.replace(/^http[s]?:\/\//, '');
+ url = url.replace(/(:|\?|\/|\\)(.*)$/, '');
+ if (ip_reg.test(url)) {
+ $("[name='host']").val('$host');
+ } else {
+ $("[name='host']").val(url);
+ }
+ });
+
+ $("#open_proxy").click(function(){
+ var status = $("input[name='open_proxy']").prop("checked")==true?1:0;
+ if(status==1){
+ $("input[name='open_proxy']").prop("checked",false);
+ }else{
+ $("input[name='open_proxy']").prop("checked",true);
+ }
+ });
+
+ $('#open_cache').click(function(){
+ var status = $("input[name='open_cache']").prop("checked")==true?1:0;
+ if(status==1){
+ $('#cache_time').hide();
+ $("input[name='open_cache']").prop("checked",false);
+ }else{
+ $('#cache_time').show();
+ $("input[name='open_cache']").prop("checked",true);
+ }
+ });
+ },
+ yes:function(index,layer_ro){
+ var data = $('#form_proxy').serializeArray();
var t = {};
t['name'] = 'siteName';
t['value'] = siteName;
data.push(t);
- var loading = layer.msg('添加中...',{icon:16,time:0,shade: [0.3, '#000']});
+ // console.log(data);
+ var loading = layer.msg('正在'+proxy_title+'...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/site/set_proxy',data, function(res) {
layer.close(loading);
- if (res.status) {
- layer.close(proxy_form);
- toProxy(siteName)
- } else {
- layer.msg(res.msg, {icon: 2});
+ if (!res.status){
+ layer.msg(res.msg, {icon: 2,time:10000});
+ return;
}
+
+ showMsg(proxy_title+"成功!",function(){
+ layer.close(index);
+ toProxy(siteName);
+ },{icon: 1, time:2000});
},'json');
}
});
}
if (type == 2) {
+ var loading = layer.msg('正在删除中...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('/site/del_proxy', {siteName: siteName,id: obj,}, function(res) {
+ layer.close(loading);
if (res.status == true) {
- layer.msg('删除成功', {time: 1000,icon: 1});
- toProxy(siteName)
+ showMsg('删除成功', function(){
+ toProxy(siteName);
+ },{time: 1000,icon: 1});
} else {
layer.msg(res.msg, {time: 1000,icon: 2});
}
@@ -1650,90 +1732,118 @@ function toProxy(siteName, type, obj) {
var data = {siteName: siteName,id: obj};
$.post('/site/get_proxy_conf', data, function(res) {
layer.close(laoding);
- if (res.status == true) {
- var mBody = "
\
- \
- ";
- var editor;
- var index = layer.open({
- type: 1,
- title: '编辑配置文件',
- closeBtn: 1,
- shadeClose: true,
- area: ['500px', '500px'],
- btn: ['提交','关闭'],
- content: mBody,
- success: function () {
- editor = CodeMirror.fromTextArea(document.getElementById("configProxyBody"), {
- extraKeys: {"Ctrl-Space": "autocomplete"},
- lineNumbers: true,
- matchBrackets:true,
- });
- editor.focus();
- $(".CodeMirror-scroll").css({"height":"300px","margin":0,"padding":0});
- $("#onlineEditFileBtn").unbind('click');
- },
- yes:function(index,layero){
- $("#configProxyBody").empty().text(editor.getValue());
- var load = layer.load();
- var data = {
- siteName: siteName,
- id: obj,
- config: editor.getValue(),
- };
-
- $.post('/site/save_proxy_conf', data, function(res) {
- layer.close(load)
- if (res.status == true) {
- layer.msg('保存成功', {icon: 1});
- layer.close(index);
- } else {
- layer.msg(res.msg, {time: 3000,icon: 2});
- }
- },'json');
- return true;
- },
- });
- } else {
+ if (!res.status){
layer.msg('请求错误!!', {time: 3000,icon: 2});
+ return;
}
+
+ var mBody = "\
- \
-
\
+ \
+ ";
+ var editor;
+ var index = layer.open({
+ type: 1,
+ title: '编辑配置文件',
+ closeBtn: 1,
+ shadeClose: true,
+ area: ['500px', '500px'],
+ btn: ['提交','关闭'],
+ content: mBody,
+ success: function () {
+ editor = CodeMirror.fromTextArea(document.getElementById("configProxyBody"), {
+ extraKeys: {"Ctrl-Space": "autocomplete"},
+ lineNumbers: true,
+ matchBrackets:true,
+ });
+ editor.focus();
+ $(".CodeMirror-scroll").css({"height":"300px","margin":0,"padding":0});
+ $("#onlineEditFileBtn").unbind('click');
+ },
+ yes:function(index,layero){
+ $("#configProxyBody").empty().text(editor.getValue());
+ var load = layer.load();
+ var data = {
+ siteName: siteName,
+ id: obj,
+ config: editor.getValue(),
+ };
+
+ $.post('/site/save_proxy_conf', data, function(res) {
+ layer.close(load)
+ if (res.status == true) {
+ layer.msg('保存成功', {icon: 1});
+ layer.close(index);
+ } else {
+ layer.msg(res.msg, {time: 3000,icon: 2});
+ }
+ },'json');
+ return true;
+ },
+ });
},'json');
- return
+ return;
}
if (type == 10 || type == 11) {
//[11]启动 或 停止[10]
status = type==10 ? '0' : '1';
var loading = layer.msg(lan.site.the_msg,{icon:16,time:0,shade: [0.3, '#000']});
- $.post('/site/set_proxy_status', {siteName: siteName,'status':status,'id':obj}, function(res) {
+ $.post('/site/set_proxy_status', {siteName: siteName,'status':status,'id':obj}, function(rdata) {
layer.close(loading);
- if (res.status == true) {
- layer.msg('设置成功', {icon: 1});
- toProxy(siteName);
- } else {
+ if (!rdata.status){
layer.msg(res.msg, {time: 3000,icon: 2});
+ return;
}
+
+ showMsg("设置成功",function(){
+ toProxy(siteName);
+ },{icon: 1,time:2000});
+ },'json');
+ return;
+ }
+
+ if (type == 20 || type == 21) {
+ //[20] 开始缓存 或 [21] 停止缓存
+ var status = type == 20 ? 'on' : '';
+ obj['open_cache'] = status;
+ obj['siteName'] = siteName;
+
+ var loading = layer.msg('正在提交请求...',{icon:16,time:0,shade: [0.3, '#000']});
+ $.post('/site/set_proxy',obj, function(rdata) {
+ layer.close(loading);
+ if (!rdata.status){
+ layer.msg(rdata.msg, {icon: 2,time:2000});
+ return;
+ }
+
+ showMsg("设置成功!",function(){
+ toProxy(siteName);
+ },{icon: 1, time:2000});
},'json');
return;
}
var body = '\
+ \
+
\
\
- \
+ \
\
\
|