diff --git a/.gitignore b/.gitignore index 777de65c3..145ee9cdf 100644 --- a/.gitignore +++ b/.gitignore @@ -138,6 +138,7 @@ data/ipv6.pl data/restart.pl data/ssl.pl data/edate.pl +data/osname.pl plugins/l2tp plugins/openlitespeed @@ -146,3 +147,4 @@ plugins/mtproxy debug.out + diff --git a/class/core/config_api.py b/class/core/config_api.py index 822dfd35c..ef4d50c59 100755 --- a/class/core/config_api.py +++ b/class/core/config_api.py @@ -17,7 +17,7 @@ class config_api: # 进行中. # 兼容主流Linux系统 - __version = '0.8.6.11' + __version = '0.8.6.12' def __init__(self): pass diff --git a/class/core/db.py b/class/core/db.py index 5be95e8b9..901d0c8cd 100755 --- a/class/core/db.py +++ b/class/core/db.py @@ -3,6 +3,7 @@ import sqlite3 import os +import sys class Sql(): @@ -31,6 +32,14 @@ class Sql(): except Exception as ex: return "error: " + str(ex) + def autoTextFactory(self): + if sys.version_info[0] == 3: + self.__DB_CONN.text_factory = lambda x: str( + x, encoding="utf-8", errors='ignore') + else: + self.__DB_CONN.text_factory = lambda x: unicode( + x, "utf-8", "ignore") + def dbfile(self, name): self.__DB_FILE = 'data/' + name + '.db' return self diff --git a/class/core/mw.py b/class/core/mw.py index 6a0aa9413..cd997d856 100755 --- a/class/core/mw.py +++ b/class/core/mw.py @@ -733,7 +733,7 @@ def makeConf(): file = getRunDir() + '/data/json/config.json' if not os.path.exists(file): c = {} - c['title'] = 'Linux面板' + c['title'] = 'mdserver-web | linux面板' c['home'] = 'http://github/midoks/mdserver-web' c['recycle_bin'] = True c['template'] = 'default' @@ -1022,3 +1022,13 @@ def getMyORM(): import orm o = orm.ORM() return o + + +def getMyORMDb(): + ''' + 获取MySQL资源的ORM pip install mysqlclient==2.0.3 | pip install mysql-python + ''' + sys.path.append(os.getcwd() + "/class/plugin") + import ormDb + o = ormDb.ORM() + return o diff --git a/class/core/site_api.py b/class/core/site_api.py index 8bb906b9a..0593284d6 100755 --- a/class/core/site_api.py +++ b/class/core/site_api.py @@ -387,9 +387,19 @@ class site_api: os.system('mkdir -p ' + vpath) data = [] for d in os.listdir(vpath): + + # keyPath = self.sslDir + siteName + '/privkey.pem' + # certPath = self.sslDir + siteName + '/fullchain.pem' + + keyPath = vpath + '/' + d + '/privkey.pem' + certPath = vpath + '/' + d + '/fullchain.pem' + if os.path.exists(keyPath) and os.path.exists(certPath): + self.saveCert(keyPath, certPath) + mpath = vpath + '/' + d + '/info.json' if not os.path.exists(mpath): continue + tmp = mw.readFile(mpath) if not tmp: continue @@ -479,8 +489,8 @@ class site_api: mw.execShell('\\cp -a /tmp/backup2.conf ' + csrpath) return mw.returnJson(False, 'ERROR:
' + isError.replace("\n", '
') + '
') - mw.restartWeb() mw.writeLog('网站管理', '证书已保存!') + mw.restartWeb() return mw.returnJson(True, '证书已保存!') def setCertToSiteApi(self): @@ -2023,7 +2033,7 @@ location ^~ {from} { def getPhpVersion(self): phpVersions = ('00', '52', '53', '54', '55', - '56', '70', '71', '72', '73', '74', '80', '81') + '56', '70', '71', '72', '73', '74', '80', '81', '82') data = [] for val in phpVersions: tmp = {} @@ -2280,7 +2290,7 @@ location /{ certInfo = self.getCertName(certPath) if not certInfo: return mw.returnData(False, '证书解析失败!') - vpath = self.sslDir + certInfo['subject'] + vpath = self.sslDir + certInfo['subject'].strip() if not os.path.exists(vpath): os.system('mkdir -p ' + vpath) mw.writeFile(vpath + '/privkey.pem', diff --git a/class/plugin/orm.py b/class/plugin/orm.py index b38e8683a..ab1951bbe 100755 --- a/class/plugin/orm.py +++ b/class/plugin/orm.py @@ -18,6 +18,8 @@ class ORM: __DB_CNF = '/etc/my.cnf' __DB_SOCKET = '/www/server/mysql/mysql.sock' + __DB_CHARSET = "utf8" + def __Conn(self): '''连接MYSQL数据库''' try: @@ -25,19 +27,19 @@ class ORM: if os.path.exists(self.__DB_SOCKET): try: self.__DB_CONN = connector.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, - port=self.__DB_PORT, charset="utf8", connect_timeout=1, unix_socket=self.__DB_SOCKET) + port=self.__DB_PORT, charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET) except Exception as e: self.__DB_HOST = '127.0.0.1' self.__DB_CONN = connector.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, - port=self.__DB_PORT, charset="utf8", connect_timeout=1, unix_socket=self.__DB_SOCKET) + port=self.__DB_PORT, charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET) else: try: self.__DB_CONN = connector.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, - port=self.__DB_PORT, charset="utf8", connect_timeout=1) + port=self.__DB_PORT, charset=self.__DB_CHARSET, connect_timeout=1) except Exception as e: self.__DB_HOST = '127.0.0.1' self.__DB_CONN = connector.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, - port=self.__DB_PORT, charset="utf8", connect_timeout=1) + port=self.__DB_PORT, charset=self.__DB_CHARSET, connect_timeout=1) self.__DB_CUR = self.__DB_CONN.cursor() return True @@ -51,6 +53,9 @@ class ORM: def setSocket(self, sock): self.__DB_SOCKET = sock + def setCharset(self, charset): + self.__DB_CHARSET = charset + def setPort(self, port): self.__DB_PORT = port diff --git a/class/plugin/ormDb.py b/class/plugin/ormDb.py new file mode 100755 index 000000000..f747c651d --- /dev/null +++ b/class/plugin/ormDb.py @@ -0,0 +1,109 @@ +# coding: utf-8 + +import re +import os +import sys + + +class ORM: + __DB_PASS = None + __DB_USER = 'root' + __DB_PORT = 3306 + __DB_HOST = 'localhost' + __DB_CONN = None + __DB_CUR = None + __DB_ERR = None + __DB_CNF = '/etc/my.cnf' + + __DB_SOCKET = '/www/server/mysql/mysql.sock' + __DB_CHARSET = 'utf8' + + def __Conn(self): + '''连接MYSQL数据库''' + try: + + try: + import MySQLdb + except Exception as ex: + self.__DB_ERR = ex + return False + + # print(self.__DB_HOST) + # print(self.__DB_USER) + # print(self.__DB_PASS) + # print(self.__DB_PORT) + # print(self.__DB_CHARSET) + # print(self.__DB_SOCKET) + if os.path.exists(self.__DB_SOCKET): + try: + self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, + port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET) + except Exception as e: + print(e) + self.__DB_HOST = '127.0.0.1' + self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, + port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET) + else: + try: + self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, + port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1) + except Exception as e: + self.__DB_HOST = '127.0.0.1' + self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS, + port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1) + + self.__DB_CUR = self.__DB_CONN.cursor() + + return True + except MySQLdb.Error as e: + self.__DB_ERR = e + return False + + def setDbConf(self, conf): + self.__DB_CNF = conf + + def setSocket(self, sock): + self.__DB_SOCKET = sock + + def setCharset(self, charset): + self.__DB_CHARSET = charset + + def setPort(self, port): + self.__DB_PORT = port + + def setPwd(self, pwd): + self.__DB_PASS = pwd + + def getPwd(self): + return self.__DB_PASS + + def execute(self, sql): + # 执行SQL语句返回受影响行 + if not self.__Conn(): + return self.__DB_ERR + try: + result = self.__DB_CUR.execute(sql) + self.__DB_CONN.commit() + self.__Close() + return result + except Exception as ex: + return ex + + def query(self, sql): + # 执行SQL语句返回数据集 + if not self.__Conn(): + return self.__DB_ERR + try: + self.__DB_CUR.execute(sql) + result = self.__DB_CUR.fetchall() + # 将元组转换成列表 + data = map(list, result) + self.__Close() + return data + except Exception as ex: + return ex + + # 关闭连接 + def __Close(self): + self.__DB_CUR.close() + self.__DB_CONN.close() diff --git a/index.html b/index.html deleted file mode 100644 index bfb8d9505..000000000 --- a/index.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - - - -debug – 又一个WordPress站点 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - -
- -
- - -
- - - - - diff --git a/plugins/mariadb/index.py b/plugins/mariadb/index.py index 964519e2f..e8cba8947 100755 --- a/plugins/mariadb/index.py +++ b/plugins/mariadb/index.py @@ -144,10 +144,12 @@ def pSqliteDb(dbname='databases'): def pMysqlDb(): - db = mw.getMyORM() + # mysql.connector + # db = mw.getMyORM() + # MySQLdb | + db = mw.getMyORMDb() db.setDbConf(getConf()) - db.setPort(getDbPort()) db.setSocket(getSocketFile()) diff --git a/plugins/mysql-yum/index.py b/plugins/mysql-yum/index.py index d1fc6dea1..02a970347 100755 --- a/plugins/mysql-yum/index.py +++ b/plugins/mysql-yum/index.py @@ -132,7 +132,12 @@ def pSqliteDb(dbname='databases'): def pMysqlDb(): - db = mw.getMyORM() + # mysql.connector + # db = mw.getMyORM() + # MySQLdb | + db = mw.getMyORMDb() + + # db = mw.getMyORM() db.__DB_CNF = getConf() db.setPort(getDbPort()) db.setSocket(getSocketFile()) diff --git a/plugins/mysql/conf/my.cnf b/plugins/mysql/conf/my.cnf index c699ed3e3..369e55b28 100644 --- a/plugins/mysql/conf/my.cnf +++ b/plugins/mysql/conf/my.cnf @@ -35,6 +35,7 @@ open_files_limit = 65535 #skip-external-locking #loose-skip-innodb #skip-grant-tables +skip-ssl log-bin=mysql-bin diff --git a/plugins/mysql/conf/my5.7.cnf b/plugins/mysql/conf/my5.7.cnf index b0a71d37f..5053013b6 100644 --- a/plugins/mysql/conf/my5.7.cnf +++ b/plugins/mysql/conf/my5.7.cnf @@ -37,6 +37,7 @@ max_allowed_packet = 128M #loose-skip-innodb #skip-networking #skip-name-resolve +skip-ssl log-bin=mysql-bin binlog_format=mixed diff --git a/plugins/mysql/conf/my8.0.cnf b/plugins/mysql/conf/my8.0.cnf index 7e390ce92..e1e82a44a 100644 --- a/plugins/mysql/conf/my8.0.cnf +++ b/plugins/mysql/conf/my8.0.cnf @@ -38,6 +38,8 @@ max_allowed_packet = 128M #loose-skip-innodb #skip-networking #skip-name-resolve +skip-ssl + log-bin=mysql-bin binlog_format=mixed diff --git a/plugins/mysql/index.py b/plugins/mysql/index.py index d157d5db3..8aba0b894 100755 --- a/plugins/mysql/index.py +++ b/plugins/mysql/index.py @@ -134,9 +134,14 @@ def pSqliteDb(dbname='databases'): def pMysqlDb(): - db = mw.getMyORM() + # mysql.connector + # db = mw.getMyORM() + # MySQLdb | + db = mw.getMyORMDb() + db.setPort(getDbPort()) db.setSocket(getSocketFile()) + # db.setCharset("utf8") db.setPwd(pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')) return db @@ -1495,6 +1500,7 @@ def getMasterStatus(version=''): db = pMysqlDb() dlist = db.query('show slave status') + dlist = list(dlist) # print(dlist, len(dlist)) if len(dlist) > 0 and (dlist[0][10] == 'Yes' or dlist[0][11] == 'Yes'): data['slave_status'] = True diff --git a/plugins/php/versions/73/install.sh b/plugins/php/versions/73/install.sh index d330efe35..b213717e0 100755 --- a/plugins/php/versions/73/install.sh +++ b/plugins/php/versions/73/install.sh @@ -10,6 +10,10 @@ sourcePath=${serverPath}/source sysName=`uname` install_tmp=${rootPath}/tmp/mw_install.pl +function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } +function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; } +function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; } +function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } version=7.3.33 PHP_VER=73 @@ -49,6 +53,12 @@ if [ "$IS_64BIT" == "64" ];then OPTIONS="${OPTIONS} --with-libdir=lib64" fi +ZIP_OPTION='--enable-zip' +libzip_version=`pkg-config libzip --modversion` +if version_lt "$libzip_version" "0.11.0" ;then + export PKG_CONFIG_PATH=$serverPath/lib/libzip/lib/pkgconfig + ZIP_OPTION="--with-libzip=$serverPath/lib/libzip" +fi if [ ! -d $serverPath/php/73 ];then cd $sourcePath/php/php${PHP_VER} && ./configure \ @@ -60,7 +70,7 @@ if [ ! -d $serverPath/php/73 ];then --with-pdo-mysql=mysqlnd \ --with-zlib-dir=$serverPath/lib/zlib \ --enable-ftp \ - --enable-zip \ + $ZIP_OPTION\ --enable-sockets \ --enable-simplexml \ --enable-mbstring \ diff --git a/plugins/php/versions/74/install.sh b/plugins/php/versions/74/install.sh index 00bb529ed..9e93d2370 100755 --- a/plugins/php/versions/74/install.sh +++ b/plugins/php/versions/74/install.sh @@ -11,6 +11,11 @@ sysName=`uname` install_tmp=${rootPath}/tmp/mw_install.pl +function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } +function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; } +function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; } +function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } + version=7.4.26 PHP_VER=74 Install_php() @@ -22,6 +27,7 @@ mkdir -p $serverPath/php cd $serverPath/mdserver-web/plugins/php/lib && /bin/bash freetype_new.sh cd $serverPath/mdserver-web/plugins/php/lib && /bin/bash zlib.sh +cd $serverPath/mdserver-web/plugins/php/lib && /bin/bash libzip.sh if [ ! -d $sourcePath/php/php${PHP_VER} ];then @@ -49,9 +55,7 @@ if [ $sysName == 'Darwin' ]; then export LDFLAGS="-L/usr/local/opt/libxml2/lib" else OPTIONS='--without-iconv' - # OPTIONS="--with-iconv=${serverPath}/lib/libiconv" OPTIONS="${OPTIONS} --with-curl" - # OPTIONS="${OPTIONS} --with-zip=${serverPath}/lib/libzip" fi IS_64BIT=`getconf LONG_BIT` @@ -61,6 +65,14 @@ fi echo "$sourcePath/php/php${PHP_VER}" +ZIP_OPTION='--with-zip' +libzip_version=`pkg-config libzip --modversion` +if version_lt "$libzip_version" "0.11.0" ;then + export PKG_CONFIG_PATH=$serverPath/lib/libzip/lib/pkgconfig + ZIP_OPTION="--with-zip=$serverPath/lib/libzip" +fi + + if [ ! -d $serverPath/php/${PHP_VER} ];then cd $sourcePath/php/php${PHP_VER} && make clean ./buildconf --force @@ -72,7 +84,7 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then --with-mysqli=mysqlnd \ --with-pdo-mysql=mysqlnd \ --with-zlib-dir=$serverPath/lib/zlib \ - --with-zip \ + $ZIP_OPTION \ --enable-ftp \ --enable-mbstring \ --enable-sockets \ diff --git a/plugins/php/versions/80/install.sh b/plugins/php/versions/80/install.sh index 300b3654a..3d075717b 100755 --- a/plugins/php/versions/80/install.sh +++ b/plugins/php/versions/80/install.sh @@ -10,6 +10,11 @@ sourcePath=${serverPath}/source sysName=`uname` install_tmp=${rootPath}/tmp/mw_install.pl +function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } +function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; } +function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; } +function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } + version=8.0.21 PHP_VER=80 @@ -55,6 +60,13 @@ if [ "$IS_64BIT" == "64" ];then OPTIONS="${OPTIONS} --with-libdir=lib64" fi +ZIP_OPTION='--with-zip' +libzip_version=`pkg-config libzip --modversion` +if version_lt "$libzip_version" "0.11.0" ;then + export PKG_CONFIG_PATH=$serverPath/lib/libzip/lib/pkgconfig + ZIP_OPTION="--with-zip=$serverPath/lib/libzip" +fi + echo "$sourcePath/php/php${PHP_VER}" if [ ! -d $serverPath/php/${PHP_VER} ];then @@ -68,7 +80,7 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then --with-mysqli=mysqlnd \ --with-pdo-mysql=mysqlnd \ --with-zlib-dir=$serverPath/lib/zlib \ - --with-zip \ + $ZIP_OPTION \ --enable-ftp \ --enable-mbstring \ --enable-sockets \ diff --git a/plugins/php/versions/81/install.sh b/plugins/php/versions/81/install.sh index f677d84f0..0316cc29b 100755 --- a/plugins/php/versions/81/install.sh +++ b/plugins/php/versions/81/install.sh @@ -10,6 +10,11 @@ sourcePath=${serverPath}/source sysName=`uname` install_tmp=${rootPath}/tmp/mw_install.pl +function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } +function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; } +function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; } +function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } + version=8.1.8 PHP_VER=81 @@ -49,6 +54,13 @@ else OPTIONS="${OPTIONS} --with-curl" fi +ZIP_OPTION='--with-zip' +libzip_version=`pkg-config libzip --modversion` +if version_lt "$libzip_version" "0.11.0" ;then + export PKG_CONFIG_PATH=$serverPath/lib/libzip/lib/pkgconfig + ZIP_OPTION="--with-zip=$serverPath/lib/libzip" +fi + echo "$sourcePath/php/php${PHP_VER}" @@ -63,7 +75,7 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then --with-mysqli=mysqlnd \ --with-pdo-mysql=mysqlnd \ --with-zlib-dir=$serverPath/lib/zlib \ - --with-zip \ + $ZIP_OPTION \ --enable-ftp \ --enable-mbstring \ --enable-sockets \ diff --git a/plugins/php/versions/82/install.sh b/plugins/php/versions/82/install.sh index 33d3c6fad..c18779c45 100755 --- a/plugins/php/versions/82/install.sh +++ b/plugins/php/versions/82/install.sh @@ -10,6 +10,11 @@ sourcePath=${serverPath}/source sysName=`uname` install_tmp=${rootPath}/tmp/mw_install.pl +function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } +function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; } +function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; } +function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } + version=8.2.0alpha2 PHP_VER=82 @@ -50,6 +55,14 @@ if [ "$IS_64BIT" == "64" ];then OPTIONS="${OPTIONS} --with-libdir=lib64" fi +ZIP_OPTION='--with-zip' +libzip_version=`pkg-config libzip --modversion` +if version_lt "$libzip_version" "0.11.0" ;then + export PKG_CONFIG_PATH=$serverPath/lib/libzip/lib/pkgconfig + ZIP_OPTION="--with-zip=$serverPath/lib/libzip" +fi + + echo "$sourcePath/php/php${PHP_VER}" if [ ! -d $serverPath/php/${PHP_VER} ];then @@ -63,7 +76,7 @@ if [ ! -d $serverPath/php/${PHP_VER} ];then --with-mysqli=mysqlnd \ --with-pdo-mysql=mysqlnd \ --with-zlib-dir=$serverPath/lib/zlib \ - --with-zip \ + $ZIP_OPTION \ --enable-mbstring \ --enable-ftp \ --enable-sockets \ diff --git a/plugins/rsyncd/conf/config.json b/plugins/rsyncd/conf/config.json new file mode 100644 index 000000000..be3fd10a8 --- /dev/null +++ b/plugins/rsyncd/conf/config.json @@ -0,0 +1,26 @@ +{ + "receive":{ + "default":{ + "uid": "root", + "use chroot": "no", + "dont compress": "*.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 *.mp4 *.avi *.swf *.rar", + "hosts allow": "", + "max connections": 200, + "gid": "root", + "timeout": 600, + "pid file": "/var/run/rsyncd.pid", + "log file": "/var/log/rsyncd.log", + "port": 873 + }, + "list":[] + }, + "send":{ + "default":{ + "logfile": "/www/server/rsyncd/lsyncd.log", + "inotifyMode": "CloseWrite", + "maxProcesses": 8, + "statusFile": "/www/server/rsyncd/lsyncd.status" + }, + "list":[] + } +} \ No newline at end of file diff --git a/plugins/rsyncd/conf/lsyncd.conf b/plugins/rsyncd/conf/lsyncd.conf new file mode 100644 index 000000000..b2ed2416f --- /dev/null +++ b/plugins/rsyncd/conf/lsyncd.conf @@ -0,0 +1,6 @@ +settings { + logfile = "{$SERVER_PATH}/rsyncd/lsyncd.log", + inotifyMode = "CloseWrite", + maxProcesses = 8, + statusFile = "{$SERVER_PATH}/rsyncd/lsyncd.status" +} \ No newline at end of file diff --git a/plugins/rsyncd/conf/rsyncd.conf b/plugins/rsyncd/conf/rsyncd.conf index f880ee235..43d17f270 100644 --- a/plugins/rsyncd/conf/rsyncd.conf +++ b/plugins/rsyncd/conf/rsyncd.conf @@ -5,5 +5,4 @@ max connections = 100 log file = /var/log/rsyncd.log pid file = /var/run/rsyncd.pid list = false -hosts allow = * -secrets file = /etc/rsyncd.passwd \ No newline at end of file +hosts allow = * \ No newline at end of file diff --git a/plugins/rsyncd/index.html b/plugins/rsyncd/index.html index be8c4a452..7886ef458 100755 --- a/plugins/rsyncd/index.html +++ b/plugins/rsyncd/index.html @@ -1,12 +1,79 @@ +

服务

自启动

-

配置修改

-

密钥配置

+

发送配置

接收配置

-

日志

说明

@@ -16,8 +83,12 @@
\ No newline at end of file diff --git a/plugins/rsyncd/index.py b/plugins/rsyncd/index.py index d5be125c5..d1fb9f91e 100755 --- a/plugins/rsyncd/index.py +++ b/plugins/rsyncd/index.py @@ -73,18 +73,24 @@ def status(): "ps -ef|grep rsync |grep -v grep | grep -v python | awk '{print $2}'") if data[0] == '': return 'stop' + + # data = mw.execShell( + # "ps -ef|grep lsyncd |grep -v grep | grep -v python | awk '{print $2}'") + # if data[0] == '': + # return 'stop' + return 'start' def appConf(): return getServerDir() + '/rsyncd.conf' - # return '/etc/rsyncd.conf' -def appConfPwd(): - # if mw.isAppleSystem(): - return getServerDir() + '/rsyncd.passwd' - # return '/etc/rsyncd.passwd' +def appAuthPwd(name): + nameDir = getServerDir() + '/receive/' + name + if not os.path.exists(nameDir): + mw.execShell("mkdir -p " + nameDir) + return nameDir + '/auth.db' def getLog(): @@ -97,8 +103,17 @@ def getLog(): return tmp.groups()[0] -def initDreplace(): +def getLsyncdLog(): + path = getServerDir() + "/lsyncd.conf" + conf = mw.readFile(path) + rep = 'logfile\s*=\s*\"(.*)\"' + tmp = re.search(rep, conf) + if not tmp: + return '' + return tmp.groups()[0] + +def initDReceive(): # conf conf_path = appConf() conf_tpl_path = getPluginDir() + '/conf/rsyncd.conf' @@ -106,18 +121,13 @@ def initDreplace(): content = mw.readFile(conf_tpl_path) mw.writeFile(conf_path, content) - # pwd - confpwd_path = appConfPwd() - if not os.path.exists(confpwd_path): - mw.writeFile(confpwd_path, '') - mw.execShell('chmod 0600 ' + confpwd_path) - initD_path = getServerDir() + '/init.d' if not os.path.exists(initD_path): os.mkdir(initD_path) - file_bin = initD_path + '/' + getPluginName() + file_bin = initD_path + '/' + getPluginName() file_tpl = getInitDTpl() + # print(file_bin, file_tpl) # initd replace if not os.path.exists(file_bin): content = mw.readFile(file_tpl) @@ -132,14 +142,14 @@ def initDreplace(): if os.path.exists(systemDir) and not os.path.exists(systemService): rsync_bin = mw.execShell('which rsync')[0].strip() if rsync_bin == '': - print('rsync缺失!') + print('rsync missing!') exit(0) service_path = mw.getServerDir() - se_content = mw.readFile(systemServiceTpl) - se_content = se_content.replace('{$SERVER_PATH}', service_path) - se_content = se_content.replace('{$RSYNC_BIN}', rsync_bin) - mw.writeFile(systemService, se_content) + se = mw.readFile(systemServiceTpl) + se = se.replace('{$SERVER_PATH}', service_path) + se = se.replace('{$RSYNC_BIN}', rsync_bin) + mw.writeFile(systemService, se) mw.execShell('systemctl daemon-reload') rlog = getLog() @@ -148,6 +158,89 @@ def initDreplace(): return file_bin +def initDSend(): + + service_path = mw.getServerDir() + + conf_path = getServerDir() + '/lsyncd.conf' + conf_tpl_path = getPluginDir() + '/conf/lsyncd.conf' + if not os.path.exists(conf_path): + content = mw.readFile(conf_tpl_path) + content = content.replace('{$SERVER_PATH}', service_path) + mw.writeFile(conf_path, content) + + initD_path = getServerDir() + '/init.d' + if not os.path.exists(initD_path): + os.mkdir(initD_path) + + # initd replace + file_bin = initD_path + '/lsyncd' + file_tpl = getPluginDir() + "/init.d/lsyncd.tpl" + if not os.path.exists(file_bin): + content = mw.readFile(file_tpl) + content = contentReplace(content) + mw.writeFile(file_bin, content) + mw.execShell('chmod +x ' + file_bin) + + lock_file = getServerDir() + "/installed.pl" + # systemd + systemDir = mw.systemdCfgDir() + systemService = systemDir + '/lsyncd.service' + systemServiceTpl = getPluginDir() + '/init.d/lsyncd.service.tpl' + if not os.path.exists(lock_file): + lsyncd_bin = mw.execShell('which lsyncd')[0].strip() + if lsyncd_bin == '': + print('lsyncd missing!') + exit(0) + + content = mw.readFile(systemServiceTpl) + content = content.replace('{$SERVER_PATH}', service_path) + content = content.replace('{$LSYNCD_BIN}', lsyncd_bin) + mw.writeFile(systemService, content) + mw.execShell('systemctl daemon-reload') + + mw.writeFile(lock_file, "ok") + + lslog = getLsyncdLog() + if os.path.exists(lslog): + mw.writeFile(lslog, '') + + return file_bin + + +def getDefaultConf(): + path = getServerDir() + "/config.json" + data = mw.readFile(path) + data = json.loads(data) + return data + + +def setDefaultConf(data): + path = getServerDir() + "/config.json" + mw.writeFile(path, json.dumps(data)) + return True + + +def initConfigJson(): + path = getServerDir() + "/config.json" + tpl = getPluginDir() + "/conf/config.json" + if not os.path.exists(path): + data = mw.readFile(tpl) + data = json.loads(data) + mw.writeFile(path, json.dumps(data)) + + +def initDreplace(): + + initDSend() + + # conf + file_bin = initDReceive() + initConfigJson() + + return file_bin + + def rsyncOp(method): file = initDreplace() if not mw.isAppleSystem(): @@ -186,6 +279,12 @@ def initdStatus(): data = mw.execShell(shell_cmd) if data[0] == '': return 'fail' + + shell_cmd = 'systemctl status lsyncd | grep loaded | grep "enabled;"' + data = mw.execShell(shell_cmd) + if data[0] == '': + return 'fail' + return 'ok' @@ -193,6 +292,7 @@ def initdInstall(): if mw.isAppleSystem(): return "Apple Computer does not support" + mw.execShell('systemctl enable lsyncd') mw.execShell('systemctl enable rsyncd') return 'ok' @@ -202,6 +302,7 @@ def initdUinstall(): if mw.isAppleSystem(): return "Apple Computer does not support" + mw.execShell('systemctl diable lsyncd') mw.execShell('systemctl diable rsyncd') return 'ok' @@ -211,6 +312,7 @@ def getRecListData(): content = mw.readFile(path) flist = re.findall("\[(.*)\]", content) + flist_len = len(flist) ret_list = [] for i in range(flist_len): @@ -226,31 +328,27 @@ def getRecListData(): t1 = re.search(reg, content, re.S) if t1: args = t1.groups()[0] - # print 'args start', args, 'args_end' - t2 = re.findall('\s*(.*)\s*=\s*(.*)', args, re.M) + # print('args start', args, 'args_end') + t2 = re.findall('\s*(.*)\s*\=\s*?(.*)?', args, re.M | re.I) for i in range(len(t2)): - tmp[t2[i][0].strip()] = t2[i][1] + tmp[t2[i][0].strip()] = t2[i][1].strip() ret_list.append(tmp) + return ret_list +def getRecListDataBy(name): + l = getRecListData() + for x in range(len(l)): + if name == l[x]["name"]: + return l[x] + + def getRecList(): ret_list = getRecListData() return mw.returnJson(True, 'ok', ret_list) -def getUPwdList(): - pwd_path = appConfPwd() - pwd_content = mw.readFile(pwd_path) - plist = pwd_content.strip().split('\n') - plist_len = len(plist) - data = {} - for x in range(plist_len): - tmp = plist[x].split(':') - data[tmp[0]] = tmp[1] - return data - - def addRec(): args = getArgs() data = checkArgs(args, ['name', 'path', 'pwd', 'ps']) @@ -262,10 +360,12 @@ def addRec(): args_path = args['path'] args_ps = args['ps'] - pwd_path = appConfPwd() - pwd_content = mw.readFile(pwd_path) - pwd_content += args_name + ':' + args_pwd + "\n" - mw.writeFile(pwd_path, pwd_content) + delRecBy(args_name) + + auth_path = appAuthPwd(args_name) + pwd_content = args_name + ':' + args_pwd + "\n" + mw.writeFile(auth_path, pwd_content) + mw.execShell("chmod 600 " + auth_path) path = appConf() content = mw.readFile(path) @@ -274,71 +374,498 @@ def addRec(): con += 'path = ' + args_path + "\n" con += 'comment = ' + args_ps + "\n" con += 'auth users = ' + args_name + "\n" + con += 'ignore errors' + "\n" + con += 'secrets file = ' + auth_path + "\n" con += 'read only = false' - content = content + con + content = content.strip() + "\n" + con mw.writeFile(path, content) return mw.returnJson(True, '添加成功') -def delRec(): +def getRec(): args = getArgs() data = checkArgs(args, ['name']) if not data[0]: return data[1] - args_name = args['name'] - cmd = "sed -i '_bak' '/" + args_name + "/d' " + appConfPwd() - mw.execShell(cmd) + name = args['name'] - try: + if name == "": + tmp = {} + tmp["name"] = "" + tmp["comment"] = "" + tmp["path"] = mw.getWwwDir() + tmp["pwd"] = mw.getRandomString(16) + return mw.returnJson(True, 'OK', tmp) + + data = getRecListDataBy(name) + + content = mw.readFile(data['secrets file']) + pwd = content.strip().split(":") + data['pwd'] = pwd[1] + return mw.returnJson(True, 'OK', data) + +def delRecBy(name): + try: path = appConf() content = mw.readFile(path) - ret_list = getRecListData() - ret_list_len = len(ret_list) + reclist = getRecListData() + ret_list_len = len(reclist) is_end = False next_name = '' for x in range(ret_list_len): - tmp = ret_list[x] - if tmp['name'] == args_name: + tmp = reclist[x] + if tmp['name'] == name: + + secrets_file = tmp['secrets file'] + tp = os.path.dirname(secrets_file) + if os.path.exists(tp): + mw.execShell("rm -rf " + tp) + if x + 1 == ret_list_len: is_end = True else: - next_name = ret_list[x + 1]['name'] + next_name = reclist[x + 1]['name'] reg = '' if is_end: - reg = '\[' + args_name + '\]\s*(.*)' + reg = '\[' + name + '\]\s*(.*)' else: - reg = '\[' + args_name + '\]\s*(.*)\s*\[' + next_name + '\]' + reg = '\[' + name + '\]\s*(.*)\s*\[' + next_name + '\]' conre = re.search(reg, content, re.S) content = content.replace( - "[" + args_name + "]\n" + conre.groups()[0], '') + "[" + name + "]\n" + conre.groups()[0], '') mw.writeFile(path, content) - return mw.returnJson(True, '删除成功!') except Exception as e: - return mw.returnJson(False, '删除失败!') + return False + return True -def cmdRec(): +def delRec(): args = getArgs() data = checkArgs(args, ['name']) if not data[0]: return data[1] + name = args['name'] + ok = delRecBy(name) + if ok: + return mw.returnJson(True, '删除成功!') + return mw.returnJson(False, '删除失败!') - an = args['name'] - pwd_list = getUPwdList() + +def cmdRecSecretKey(): + import base64 + + args = getArgs() + data = checkArgs(args, ['name']) + if not data[0]: + return data[1] + + name = args['name'] + info = getRecListDataBy(name) + + secrets_file = info['secrets file'] + content = mw.readFile(info['secrets file']) + pwd = content.strip().split(":") + + m = {"A": info['name'], "B": pwd[1], "C": "873"} + m = json.dumps(m) + m = m.encode("utf-8") + m = base64.b64encode(m) + cmd = m.decode("utf-8") + return mw.returnJson(True, 'OK!', cmd) + + +def cmdRecCmd(): + args = getArgs() + data = checkArgs(args, ['name']) + if not data[0]: + return data[1] + + name = args['name'] + info = getRecListDataBy(name) ip = mw.getLocalIp() - cmd = 'echo "' + pwd_list[an] + '" > /tmp/p.pass' + "
" - cmd += 'chmod 600 /tmp/p.pass' + "
" - cmd += 'rsync -arv --password-file=/tmp/p.pass --progress --delete /project ' + \ - an + '@' + ip + '::' + an + content = mw.readFile(info['secrets file']) + pwd = content.strip().split(":") + + tmp_name = '/tmp/' + name + '.pass' + + cmd = 'echo "' + pwd[1] + '" > ' + tmp_name + '
' + cmd += 'chmod 600 ' + tmp_name + '
' + cmd += 'rsync -arv --password-file=' + tmp_name + \ + ' --progress --delete /project ' + name + '@' + ip + '::' + name return mw.returnJson(True, 'OK!', cmd) -# rsyncdReceive + +# ----------------------------- rsyncdSend start ------------------------- + + +def lsyncdReload(): + mw.execShell('systemctl reload lsyncd') + + +def makeLsyncdConf(data): + # print(data) + + lsyncd_data = data['send'] + lsyncd_setting = lsyncd_data['default'] + + content = "settings {\n" + for x in lsyncd_setting: + v = lsyncd_setting[x] + # print(v, type(v)) + if type(v) == str: + content += "\t" + x + ' = "' + v + "\",\n" + elif type(v) == int: + content += "\t" + x + ' = ' + str(v) + ",\n" + content += "}\n\n" + + lsyncd_list = lsyncd_data['list'] + + rsync_bin = mw.execShell('which rsync')[0].strip() + send_dir = getServerDir() + "/send" + + if len(lsyncd_list) > 0: + for x in range(len(lsyncd_list)): + + t = lsyncd_list[x] + name_dir = send_dir + "/" + t["name"] + if not os.path.exists(name_dir): + mw.execShell("mkdir -p " + name_dir) + + cmd_exclude = name_dir + "/exclude" + cmd_exclude_txt = "" + for x in t['exclude']: + cmd_exclude_txt += x + "\n" + mw.writeFile(cmd_exclude, cmd_exclude_txt) + cmd_pass = name_dir + "/pass" + mw.writeFile(cmd_pass, t['password']) + mw.execShell("chmod 600 " + cmd_pass) + + delete_ok = ' ' + if t['delete'] == "true": + delete_ok = ' --delete ' + + remote_addr = t['name'] + '@' + t['ip'] + "::" + t['name'] + cmd = rsync_bin + " -avzP " + "--port=" + str(t['rsync']['port']) + " --bwlimit=" + t['rsync'][ + 'bwlimit'] + delete_ok + " --exclude-from=" + cmd_exclude + " --password-file=" + cmd_pass + " " + t["path"] + " " + remote_addr + mw.writeFile(name_dir + "/cmd", cmd) + mw.execShell("cmod +x " + name_dir + "/cmd") + + if t['realtime'] == "false": + continue + + # print(x, t) + content += "sync {\n" + content += "\tdefault.rsync,\n" + content += "\tsource = \"" + t['path'] + "\",\n" + content += "\ttarget = \"" + remote_addr + "\",\n" + content += "\tdelete = " + t['delete'] + ",\n" + content += "\tdelay = " + t['delay'] + ",\n" + content += "\tinit = false,\n" + + exclude_str = json.dumps(t['exclude']) + exclude_str = exclude_str.replace("[", "{") + exclude_str = exclude_str.replace("]", "}") + # print(exclude_str) + content += "\texclude = " + exclude_str + ",\n" + + # rsync + content += "\trsync = {\n" + content += "\t\tbinary = \"" + rsync_bin + "\",\n" + content += "\t\tarchive = true,\n" + content += "\t\tverbose = true,\n" + content += "\t\tcompress = " + t['rsync']['compress'] + ",\n" + content += "\t\tpassword_file = \"" + cmd_pass + "\",\n" + + content += "\t\t_extra = {\"--bwlimit=" + t['rsync'][ + 'bwlimit'] + "\", \"--port=" + str(t['rsync']['port']) + "\"},\n" + + content += "\t}\n" + content += "}\n" + + path = getServerDir() + "/lsyncd.conf" + mw.writeFile(path, content) + + lsyncdReload() + + import tool_task + tool_task.createBgTask(lsyncd_list) + + +def lsyncdListFindIp(slist, ip): + for x in range(len(slist)): + if slist[x]["ip"] == ip: + return (True, x) + return (False, -1) + + +def lsyncdListFindName(slist, name): + for x in range(len(slist)): + if slist[x]["name"] == name: + return (True, x) + return (False, -1) + + +def lsyncdList(): + data = getDefaultConf() + send = data['send'] + return mw.returnJson(True, "设置成功!", send) + + +def lsyncdGet(): + import base64 + args = getArgs() + data = checkArgs(args, ['name']) + if not data[0]: + return data[1] + + name = args['name'] + data = getDefaultConf() + + slist = data['send']["list"] + res = lsyncdListFindName(slist, name) + + rsync = { + 'bwlimit': "1024", + "compress": "true", + "archive": "true", + "verbose": "true" + } + + info = { + "secret_key": '', + "ip": '', + "path": mw.getServerDir(), + 'rsync': rsync, + 'realtime': "true", + 'delete': "false", + } + if res[0]: + list_index = res[1] + info = slist[list_index] + m = {"A": info['name'], "B": info["password"], "C": "873"} + m = json.dumps(m) + m = m.encode("utf-8") + m = base64.b64encode(m) + info['secret_key'] = m.decode("utf-8") + return mw.returnJson(True, "OK", info) + + +def lsyncdDelete(): + args = getArgs() + data = checkArgs(args, ['name']) + if not data[0]: + return data[1] + + name = args['name'] + data = getDefaultConf() + slist = data['send']["list"] + res = lsyncdListFindName(slist, name) + retdata = {} + if res[0]: + list_index = res[1] + slist.pop(list_index) + + data['send']["list"] = slist + setDefaultConf(data) + makeLsyncdConf(data) + return mw.returnJson(True, "OK") + + +def lsyncdAdd(): + import base64 + + args = getArgs() + data = checkArgs(args, ['ip', 'conn_type', 'path', + 'secret_key', 'delay', 'period']) + if not data[0]: + return data[1] + + ip = args['ip'] + path = args['path'] + + conn_type = args['conn_type'] + secret_key = args['secret_key'] + delete = args['delete'] + realtime = args['realtime'] + delay = args['delay'] + bwlimit = args['bwlimit'] + compress = args['compress'] + period = args['period'] + + hour = args['hour'] + minute = args['minute'] + minute_n = args['minute-n'] + + info = { + "ip": ip, + "path": path, + "delete": delete, + "realtime": realtime, + 'delay': delay, + "conn_type": conn_type, + "period": period, + "hour": hour, + "minute": minute, + "minute-n": minute_n, + } + + if conn_type == "key": + try: + m = base64.b64decode(secret_key) + m = json.loads(m) + info['name'] = m['A'] + info['password'] = m['B'] + info['port'] = m['C'] + except Exception as e: + return mw.returnJson(False, "接收密钥格式错误!") + else: + data = checkArgs(args, ['uname']) + if not data[0]: + return data[1] + + info['name'] = args['uname'] + info['password'] = args['uname'] + + rsync = { + 'bwlimit': bwlimit, + "port": info['port'], + "compress": compress, + "archive": "true", + "verbose": "true" + } + + info['rsync'] = rsync + + if not 'exclude' in info: + info["exclude"] = [ + "/**.upload.tmp", + "**/*.log", + "**/*.tmp", + "**/*.temp", + ".git", + ".gitignore", + ".user.ini", + ] + + data = getDefaultConf() + slist = data['send']["list"] + res = lsyncdListFindName(slist, info['name']) + if res[0]: + list_index = res[1] + slist[list_index] = info + else: + slist.append(info) + + data['send']["list"] = slist + + setDefaultConf(data) + makeLsyncdConf(data) + return mw.returnJson(True, "设置成功!") + + +def lsyncdRun(): + args = getArgs() + data = checkArgs(args, ['name']) + if not data[0]: + return data[1] + + send_dir = getServerDir() + "/send" + name = args['name'] + app_dir = send_dir + "/" + name + + cmd = "bash " + app_dir + "/cmd >> " + app_dir + "/run.log" + " 2>&1 &" + mw.execShell(cmd) + return mw.returnJson(True, "执行成功!") + + +def lsyncdConfLog(): + logs_path = getServerDir() + "/lsyncd.log" + return logs_path + + +def lsyncdLog(): + args = getArgs() + data = checkArgs(args, ['name']) + if not data[0]: + return data[1] + + send_dir = getServerDir() + "/send" + name = args['name'] + app_dir = send_dir + "/" + name + return app_dir + "/run.log" + + +def lsyncdGetExclude(): + args = getArgs() + data = checkArgs(args, ['name']) + if not data[0]: + return data[1] + + data = getDefaultConf() + slist = data['send']["list"] + res = lsyncdListFindName(slist, args['name']) + i = res[1] + info = slist[i] + return mw.returnJson(True, "OK!", info['exclude']) + + +def lsyncdRemoveExclude(): + args = getArgs() + data = checkArgs(args, ['name', 'exclude']) + if not data[0]: + return data[1] + + exclude = args['exclude'] + + data = getDefaultConf() + slist = data['send']["list"] + res = lsyncdListFindName(slist, args['name']) + i = res[1] + info = slist[i] + + exclude_list = info['exclude'] + exclude_pop_key = -1 + for x in range(len(exclude_list)): + if exclude_list[x] == exclude: + exclude_pop_key = x + + if exclude_pop_key > -1: + exclude_list.pop(exclude_pop_key) + + data['send']["list"][i]['exclude'] = exclude_list + setDefaultConf(data) + makeLsyncdConf(data) + return mw.returnJson(True, "OK!", exclude_list) + + +def lsyncdAddExclude(): + args = getArgs() + data = checkArgs(args, ['name', 'exclude']) + if not data[0]: + return data[1] + + exclude = args['exclude'] + + data = getDefaultConf() + slist = data['send']["list"] + res = lsyncdListFindName(slist, args['name']) + i = res[1] + info = slist[i] + + exclude_list = info['exclude'] + exclude_list.append(exclude) + + data['send']["list"][i]['exclude'] = exclude_list + setDefaultConf(data) + makeLsyncdConf(data) + return mw.returnJson(True, "OK!", exclude_list) + if __name__ == "__main__": func = sys.argv[1] if func == 'status': @@ -359,8 +886,6 @@ if __name__ == "__main__": print(initdUinstall()) elif func == 'conf': print(appConf()) - elif func == 'conf_pwd': - print(appConfPwd()) elif func == 'run_log': print(getLog()) elif func == 'rec_list': @@ -369,7 +894,31 @@ if __name__ == "__main__": print(addRec()) elif func == 'del_rec': print(delRec()) - elif func == 'cmd_rec': - print(cmdRec()) + elif func == 'get_rec': + print(getRec()) + elif func == 'cmd_rec_secret_key': + print(cmdRecSecretKey()) + elif func == 'cmd_rec_cmd': + print(cmdRecCmd()) + elif func == 'lsyncd_list': + print(lsyncdList()) + elif func == 'lsyncd_add': + print(lsyncdAdd()) + elif func == 'lsyncd_get': + print(lsyncdGet()) + elif func == 'lsyncd_delete': + print(lsyncdDelete()) + elif func == 'lsyncd_run': + print(lsyncdRun()) + elif func == 'lsyncd_log': + print(lsyncdLog()) + elif func == 'lsyncd_conf_log': + print(lsyncdConfLog()) + elif func == 'lsyncd_get_exclude': + print(lsyncdGetExclude()) + elif func == 'lsyncd_remove_exclude': + print(lsyncdRemoveExclude()) + elif func == 'lsyncd_add_exclude': + print(lsyncdAddExclude()) else: print('error') diff --git a/plugins/rsyncd/info.json b/plugins/rsyncd/info.json index c23d4247b..3ab33843a 100755 --- a/plugins/rsyncd/info.json +++ b/plugins/rsyncd/info.json @@ -5,7 +5,7 @@ "name":"rsyncd", "type":"软件", "ps":"rsyncd同步助手", - "versions":"1.0", + "versions":"2.0", "shell":"install.sh", "checks":"server/rsyncd", "path": "server/rsyncd", diff --git a/plugins/rsyncd/init.d/lsyncd.service.tpl b/plugins/rsyncd/init.d/lsyncd.service.tpl new file mode 100755 index 000000000..7c6a03c60 --- /dev/null +++ b/plugins/rsyncd/init.d/lsyncd.service.tpl @@ -0,0 +1,10 @@ +[Unit] +Description=Lightweight inotify based sync daemon +ConditionPathExists={$SERVER_PATH}/rsyncd/lsyncd.conf + +[Service] +Type=simple +ExecStart={$LSYNCD_BIN} -nodaemon {$SERVER_PATH}/rsyncd/lsyncd.conf + +[Install] +WantedBy=multi-user.target diff --git a/plugins/rsyncd/init.d/lsyncd.tpl b/plugins/rsyncd/init.d/lsyncd.tpl new file mode 100755 index 000000000..a5ccdcad6 --- /dev/null +++ b/plugins/rsyncd/init.d/lsyncd.tpl @@ -0,0 +1,108 @@ +#!/bin/bash +# +# chkconfig: - 85 15 +# description: Lightweight inotify based sync daemon +# +# processname: lsyncd +# config: /etc/lsyncd.conf +# config: /etc/sysconfig/lsyncd +# pidfile: /var/run/lsyncd.pid +# Source function library + +if [ -f /etc/init.d/functions ];then + . /etc/init.d/functions +fi + +if [ -f /lib/lsb/init-functions ];then + . /lib/lsb/init-functions +fi + +# Source networking configuration. +if [ -f /etc/sysconfig/network ];then + . /etc/sysconfig/network +fi + +LSYNCD_OPTIONS="-pidfile /var/run/lsyncd.pid {$SERVER_PATH}/rsyncd/lsyncd.conf" +if [ -e /etc/sysconfig/lsyncd ]; then + . /etc/sysconfig/lsyncd +fi +RETVAL=0 +prog="lsyncd" +thelock=/var/lock/subsys/lsyncd +LSYNCD_USER=root + +start() { + [ -f {$SERVER_PATH}/rsyncd/lsyncd.conf ] || exit 6 + echo -n $"Starting $prog: " + if [ $UID -ne 0 ]; then + RETVAL=1 + failure + else + nohup /usr/bin/lsyncd $LSYNCD_OPTIONS > /dev/null & + RETVAL=$? + [ $RETVAL -eq 0 ] && touch $thelock + fi; + echo + return $RETVAL +} + +stop() { + echo -n $"Stopping $prog: " + if [ $UID -ne 0 ]; then + RETVAL=1 + failure + else + killproc lsyncd + RETVAL=$? + [ $RETVAL -eq 0 ] && rm -f $thelock + fi; + echo + return $RETVAL +} + +reload(){ + echo -n $"Reloading $prog: " + killproc lsyncd -HUP + RETVAL=$? + echo + return $RETVAL +} + +restart(){ + stop + start +} + +condrestart(){ + [ -e $thelock ] && restart + return 0 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + + restart) + restart + ;; + reload) + reload + ;; + condrestart) + condrestart + ;; + + status) + status lsyncd + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}" + RETVAL=1 +esac + +exit $RETVAL diff --git a/plugins/rsyncd/install.sh b/plugins/rsyncd/install.sh index bf574b182..cd46f0902 100755 --- a/plugins/rsyncd/install.sh +++ b/plugins/rsyncd/install.sh @@ -14,25 +14,35 @@ sysName=`uname` # bash /www/server/mdsever-web/scripts/getos.sh bash ${rootPath}/scripts/getos.sh OSNAME=`cat ${rootPath}/data/osname.pl` -VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'` +echo $OSNAME install_tmp=${rootPath}/tmp/mw_install.pl Install_rsyncd() { echo '正在安装脚本文件...' > $install_tmp - mkdir -p $serverPath/rsyncd + if [ "$OSNAME" == "debian'" ] || [ "$OSNAME" == "ubuntu'" ];then apt install -y rsync + apt install -y lsyncd elif [[ "$OSNAME" == "arch" ]]; then echo y | pacman -Sy rsync + echo y | pacman -Sy lsyncd + elif [[ "$OSNAME" == "macos" ]]; then + # brew install rsync + # brew install lsyncd + echo "ok" else yum install -y rsync + yum install -y lsyncd fi + mkdir -p $serverPath/rsyncd + mkdir -p $serverPath/rsyncd/receive + mkdir -p $serverPath/rsyncd/send - echo '1.0' > $serverPath/rsyncd/version.pl + echo '2.0' > $serverPath/rsyncd/version.pl echo '安装完成' > $install_tmp cd ${rootPath} && python3 ${rootPath}/plugins/rsyncd/index.py start cd ${rootPath} && python3 ${rootPath}/plugins/rsyncd/index.py initd_install @@ -51,6 +61,7 @@ Uninstall_rsyncd() if [ -f $serverPath/rsyncd/initd/rsyncd ];then $serverPath/rsyncd/initd/rsyncd stop fi + rm -rf $serverPath/rsyncd echo "卸载完成" > $install_tmp } diff --git a/plugins/rsyncd/js/base64.js b/plugins/rsyncd/js/base64.js new file mode 100644 index 000000000..4a5caa2a7 --- /dev/null +++ b/plugins/rsyncd/js/base64.js @@ -0,0 +1,149 @@ +//base64.js +function base64_encode(str) { + var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var out, i, len; + var c1, c2, c3; + + len = str.length; + i = 0; + out = ""; + while(i < len) { + c1 = str.charCodeAt(i++) & 0xff; + if(i == len) + { + out += base64EncodeChars.charAt(c1 >> 2); + out += base64EncodeChars.charAt((c1 & 0x3) << 4); + out += "=="; + break; + } + c2 = str.charCodeAt(i++); + if(i == len) + { + out += base64EncodeChars.charAt(c1 >> 2); + out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); + out += base64EncodeChars.charAt((c2 & 0xF) << 2); + out += "="; + break; + } + c3 = str.charCodeAt(i++); + out += base64EncodeChars.charAt(c1 >> 2); + out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); + out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)); + out += base64EncodeChars.charAt(c3 & 0x3F); + } + return out; +} + +function base64_decode(str) { + var base64DecodeChars = new Array( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1); + var c1, c2, c3, c4; + var i, len, out; + + len = str.length; + i = 0; + out = ""; + while(i < len) { + /* c1 */ + do { + c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; + } while(i < len && c1 == -1); + if(c1 == -1) + break; + + /* c2 */ + do { + c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; + } while(i < len && c2 == -1); + if(c2 == -1) + break; + + out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); + + /* c3 */ + do { + c3 = str.charCodeAt(i++) & 0xff; + if(c3 == 61) + return out; + c3 = base64DecodeChars[c3]; + } while(i < len && c3 == -1); + if(c3 == -1) + break; + + out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); + + /* c4 */ + do { + c4 = str.charCodeAt(i++) & 0xff; + if(c4 == 61) + return out; + c4 = base64DecodeChars[c4]; + } while(i < len && c4 == -1); + if(c4 == -1) + break; + out += String.fromCharCode(((c3 & 0x03) << 6) | c4); + } + return out; +} + +function utf16to8(str) { + var out, i, len, c; + + out = ""; + len = str.length; + for(i = 0; i < len; i++) { + c = str.charCodeAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) { + out += str.charAt(i); + } else if (c > 0x07FF) { + out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); + out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); + } else { + out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); + out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); + } + } + return out; +} + +function utf8to16(str) { + var out, i, len, c; + var char2, char3; + + out = ""; + len = str.length; + i = 0; + while(i < len) { + c = str.charCodeAt(i++); + switch(c >> 4) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + // 0xxxxxxx + out += str.charAt(i-1); + break; + case 12: case 13: + // 110x xxxx 10xx xxxx + char2 = str.charCodeAt(i++); + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + char2 = str.charCodeAt(i++); + char3 = str.charCodeAt(i++); + out += String.fromCharCode(((c & 0x0F) << 12) | + ((char2 & 0x3F) << 6) | + ((char3 & 0x3F) << 0)); + break; + } + } + + return out; +} \ No newline at end of file diff --git a/plugins/rsyncd/js/rsyncd.js b/plugins/rsyncd/js/rsyncd.js index ae8d2d9a8..e70a76e54 100755 --- a/plugins/rsyncd/js/rsyncd.js +++ b/plugins/rsyncd/js/rsyncd.js @@ -36,6 +36,542 @@ function rsPost(method,args,callback, title){ },'json'); } +///////////////// ----------------- 发送配置 ---------------- ////////////// + +function createSendTask(name = ''){ + var args = {}; + args["name"] = name; + rsPost('lsyncd_get', args, function(rdata){ + var rdata = $.parseJSON(rdata.data); + var data = rdata.data; + console.log(data); + + var layerName = '创建'; + if (name!=''){ + layerName = '编辑'; + } + + var compress_true = ""; + var compress_false = ""; + if (data['rsync']['compress'] == 'true'){ + compress_true = "selected"; + compress_false = ""; + } else { + compress_true = ""; + compress_false = "selected"; + } + + + var delete_true = ""; + var delete_false = ""; + if (data['delete'] == 'false'){ + delete_true = "selected"; + delete_false = ""; + } else { + delete_true = ""; + delete_false = "selected"; + } + + + var realtime_true = ""; + var realtime_false = ""; + if (data['realtime'] == 'true'){ + realtime_true = "selected"; + realtime_false = ""; + } else { + realtime_true = ""; + realtime_false = "selected"; + } + + + var period_day = ""; + var period_minute_n = ""; + if (data['period'] == 'day'){ + period_day = "selected"; + period_minute_n = ""; + } else { + period_day = ""; + period_minute_n = "selected"; + } + + + var layerID = layer.open({ + type: 1, + area: ['600px','500px'], + title: layerName+"发送任务", + closeBtn: 1, + shift: 0, + shadeClose: false, + btn: ['提交','取消'], + content:"
\ +
\ + 服务器IP\ +
\ + \ +
\ +
\ +
\ + 同步目录\ +
\ + \ + ?\ +
\ +
\ +
\ + 同步方式\ +
\ + \ + ?\ + 同步周期\ + \ +
\ +
\ + \ +
\ + 限速\ +
\ + KB\ + ?\ + 延迟 秒\ + ?\ +
\ +
\ +
\ + 连接方式\ +
\ + \ + 压缩传输\ + \ + ?\ +
\ +
\ +
\ + 接收密钥\ +
\ + \ +
\ +
\ +
\ + 用户名\ +
\ + \ +
\ +
\ +
\ + 密码\ +
\ + \ +
\ +
\ +
\ + 端口\ +
\ + \ +
\ +
\ +
    \ +
\ +
", + success:function(){ + $('[data-toggle="tooltip"]').tooltip(); + + $(".conn-user").hide(); + $("select[name='conn_type']").change(function(){ + if($(this).val() == 'key'){ + $(".conn-user").hide(); + $(".conn-key").show(); + }else{ + $(".conn-user").show(); + $(".conn-key").hide(); + } + }); + + + var selVal = $('.synchronization option:selected').val(); + if (selVal == "false"){ + $('#period').show(); + }else{ + $('#period').hide(); + $('.hour input,.minute input').val('0'); + $('.minute-n input').val('1'); + } + $('.synchronization').change(function(event) { + var selVal = $('.synchronization option:selected').val(); + if (selVal == "false"){ + $('#period').show(); + }else{ + $('#period').hide(); + $('.hour input,.minute input').val('0'); + $('.minute-n input').val('1'); + } + }); + + $("select[name='delete']").change(function(){ + if($(this).val() == 'true'){ + var mpath = $('input[name="path"]').val(); + var msg = '
警告:您选择了完全同步,将会使本机同步与目标机器指定目录的文件保持一致,' + +'
请确认目录设置是否有误,一但设置错误,可能导致目标机器的目录文件被删除!
' + +'

注意: 同步程序将本机目录:' + +mpath+'的所有数据同步到目标服务器,若目标服务器的同步目录存在其它文件将被删除!

已了解风险,请按确定继续
'; + + layer.confirm(msg,{title:'数据安全风险警告',icon:2,closeBtn: 1,shift: 5, + btn2:function(){ + setTimeout(function(){$($("select[name='delete']").children("option")[0]).prop('selected',true);},100); + } + }); + } + }); + + + var selVal = $('#period select option:selected').val(); + if (selVal == 'day'){ + $('.hour,.minute').show(); + if ($('.hour input').val() == ''){ + $('.hour input,.minute input').val('0'); + } + $('.minute-n').hide(); + }else{ + $('.hour,.minute').hide(); + $('.minute-n').show(); + if ($('.minute-n input').val() == ''){ + $('.minute-n input').val('1'); + } + } + $('#period').change(function(event) { + var selVal = $('#period select option:selected').val(); + if (selVal == 'day'){ + $('.hour,.minute').show(); + if ($('.hour input').val() == ''){ + $('.hour input,.minute input').val('0'); + } + $('.minute-n').hide(); + }else{ + $('.hour,.minute').hide(); + $('.minute-n').show(); + if ($('.minute-n input').val() == ''){ + $('.minute-n input').val('1'); + } + } + }); + }, + yes:function(index){ + var args = {}; + var conn_type = $("select[name='conn_type']").val(); + + if(conn_type == 'key'){ + if ( $('textarea[name="secret_key"]').val() != ''){ + args['secret_key'] = $('textarea[name="secret_key"]').val(); + } else { + layer.msg('请输入接收密钥!'); + return false; + } + } else { + args['sname'] = $("input[name='u_user']").val(); + args['password'] = $("input[name='u_pass']").val(); + var port = Number($("input[name='u_port']").val()); + args['port'] = port; + if (!args['sname'] || !args['password'] || !args['port']){ + layer.msg('请输入帐号、密码、端口信息'); + return false; + } + } + + if ($('input[name="ip"]').val() == ''){ + layer.msg('请输入服务器IP地址!'); + return false; + } + + args['sname'] = $("input[name='u_user']").val(); + args['password'] = $("input[name='u_pass']").val(); + var port = Number($("input[name='u_port']").val()); + args['port'] = port; + + + args['ip'] = $('input[name="ip"]').val(); + args['path'] = $('input[name="path"]').val(); + args['delete'] = $('select[name="delete"]').val(); + args['realtime'] = $('select[name="realtime"]').val(); + args['delay'] = $('input[name="delay"]').val(); + + args['bwlimit'] = $('input[name="bwlimit"]').val(); + args['conn_type'] = $('select[name="conn_type"]').val(); + args['compress'] = $('select[name="compress"]').val(); + + args['period'] = $('select[name="period"]').val(); + args['hour'] = $('input[name="hour"]').val(); + args['minute'] = $('input[name="minute"]').val(); + args['minute-n'] = $('input[name="minute-n"]').val(); + + rsPost('lsyncd_add', args, function(rdata){ + var rdata = $.parseJSON(rdata.data); + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + + if (rdata.status){ + setTimeout(function(){layer.close(index);},2000); + return; + } + }); + return true; + } + }); + }); +} + +function lsyncdDelete(name){ + safeMessage('删除['+name+']', '您真的要删除['+name+']吗?', function(){ + var args = {}; + args['name'] = name; + rsPost('lsyncd_delete', args, function(rdata){ + var rdata = $.parseJSON(rdata.data); + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + setTimeout(function(){lsyncdSend();},2000); + }); + }); +} + + +function lsyncdRun(name){ + var args = {}; + args["name"] = name; + rsPost('lsyncd_run', args, function(rdata){ + var rdata = $.parseJSON(rdata.data); + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + }); +} + +function lsyncdLog(name){ + var args = {}; + args["name"] = name; + pluginStandAloneLogs("rsyncd", '', "lsyncd_log", JSON.stringify(args)); +} + + +function lsyncdExclude(name){ + layer.open({ + type:1, + title:'过滤器', + area: '400px', + shadeClose:false, + closeBtn:2, + content:'
\ +
\ +
\ + 排除的文件和目录\ + \ + \ +
\ +
\ +
\ +
\ +
\ +
\ +
    \ +
  • 排除的文件和目录是指当前目录下不需要同步的目录或者文件
  • \ +
  • 如果规则以斜线 /开头,则从头开始要匹配全部
  • \ +
  • 如果规则以 /结尾,则要匹配监控路径的末尾
  • \ +
  • ? 匹配任何字符,但不包括/
  • \ +
  • * 匹配0或多个字符,但不包括/
  • \ +
  • ** 匹配0或多个字符,可以是/
  • \ +
\ +
\ +
' + }); + + function getIncludeExclude(mName){ + loadT = layer.msg('正在获取数据...',{icon:16,time:0,shade: [0.3, '#000']}); + rsPost('lsyncd_get_exclude',{"name":mName}, function(rdata) { + layer.close(loadT); + + var rdata = $.parseJSON(rdata.data); + var res = rdata.data; + + var list='' + for (var i = 0; i < res.length; i++) { + list += ''+ res[i] +'删除'; + } + $('.lsyncd_exclude .BlockList tbody').empty().append(list); + }); + } + getIncludeExclude(name); + + + function addArgs(name,exclude){ + loadT = layer.msg('正在添加...',{icon:16,time:0,shade: [0.3, '#000']}); + rsPost('lsyncd_add_exclude', {name:name,exclude:exclude}, function(res){ + layer.close(loadT); + + console.log('addArgs:',res); + + if (res.status){ + getIncludeExclude(name); + $('.lsyncd_exclude input').val(''); + layer.msg(res.msg); + }else{ + layer.msg(res.msg); + } + }); + } + $('.addList').click(function(event) { + var val = $(this).prev().val(); + if(val == ''){ + layer.msg('当前输入内容为空,请输入'); + return false; + } + addArgs(name,val); + }); + $('.lsyncd_exclude input').keyup(function(event){ + if (event.which == 13){ + var val = $(this).val(); + if(val == ''){ + layer.msg('当前输入内容为空,请输入'); + return false; + } + addArgs(name,val); + } + }); + + + $('.lsyncd_exclude').on('click', '.delList', function(event) { + loadT = layer.msg('正在删除...',{icon:16,time:0,shade: [0.3, '#000']}); + var val = $(this).parent().prev().text(); + rsPost('lsyncd_remove_exclude',{"name":name,exclude:val}, function(rdata) { + layer.close(loadT); + + console.log(rdata) + var rdata = $.parseJSON(rdata.data); + var res = rdata.data; + + var list='' + for (var i = 0; i < res.length; i++) { + list += ''+ res[i] +'删除'; + } + $('.lsyncd_exclude .BlockList tbody').empty().append(list); + }); + }); +} + +function lsyncdConfLog(){ + pluginStandAloneLogs("rsyncd","","lsyncd_conf_log");; +} + +function lsyncdSend(){ + rsPost('lsyncd_list', '', function(data){ + var rdata = $.parseJSON(data.data); + console.log(rdata); + if (!rdata.status){ + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + return; + } + var list = rdata.data.list; + var con = ''; + + con += '
\ + \ + \ +
'; + + con += '
'; + con += ''; + con += ''; + con += ''; + con += ''; + con += ''; + con += ''; + con += ''; + con += ''; + + con += ''; + + + + for (var i = 0; i < list.length; i++) { + var mode = '增量'; + if (list[i]['delete'] == 'true'){ + mode = '完全'; + } else { + mode = '增量'; + } + + var period = "实时"; + if (list[i]['realtime'] == 'true'){ + period = '实时'; + } else { + period = '定时'; + } + + con += ''+ + '' + + '' + + '' + + '' + + '' + + '\ + '; + } + + con += ''; + con += '
名称(标识)源目录同步到模式周期操作
' + list[i]['name']+'' + list[i]['path']+'' + list[i]['ip']+":"+"cc"+'' + mode+'' + period +'\ + 同步\ + | 日志\ + | 过滤器\ + | 编辑\ + | 删除\ +
'; + + $(".soft-man-con").html(con); + }); +} + + + +///////////////// ----------------- 接收配置 ---------------- ////////////// +function rsyncdConf(){ + rsPost('conf', {}, function(rdata){ + rpath = rdata['data']; + if (rdata['status']){ + onlineEditFile(0, rpath); + } else { + layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']}); + } + }); +} + +function rsyncdLog(){ + pluginStandAloneLogs("rsyncd","","run_log"); +} + function rsyncdReceive(){ rsPost('rec_list', '', function(data){ @@ -47,6 +583,12 @@ function rsyncdReceive(){ // console.log(rdata); var list = rdata.data; var con = ''; + + con += '
\ + \ + \ +
'; + con += '
'; con += ''; con += ''; @@ -61,10 +603,12 @@ function rsyncdReceive(){ for (var i = 0; i < list.length; i++) { con += ''+ '' + - '' + + '' + '' + '\ '; } @@ -76,61 +620,67 @@ function rsyncdReceive(){ }); } -function addReceive(){ - var loadOpen = layer.open({ - type: 1, - title: '创建接收', - area: '400px', - content:"
\ -
\ - 项目名\ -
\ - \ -
\ -
\ -
\ - 密钥\ -
\ - \ - \ -
\ -
\ -
\ - 同步到\ -
\ - \ - \ -
\ -
\ -
\ - 备注\ -
\ - \ -
\ -
\ -
\ - \ -
\ -
", - success:function(layero, index){ - repeatPwd(16); + +function addReceive(name = ""){ + rsPost('get_rec',{"name":name},function(rdata) { + var rdata = $.parseJSON(rdata.data); + var data = rdata.data; + + var readonly = ""; + if (name !=""){ + readonly = 'readonly="readonly"' } - }); - $('#add_ok').click(function(){ - _data = {}; - _data['name'] = $('#name').val(); - _data['pwd'] = $('#MyPassword').val(); - _data['path'] = $('#inputPath').val(); - _data['ps'] = $('#ps').val(); - var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); - rsPost('add_rec', _data, function(data){ - var rdata = $.parseJSON(data.data); - layer.close(loadOpen); - layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); - setTimeout(function(){rsyncdReceive();},2000); + var loadOpen = layer.open({ + type: 1, + title: '创建接收', + area: '400px', + btn:['确认','取消'], + content:"
\ +
\ + 项目名\ +
\ + \ +
\ +
\ +
\ + 密钥\ +
\ + \ + \ +
\ +
\ +
\ + 同步到\ +
\ + \ + \ +
\ +
\ +
\ + 备注\ +
\ + \ +
\ +
\ +
", + success:function(layero, index){}, + yes:function(){ + var args = {}; + args['name'] = $('#name').val(); + args['pwd'] = $('#MyPassword').val(); + args['path'] = $('#inputPath').val(); + args['ps'] = $('#ps').val(); + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + rsPost('add_rec', args, function(data){ + var rdata = $.parseJSON(data.data); + layer.close(loadOpen); + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + setTimeout(function(){rsyncdReceive();},2000); + }); + } }); - }); + }) } @@ -146,20 +696,34 @@ function delReceive(name){ }); } -function cmdReceive(name){ +function cmdRecSecretKey(name){ var _data = {}; _data['name'] = name; - rsPost('cmd_rec', _data, function(data){ + rsPost('cmd_rec_secret_key', _data, function(data){ var rdata = $.parseJSON(data.data); layer.open({ type: 1, - title: '命令事例', + title: '接收密钥', area: '400px', - content:"
"+rdata.data+"
" + content:"
" }); }); } +function cmdRecCmd(name){ + var _data = {}; + _data['name'] = name; + rsPost('cmd_rec_cmd', _data, function(data){ + var rdata = $.parseJSON(data.data); + layer.open({ + type: 1, + title: '接收命令例子', + area: '400px', + content:"
"+rdata.data+"
" + }); + }); +} + function rsRead(){ var readme = '
    '; diff --git a/plugins/rsyncd/tool_task.py b/plugins/rsyncd/tool_task.py new file mode 100644 index 000000000..0d332ea9b --- /dev/null +++ b/plugins/rsyncd/tool_task.py @@ -0,0 +1,149 @@ +# coding:utf-8 + +import sys +import io +import os +import time +import json + +sys.path.append(os.getcwd() + "/class/core") +import mw + + +app_debug = False +if mw.isAppleSystem(): + app_debug = True + + +def getPluginName(): + return 'rsyncd' + + +def getPluginDir(): + return mw.getPluginDir() + '/' + getPluginName() + + +def getServerDir(): + return mw.getServerDir() + '/' + getPluginName() + + +def getTaskConf(): + conf = getServerDir() + "/task_config.json" + return conf + + +def getConfigData(): + try: + return json.loads(mw.readFile(getTaskConf())) + except: + pass + return [] + + +def getConfigTpl(): + tpl = { + "name": "", + "task_id": -1, + } + return tpl + + +def createBgTask(data): + removeBgTask() + for d in data: + if d['realtime'] == "false": + createBgTaskByName(d['name'], d) + + +def createBgTaskByName(name, args): + cfg = getConfigTpl() + _name = "[勿删]同步插件定时任务[" + name + "]" + res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find() + if res: + return True + + if "task_id" in cfg.keys() and cfg["task_id"] > 0: + res = mw.M("crontab").field("id, name").where( + "id=?", (cfg["task_id"],)).find() + if res and res["id"] == cfg["task_id"]: + print("计划任务已经存在!") + return True + import crontab_api + api = crontab_api.crontab_api() + + period = args['period'] + _hour = '' + _minute = '' + _where1 = '' + _type_day = "day" + if period == 'day': + _type_day = 'day' + _hour = args['hour'] + _minute = args['minute'] + elif period == 'minute-n': + _type_day = 'minute-n' + _where1 = args['minute-n'] + _minute = '' + + cmd = ''' +rname=%s +plugin_path=%s +logs_file=$plugin_path/send/${rname}/run.log +''' % (name, getServerDir()) + cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT" >> $logs_file' + "\n" + cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n" + cmd += 'bash $plugin_path/send/${rname}/cmd >> $logs_file 2>&1' + "\n" + cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n" + cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n" + + params = { + 'name': _name, + 'type': _type_day, + 'week': "", + 'where1': _where1, + 'hour': _hour, + 'minute': _minute, + 'save': "", + 'backup_to': "", + 'stype': "toShell", + 'sname': '', + 'sbody': cmd, + 'urladdress': '', + } + + task_id = api.add(params) + if task_id > 0: + cfg["task_id"] = task_id + cfg["name"] = name + + _dd = getConfigData() + _dd.append(cfg) + mw.writeFile(getTaskConf(), json.dumps(_dd)) + + +def removeBgTask(): + cfg_list = getConfigData() + for x in range(len(cfg_list)): + cfg = cfg_list[x] + if "task_id" in cfg.keys() and cfg["task_id"] > 0: + res = mw.M("crontab").field("id, name").where( + "id=?", (cfg["task_id"],)).find() + if res and res["id"] == cfg["task_id"]: + import crontab_api + api = crontab_api.crontab_api() + data = api.delete(cfg["task_id"]) + if data[0]: + cfg["task_id"] = -1 + cfg_list[x] = cfg + mw.writeFile(getTaskConf(), '[]') + return True + return False + + +if __name__ == "__main__": + if len(sys.argv) > 1: + action = sys.argv[1] + if action == "remove": + removeBgTask() + elif action == "add": + createBgTask() diff --git a/plugins/webstats/index.py b/plugins/webstats/index.py index fea2ca39d..fd9d4c44a 100755 --- a/plugins/webstats/index.py +++ b/plugins/webstats/index.py @@ -988,29 +988,32 @@ def getIpStatList(): if ip == "127.0.0.1": clist[i]['area'] = "本地" elif geoip_exists: - response = reader.city(ip) - country = response.country.names["zh-CN"] - - # print(ip, response.subdivisions) - _subdivisions = response.subdivisions try: - if len(_subdivisions) < 1: + response = reader.city(ip) + country = response.country.names["zh-CN"] + + # print(ip, response.subdivisions) + _subdivisions = response.subdivisions + try: + if len(_subdivisions) < 1: + subdivisions = "" + else: + subdivisions = "," + response.subdivisions.most_specific.names[ + "zh-CN"] + except Exception as e: subdivisions = "" - else: - subdivisions = "," + response.subdivisions.most_specific.names[ - "zh-CN"] - except Exception as e: - subdivisions = "" - try: - if 'zh-CN' in response.city.names: - city = "," + response.city.names["zh-CN"] - else: - city = "," + response.city.names["en"] - except Exception as e: - city = "" + try: + if 'zh-CN' in response.city.names: + city = "," + response.city.names["zh-CN"] + else: + city = "," + response.city.names["en"] + except Exception as e: + city = "" - clist[i]['area'] = country + subdivisions + city + clist[i]['area'] = country + subdivisions + city + except Exception as e: + clist[i]['area'] = "内网?" return mw.returnJson(True, 'ok', clist) diff --git a/plugins/webstats/js/stats.js b/plugins/webstats/js/stats.js index 33b8c71e8..8dcb67931 100644 --- a/plugins/webstats/js/stats.js +++ b/plugins/webstats/js/stats.js @@ -1996,8 +1996,8 @@ function wsTableErrorLogRequest(page){ list += '
'; list += ''; list += ''; - list += ''; - list += ''; + list += ''; + list += ''; list += ''; list += ''; } @@ -2205,8 +2205,8 @@ function wsTableLogRequest(page){ list += ''; list += ''; list += ''; - list += ''; - list += ''; + list += ''; + list += ''; list += ''; list += ''; } diff --git a/plugins/webstats/lua/webstats_log.lua b/plugins/webstats/lua/webstats_log.lua index 5ece00bf5..78732f005 100644 --- a/plugins/webstats/lua/webstats_log.lua +++ b/plugins/webstats/lua/webstats_log.lua @@ -174,6 +174,12 @@ log_by_lua_block { return count end + local function split_bylog(str,reps ) + local resultStrList = {} + string.gsub(str,'[^'..reps..']+',function(w) table.insert(resultStrList,w) end) + return resultStrList + end + local function is_ipaddr_bylog(client_ip) local cipn = split_bylog(client_ip,'.') if arrlen_bylog(cipn) < 4 then return false end @@ -186,12 +192,6 @@ log_by_lua_block { return true end - local function split_bylog(str,reps ) - local resultStrList = {} - string.gsub(str,'[^'..reps..']+',function(w) table.insert(resultStrList,w) end) - return resultStrList - end - local function get_client_ip_bylog() local client_ip = "unknown" local cdn = auto_config['cdn'] diff --git a/plugins/webstats/tool_migrate.py b/plugins/webstats/tool_migrate.py index 5d6499f29..88aede22b 100644 --- a/plugins/webstats/tool_migrate.py +++ b/plugins/webstats/tool_migrate.py @@ -66,7 +66,9 @@ def pSqliteDb(dbname='web_logs', site_name='unset', fn="logs"): conn.execute("PRAGMA page_size = 4096", ()) conn.execute("PRAGMA journal_mode = wal", ()) - conn.text_factory = lambda x: str(x, encoding="utf-8", errors='ignore') + conn.autoTextFactory() + + # conn.text_factory = lambda x: str(x, encoding="utf-8", errors='ignore') # conn.text_factory = lambda x: unicode(x, "utf-8", "ignore") return conn diff --git a/plugins/webstats/tool_task.py b/plugins/webstats/tool_task.py index d2ab34fdf..fe129ee31 100644 --- a/plugins/webstats/tool_task.py +++ b/plugins/webstats/tool_task.py @@ -61,7 +61,8 @@ def createBgTask(): import crontab_api api = crontab_api.crontab_api() - cmd = "nice -n 10 python3 " + getPluginDir() + "/tool_task.py execute" + cmd = "cd " + mw.getServerDir() + "/mdserver-web && nice -n 10 python3 " + \ + getPluginDir() + "/tool_task.py execute" params = { 'name': name, 'type': 'day', diff --git a/plugins/xhprof/conf/xhprof.conf b/plugins/xhprof/conf/xhprof.conf index bdc8095d5..92df8fb24 100755 --- a/plugins/xhprof/conf/xhprof.conf +++ b/plugins/xhprof/conf/xhprof.conf @@ -6,7 +6,7 @@ server root {$SERVER_PATH}/xhprof/xhprof_html; #error_page 404 /404.html; - include enable-php-{$PHP_VER}.conf; + include {$SERVER_PATH}/web_conf/php/conf/enable-php-{$PHP_VER}.conf; location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { diff --git a/route/static/app/public.js b/route/static/app/public.js index 5e672e8c9..6063fa656 100755 --- a/route/static/app/public.js +++ b/route/static/app/public.js @@ -2031,6 +2031,50 @@ function pluginRollingLogs(_name, version, func, _args, line){ },1000); },'json'); } + + +function pluginStandAloneLogs(_name, version, func, _args, line){ + if ( typeof(version) == 'undefined' ){ + version = ''; + } + + var func_name = 'error_log'; + if ( typeof(func) != 'undefined' ){ + func_name = func; + } + + var file_line = 100; + if ( typeof(line) != 'undefined' ){ + file_line = line; + } + + + layer.open({ + type: 1, + title: _name + '日志', + area: '640px', + content:'
\ + \ +
' + }); + + $.post('/plugins/run', {name:_name, func:func_name, version:version,args:_args},function (data) { + var fileName = data.data; + $.post('/files/get_last_body', 'path=' + fileName+'&line='+file_line, function(rdata) { + if (!rdata.status){ + return; + } + + if(rdata.data == '') { + rdata.data = '当前没有日志!'; + } + var ebody = ''; + $("#plugins_stand_alone_logs").html(ebody); + var ob = document.getElementById('plugins_stand_alone_logs'); + ob.scrollTop = ob.scrollHeight; + },'json'); + },'json'); +} /*** 其中功能,针对插件通过库使用 end ***/ diff --git a/route/templates/default/config.html b/route/templates/default/config.html index 5f7e5d7aa..8ada07c7a 100755 --- a/route/templates/default/config.html +++ b/route/templates/default/config.html @@ -26,6 +26,7 @@ +
@@ -60,11 +62,14 @@ 修改 面板管理入口,设置后只能通过指定安全入口登录面板,如: /abc

+ +

默认建站目录 diff --git a/route/templates/default/layout.html b/route/templates/default/layout.html index cdb4a7a8b..b14187021 100755 --- a/route/templates/default/layout.html +++ b/route/templates/default/layout.html @@ -5,7 +5,7 @@ - mdserver-web|linux面板 + {{data['title']}} diff --git a/scripts/lib.sh b/scripts/lib.sh index 19e558357..6535b65aa 100755 --- a/scripts/lib.sh +++ b/scripts/lib.sh @@ -115,7 +115,7 @@ pip3 install gevent-websocket==0.10.1 pip3 install flask-caching==1.10.1 pip3 install flask-session==0.3.2 pip3 install flask-socketio==5.2.0 -# pip3 install mysqlclient +pip3 install mysqlclient if [ ! -f /www/server/mdserver-web/bin/activate ];then @@ -133,5 +133,5 @@ pip3 install gevent-websocket==0.10.1 pip3 install flask-caching==1.10.1 pip3 install flask-session==0.3.2 pip3 install flask-socketio==5.2.0 -# pip3 install mysqlclient +pip3 install mysqlclient

服务名
' + list[i]['name']+'' + list[i]['path']+'' + list[i]['path']+'' + list[i]['comment']+'\ - 命令\ + 命令\ + | 密钥\ + | 编辑\ | 删除
' + data[i]['ip'] +'' + toSize(data[i]['body_length']) +'' + toSecond(data[i]['request_time']) +'' + data[i]['uri'] +'' + data[i]['status_code']+'/' + data[i]['method'] +'' + data[i]['uri'] +'' + data[i]['status_code']+'/' + data[i]['method'] +'详情
' + data[i]['ip'] +'' + toSize(data[i]['body_length']) +'' + toSecond(data[i]['request_time']) +'' + data[i]['uri'] +'' + data[i]['status_code']+'/' + data[i]['method'] +'' + data[i]['uri'] +'' + data[i]['status_code']+'/' + data[i]['method'] +'详情