# coding: utf-8
# +-------------------------------------------------------------------
# | 宝塔Linux面板
# +-------------------------------------------------------------------
# | Copyright (c) 2015-2016 宝塔软件(http://bt.cn) All rights reserved.
# +-------------------------------------------------------------------
# | Author: 沐落 <cjx@bt.cn>
# +-------------------------------------------------------------------
import os, sys

panelPath = os.getenv('BT_PANEL')
os.chdir(panelPath)
sys.path.insert(0, panelPath + "/class/")

try:
    from BTPanel import session, cache

except:
    pass
import public, os, json, time, apache, iis, psutil, shutil, platform, re

os_version = 'Linux'
if os.getenv('BT_PANEL'): os_version = 'Windows'


class ajax:
    def get_iis_status(self, get):
        return iis.iis().get_iis_status(get)

    def get_iis_request_list(self, get):
        return iis.iis().get_iis_request_list(get)

    # 安装反向代理
    def setup_iis_proxy(self, get):
        a = iis.iis()
        return a.setup_iis_proxy(get)

    # 获取反向代理安装状态
    def get_iis_proxy_config(self, get):
        a = iis.iis()
        return a.get_iis_proxy_config(get)

    # 设置反向代理默认配置
    def set_iis_proxy_config(self, get):
        a = iis.iis()
        return a.set_iis_proxy_config(get)

    def set_iis_proxy_config(self, get):
        a = iis.iis()
        return a.set_iis_proxy_config(get)

    # mime类型
    def get_mimes(self, get):
        return iis.iis().get_mimes(get)

    # mime类型
    def add_mimes(self, get):
        return iis.iis().add_mimes(get)

    # mime类型
    def del_mimes(self, get):
        return iis.iis().del_mimes(get)

    def get_iis_request(self, get):
        import win32com, pythoncom
        try:
            import wmi
        except:
            os.system(public.get_run_pip('[PIP] install wmi'))
            import wmi

        pythoncom.CoInitialize()
        vim_obj = win32com.client.GetObject("winmgmts:/root/cimv2")
        iiscon = vim_obj.ExecQuery(
            'Select Name,TotalBytesReceived,TotalBytesSent,TotalBytesTransferred,TotalMethodRequests,TotalGetRequests,TotalPostRequests,CurrentConnections,MaximumConnections From Win32_PerfFormattedData_W3SVC_WebService where name="_Total"')
        data = {}
        for item in iiscon:
            data['TotalBytesReceived'] = item.TotalBytesReceived
            data['TotalBytesSent'] = item.TotalBytesSent
            data['TotalBytesTransferred'] = item.TotalBytesTransferred
            data['TotalMethodRequests'] = item.TotalMethodRequests
            data['TotalGetRequests'] = item.TotalGetRequests
            data['TotalPostRequests'] = item.TotalPostRequests
            data['CurrentConnections'] = item.CurrentConnections
            data['MaximumConnections'] = item.MaximumConnections

        return data

    def GetApacheStatus(self, get):
        a = apache.apache()
        return a.GetApacheStatus()

    # 获取web服务器运行用户
    def get_run_user(self, get):
        webserver = public.get_webserver();
        ret = public.ExecShell("sc qc {}".format(webserver))[0]

        data = {}
        data['web'] = webserver
        data['user'] = ''
        if ret.find('LocalSystem') >= 0:
            data['user'] = "system"
        elif ret.find('www') >= 0:
            data['user'] = 'www'
        return data

    def change_server_users(self, name, user='LocalSystem', password=None):
        import win32service
        scm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ALL_ACCESS)
        if not scm: return False

        svc = win32service.OpenService(scm, name, win32service.SC_MANAGER_ALL_ACCESS)
        if not svc: return False
        win32service.ChangeServiceConfig(svc, win32service.SERVICE_NO_CHANGE, win32service.SERVICE_AUTO_START, win32service.SERVICE_NO_CHANGE, None, None, 0, None, user, password, None)
        return True

    # 设置运行目录
    def set_run_user(self, get):

        if not hasattr(get, 'user'):
            return public.returnMsg(False, "参数传递错误.")

        webserver = public.get_webserver();
        server_info = {'nginx': {'name': 'nginx', 'disName': 'nginx', 'path': os.getenv("BT_SETUP") + '/nginx/nginx_server.exe', 'args': '',
                                 'ps': 'nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件（IMAP/POP3）代理服务器，并在一个BSD-like 协议下发行'},
                       'apache': {'name': 'apache', 'disName': 'apache', 'path': os.getenv("BT_SETUP") + '/apache/bin/httpd.exe', 'args': '-k runservice',
                                  'ps': 'Apache是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上，由于其跨平台和安全性被广泛使用，是最流行的Web服务器端软件之一'}}
        if not webserver in server_info: return public.returnMsg(False, "参数传递错误.")

        info = server_info[webserver]

        public.set_server_status(webserver, "stop")
        user = get.user
        if user == 'system':
            self.change_server_users(webserver)
        else:
            tpath = os.getenv("BT_SETUP") + '/panel/script/BtTools.exe'
            public.ExecShell("{} add_user_bywww {}".format(tpath, os.getenv("BT_SETUP")))

            che_user = public.ExecShell("net user")[0];
            if che_user.find("www") < 0: return public.returnMsg(False, "www用户创建失败,请检查安全软件是否拦截.")

            pwdpath = os.getenv("BT_SETUP") + '/panel/data/www'
            if not os.path.exists(pwdpath): return public.returnMsg(False, "www用户创建失败,请检查安全软件是否拦截1.")

            public.set_file_access(os.getenv("BT_SETUP") + "/" + webserver, "www", public.file_all)

            ret = self.change_server_users(webserver, '.\\www', public.readFile(pwdpath))
            os.remove(pwdpath)
            if not ret: return public.returnMsg(False, "修改失败.")

        public.serviceReload()
        return public.returnMsg(True, "切换成功，当前运行用户为【{}】.".format(user))

    # cgi管理器
    def get_nginx_cig_admin(self, get):
        ini_path = os.getenv("BT_SETUP") + '/nginx/config.ini'
        if not os.path.exists(ini_path):  return public.returnMsg(False, "配置文件不存在.")

        import re
        data = {}
        conf = public.readFile(ini_path);
        slist = ['php_versions', 'php_cgi_process', 'php_cgi_process_thread', 'restart_delay', 'php_cgi_help_process', 'php_cgi_help_process_thread', 'helpers_delay']
        for x in slist:
            try:
                data[x] = re.search(x + '\s?=(.+)', conf).groups()[0].strip();
            except:
                data[x] = 0
        return data;

    def set_nginx_cig_admin(self, get):
        ini_path = os.getenv("BT_SETUP") + '/nginx/config.ini'
        if not os.path.exists(ini_path):
            return public.returnMsg(False, "配置文件不存在.")

        import re
        conf = public.readFile(ini_path)
        slist = ['php_versions', 'php_cgi_process', 'php_cgi_process_thread', 'restart_delay', 'php_cgi_help_process', 'php_cgi_help_process_thread', 'helpers_delay']
        for x in slist:
            conf = re.sub(x + '\s?=.+', x + ' = ' + get[x], conf);

        public.writeFile(ini_path, conf)
        public.serviceReload();
        return public.returnMsg(True, "修改成功.")

    def GetProcessCpuPercent(self, i, process_cpu):
        try:
            pp = psutil.Process(i)
            if pp.name() not in process_cpu.keys():
                process_cpu[pp.name()] = float(pp.cpu_percent(interval=0.1))
            else:
                process_cpu[pp.name()] += float(pp.cpu_percent(interval=0.1))
        except:
            pass

    def GetProcesMenuPercent(self, i, process_men):
        try:
            pp = psutil.Process(i)
            if pp.name() not in process_men.keys():
                process_men[pp.name()] = pp.memory_info().rss / 1024 / 1024;
            else:
                process_men[pp.name()] += pp.memory_info().rss / 1024 / 1024;
        except:
            pass

    def GetNginxStatus(self, get):
        # 取Nginx负载状态
        worker = 0;
        workermen = 0
        process_cpu = {}
        process_men = {}

        if public.get_server_status('nginx') < 0: return public.returnMsg(False, "获取失败，服务未启动.")

        # 先尝试127.0.0.1,不成功则loaclhost
        result = public.HttpGet('http://localhost/nginx_status', 15)
        if type(result) == bool: return public.returnMsg(False, "获取失败，可能服务未启动，通过以下方式排除错误：<br>1、检查80端口是否被占用<br>2、检查配置文件是否存在错误")

        tmp = result.split()
        if len(tmp) < 8: return public.returnMsg(False, "获取失败，可能服务未启动，通过以下方式排除错误：<br>1、检查80端口是否被占用<br>2、检查配置文件是否存在错误")

        for proc in psutil.process_iter():
            if proc.name() == "nginx.exe":
                worker = worker + 1;
                self.GetProcessCpuPercent(proc.pid, process_cpu)
                self.GetProcesMenuPercent(proc.pid, process_men)

        data = {}
        if "request_time" in tmp:
            data['accepts'] = tmp[8]
            data['handled'] = tmp[9]
            data['requests'] = tmp[10]
            data['Reading'] = tmp[13]
            data['Writing'] = tmp[15]
            data['Waiting'] = tmp[17]
        else:
            data['accepts'] = tmp[9]
            data['handled'] = tmp[7]
            data['requests'] = tmp[8]
            data['Reading'] = tmp[11]
            data['Writing'] = tmp[13]
            data['Waiting'] = tmp[15]
        data['active'] = tmp[2]
        data['worker'] = worker
        data['workercpu'] = round(float(process_cpu.get("nginx.exe",0)), 2)
        data['workermen'] = "%s%s" % (int(process_men.get('nginx.exe',0)), " MB")
        return data

    def GetPHPStatus(self, get):
        # 取指定PHP版本的负载状态
        return public.returnMsg(False, "暂不支持!")

    def CheckStatusConf(self):
        return public.returnMsg(False, "暂不支持!")

    def GetTaskCount(self, get):
        # 取任务数量
        return public.M('tasks').where("status!=?", ('1',)).count()

    def GetSoftList(self, get):
        # 取软件列表
        import json, os
        tmp = public.readFile('{}/data/softList.conf'.format(panelPath)).replace("{SETUP_PATH}", public.format_path(os.getenv("BT_SETUP")));
        data = json.loads(tmp)
        for x in data['webs']:
            if x['name'] == 'IIS':
                x['versions'] = [{'status': False, 'version': self.get_iis_verison()}]
        bt_path = public.get_setup_path()
        if os.path.exists(bt_path + '/nginx/version.pl') or os.path.exists(bt_path + '/apache/version.pl') or os.path.exists(bt_path + '/mysql/version.pl') or os.path.exists(bt_path + '/php/version.pl') or self.get_iis_version():
            public.writeFile('data/recommend_install.pl', 'True')
            data['is_show'] = False
            return data
        data['is_show'] = not os.path.exists('data/recommend_install.pl')
        return data

    def get_iis_version(self):
        try:
            import winreg
            # 打开注册表项
            key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\InetStp")

            # 读取VersionString值
            version_string, _ = winreg.QueryValueEx(key, "VersionString")

            # 关闭注册表项
            winreg.CloseKey(key)

            return version_string
        except:
            return False

    def set_setup_status(self, get):
        # 设置安装状态
        public.writeFile('data/recommend_install.pl', 'True')
        return public.returnMsg(True, '设置成功!')

    def get_iis_verison(self):
        import re
        sys_vs = public.get_sys_version()
        if int(sys_vs[0]) == 6:
            version = '7.5'
            if int(sys_vs[1]) >= 2:
                version = '8.5'
                status = public.get_server_status('w3svc')
                if status > -1:
                    version = public.ReadReg('SOFTWARE\\Microsoft\\InetStp', 'SetupString')
                    if version:
                        version = re.search('(\d+\.\d+)', version).groups()[0]

        elif int(sys_vs[0]) == 10:
            version = '10.0'
        return version

    def GetLibList(self, get):
        # 取插件列表
        import json, os
        tmp = public.readFile('data/libList.conf');
        data = json.loads(tmp)
        for i in range(len(data)):
            data[i]['status'] = self.CheckLibInstall(data[i]['check']);
            data[i]['optstr'] = self.GetLibOpt(data[i]['status'], data[i]['opt']);
        return data

    # 获取文件列表
    def GetQiniuFileList(self, get):
        try:
            import json

            result = public.ExecShell(public.get_run_python("[PYTHON] " + public.GetConfigValue('setup_path') + "/panel/script/backup_" + get.name + ".py list"))
            return json.loads(result[0]);
        except:
            return public.returnMsg(False, '获取列表失败,请检查[AK/SK/存储空间]设是否正确!');

    # 取网络连接列表
    def GetNetWorkList(self, get):
        import psutil
        netstats = psutil.net_connections()
        networkList = []
        for netstat in netstats:
            tmp = {}
            if netstat.type == 1:
                tmp['type'] = 'tcp'
            else:
                tmp['type'] = 'udp'
            tmp['family'] = netstat.family
            tmp['laddr'] = netstat.laddr
            tmp['raddr'] = netstat.raddr
            tmp['status'] = netstat.status
            p = psutil.Process(netstat.pid)
            tmp['process'] = p.name()
            tmp['pid'] = netstat.pid
            networkList.append(tmp)
            del (p)
            del (tmp)
        networkList = sorted(networkList, key=lambda x: x['status'], reverse=True)
        return networkList

    # 取进程列表
    def GetProcessList(self, get):
        import psutil
        Pids = psutil.pids()

        processList = []
        for pid in Pids:
            try:
                tmp = {}
                p = psutil.Process(pid)
                if p.exe() == "": continue

                tmp['name'] = p.name();  # 进程名称
                if self.GoToProcess(tmp['name']): continue

                tmp['pid'] = pid;  # 进程标识
                tmp['status'] = p.status();  # 进程状态
                tmp['user'] = p.username();  # 执行用户
                cputimes = p.cpu_times()
                tmp['cpu_percent'] = p.cpu_percent(0.1)
                tmp['cpu_times'] = cputimes.user  # 进程占用的CPU时间
                tmp['memory_percent'] = round(p.memory_percent(), 3)  # 进程占用的内存比例
                pio = p.io_counters()
                tmp['io_write_bytes'] = pio.write_bytes  # 进程总共写入字节数
                tmp['io_read_bytes'] = pio.read_bytes  # 进程总共读取字节数
                tmp['threads'] = p.num_threads()  # 进程总线程数

                processList.append(tmp)
                del (p)
                del (tmp)
            except:
                continue
        import operator
        processList = sorted(processList, key=lambda x: x['memory_percent'], reverse=True)
        processList = sorted(processList, key=lambda x: x['cpu_times'], reverse=True)
        return processList

    def GetNetWorkIo(self, get):
        # 取指定时间段的网络Io
        data = public.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (get.start, get.end)).field('id,up,down,total_up,total_down,down_packets,up_packets,addtime').order(
            'id desc').select()
        return self.ToAddtime(data)

    # def GetDiskIo(self,get):
    #    #取指定时间段的磁盘Io
    #    data = public.M('diskio').dbfile('system').where("addtime>=? AND addtime<=?",(get.start,get.end)).field('id,read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime').order('id asc').select()
    #    return self.ToAddtime(data)

    def ToAddtime(self, data, tomem=False, types=None):
        import time
        # 格式化addtime列

        if tomem:
            import psutil
            mPre = (psutil.virtual_memory().total / 1024 / 1024) / 100
        length = len(data)
        he = 1
        if length > 100: he = 1
        if length > 1000: he = 3
        if length > 10000: he = 15
        if he == 1:
            for i in range(length):
                try:
                    if types:
                        key = '{}_top'.format(types)
                        if key in data[i]:
                            data[i][key] = json.loads(data[i][key])
                        if 'memory_top' in data[i]:
                            data[i]['memory_top'] = json.loads(data[i]['memory_top'])
                    data[i]['addtime'] = time.strftime('%m/%d %H:%M', time.localtime(float(data[i]['addtime'])))
                    if 'process_list' in data[i]:
                        data[i]['process_list'] = json.loads(data[i]['process_list'])
                    if tomem and data[i]['mem'] > 100: data[i]['mem'] = data[i]['mem'] / mPre
                    if tomem in [None]:
                        if type(data[i]['down_packets']) == str:
                            data[i]['down_packets'] = json.loads(data[i]['down_packets'])
                            data[i]['up_packets'] = json.loads(data[i]['up_packets'])
                except:
                    continue
            return data
        else:
            count = 0
            tmp = []
            couns = 0
            for value in data:
                if count < he:  # 0 1 2
                    count += 1
                    # cpu大于60的时候，随机取
                    if types == "cpu" and 'pro' in value and value['pro'] > 60:
                        couns += 1
                        # he等于3 的时候 百分之50的概率取  当he等于15的时候 百分之33的概率取
                        if (he == 3 and couns % 2 == 0) or (he == 15 and couns % 3 == 0):
                            if types:
                                key = '{}_top'.format(types)
                                if key in value:
                                    value[key] = json.loads(value[key])
                                if 'memory_top' in value:
                                    value['memory_top'] = json.loads(value['memory_top'])
                            value['addtime'] = time.strftime('%m/%d %H:%M', time.localtime(float(value['addtime'])))
                            if tomem and 'mem' in value and value['mem'] > 100: value['mem'] = value['mem'] / mPre
                            if tomem in [None]:
                                if type(value['down_packets']) == str:
                                    value['down_packets'] = json.loads(value['down_packets'])
                                    value['up_packets'] = json.loads(value['up_packets'])
                            tmp.append(value)
                    continue
                try:
                    if types:
                        key = '{}_top'.format(types)
                        if key in value:
                            value[key] = json.loads(value[key])
                        if 'memory_top' in value:
                            value['memory_top'] = json.loads(value['memory_top'])
                    value['addtime'] = time.strftime('%m/%d %H:%M', time.localtime(float(value['addtime'])))
                    if tomem and 'mem' in value and value['mem'] > 100: value['mem'] = value['mem'] / mPre
                    if tomem in [None]:
                        if type(value['down_packets']) == str:
                            value['down_packets'] = json.loads(value['down_packets'])
                            value['up_packets'] = json.loads(value['up_packets'])
                    tmp.append(value)
                    count = 0
                except:
                    continue
            return tmp

    def __format_field(self, field):
        import re
        fields = []
        for key in field:
            s_as = re.search(r'\s+as\s+', key, flags=re.IGNORECASE)
            if s_as:
                as_tip = s_as.group()
                key = key.split(as_tip)[1]
            fields.append(key)
        return fields

    def GetCpuIo(self, get):
        # 取指定时间段的CpuIo
        panel_path = public.get_panel_path()
        data_path = "{}/data/sql_index.pl".format(panel_path)
        if not os.path.exists(data_path):
            self.create_sql_index()
        __OPT_FIELD = "*"
        tmp_cols = public.M('cpuio').dbfile('system').query('PRAGMA table_info(cpuio)', ())
        cols = []
        for col in tmp_cols:
            if len(col) > 2: cols.append('`' + col[1] + '`')
        if len(cols) > 0:
            cols.append("cpu_top")
            cols.append("memory_top")
            __OPT_FIELD = ','.join(cols)
        data = public.M('cpuio').dbfile('system').query(
            "SELECT cpuio.*,process_top_list.cpu_top,process_top_list.memory_top from cpuio inner join process_top_list on cpuio.addtime=process_top_list.addtime where cpuio.addtime>={} AND cpuio.addtime<={} ORDER BY cpuio.addtime desc;".format(
                get.start, get.end), ())
        try:
            if __OPT_FIELD != "*":
                fields = self.__format_field(__OPT_FIELD.split(','))
                tmp = []
                for row in data:
                    i = 0
                    tmp1 = {}
                    for key in fields:
                        tmp1[key.strip('`')] = row[i]
                        i += 1
                    tmp.append(tmp1)
                    del (tmp1)
                data = tmp
        except:
            return []
        return self.ToAddtime(data, True, 'cpu')

    def GetDiskIo(self, get):
        # 取指定时间段的磁盘Io
        __OPT_FIELD = "*"
        tmp_cols = public.M('diskio').dbfile('system').query('PRAGMA table_info(diskio)', ())
        cols = []
        for col in tmp_cols:
            if len(col) > 2: cols.append('`' + col[1] + '`')
        if len(cols) > 0:
            cols.append("disk_top")
            __OPT_FIELD = ','.join(cols)
        data = public.M('diskio').dbfile('system').query(
            "SELECT diskio.*,process_top_list.disk_top from diskio inner join process_top_list on diskio.addtime=process_top_list.addtime where diskio.addtime>={} AND diskio.addtime<={} ORDER BY diskio.addtime desc;".format(
                get.start, get.end), ())
        try:
            if __OPT_FIELD != "*":
                fields = self.__format_field(__OPT_FIELD.split(','))
                tmp = []
                for row in data:
                    i = 0
                    tmp1 = {}
                    for key in fields:
                        tmp1[key.strip('`')] = row[i]
                        i += 1
                    tmp.append(tmp1)
                    del (tmp1)
                data = tmp
        except:
            return []
        return self.ToAddtime(data, True, 'disk')

    # def GetCpuIo(self,get):
    #    #取指定时间段的CpuIo
    #    data = public.M('cpuio').dbfile('system').where("addtime>=? AND addtime<=?",(get.start,get.end)).field('id,pro,mem,addtime').order('id asc').select()

    #    #data = self.get_io_data(get)
    #    return self.ToAddtime(data,True)

    def get_load_average(self, get):
        data = public.M('load_average').dbfile('system').where("addtime>=? AND addtime<=?", (get.start, get.end)).field('id,pro,one,five,fifteen,addtime').order('id asc').select()
        return self.ToAddtime(data)

    def get_io_data(self, get):
        """
        @name 处理监控数据去除5%的极值
        """

        skey = 'cpu'
        result = []
        data = public.M('cpuio').dbfile('system').where("addtime>=? AND addtime<=?", (get.start, get.end)).field('id,pro,mem,addtime').order('addtime desc').select()
        num = int(len(data) * 0.05)

        s_list = []

        pre_val = []
        for val in data:
            if len(pre_val) < 2:
                pre_val.append(val)
                continue

            if skey == 'cpu':

                if abs(pre_val[0]['pro'] - pre_val[1]['pro']) >= 30 and abs(pre_val[1]['pro'] - val['pro']) >= 30:

                    if abs(pre_val[0]['pro'] - val['pro']) < 30:
                        print('-------------------')
                        print(pre_val[0]['id'], public.format_date(times=pre_val[0]['addtime']), pre_val[0]['pro'])
                        print(pre_val[1]['id'], public.format_date(times=pre_val[1]['addtime']), pre_val[1]['pro'])
                        print(val['id'], public.format_date(times=val['addtime']), val['pro'])

                        print('-------------------')
                        s_list.append(pre_val[1])
            pre_val.append(val)
            pre_val = pre_val[1:]
        skip_list = []

        s_list = sorted(s_list, key=lambda x: x['pro'], reverse=True)
        for x in s_list:
            if len(skip_list) >= num:
                break
            skip_list.append(x['id'])
        # 重新组合数据
        for val in data:
            if val['id'] in skip_list:
                continue
            result.append(val)
        result = sorted(result, key=lambda x: x['id'], reverse=False)
        return result

    def GetInstalleds(self, softlist):
        softs = ''
        for soft in softlist['data']:
            try:
                for v in soft['versions']:
                    if v['status']: softs += soft['name'] + '-' + v['version'] + '|';
            except:
                pass
        return softs

    def update_python(self, get):

        tmpPath = "{}/update".format(os.getenv('BT_SETUP'))
        if not os.path.exists(tmpPath): os.makedirs(tmpPath)

        loacl_path = "{}/BtSoft.exe".format(tmpPath)
        httpUrl = public.get_url()
        if not httpUrl: httpUrl = 'https://download.bt.cn'
        downUrl = httpUrl + '/win/panel/BtSoft.exe'
        if os.path.exists(loacl_path): os.remove(loacl_path)

        public.downloadFileByWget(downUrl, loacl_path)
        if os.path.getsize(loacl_path) < 1024: return public.returnMsg(False, "文件下载失败.");

        os_ver = public.ReadReg("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName")
        msu_shell = ''
        if os_ver.find('2008') >= 0:
            public.downloadFileByWget("{}/win/panel/data/Windows6.1-KB2533623-x64.msu".format(httpUrl), "{}/Windows6.1-KB2533623-x64.msu".format(tmpPath));
            msu_shell = '@echo 正在安装补丁，安装完成后，重启服务器生效 \r\n{}/Windows6.1-KB2533623-x64.msu'.format(tmpPath)

        shell = "@echo 此脚本用于升级Python环境，升级后请删除此目录，并重启服务器 \r\n{}\r\n{}".format(loacl_path, msu_shell)
        public.writeFile("C:/Program Files/python/update.pl", "True")
        public.writeFile("{}/update.bat".format(tmpPath), shell, 'w+', 'gbk')

        return public.returnMsg(True, "安装脚本生成成功，请通过远程桌面连接至服务器，双击【{}】执行.".format(public.format_path("{}/update.bat".format(tmpPath))));

    def ignore_version(self, get):
        """
        @忽略版本更新
        """
        version = get.version
        path = '{}/data/no_update.pl'.format(public.get_panel_path())
        try:
            data = json.loads(public.readFile(path))
        except:
            data = []

        if not version in data: data.append(version)

        public.writeFile(path, json.dumps(data))
        try:
            del (session['updateInfo'])
        except:
            pass

        return public.returnMsg(True, "忽略成功，此版本将不再提醒更新.")

    def UpdatePanel(self, get):
        # try:
        # 取回远程版本信息

        path = '{}/data/local.txt'.format(public.get_panel_path())
        if os.path.exists(path):
            data = json.loads(public.readFile(path))
            data['msg']['version'] = public.version()
            data['msg']['beta']['version'] = public.version()
            return data
        if 'updateInfo' in session and hasattr(get, 'check') == False:
            updateInfo = session['updateInfo']
        else:
            logs = ''
            try:
                logs = public.get_debug_log()
            except:
                pass

            import psutil, panelPlugin, system;
            mem = psutil.virtual_memory()
            mplugin = panelPlugin.panelPlugin()
            mplugin.ROWS = 10000
            panelsys = system.system()
            data = public.get_user_info()
            data['sites'] = str(public.M('sites').count())
            data['ftps'] = str(public.M('ftps').count())
            data['databases'] = str(public.M('databases').count())

            cpu_str = ''
            try:
                cpu_str = str(psutil.cpu_count())
            except:
                pass

            mem_str = '0'
            try:
                mem_str = str(mem.total / 1024 / 1024)
            except:
                pass

            web_server = public.get_webserver()
            if not web_server: web_server = ''

            data['system'] = panelsys.GetSystemVersion() + '|' + mem_str + 'MB|' + public.getCpuType() + '*' + cpu_str + '|' + web_server + '|' + public.version()
            slist = mplugin.getPluginList(None)
            if slist: data['system'] += '||' + self.GetInstalleds(slist)

            data['logs'] = logs
            data['oem'] = ''
            data['intrusion'] = 0
            data['uid'] = self.get_uid()
            data['force'] = 1

            msg = public.getMsg('PANEL_UPDATE_MSG')
            sUrl = public.GetConfigValue('home') + '/api/wpanel/updateWindows'
            result = public.httpPost(sUrl, data, 10)
            try:
                updateInfo = json.loads(result)
            except:
                try:
                    result = public.httpPost(sUrl, data, 60)
                    updateInfo = json.loads(result)
                except:
                    raise public.PanelError("连接宝塔官网（www.bt.cn）异常，请检查服务网络状况")
            public.writeFile('c:/update.txt', json.dumps(updateInfo))

            if not updateInfo: return public.returnMsg(False, "CONNECT_ERR")
            updateInfo['msg'] = msg

        session['updateInfo'] = updateInfo
        # 检查是否需要升级
        if updateInfo['is_beta'] == 1:
            if updateInfo['beta']['version'] == session['version']: return public.returnMsg(False, updateInfo)
        else:
            if updateInfo['version'] == session['version']: return public.returnMsg(False, updateInfo)

        # 是否执行升级程序
        if (updateInfo['force'] == True or hasattr(get, 'toUpdate') == True or os.path.exists('data/autoUpdate.pl') == True):
            if updateInfo['is_beta'] == 1: updateInfo['version'] = updateInfo['beta']['version']

            if public.is_debug(): return public.returnMsg(False, '更新失败，请先前往面板设置页，关闭开发者模式.')

            try:
                if not public.get_update_file(): return public.returnMsg(False, '更新失败，更新脚本下载失败.')
            except:
                pass

            import panel_update
            update = panel_update.panel_update()
            ret = update.UpdatePanel(updateInfo['version'])
            if not ret['status']: return ret

            session['version'] = updateInfo['version']
            if 'getCloudPlugin' in session: del (session['getCloudPlugin'])
            if updateInfo['is_beta'] == 1: self.to_beta()

            return public.returnMsg(True, 'PANEL_UPDATE', (updateInfo['version'],))

        # 输出新版本信息
        data = {
            'status': True,
            'version': updateInfo['version'],
            'updateMsg': updateInfo['updateMsg'],
        }

        py_version = platform.python_version()

        updateInfo['update_py'] = False
        if updateInfo['py_version'] != py_version:
            updateInfo['update_py'] = True

        updateInfo['beta']['update_py'] = False
        if updateInfo['beta']['py_version'] != py_version:
            updateInfo['beta']['update_py'] = True

        updateInfo['ignore'] = []
        no_path = '{}/data/no_update.pl'.format(public.get_panel_path())
        if os.path.exists(no_path):
            try:
                updateInfo['ignore'] = json.loads(public.readFile(no_path))
            except:
                pass

        return public.returnMsg(True, updateInfo)
        # except Exception as ex:
        #    return public.returnMsg(False,"更新失败 --> " + str(ex));

    def get_uid(self):
        try:
            userInfo = json.loads(public.ReadFile('data/userInfo.json'))
            return userInfo['uid']
        except:
            return 0

    def to_beta(self):
        try:
            userInfo = json.loads(public.ReadFile('data/userInfo.json'))
            p_data = {}
            p_data['uid'] = userInfo['uid']
            p_data['access_key'] = userInfo['access_key']
            p_data['username'] = userInfo['username']
            public.HttpPost(public.GetConfigValue('home') + '/api/wpanel/to_beta', p_data, 5)
        except:
            pass

    # 检查是否安装任何
    def CheckInstalled(self, get):
        checks = ['nginx', 'apache', 'W3SVC', 'FileZilla Server', 'mysql', 'phpmyadmin', 'php']
        import os
        for name in checks:
            if name == 'phpmyadmin':
                filename = os.getenv("BT_SETUP") + '/' + name
                if os.path.exists(filename): return True
            elif name == 'php':
                filename = os.getenv("BT_SETUP") + '/' + name
                if os.path.exists(filename):
                    dirs = os.listdir(filename)
                    if len(dirs) > 0: return True
            else:
                status = public.get_server_status(name)
                if status >= 0:
                    if name == 'W3SVC':
                        if os.path.exists('data/iis.setup'):
                            return True
                    else:
                        return True
        return False

    # 取已安装软件列表
    def GetInstalled(self, get):
        import system
        data = system.system().GetConcifInfo()
        return data

    # 取PHP配置
    def GetPHPConfig(self, get):
        import re, json

        filename = public.GetConfigValue('setup_path') + '/php/' + get.version + '/php.ini'
        if not os.path.exists(filename): return public.returnMsg(False, 'PHP_NOT_EXISTS');
        phpini = public.readFile(filename)

        data = {}
        rep = "disable_functions\s*=\s{0,1}(.*)"
        tmp = re.search(rep, phpini).groups()
        data['disable_functions'] = tmp[0]

        rep = "upload_max_filesize\s*=\s*([0-9]+)(M|m|K|k)"
        tmp = re.search(rep, phpini).groups()
        data['max'] = tmp[0]

        rep = u"\n;*\s*cgi\.fix_pathinfo\s*=\s*([0-9]+)\s*\n"
        tmp = re.search(rep, phpini).groups()

        if tmp[0] == '0':
            data['pathinfo'] = False
        else:
            data['pathinfo'] = True
        self.getCloudPHPExt(get)
        phplib = json.loads(public.readFile('data/phplib.win'))
        libs = []
        tasks = public.M('tasks').where("status!=?", ('1',)).field('status,name').select()
        for lib in phplib:
            lib['task'] = '1'
            for task in tasks:
                tmp = public.getStrBetween('[', ']', task['name'])
                if not tmp: continue
                tmp1 = tmp.split('-')
                if tmp1[0].lower() == lib['name'].lower():
                    lib['task'] = task['status']
                    lib['phpversions'] = []
                    lib['phpversions'].append(tmp1[1])
            check_lib = re.search('\n+;?\w+.*' + lib['check'].replace('[version]', get.version) + '\s*', phpini)
            lib['status'] = False
            if check_lib:
                if check_lib.group().find(";") < 0:
                    lib['status'] = True

            libs.append(lib)

        data['libs'] = libs
        return data

    # 获取当前下载节点
    def get_download_url(self):
        url = cache.get('download_url')
        if not url:
            cache.set('download_url', url, 1800)
        return url

    # 获取PHP扩展
    def getCloudPHPExt(self, get):
        import json
        try:
            if 'php_ext' in session: return True

            download_url = self.get_download_url() + '/install/lib/phplib.json'
            tstr = public.httpGet(download_url)
            data = json.loads(tstr)
            if not data: return False
            public.writeFile('data/phplib.conf', json.dumps(data))
            session['php_ext'] = True
            return True
        except:
            return False

    # 取PHPINFO信息
    def GetPHPInfo(self, get):
        version = get.version
        ext_path = os.getenv("BT_SETUP") + '/php/' + version + '/php.exe'
        if os.path.exists(ext_path):
            rRet = public.ExecShell('%s -r "echo phpinfo();"' % ext_path, None, None, None, True)
            return public.returnMsg(True, rRet[0]);
        return public.returnMsg(False, "请先安装PHP" + version);

    # 检测PHPINFO配置
    def CheckPHPINFO(self):
        php_versions = ['52', '53', '54', '55', '56', '70', '71', '72', '73', '74', '75', '80'];
        return public.returnMsg(False, "暂不支持!")

    # 清理日志
    def delClose(self, get):
        try:
            if session['uid'] == 1:
                public.M('logs').where('id>?', (0,)).delete();
                public.WriteLog('TYPE_CONFIG', 'LOG_CLOSE');
                return public.returnMsg(True, 'LOG_CLOSE');
        except:
            pass
        return public.returnMsg(False, '权限不足，请通过管理员用户清空日志.');

    # 设置PHPMyAdmin
    def setPHPMyAdmin(self, get):
        if hasattr(get, 'phpversion'):
            version = get.phpversion
            phpmyadmin_version = public.readFile(os.getenv("BT_SETUP") + '/phpmyadmin/version.pl')
            if phpmyadmin_version == '4.0' and (version != '53' and version != '54'):
                return public.returnMsg(False, 'phpmyadmin 4.0仅支持php5.3/5.4');

            import panelSite
            get.siteName = 'phpmyadmin'
            get.version = version
            panelSite.panelSite().SetPHPVersion(get)

            return public.returnMsg(True, '修改phpmyadmin的php版本为[php-' + version + ']成功');
        elif hasattr(get, 'port'):
            import panelSite
            panel_site = panelSite.panelSite()

            get.siteName = 'phpmyadmin'
            try:
                phpVersion = panel_site.GetSitePHPVersion(get)['phpversion']
            except:
                phpVersion = '00'

            port = get.port

            mainPort = public.readFile('data/port.pl').strip();
            rulePort = ['80', '443', '21', '20', '8080', '8081', '8089', '11211', '6379', mainPort]
            if port in rulePort:
                return public.returnMsg(False, 'AJAX_PHPMYADMIN_PORT_ERR');

            # 先删除，后添加
            webserver = public.GetWebServer()
            if webserver == 'iis':
                _appcmd = os.getenv("SYSTEMDRIVE") + '\\Windows\\System32\\inetsrv\\appcmd.exe'
                info = panel_site.get_site_info('phpmyadmin')
                for x in info['domains']:
                    public.ExecShell(_appcmd + " set site phpmyadmin /-bindings.[protocol='http',bindingInformation='*:" + x['port'] + ":" + x['domain'] + "']")
                public.ExecShell(_appcmd + " set site phpmyadmin /+bindings.[protocol='http',bindingInformation='*:" + port + ":']")
            elif webserver == 'apache':
                confPath = panel_site.get_conf_path(get.siteName)
                conf = public.readFile(confPath)
                conf = re.sub('VirtualHost\s+\*:\d+', 'VirtualHost *:' + port, conf)
                conf = re.sub('ServerAlias.*', 'ServerAlias phpmyadmin', conf)
                public.writeFile(confPath, conf)
                panel_site.apacheAddPort(port)
                public.serviceReload()

            elif webserver == 'nginx':
                confPath = panel_site.get_conf_path(get.siteName)
                conf = public.readFile(confPath)
                conf = re.sub('listen.*', 'listen ' + port + ';', conf)
                public.writeFile(confPath, conf)
                public.serviceReload()

            # 放行端口
            __version = public.get_sys_version()
            ps = "phpmyadmin端口"
            if public.M('firewall').where("port=?", (port,)).count() <= 0:
                shell = 'netsh firewall set portopening tcp ' + port.replace(':', '-') + ' ' + ps
                if int(__version[0]) == 6:
                    shell = 'netsh advfirewall firewall add rule name=' + ps + ' dir=in action=allow protocol=tcp localport=' + port.replace(':', '-')
                result = public.ExecShell(shell);
                public.WriteLog("TYPE_FIREWALL", 'FIREWALL_ACCEPT_PORT', (port,))
                addtime = time.strftime('%Y-%m-%d %X', time.localtime())
                public.M('firewall').add('port,ps,addtime', (port, ps, addtime))

            return public.returnMsg(True, '修改phpmyadmin的端口为[' + port + ']');
        elif hasattr(get, 'status'):
            pass
        return public.returnMsg(False, "暂不支持!")

    def ToPunycode(self, get):
        import re;
        get.domain = get.domain.encode('utf8');
        tmp = get.domain.split('.');
        newdomain = '';
        for dkey in tmp:
            # 匹配非ascii字符
            match = re.search(u"[\x80-\xff]+", dkey);
            if not match:
                newdomain += dkey + '.';
            else:
                newdomain += 'xn--' + dkey.decode('utf-8').encode('punycode') + '.'
        return newdomain[0:-1];

    # 保存PHP排序
    def phpSort(self, get):
        if public.writeFile(os.getenv("BT_SETUP") + '/php/sort.pl', get.ssort): return public.returnMsg(True, 'SUCCESS');
        return public.returnMsg(False, 'ERROR');

    # 获取广告代码
    def GetAd(self, get):
        try:
            return public.HttpGet(public.GetConfigValue('home') + '/Api/GetAD?name=' + get.name + '&soc=' + get.soc);
        except:
            return '';

    # 获取进度
    def GetSpeed(self, get):
        return public.getSpeed();

    # 检查登录状态
    def CheckLogin(self, get):
        return True;

    # 获取警告标识
    def GetWarning(self, get):
        warningFile = 'data/warning.json'
        if not os.path.exists(warningFile): return public.returnMsg(False, '警告列表不存在!');
        import json, time;
        wlist = json.loads(public.readFile(warningFile));
        wlist['time'] = int(time.time());
        return wlist;

    # 设置警告标识
    def SetWarning(self, get):
        wlist = self.GetWarning(get);
        id = int(get.id);
        import time, json;
        for i in range(len(wlist['data'])):
            if wlist['data'][i]['id'] == id:
                wlist['data'][i]['ignore_count'] += 1;
                wlist['data'][i]['ignore_time'] = int(time.time());

        warningFile = 'data/warning.json'
        public.writeFile(warningFile, json.dumps(wlist));
        return public.returnMsg(True, 'SET_SUCCESS');

    # 获取PHP-FPM状态
    def GetMemcachedStatus(self, get):
        """
        @name 获取memcached状态
        @description 获取memcached状态
        @param
        @return
        """
        import telnetlib, re

        try:
            config_path = public.GetConfigValue('setup_path') + '/memcached/config.json';
            conf = public.readFile(config_path);
            conf = json.loads(conf)
        except:
            return public.returnMsg(False, "配置文件错误，请勿直接手动更改配置文件")

        bind = '127.0.0.1'
        array1 = conf['bind'].split(' ')
        if len(array1) > 1: bind = array1[1]

        if public.get_server_status('memcached') <= 0: return public.returnMsg(False, "获取失败，服务未启动.")

        port = 11211
        array2 = conf['port'].split(' ')
        if len(array1) > 1: port = int(array2[1])

        tn = telnetlib.Telnet(bind, port);
        tn.write(b"stats\n");
        tn.write(b"quit\n");
        data = tn.read_all();
        if type(data) == bytes: data = data.decode('utf-8')

        data = data.replace('STAT', '').replace('END', '').split("\n");
        result = {}
        res = ['cmd_get', 'get_hits', 'get_misses', 'limit_maxbytes', 'curr_items', 'bytes', 'evictions', 'limit_maxbytes', 'bytes_written', 'bytes_read', 'curr_connections'];
        for d in data:
            if len(d) < 3: continue;
            t = d.split();
            if not t[0] in res: continue;
            result[t[0]] = int(t[1]);
        result['hit'] = 1;
        if result['get_hits'] > 0 and result['cmd_get'] > 0:
            result['hit'] = float(result['get_hits']) / float(result['cmd_get']) * 100;

        conf = public.readFile(public.GetConfigValue('setup_path') + '/memcached/config.json');
        conf = json.loads(conf)
        for x in conf:
            result[x] = conf[x].split(' ')[1]
        return result;

    # 设置memcached缓存大小
    def SetMemcachedCache(self, get):

        config_path = public.GetConfigValue('setup_path') + '/memcached/config.json';
        conf = public.readFile(config_path);
        conf = json.loads(conf)
        getdict = get.__dict__

        if int(get['maxconn']) < 30: return public.returnMsg(True, "最大连接数不得低于30!")

        for i in getdict.keys():
            if i != "__module__" and i != "__doc__" and i != "data" and i != "args" and i != "action" and i != "s" and i != "name":
                old_val = conf[i].split(' ')
                if len(old_val) > 1:
                    conf[i] = old_val[0] + ' ' + getdict[i]
        public.writeFile(config_path, json.dumps(conf))

        public.set_server_status('memcached', 'stop')
        args = ''
        for x in conf:
            args += ' ' + conf[x]

        public.writeFile(public.GetConfigValue('setup_path') + '/memcached/runservice', args)
        public.set_server_status('memcached', 'start')

        return public.returnMsg(True, "修改成功!")

    # 申请内测版
    def apple_beta(self, get):
        try:
            userInfo = json.loads(public.ReadFile('data/userInfo.json'))
            p_data = {}
            p_data['uid'] = userInfo['uid'];
            p_data['access_key'] = userInfo['access_key']
            p_data['username'] = userInfo['username']
            result = public.HttpPost(public.GetConfigValue('home') + '/api/wpanel/apple_beta', p_data, 5)
            try:
                return json.loads(result)
            except:
                return public.returnMsg(False, 'AJAX_CONN_ERR')
        except:
            return public.returnMsg(False, 'AJAX_USER_BINDING_ERR')

    # 切回正式版
    def to_not_beta(self, get):
        try:
            userInfo = json.loads(public.ReadFile('data/userInfo.json'))
            p_data = {}
            p_data['uid'] = userInfo['uid'];
            p_data['access_key'] = userInfo['access_key']
            p_data['username'] = userInfo['username']
            result = public.HttpPost(public.GetConfigValue('home') + '/api/wpanel/to_not_beta', p_data, 5)
            try:
                return json.loads(result)
            except:
                return public.returnMsg(False, 'AJAX_CONN_ERR')
        except:
            return public.returnMsg(False, 'AJAX_USER_BINDING_ERR')

    # 升级测试版
    def to_beta(self):
        try:
            userInfo = json.loads(public.ReadFile('data/userInfo.json'))
            p_data = {}
            p_data['uid'] = userInfo['uid'];
            p_data['access_key'] = userInfo['access_key']
            p_data['username'] = userInfo['username']
            public.HttpPost(public.GetConfigValue('home') + '/api/wpanel/to_beta', p_data, 5)
        except:
            pass

    # 获取最新的5条测试版更新日志
    def get_beta_logs(self, get):
        try:
            data = json.loads(public.HttpGet(public.GetConfigValue('home') + '/api/wpanel/get_beta_logs'))
            return data
        except:
            return public.returnMsg(False, 'AJAX_CONN_ERR')

    # 取PHP-FPM日志
    def GetFpmLogs(self, get):
        return public.returnMsg(False, "暂不支持!")

    # 取PHP慢日志
    def GetFpmSlowLogs(self, get):
        return public.returnMsg(False, "暂不支持!")

    # 取指定日志
    def GetOpeLogs(self, get):
        if not os.path.exists(get.path): return public.returnMsg(False, '日志文件不存在!');
        return public.returnMsg(True, public.GetNumLines(get.path, 1000));

    # 取指定行
    def get_lines(self, args):
        if not os.path.exists(args.filename): return public.returnMsg(False, '指定日志文件不存在!')

        limit = 10
        if 'num' in args: limit = int(args['num'])
        s_body = public.GetNumLines(args.filename, limit)

        if len(s_body.strip()) == 0:
            return public.returnMsg(True, '正在下载安装脚本（长时间停留此页面请重启面板）...')

        return public.returnMsg(True, s_body)

    # 检查用户绑定是否正确
    def check_user_auth(self, get):
        m_key = 'check_user_auth'
        if m_key in session: return session[m_key]
        u_path = 'data/userInfo.json'
        try:
            userInfo = json.loads(public.ReadFile(u_path))
        except:
            if os.path.exists(u_path): os.remove(u_path)
            return public.returnMsg(False, '宝塔帐户绑定已失效，请在[设置]页面重新绑定!')
        pdata = {'access_key': userInfo['access_key'], 'secret_key': userInfo['secret_key']}
        result = public.httpPost(public.GetConfigValue('home') + '/api/panel/check_auth_key', pdata, 3);
        if result == '0':
            if os.path.exists(u_path): os.remove(u_path)
            return public.returnMsg(False, '宝塔帐户绑定已失效，请在[设置]页面重新绑定!')
        if result == '1':
            session[m_key] = public.returnMsg(True, '绑定有效!')
            return session[m_key]
        return public.returnMsg(True, result)

    """
    @dns解析模块配置
    """

    def get_dns_config(self, get):
        data = {}
        path = "{}/class/dnsapi/dns_api.json".format(panelPath)
        if os.path.exists(path):
            data = json.loads(public.readFile(path))
        return data

    """
    @保存dns解析模块
    """

    def set_dns_config(self, get):
        path = "{}/class/dnsapi/dns_api.json".format(panelPath)
        data = self.get_dns_config()
        for x in data:
            if x['name'] == get['dns_name']:
                for item in x['data']:
                    if item['key'] in get: item['value'] = get[item['key']]
        public.writeFile(path, json.dumps(data))
        return public.returnMsg(True, "保存成功!")

    def download_pay_type(self, path):
        public.downloadFile(public.get_url() + '/win/panel/data/pay_type.json', path)
        return True

    """
    获取推荐列表
    """

    def get_pay_type(self, get):
        spath = '{}/data/pay_type.json'.format(public.get_panel_path())
        if os.path.exists(spath) and os.path.getsize(spath) <= 0:
            os.remove(spath)

        if not os.path.exists(spath):
            public.run_thread(self.download_pay_type, (spath,))
        try:
            data = json.loads(public.readFile("data/pay_type.json"))
        except json.decoder.JSONDecodeError:
            os.remove(spath)
            public.run_thread(self.download_pay_type, (spath,))
        except Exception:
            data = {}
        # down = cache.get('pay_type')
        # if not down:
        #     public.run_thread(self.download_pay_type,(spath,))
        #     cache.set('pay_type',1,86400)
        # try:
        #     data = json.loads(public.readFile("data/pay_type.json"))
        # except :
        #     data = {}

        import panelPlugin
        plu_panel = panelPlugin.panelPlugin()
        plugin_list = plu_panel.get_cloud_list()

        for item in data:
            if 'list' in item:
                item['list'] = self.__get_home_list(item['list'], item['type'], plugin_list, plu_panel)
                if item['type'] == 1:
                    if len(item['list']) > 4: item['list'] = item['list'][:4]
            if item['type'] == 0 and plugin_list['pro'] >= 0:
                item['show'] = False
        return data

    def __get_home_list(self, sList, stype, plugin_list, plu_panel):
        """
            @name 获取首页软件列表推荐
        """
        nList = []
        webserver = public.get_webserver()
        for x in sList:
            for plugin_info in plugin_list['list']:
                if x['name'] == plugin_info['name']:
                    if plugin_info['endtime'] >= 0:
                        x['isBuy'] = True
            is_check = False
            if 'dependent' in x:
                if x['dependent'] == webserver: is_check = True
            else:
                is_check = True
            if is_check:
                info = plu_panel.get_soft_find(x['name'])
                if info:
                    if stype == 1:
                        if plugin_list['pro'] >= 0: continue
                        if not info['setup']:
                            x['install'] = info['setup']
                            nList.append(x)
                    else:
                        x['install'] = info['setup']
                        nList.append(x)
        return nList

    def get_pd(self, get):
        # 获取授权信息
        from BTPanel import cache
        tmp = -1
        try:
            import panelPlugin
            # get = public.dict_obj()
            # get.init = 1
            tmp1 = panelPlugin.panelPlugin().get_cloud_list(get)
        except:
            tmp1 = None
        if tmp1:
            tmp = tmp1[public.to_string([112, 114, 111])]
            ltd = tmp1.get('ltd', -1)
        else:
            ltd = -1
            tmp4 = cache.get(public.to_string([112, 95, 116, 111, 107, 101, 110]))
            if tmp4:
                tmp_f = public.to_string([100, 97, 116, 97, 47]) + tmp4
                if not os.path.exists(tmp_f): public.writeFile(tmp_f, '-1')
                tmp = public.readFile(tmp_f)
                if tmp: tmp = int(tmp)

        if ltd < 1:

            if tmp == 0:
                pass
            if ltd == -2:
                tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 108, 116, 100,
                                         45, 103, 114, 97, 121, 34, 62, 60, 115, 112, 97, 110, 32, 115, 116, 121, 108, 101,
                                         61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102, 111,
                                         110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32, 98, 111, 108, 100, 59, 109, 97,
                                         114, 103, 105, 110, 45, 114, 105, 103, 104, 116, 58, 53, 112, 120, 34, 62, 24050, 36807,
                                         26399, 60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
                                         108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105, 99, 107, 61, 34, 98, 116, 46, 115, 111,
                                         102, 116, 46, 117, 112, 100, 97, 116, 97, 95, 108, 116, 100, 40, 41, 34, 62, 32493,
                                         36153, 60, 47, 97, 62, 60, 47, 115, 112, 97, 110, 62])
            elif tmp == -1:
                tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98,
                                         116, 112, 114, 111, 45, 102, 114, 101, 101, 34, 32, 111, 110, 99, 108, 105, 99, 107,
                                         61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 117, 112, 100, 97, 116, 97, 95, 99,
                                         111, 109, 109, 101, 114, 99, 105, 97, 108, 95, 118, 105, 101, 119, 40, 41, 34,
                                         32, 116, 105, 116, 108, 101, 61, 34, 28857, 20987, 21319, 32423, 21040,
                                         21830, 19994, 29256, 34, 62, 20813, 36153, 29256, 60, 47, 115, 112, 97, 110, 62])
            elif tmp == -2:
                tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
                                         112, 114, 111, 45, 103, 114, 97, 121, 34, 62, 60, 115, 112, 97, 110, 32,
                                         115, 116, 121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35,
                                         102, 99, 54, 100, 50, 54, 59, 102, 111, 110, 116, 45, 119, 101, 105, 103,
                                         104, 116, 58, 32, 98, 111, 108, 100, 59, 109, 97, 114, 103, 105, 110, 45,
                                         114, 105, 103, 104, 116, 58, 53, 112, 120, 34, 62, 24050, 36807, 26399,
                                         60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115, 115, 61, 34,
                                         98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105, 99, 107, 61,
                                         34, 98, 116, 46, 115, 111, 102, 116, 46, 117, 112, 100, 97, 116, 97, 95,
                                         112, 114, 111, 40, 41, 34, 62, 32493, 36153, 60, 47, 97, 62, 60,
                                         47, 115, 112, 97, 110, 62])
            if tmp >= 0 and ltd in [-1, -2]:
                if tmp == 0:
                    tmp2 = public.to_string([27704, 20037, 25480, 26435])
                    tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
                                             112, 114, 111, 34, 62, 123, 48, 125, 60, 115, 112, 97, 110, 32, 115, 116,
                                             121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 102, 99, 54, 100,
                                             50, 54, 59, 102, 111, 110, 116, 45, 119, 101, 105, 103, 104, 116,
                                             58, 32, 98, 111, 108, 100, 59, 34, 62, 123, 49, 125, 60, 47, 115,
                                             112, 97, 110, 62, 60, 47, 115, 112, 97, 110, 62]).format(
                        public.to_string([21040, 26399, 26102, 38388, 65306]), tmp2)
                else:
                    tmp2 = time.strftime(public.to_string([37, 89, 45, 37, 109, 45, 37, 100]), time.localtime(tmp))
                    tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
                                             112, 114, 111, 34, 62, 21040, 26399, 26102, 38388, 65306, 60, 115, 112,
                                             97, 110, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111, 108, 111, 114,
                                             58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102, 111, 110, 116, 45, 119,
                                             101, 105, 103, 104, 116, 58, 32, 98, 111, 108, 100, 59, 109, 97, 114,
                                             103, 105, 110, 45, 114, 105, 103, 104, 116, 58, 53, 112, 120, 34, 62, 123,
                                             48, 125, 60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115,
                                             115, 61, 34, 98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105, 99,
                                             107, 61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 117, 112, 100, 97,
                                             116, 97, 95, 112, 114, 111, 40, 41, 34, 62, 32493, 36153, 60, 47, 97, 62, 60,
                                             47, 115, 112, 97, 110, 62]).format(tmp2)
            else:
                tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 112,
                                         114, 111, 45, 103, 114, 97, 121, 34, 32, 111, 110, 99, 108, 105, 99, 107,
                                         61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 117, 112, 100, 97, 116, 97,
                                         95, 112, 114, 111, 40, 41, 34, 32, 116, 105, 116, 108, 101, 61, 34, 28857,
                                         20987, 21319, 32423, 21040, 19987, 19994, 29256, 34, 62, 20813, 36153,
                                         29256, 60, 47, 115, 112, 97, 110, 62])
        else:
            tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 108, 116,
                                     100, 34, 62, 21040, 26399, 26102, 38388, 65306, 60, 115, 112, 97, 110, 32, 115, 116,
                                     121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 102, 99, 54, 100, 50,
                                     54, 59, 102, 111, 110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32, 98, 111,
                                     108, 100, 59, 109, 97, 114, 103, 105, 110, 45, 114, 105, 103, 104, 116, 58, 53,
                                     112, 120, 34, 62, 123, 125, 60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108,
                                     97, 115, 115, 61, 34, 98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105,
                                     99, 107, 61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 117, 112, 100, 97, 116, 97,
                                     95, 108, 116, 100, 40, 41, 34, 62, 32493, 36153, 60, 47, 97, 62, 60, 47, 115,
                                     112, 97, 110, 62]).format(time.strftime(public.to_string([37, 89, 45, 37, 109, 45, 37, 100]), time.localtime(ltd)))

        return tmp3, tmp, ltd

    def set_module_logs(self, get):
        """
        @模块使用次数
        @mod_name 模块名称
        @fun_name 函数名
        """
        count = 1
        if 'count' in get: count = int(get.count)
        ret = public.set_module_logs(get.mod_name, get.fun_name, count)
        return ret

    def check_auth_ip(self, get):
        """
        @name 检查授权ip
        """
        return public.check_auth_ip()

    def get_panel_error_info(self, get):
        """
        @name 处理面板常用错误
        """

        error = get.error
        force = 0
        if 'force' in get: force = int(get.force)

        path = '{}/data/panel_error_info.json'.format(public.get_panel_path())
        if not os.path.exists(path) or force:
            public.downloadFile(public.get_url() + '/linux/panel/panel_error_info.json', path)

        if not os.path.exists(path):
            return public.returnMsg(False, '获取失败!')

        data = []
        try:
            data = json.loads(public.readFile(path))
        except:
            pass

        for info in data:
            if 'key' in info:
                for val in info['key']:
                    if not val: continue
                    total, num = 0, 0
                    for tmp in val.split('&'):
                        total += 1
                        if error.lower().find(tmp.lower()) >= 0:
                            num += 1

                    if total > 0 and num == total:
                        return public.returnMsg(True, info['value'])
        return public.returnMsg(False, '未识别的错误信息，请前往<a href="https://www.bt.cn/bbs" class="btlink">宝塔论坛</a> 发帖提问.')

    def create_sql_index(self):
        try:
            import db
            sql = db.Sql().dbfile('system')
            if not sql.query("SELECT name FROM sqlite_master WHERE type='index' AND name='cpu'"):
                sql.execute("CREATE INDEX 'cpu' ON 'cpuio'('addtime')")
            if not sql.query("SELECT name FROM sqlite_master WHERE type='index' AND name='ntwk'"):
                sql.execute("CREATE INDEX 'ntwk' ON 'network'('addtime')")
            if not sql.query("SELECT name FROM sqlite_master WHERE type='index' AND name='disk'"):
                sql.execute("CREATE INDEX 'disk' ON 'diskio'('addtime')")
            if not sql.query("SELECT name FROM sqlite_master WHERE type='index' AND name='load'"):
                sql.execute("CREATE INDEX 'load' ON 'load_average'('addtime')")
            if not sql.query("SELECT name FROM sqlite_master WHERE type='index' AND name='proc'"):
                sql.execute("CREATE INDEX 'proc' ON 'process_top_list'('addtime')")
            public.writeFile('data/sql_index.pl', 'True')
        except:
            pass