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

import system, psutil, time, public, db, os, sys, json

setup_path = public.GetConfigValue('setup_path')
os.chdir(setup_path + '/panel')
sm = system.system()
taskConfig = json.loads(public.ReadFile('config/task.json'))

oldEdate = None
def control_init():
    try:
        rtips = '{}/panel/data/restart.pl'.format(setup_path)
        reload_tips = '{}/panel/data/reload.pl'.format(setup_path)
        if os.path.exists(rtips): os.remove(rtips)
        if os.path.exists(reload_tips): os.remove(reload_tips)
    except:
        pass
    sql = db.Sql().dbfile('system')
    csql = '''CREATE TABLE IF NOT EXISTS `load_average` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`pro` REAL,
`one` REAL,
`five` REAL,
`fifteen` REAL,
`addtime` INTEGER
)'''
    sql.execute(csql, ())
    public.M('sites').execute("alter TABLE sites add edate integer DEFAULT '0000-00-00'", ());
    public.M('sites').execute("alter TABLE sites add type_id integer DEFAULT 0", ());
    public.M('sites').execute("alter TABLE sites add type_version TEXT DEFAULT ''", ());

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'sites', '%type_id%')).count():
        public.M('sites').execute("alter TABLE sites add type_id integer DEFAULT 0", ())

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'sites', '%edate%')).count():
        public.M('sites').execute("alter TABLE sites add edate integer DEFAULT '0000-00-00'", ())

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?',
                                           ('table', 'sites', '%project_type%')).count():
        public.M('sites').execute("alter TABLE sites add project_type STRING DEFAULT 'PHP'", ())

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?',
                                           ('table', 'sites', '%project_config%')).count():
        public.M('sites').execute("alter TABLE sites add project_config STRING DEFAULT '{}'", ())

    sql = db.Sql()
    csql = '''CREATE TABLE IF NOT EXISTS `site_types` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` REAL,
`ps` REAL
)'''
    sql.execute(csql, ())

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'logs', '%username%')).count():
        public.M('logs').execute("alter TABLE logs add uid integer DEFAULT '1'", ())
        public.M('logs').execute("alter TABLE logs add username TEXT DEFAULT 'system'", ())

    if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'download_token')).count():
        csql = '''CREATE TABLE IF NOT EXISTS `download_token` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`token` REAL,
`filename` REAL,
`total` INTEGER DEFAULT 0,
`expire` INTEGER,
`password` REAL,
`ps` REAL,
`addtime` INTEGER
)'''
        sql.execute(csql, ())

    if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'messages')).count():
        csql = '''CREATE TABLE IF NOT EXISTS `messages` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`level` TEXT,
`msg` TEXT,
`state` INTEGER DEFAULT 0,
`expire` INTEGER,
`addtime` INTEGER
)'''
        sql.execute(csql, ())

    if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'temp_login')).count():
        csql = '''CREATE TABLE IF NOT EXISTS `temp_login` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`token` REAL,
`salt` REAL,
`state` INTEGER,
`login_time` INTEGER,
`login_addr` REAL,
`logout_time` INTEGER,
`expire` INTEGER,
`addtime` INTEGER
)'''
        sql.execute(csql, ())


    if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'database_servers')).count():
        csql = '''CREATE TABLE IF NOT EXISTS `database_servers` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`db_host` REAL,
`db_port` REAL,
`db_user` INTEGER,
`db_password` INTEGER,
`db_type` REAL,
`ps` REAL,
`addtime` INTEGER
)'''
        sql.execute(csql,())

    sql.execute("alter TABLE backup add backup_type TEXT", ());
    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'database_servers','%db_type%')).count():
        public.M('databases').execute("alter TABLE database_servers add db_type REAL DEFAULT 'mysql'",())

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'databases','%sid%')).count():
        public.M('databases').execute("alter TABLE databases add sid integer DEFAULT 0",())
    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'databases','%db_type%')).count():
        public.M('databases').execute("alter TABLE databases add db_type integer DEFAULT '0'",())

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'databases','%conn_config%')).count():
        public.M('databases').execute("alter TABLE databases add conn_config STRING DEFAULT '{}'",())

    first_init()

    if os.path.exists('plugin/testa/testa_main.py'):
        import shutil
        shutil.rmtree('plugin/testa')
    clean_session()

    public.M('users').where('email=? or email=?', ('287962566@qq.com', 'amw_287962566@qq.com')).setField('email','test@message.com')

    if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'users', '%salt%')).count():
        public.M('users').execute("ALTER TABLE 'users' ADD 'salt' TEXT", ())

    ndb = public.M('databases').order("id desc").field('id,pid,name,username,password,accept,ps,addtime,type').select()
    if type(ndb) == str:
        public.M('databases').execute("alter TABLE databases add type TEXT DEFAULT MySQL",());

    public.chdck_salt()

    lpath = '{}/data/local.txt'.format(public.get_panel_path())
    if not os.path.exists(lpath): public.run_thread(public.get_pip_url)


    stop_iis_default()
    re_nginx()
    re_iis()
    check_dnsapi()
    check_default_curl_file()
    # check_safe()

    test_ping()
    try:
        pma_path = public.to_path(setup_path + '/phpmyadmin/pma')
        if os.path.exists(pma_path): os.system("rd /s/q {}".format())

        ad_path = public.to_path(setup_path + '/panel/plugin/adminer')
        if os.path.exists(ad_path): os.system("rd /s/q {}".format(ad_path))

        public.ExecShell('net start btTask')
    except:
        pass

    try:
        if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?',('table', 'messages', '%retry_num%')).count():
            public.M('messages').execute("alter TABLE messages add send integer DEFAULT 0", ())
            public.M('messages').execute("alter TABLE messages add retry_num integer DEFAULT 0", ())
    except:pass

    try:
        sync_node_list()
    except : pass

def check_default_curl_file():
    default_file = '{}/data/default_curl.pl'.format(public.get_panel_path())
    if os.path.exists(default_file):
        default_curl_body = public.readFile(default_file)
        if default_curl_body:
            public.WriteFile(default_file,default_curl_body.strip())

def sync_node_list():
    import config
    config.config().sync_cloud_node_list()

def test_ping():
    _f = 'data/ping_token.pl'
    if os.path.exists(_f): os.remove(_f)

    try:
        import panelPing
        panelPing.Test().create_token()
    except:
        pass


def re_pma():
    pass
#    try:
#        web_server = public.get_webserver()
#        pma_path = setup_path + '/phpmyadmin'
#        if web_server == 'iis':
#            cpath = pma_path + '/web_config/rewrite.config'
#            if not os.path.exists(cpath): return
#            conf = public.readFile(cpath)
#            if conf.find('deny_pma') == -1:
#                public.writeFile(cpath, '''<?xml version="1.0" encoding="UTF-8"?>
#<rules>
#	<clear />
#    <rule name="deny_pma" stopProcessing="true">
#        <match url="^pma" />
#        <action type="AbortRequest" />
#    </rule>
#</rules>''')
#                public.serviceReload('phpmyadmin')
#        elif web_server == 'apache':
#            cpath = setup_path + '/phpmyadmin/.htaccess'
#            if not os.path.exists(cpath): return;
#            conf = public.readFile(cpath)
#            if conf.find('pma') == -1:
#                public.writeFile(cpath, '''RewriteEngine on
#RewriteRule ^pma - [F,L]''')
#                public.serviceReload()
#        elif web_server == 'nginx':

#            cpath = setup_path + '/nginx/conf/rewrite/phpmyadmin'
#            if os.path.exists(cpath):
#                cpath = cpath + '/deny_pma.conf'
#                if not os.path.exists(cpath):
#                    public.writeFile(cpath, '''location ^~ /pma {
#  return 403;
#}''')
#                    public.serviceReload()
#    except:
#        pass


def check_safe():
    import panelMessage  # 引用消息提醒模块
    pm = panelMessage.panelMessage()
    if public.process_exists('SafeDogGuardCenter.exe'):
        if pm.is_level('safe_dog'):
            pm.create_message(level='safe_dog', expire=3650,msg='您的服务器安装了【安全狗】,为了不影响您正常使用，请将【面板目录】加入到白名单中 ->> <a class="btlink" href="javascript:;"></a>')

    if public.process_exists('yunsuo_agent_service'):
        if pm.is_level('safe_yunsuo'):
            pm.create_message(level='safe_yunsuo', expire=3650, msg='您的服务器安装了【云锁】,为了不影响您正常使用，请将【面板目录】加入到白名单中 ->> <a class="btlink" href="javascript:;"></a>')


# 检查dnsapi
def check_dnsapi():
    dnsapi_file = 'config/dns_api.json'
    tmp = public.readFile(dnsapi_file)
    if not tmp: return False
    dnsapi = json.loads(tmp)
    if tmp.find('CloudFlare') == -1:
        cloudflare = {
            "ps": "使用CloudFlare的API接口自动解析申请SSL",
            "title": "CloudFlare",
            "data": [{
                "value": "",
                "key": "SAVED_CF_MAIL",
                "name": "E-Mail"
            }, {
                "value": "",
                "key": "SAVED_CF_KEY",
                "name": "API Key"
            }],
            "help": "CloudFlare后台获取Global API Key",
            "name": "CloudFlareDns"
        }
        dnsapi.insert(0, cloudflare)
    check_names = {"dns_bt": "Dns_com", "dns_dp": "DNSPodDns", "dns_ali": "AliyunDns", "dns_cx": "CloudxnsDns"}
    for i in range(len(dnsapi)):
        if dnsapi[i]['name'] in check_names:
            dnsapi[i]['name'] = check_names[dnsapi[i]['name']]

    public.writeFile(dnsapi_file, json.dumps(dnsapi))
    return True


def re_iis():
    if not os.path.exists('data/re.iis'):
        data = public.M('sites').field('id,name,path').select()
        for x in data:
            try:
                path = "{}/web_config/php.config".format(x['path'])
                if os.path.exists(path):
                    conf = public.readFile(path)
                    if conf:
                        conf = conf.replace('Unspecified', 'File')
                        public.writeFile(path, conf)
            except:
                pass
        public.writeFile('data/re.iis', 'True')


def re_nginx():
    pPath = setup_path + '/nginx/conf/php'
    if not os.path.exists(pPath): return

    tip_file = 'data/re.nginx'
    if os.path.exists(tip_file):
        return

    n = 0
    for x in os.listdir(pPath):
        version = x.replace(".conf", "")
        if version == '00': continue

        filename = pPath + '/' + x;
        conf = public.readFile(filename)

        if conf.find('try_files') != -1 and conf.find(version) != -1: continue

        phpconfig = '''location ~ \.php(.*)$ {
    try_files $uri =404;
    fastcgi_pass   127.0.0.1:200%s;
	fastcgi_index  index.php;

	set $real_script_name $fastcgi_script_name;
	if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
			set $real_script_name $1;
			set $path_info $2;
	 }
	fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
	fastcgi_param SCRIPT_NAME $real_script_name;
	fastcgi_param PATH_INFO $path_info;

	include        fastcgi_params;
}''' % (version)

        public.writeFile(filename, phpconfig)
        n += 1
    if n > 0:
        public.writeFile(tip_file,'True')
        public.serviceReload()

    # 镜像启动重置账号和密码


def first_init():
    if os.path.exists('data/first_init.pl'):

        ver = public.readFile('data/o.pl')
        if ver == 'tencent':
            public.writeFile('data/admin_path.pl', '/tencentcloud')
        else:
            # 面板随机入口
            if not os.path.exists('data/admin_path.pl'):
                public.writeFile('data/admin_path.pl', '/' + public.GetRandomString(8))

        # 面板用户名密码
        password = public.GetRandomString(12)
        pwd = public.password_salt(public.md5(password),uid=1)
        public.M('users').where('id=?', (1,)).setField('password', pwd)

        public.writeFile('data/default.pl', password)
        public.M('users').where('id=?', (1,)).setField('username', public.GetRandomString(8))

        password1 = public.GetRandomString(110) + public.GetRandomString1(20) + public.GetRandomString2(20)
        os.system('net user www "%s"' % password1)
        public.writeFile('data/www', password1)

        password2 = public.GetRandomString(110) + public.GetRandomString1(20) + public.GetRandomString2(20)
        os.system('net user mysql "%s"' % password2)
        public.writeFile('data/mysql', password2)

        os.remove('data/first_init.pl')


# 清理多余的session文件
def clean_session():
    try:
        session_path = 'data/session'
        if not os.path.exists(session_path): return False

        l_list = []  # 已登录session
        d_list = []  # 未登录session

        for filename in os.listdir(session_path):
            filePath = '/'.join((session_path, filename))
            sobj = (filename, int(os.stat(filePath).st_mtime))
            if os.path.getsize(filePath) > 1024:
                l_list.append(sobj)
            else:
                d_list.append(sobj)

        try:
            # 已经登录session保存最新20份
            n = 0
            l_list = sorted(l_list, key=lambda x: x[1], reverse=True)
            for x in l_list:
                try:
                    if n >= 20:
                        filePath = '/'.join((session_path, x[0]))
                        os.remove(filePath)
                except:
                    pass
                n += 1
        except:pass

        try:
            # 未登录session保存最新100份
            n = 0
            d_list = sorted(d_list, key=lambda x: x[1], reverse=True)
            for x in d_list:
                try:
                    if n >= 100:
                        filePath = '/'.join((session_path, x[0]))
                        os.remove(filePath)
                except:
                    pass
                n += 1
        except:pass
    except:
        pass


# 监控任务
def control_task():
    global sm, taskConfig
    if not taskConfig['control']['open']: return False
    day = taskConfig['control']['day'];
    if day < 1:
        return False

    sql = db.Sql().dbfile('system')

    # 取当前CPU Io
    cpuUsed = sm.get_cpu_percent()
    memUsed = get_mem_used()

    # 取当前网络Io
    networkInfo = sm.GetNetWork(False)

    # 取磁盘Io
    if os.path.exists('/proc/diskstats'):
        diskInfo = sm.get_io_info()

    addtime = int(time.time())
    deltime = addtime - (day * 86400)

    data = (cpuUsed, memUsed, addtime)
    sql.table('cpuio').add('pro,mem,addtime', data)
    sql.table('cpuio').where("addtime<?", (deltime,)).delete();

    data = (networkInfo['up'], networkInfo['down'], networkInfo['upTotal'], networkInfo['downTotal'],
            networkInfo['downPackets'], networkInfo['upPackets'], addtime)
    sql.table('network').add('up,down,total_up,total_down,down_packets,up_packets,addtime', data)
    sql.table('network').where("addtime<?", (deltime,)).delete();

    if os.path.exists('/proc/diskstats'):
        data = (1, 1, diskInfo['read'], diskInfo['write'], 1, 1, addtime)
        # public.writeFile('/tmp/1.txt',str((time.time(),data)) + "\n",'a+')
        sql.table('diskio').add('read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime', data)
        sql.table('diskio').where("addtime<?", (deltime,)).delete();

    # LoadAverage
    load_average = sm.GetLoadAverage(None)
    lpro = round((load_average['one'] / load_average['max']) * 100, 2)
    if lpro > 100: lpro = 100;
    sql.table('load_average').add('pro,one,five,fifteen,addtime',
                                  (lpro, load_average['one'], load_average['five'], load_average['fifteen'], addtime))


# 取内存使用率
def get_mem_used():
    mem = psutil.virtual_memory()
    memInfo = {'memTotal': mem.total / 1024 / 1024, 'memFree': mem.free / 1024 / 1024,
               'memBuffers': mem.buffers / 1024 / 1024, 'memCached': mem.cached / 1024 / 1024}
    tmp = memInfo['memTotal'] - memInfo['memFree'] - memInfo['memBuffers'] - memInfo['memCached']
    tmp1 = memInfo['memTotal'] / 100
    return int(tmp / tmp1)




# 网站到期处理
def site_end_task():
    global oldEdate
    if not oldEdate: oldEdate = public.readFile('data/edate.pl')
    if not oldEdate: oldEdate = '0000-00-00'
    mEdate = time.strftime('%Y-%m-%d', time.localtime())
    if oldEdate == mEdate: return False
    edateSites = public.M('sites').where('edate>? AND edate<? AND (status=? OR status=?)',
                                         ('0000-00-00', mEdate, 1, u'正在运行')).field('id,name').select()
    import panelSite, common
    siteObject = panelSite.panelSite()
    for site in edateSites:
        get = common.dict_obj()
        get.id = site['id']
        get.name = site['name']
        siteObject.SiteStop(get)
    oldEdate = mEdate
    public.writeFile('data/edate.pl', mEdate)


def stop_iis_default():
    """
    @name ip建站停止默认站点
    """
    appcmd = 'C:/Windows/System32/inetsrv/appcmd.exe'
    slist = public.M('domain').select()
    for val in slist:
        try:
            if public.check_ip(val['name']):
                public.ExecShell(appcmd + ' stop site "Default Web Site"')
                find = public.M('sites').where('id=?', (val['pid'],)).find()
                if find:
                    public.ExecShell(appcmd + ' start site "' + find['name'] + '"')
        except:pass

class JobsConfig:
    JOBS = []
    SCHEDULER_API_ENABLED = True

    def __init__(self):
        global taskConfig
        self.JOBS = taskConfig['JOBS']


if __name__ == '__main__':
    control_init()
