コード例 #1
0
 def __dict__(self):
     cpurate = psutil.cpu_percent()  # 获取当前CPU 使用率
     mem = psutil.virtual_memory()
     mem_ava = mem.used / 1024 / 1024  # 换算成 MB
     mem_rate = mem.percent
     ctime = datetime.fromtimestamp(
         psutil.Process(macros.Macro('MONITOR_PID')).create_time())
     delta_time = datetime.now() - ctime
     res = {
         'cpuRate':
         '%f%%' % cpurate,
         'memoryUsage':
         '%dMB, %f%%' % (mem_ava, mem_rate),
         'routerInfo':
         self.routerInfo,
         'bindHost':
         macros.Macro('HOST'),
         'bindPort':
         macros.Macro('PORT'),
         'runningTime':
         '{days}天,{seconds}秒。创建于{ct}'.format(
             days=delta_time.days,
             seconds=delta_time.seconds,
             ct=ctime,
         )
     }
     return res
コード例 #2
0
    def _CheckInstalledInfo(packageInfoObj):
        """
        检查是否满足安装的标准
        :param packageInfoObj: 安装的信息
        :return: 返回 PackageStatus,(Staus, 消息)
        """
        a_arc = macros.Macro('ARC').upper()
        a_platform = macros.Macro('PLATFORM').upper()
        a_apt2Version = macros.Macro('VERSION')

        version = packageInfoObj.version  # 模块的版本
        platform = packageInfoObj.platform.upper()  # 支持的平台信息
        # dependencies = infoJsonObj['dependencies']  # 这个模块需要的python 模块
        arc = packageInfoObj.arc.upper()  # 获取体系结构信息
        ap2version = packageInfoObj.apt2Version  # 需要的版本
        name = packageInfoObj.name  # 模块名称
        # 是否满足安装平台
        if platform != 'ALL' and platform != a_platform:
            return (PackageStatus.Invalid, '不支持的平台:“%s”' % platform)
        # 是否满足安装平台的系统版本
        if arc != 'ALL' and arc != a_arc:
            return (PackageStatus.Invalid, '不支持的处理器体系结构:“%s”' % arc)
        # Appointed2 版本
        apt2cmp_first = ap2version.find(',')
        apt2cmp = ap2version[:apt2cmp_first]
        apt2targetver = ap2version[apt2cmp_first + 1:]
        pred = tools.compareVersion(a_apt2Version, apt2targetver,
                                    apt2cmp)  # 检查是否满足条件
        if not pred:
            return (PackageStatus.Invalid,
                    "安装目标 Appointed2 版本:‘%s’ 不满足 %s ‘%s’" %
                    (a_apt2Version, apt2cmp, apt2targetver))
        # 检查是否有已经存在的版本
        installed = BaseHandler.configMgr
        previousObj = installed.getInstalledPackages().get(
            name, None)  # 是否具有某个安装的信息,返回他的 infos
        if previousObj:
            cv = previousObj['version']
            opts = ('>', '<', '==')
            vs = (PackageStatus.NewerVersion, PackageStatus.OlderVersion,
                  PackageStatus.CurrentVersion)
            for i, opt in enumerate(opts):
                res = tools.compareVersion(version, cv, opt)
                if res:
                    return (vs[i], "安装的版本‘%s’ %s 已经安装的版本‘%s’" %
                            (version, opts[i], cv))
        else:
            return (PackageStatus.NotExists, "安装的版本‘%s’" % version)
コード例 #3
0
 def user_restart(self, enterMaintenace=False):
     """
     重启服务:直接停止事件循环,并向监控程序发送消息
     :param enterMaintenace:是否进入维护模式?
     :return:
     """
     __logger = Appointed2Server.logger
     if enterMaintenace:
         __logger.info('正在重启 Appointed2 服务并进入维护模式')
     else:
         __logger.info('正在重启 Appointed2 服务')
     mpid = macros.Macro('MONITOR_PID', False)
     sig = self.restartEnterManSignal if enterMaintenace else self.restartSignal
     if mpid:
         if os.name == 'nt':
             from libs import sendMessage as t
             # 获取重启的信号
             __logger.info('向监控进程 ‘%d’ 发送重启信号:‘%s’' % (mpid, sig))
             self.loop.stop()
             t.post(mpid, int(sig))
         else:
             self.loop.stop()
             subprocess.Popen(['kill', '-' + sig,
                               str(mpid)])  # 默认是 SIGUSR2 信号
             __logger.info('成功向监控进程 ‘%d’ 发送重启信号:‘%s’' % (mpid, sig))
コード例 #4
0
 def handle(self, request):
     """
     解压缩安装包信息
     :param request: 请求,需要使用属性 packageInfoObj, packageStatus
     :return:
     """
     # 这个是安装过程的需要
     zf = request.packageInfoObj
     try:
         if not request.packageInfoObj:
             request.put('没有指定的安装包信息', msgType='error')
             return
         if not request.packageStatus in ACCEPT_CONTINUE_INSTALLATION:
             # 不能继续安装的情况:信息不完整
             request.put('不能继续解压安装包过程:未满足安装条件')
             return
         ext_path = BaseHandler.generateExtractDir()
         kd = [d.upper() for d in macros.Macro('KEYDIRS').split(';')]
         kf = ('PACKAGE.JSON', )
         # 直接解压
         zf.extract(ext_path, kf, kd)
     except Exception as e:
         request.put('解压缩安装包失败:%s' % zf.packageFile, msgType='error')
         if request.packageInfoObj:
             request.packageInfoObj.close()  # 关闭已经打开的安装包
     else:
         if request.packageInfoObj:
             request.packageInfoObj.close()  # 关闭已经打开的安装包
         request.extractRoot = ext_path  # 这个设置的是解压的路径的根目录
         request.put('成功解压安装包:%s' % zf.packageFile)
         if super().getSuccessor():
             super().getSuccessor().handle(request)
コード例 #5
0
 def generateExtractDir():
     """
     生成安全的解压目录
     :return:
     """
     return macros.sep.join((macros.Macro('CACHEDROOT'),
                             'InstallExtractDir-' + str(time.time())))
コード例 #6
0
class BaseHandler():

    keyDirs = macros.Macro('KEYDIRS').split(';')  # 注意是关键文件夹名称的列表
    # cached_setup_dir = macros.Macro('CACHEDROOT') +  + 'temp_packages'  # 解压缩的临时文件夹
    configMgr = config.getConfigManager()

    logger = logger.get_logger()

    def __init__(self):
        self.successor = None

    def setSuccessor(self, successor):
        self.successor = successor

    def getSuccessor(self):
        return self.successor

    def handle(self, request):
        raise NotImplementedError('子类必须实现 handle')

    @staticmethod
    def generateExtractDir():
        """
        生成安全的解压目录
        :return:
        """
        return macros.sep.join((macros.Macro('CACHEDROOT'),
                                'InstallExtractDir-' + str(time.time())))
コード例 #7
0
def installDependentModules(modules, cwd):
    """
    安装python 关联的安装包
    :param modules: 模块名称,可以带有判断检查 如 aiohttp==2.3
    :param cwd: 运行的目录,可以安装目录下的 whl 文件
    :return: 返回 状态代码,输出信息,错误信息
    """
    try:
        import setuptools
    except ImportError as e:
        # 表明不支持安装
        return -1, '', '不支持安装 Python 模块'  # 未安装的列表
    # 检测pip位置
    prefix = macros.Macro('PYTHON_PREFIX')
    ostype = macros.Macro('PLATFORM')
    if ostype == 'nt':
        pippath = macros.sep.join((prefix, 'Scripts', 'pip.exe'))
    else:
        pippath = macros.sep.join(
            (prefix, 'bin', 'pip' + macros.Macro('PYTHON_VERSION')))
    if not os.path.exists(pippath):
        return -1, '不支持安装 Python 模块:无法找到 pip 程序:‘%s’' % pippath
    # 运行 pip 程序
    args = [pippath, 'install']
    args.extend(modules)
    # 运行程序
    ret = None
    try:
        p = subprocess.Popen(args=' '.join(args),
                             stderr=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             shell=True,
                             cwd=cwd)
        out, err = p.communicate()
        out_dect = chardet.detect(out)
        err_dect = chardet.detect(err)
        retout = out.decode(out_dect['encoding']) if len(out) > 0 else ''
        reterr = err.decode(err_dect['encoding']) if len(err) > 0 else ''
        ret = (p.returncode, retout, reterr)
    except Exception as e:
        ret = (-1, '', '运行模块安装程序出现异常:\n%s\n' % traceback.format_exc())
        _logger.error('运行模块安装程序出现异常。', exc_info=True)
    return ret
コード例 #8
0
 def _updateConfig(packageInfoObj):
     """
     更新已经安装的模块的信息
     :param packageInfoObj: 信息对象
     :return:
     """
     cfgmgr = BaseHandler.configMgr
     configObj = packageInfoObj.__dict__(appendOtherInfo=False)
     configObj['enable'] = True
     configObj['main_package'] = False
     configObj['configFile'] = macros.sep.join(
         (macros.Macro('CONFIGROOT'),
          '%s-%s.json' % (packageInfoObj.name, packageInfoObj.version)))
     cfgmgr.addInstalledPackageInfo(packageInfoObj.name, configObj)
     cfgmgr.save()
     return ['成功更新配置文件']
コード例 #9
0
 def _processInfoFile(infoFile, packageInfoObj):
     """
     这个函数用来辅助处理模块的信息
     :param infoFile: 信息文件
     :param packageInfoObj: 信息文件的对象
     :return:
     """
     packname = packageInfoObj.name
     packversion = packageInfoObj.version
     targetFile = macros.sep.join((macros.Macro('CONFIGROOT'),
                                   '%s-%s.json' % (packname, packversion)))
     # json 写入到config目录的文件下
     with open(targetFile, 'w') as fp:
         i = packageInfoObj.__dict__(appendOtherInfo=True)
         json.dump(i, fp, indent=4)
     # 删除原始的信息
     os.remove(infoFile)
     return ['成功更新模块配置文件:%s' % targetFile]
コード例 #10
0
 def _compileFiles(request):
     """
     编译相关的源文件
     :param request: 请求对象
     :return: 返回 状态(1没有编译,0 所有编译成功,-1 编译有错误),新增文件列表
     """
     a_platform = macros.Macro('PLATFORM')
     infoObj = request.packageInfoObj
     cwd = request.extractRoot
     compile_obj = infoObj.compile
     status = 1
     files = []
     if not compile_obj:
         return 1, files
     # 查询编译的条件
     for compile_name, compile_info in compile_obj.items():
         platform = compile_info.get('platform', '')
         if platform.upper() == 'ALL' or platform.upper(
         ) == a_platform.upper():
             # 需要编译
             status, outfile, output, err = tools.compileDynamicExtension(
                 compilerType=compile_info['compiler'],
                 srcs=compile_info['srcs'],
                 out=compile_info['out'],
                 cwd=cwd)
             # 判断条件
             if status != 0:
                 request.put(
                     "编译对象‘%s’失败,返回值:%d。\n输出的信息:\n%s\n错误/警告输出:\n%s\n" %
                     (compile_name, status, output, err))
                 return -1, files
             else:
                 request.put(
                     "编译对象‘%s’成功,返回值:%d。\n输出的信息:\n%s\n错误/警告输出:\n%s\n" %
                     (compile_name, status, output, err))
                 # 更新文件列表
                 files.append(outfile)
                 status = 0
     # 写入文件列表
     return status, files
コード例 #11
0
 def user_close(self, sendSignal=True):
     """
     调用对象的关闭服务
     :param sendSignal: 是否向宿主程序发送信号
     :return:
     """
     __logger = Appointed2Server.logger
     __logger.info('正在关闭 Appointed2 服务')
     mpid = macros.Macro('MONITOR_PID', False)
     sig = self.closeSignal
     if mpid:
         if os.name == 'nt':
             from libs import sendMessage as t
             # 获取重启的信号
             __logger.info('向监控进程 ‘%d’ 发送关闭信号:‘%s’' % (mpid, sig))
             self.loop.stop()
             if sendSignal:
                 t.post(mpid, int(sig))
         else:
             self.loop.stop()
             subprocess.Popen(['kill', '-' + sig,
                               str(mpid)])  # 默认是 SIGUSR2 信号
             __logger.info('成功向监控进程 ‘%d’ 发送关闭信号:‘%s’' % (mpid, sig))
コード例 #12
0
 def __init__(self, packageName, modObj=None, **kwargs):
     """
     模块的信息 __是受保护的内容
     valid:是否有效
     doc:注释信息
     version:模块的信息
     author:作者
     rotuers:可调用对象->{方法,路由,解释,级别,系统}
     commandLines:支持的命令行参数版本
     moduleObject:模块的实例
     main_package:是否是主模块
     :param packageName: 模块的名称
     :return:
     """
     try:
         package_root_modtype = macros.Macro('PACKAGEROOT_IMPORT')
         self.routers = dict()
         self.commandLines = dict()
         self.name = packageName
         self.main_package = False
         if self.name == 'Common':
             self.main_package = True
         if not modObj:
             # 载入packages下的模块
             targetdir = macros.Macro('PACKAGEROOT') + os.sep + packageName
             if not os.path.exists(targetdir) or not os.path.isdir(
                     targetdir):
                 self.valid = False
                 return
             modObj = getattr(
                 __import__(package_root_modtype, globals(), locals(),
                            [packageName]), packageName)  # 导入模块
         if not modObj:
             self.valid = False
             return
         self.valid = True
         self.fullName = '.'.join((package_root_modtype, packageName))
         # 读取doc、version、author以及各个路由器的信息(只在公共接口中__all__)以及路由的命令行格式(如果有)
         if getattr(modObj, '__all__', None):
             # 合法的模块
             for api in getattr(modObj, '__all__', None):
                 fn = getattr(modObj, api)
                 if callable(fn):
                     # 是一个可调用对象
                     method = getattr(fn, '__method__', None)
                     path = getattr(fn, '__route__', None)
                     adminAcquire = getattr(fn, '__adminLevel__', None)
                     if method and path:
                         # 添加路由
                         # self.routers[fn] = {'method': method, 'route': path, 'doc':inspect.getdoc(fn),
                         #                     'level':'api' if path.startswith('/api') else 'user',
                         #                     'system':self.main_package
                         #                     }  # 可调用对象->{方法,路由,解释,级别,系统}
                         # 读取命令行参数
                         if not asyncio.iscoroutinefunction(
                                 fn) and not inspect.isgeneratorfunction(
                                     fn):  # 检查是否是异步函数
                             fn = asyncio.coroutine(fn)
                         # 确定router级别
                         rt_level = 'user'
                         if path.startswith('/api'):
                             rt_level = 'api'
                         elif path.startswith('/ws'):
                             rt_level = 'websocket'
                         rt = Router.Router(
                             method=method,
                             route=path,
                             doc=inspect.getdoc(fn),
                             level=rt_level,
                             system=self.main_package,
                             func=fn,
                             acquireAdmin=adminAcquire)  # 定义成Router 类
                         self.routers[rt.flagName] = rt
         if getattr(modObj, '__cmdLines__', None):
             self.commandLines = modObj.__cmdLines__  # 直接绑定为命令行
         self.version = getattr(modObj, '__version__', '')
         self.author = getattr(modObj, '__author__', '')
         self.doc = getattr(modObj, '__doc__', '')
         self.moduleObject = modObj
         # 构建对象
         Package.logger.info('模块对象‘%s’载入成功' % self.name)
     except Exception as e:
         # 处理错误
         Package.logger.error('初始化模块对象出现问题:%s\n堆栈信息:%s\n' %
                              (str(e.args), traceback.format_exc()))
         self.valid = False
         raise e
コード例 #13
0
def run():
    """
    运行服务
    :return: 不返回值
    """
    try:
        global __logger_core
        initEnv.InitEnv(True)

        kws = dict()  # 运行参数
        loop = asyncio.get_event_loop()
        kws['loop'] = loop
        kws['logout'] = True
        # 加载配置设置器
        cfgr = config.getConfigManager()
        kws['configMgr'] = cfgr
        options, noOptArgs = getopt.getopt(
            sys.argv[1:],
            'm:h:p:r:c:e:n',
            (
                'monitorpid=',
                'host=',
                'port=',
                'restartSignal=',
                'closeSignal=',
                'dbname=',
                'dbusername='******'dbpassword='******'dbaddress=',
                'dbport=',
                'dbdbname=',  # 数据库方面
                'maintenanceSignal=',
                'nologout'))
        for name, value in options:
            if name in ('-h', '--host'):
                kws['host'] = value
            elif name in ('-p', '--port'):
                kws['port'] = int(value)
            elif name in ('-n', '--nologout'):
                kws['logout'] = False  # 不显示输出
            elif name in ('-m', '--monitorpid'):
                # 设置监控器PID
                macros.SetMacro('MONITOR_PID', int(value))
            elif name in ('--restartSignal', '-r'):
                kws['restartSignal'] = value
            elif name in ('--closeSignal', '-c'):
                kws['closeSignal'] = value
            elif name in ('--maintenanceSignal', '-e'):
                kws['maintenanceSignal'] = value
            elif name in ('--dbname', ):
                kws['dbname'] = value
            elif name in ('--dbusername', ):
                kws['dbusername'] = value
            elif name in ('--dbpassword', ):
                kws['dbpassword'] = value
            elif name in ('--dbaddress', ):
                kws['dbaddress'] = value
            elif name in ('--dbdbname', ):
                kws['dbdbname'] = value
            elif name in ('--dbport', ):
                kws['dbport'] = int(value)
            else:  # 不允许有不同的参数。可能以后会有可选的配置
                print('%s\n\n未知的参数 ‘%s’' % (__usage, name), file=sys.stderr)
                exit(-1)
        # 是否限定了启动的限定的运行的模块
        if len(noOptArgs) == 0:
            # 读取所有的模块
            packages = cfgr.getInstalledPackages()
            noOptArgs = [
                name for name, infos in packages.items() if infos['enable']
            ]
        macros.SetMacro('HOST', kws['host'])
        macros.SetMacro('PORT', kws['port'])
        macros.SetMacro('ADDRESS', 'http://%s:%d' % (kws['host'], kws['port']))
        signal.signal(signal.SIGTERM, onSignal_KILL)
        # 初始化日志系统
        fp = os.path.sep.join(
            (macros.Macro('LOGROOT'), 'server-%s.txt' % str(time.time())))
        logger.init_logger(fp, kws['logout'])
        __logger_core = logger.get_logger()
    except Exception as e:
        msg = '无法运行Appointed2服务器,因为出现错误%s,消息:%s\n%s' % (str(
            type(e)), str(e.args), traceback.format_exc())
        if __logger_core:
            __logger_core.error(msg)
        else:
            print(msg, file=sys.stderr)
        exit(-1)
    else:
        webApp_obj = None
        try:
            # print(macros.macro)

            webApp_obj = Appointed2Server(*noOptArgs, **kws)
            webApp_obj.run()
        except KeyboardInterrupt:
            pass
        if webApp_obj:
            webApp_obj.close()
コード例 #14
0
    installed = __runInfo.getInstalledPackages()
    s = '\n'.join([
        '%16s|%12s|%8s|%8s' % (infos['name'], infos['version'],
                               str(infos['enable']), str(infos['system']))
        for k, infos in installed.items()
    ])
    return rets % (len(installed), s)


if __name__ == '__main__':
    # 初始化环境
    initEnv.InitEnv(True)
    # 初始化logger 输出
    logger.init_logger(
        macros.sep.join(
            (macros.Macro('LOGROOT'), 'main-%s.log' % str(time.time()))), True)
    if os.name != 'nt':
        signal.signal(signal.SIGTERM,
                      onReceive_killSignal)  # 这个是默认的,用于关闭整个程序,Linux
        # 关联其他信号
        signal.signal(getSignalIDByStr(__runInfo.cmds['closeSignal']),
                      lambda n, s: process_kill())
        signal.signal(getSignalIDByStr(__runInfo.cmds['restartSignal']),
                      lambda n, s: process_restart())
        signal.signal(getSignalIDByStr(__runInfo.cmds['maintenanceSignal']),
                      lambda n, s: process_restart(enterMaintenance=True))
    interactive = __runInfo.interactive
    # 进行用户交互
    if not interactive:
        code = 'RUN'
    else: