diff --git a/server/share/etc/web.ini.in b/server/share/etc/web.ini.in index a39538d..8f29247 100644 --- a/server/share/etc/web.ini.in +++ b/server/share/etc/web.ini.in @@ -16,9 +16,21 @@ port=7190 # LOG_LEVEL_ERROR 4 log error message only. log-level=2 -; running in debug mode. default to 0. +; 0/1. default to 0. ; in debug mode, log-level set to 0 and trace call stack while exception raise. -debug=0 +debug-mode=0 core-server-rpc=http://127.0.0.1:52080/rpc +[database] +; sqlite/mysql +type=sqlite + +;sqlite-file=/var/lib/teleport/data/ts_db.db + +;mysql-host=127.0.0.1 +;mysql-port=3306 +;mysql-db=teleport +;mysql-prefix=tp_ +;mysql-user=user +;mysql-password=password diff --git a/server/tp_web/src/tp_web.vs2015.vcxproj b/server/tp_web/src/tp_web.vs2015.vcxproj index 3dcad89..50c13f8 100644 --- a/server/tp_web/src/tp_web.vs2015.vcxproj +++ b/server/tp_web/src/tp_web.vs2015.vcxproj @@ -1,212 +1,212 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {6548CB1D-A7BA-4A68-9B3F-A5129F77868B} - Win32Proj - tp_web - 8.1 - tp_web - - - - Application - true - v140_xp - Unicode - - - Application - false - v140_xp - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - ..\..\..\out\server\$(PlatformTarget)\$(Configuration)\ - ..\..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ - D:\apps\vld\include;$(IncludePath) - D:\apps\vld\lib\Win32;$(LibraryPath) - - - true - ..\..\out\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ - ..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ - - - false - ..\..\..\out\server\$(PlatformTarget)\$(Configuration)\ - ..\..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ - - - false - ..\..\out\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ - ..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;LIBSSH_STATIC;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MG_ENABLE_THREADS;MG_DISABLE_HTTP_DIGEST_AUTH;MG_DISABLE_MQTT;MG_DISABLE_SSI;MG_DISABLE_FILESYSTEM;%(PreprocessorDefinitions) - true - ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include - MultiThreadedDebug - - - Console - - - libcmt.lib - - - - - - - Level3 - Disabled - _DEBUG;_WINDOWS;%(PreprocessorDefinitions) - true - ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include - - - Windows - true - ../../external/windows/openssl/lib;../../external/windows/zlib/lib;../../external/windows/libssh/lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;LIBSSH_STATIC;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MG_ENABLE_THREADS;MG_DISABLE_HTTP_DIGEST_AUTH;MG_DISABLE_MQTT;MG_DISABLE_SSI;MG_DISABLE_FILESYSTEM;%(PreprocessorDefinitions) - true - ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include - MultiThreaded - - - Console - true - true - - - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - true - ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include - - - Windows - true - true - true - ../../external/windows/openssl/lib;../../external/windows/zlib/lib;../../external/windows/libssh/lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {6548CB1D-A7BA-4A68-9B3F-A5129F77868B} + Win32Proj + tp_web + 8.1 + tp_web + + + + Application + true + v140_xp + Unicode + + + Application + false + v140_xp + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + ..\..\..\out\server\$(PlatformTarget)\$(Configuration)\ + ..\..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ + D:\apps\vld\include;$(IncludePath) + D:\apps\vld\lib\Win32;$(LibraryPath) + + + true + ..\..\out\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ + ..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ + + + false + ..\..\..\out\server\$(PlatformTarget)\$(Configuration)\ + ..\..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ + + + false + ..\..\out\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ + ..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + true + ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include + MultiThreadedDebug + + + Console + + + libcmt.lib + + + + + + + Level3 + Disabled + _DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include + + + Windows + true + ../../external/windows/openssl/lib;../../external/windows/zlib/lib;../../external/windows/libssh/lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + true + ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include + MultiThreaded + + + Console + true + true + + + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + ../../../common/libex/include;../../../common/pyshell/include;../../../external/python/include + + + Windows + true + true + true + ../../external/windows/openssl/lib;../../external/windows/zlib/lib;../../external/windows/libssh/lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/www/teleport/app/eom_app/app/__init__.py b/server/www/teleport/app/eom_app/app/__init__.py index fff68ce..1df5683 100644 --- a/server/www/teleport/app/eom_app/app/__init__.py +++ b/server/www/teleport/app/eom_app/app/__init__.py @@ -1,19 +1,19 @@ -# -*- coding: utf-8 -*- - -from .core import WebServerCore -from eom_common.eomcore.logger import * - -__all__ = ['run'] - - -def run(options): - _app = WebServerCore() - - log.i('\n') - log.i('###############################################################\n') - log.i('Teleport Web Server starting ...\n') - - if not _app.init(options): - return 1 - - return _app.run() +# -*- coding: utf-8 -*- + +from .core import WebServerCore +from eom_common.eomcore.logger import * + +__all__ = ['run'] + + +def run(options): + _app = WebServerCore() + + if not _app.init(options): + return 1 + + log.i('\n') + log.i('###############################################################\n') + log.i('Teleport Web Server starting ...\n') + + return _app.run() diff --git a/server/www/teleport/app/eom_app/app/configs.py b/server/www/teleport/app/eom_app/app/configs.py index 9a6f159..930518b 100644 --- a/server/www/teleport/app/eom_app/app/configs.py +++ b/server/www/teleport/app/eom_app/app/configs.py @@ -3,7 +3,7 @@ import configparser import os -from eom_common.eomcore.logger import * +from eom_common.eomcore.logger import log __all__ = ['app_cfg'] @@ -64,27 +64,27 @@ class ConfigFile(AttrDict): if self['log_file'] is not None: self['log_path'] = os.path.dirname(self['log_file']) - self['log_level'] = LOG_INFO + self['log_level'] = log.LOG_INFO _level = _comm.getint('log-level', 2) if _level == 0: - self['log_level'] = LOG_DEBUG + self['log_level'] = log.LOG_DEBUG elif _level == 1: - self['log_level'] = LOG_VERBOSE + self['log_level'] = log.LOG_VERBOSE elif _level == 2: - self['log_level'] = LOG_INFO + self['log_level'] = log.LOG_INFO elif _level == 3: - self['log_level'] = LOG_WARN + self['log_level'] = log.LOG_WARN elif _level == 4: - self['log_level'] = LOG_ERROR + self['log_level'] = log.LOG_ERROR else: - self['log_level'] = LOG_VERBOSE + self['log_level'] = log.LOG_VERBOSE # log.set_attribute(min_level=self['log_level']) self['debug'] = False _debug = _comm.getint('debug', 0) if _debug == 1: - self['log_level'] = LOG_DEBUG + self['log_level'] = log.LOG_DEBUG self['debug'] = True self['core_server_rpc'] = _comm.get('core-server-rpc', 'http://127.0.0.1:52080/rpc') @@ -139,22 +139,7 @@ class ConfigFile(AttrDict): return True -class WebConfig: - def __init__(self): - import builtins - if '__web_config__' in builtins.__dict__: - raise RuntimeError('WebConfig object exists, you can not create more than one instance.') - - self.cfg = {} - - self.default_cfg = {} - - @property - def server_ip(self): - return self.cfg['ip'] - - -class AppConfig(dict): +class BaseAppConfig(dict): def __init__(self, **kwargs): super().__init__(**kwargs) @@ -162,36 +147,13 @@ class AppConfig(dict): if '__app_cfg__' in builtins.__dict__: raise RuntimeError('AppConfig instance already exists.') - self['_cfg_default'] = { - 'common': { # ini 小节名称 - 'port': { # 名称 - 'value': '8081', # 内容 - 'comment': None # 注释 - }, - 'log_file': { - # 'value': None, - 'comment': '`log_file` define the log file location. if not set, default location\n' - 'to %APPROOT%/log/web.log\n' - 'log-file=/var/log/blockchain-dashboard/web.log' - }, - 'log_level': { - 'value': 2, - 'comment': 'log_level can be 0 ~ 4, default value is 2.\n' - 'LOG_LEVEL_DEBUG 0 log every-thing.\n' - 'LOG_LEVEL_VERBOSE 1 log every-thing but without debug message.\n' - 'LOG_LEVEL_INFO 2 log infomation/warning/error message.\n' - 'LOG_LEVEL_WARN 3 log warning and error message.\n' - 'LOG_LEVEL_ERROR 4 log error message only.' - } - } - } + self['_cfg_default'] = {} self['_cfg_loaded'] = {} - # self['_kvs'] = AttrDict() - self['_kvs'] = {'_': AttrDict()} - self['_cfg_file'] = '' + self._on_init() + def __getattr__(self, name): if name in self['_kvs']: return self['_kvs'][name] @@ -207,8 +169,8 @@ class AppConfig(dict): _sec = '_' _key = x[0] elif 2 == len(x): - _sec = x[0] - _key = x[1] + _sec = x[0].replace('-', '_') + _key = x[1].replace('-', '_') else: raise RuntimeError('invalid name.') @@ -216,14 +178,23 @@ class AppConfig(dict): self['_kvs'][_sec] = {} self['_kvs'][_sec][_key] = val + def _on_init(self): + raise RuntimeError('can not create instance for base class.') + + def _on_get_save_info(self): + raise RuntimeError('can not create instance for base class.') + + def _on_load(self, cfg_parser): + raise RuntimeError('can not create instance for base class.') + def set_kv(self, key, val): x = key.split('::') if 1 == len(x): _sec = '_' _key = x[0] elif 2 == len(x): - _sec = x[0] - _key = x[1] + _sec = x[0].replace('-', '_') + _key = x[1].replace('-', '_') else: raise RuntimeError('invalid name.') @@ -238,8 +209,8 @@ class AppConfig(dict): _sec = '_' _key = x[0] elif 2 == len(x): - _sec = x[0] - _key = x[1] + _sec = x[0].replace('-', '_') + _key = x[1].replace('-', '_') else: raise RuntimeError('invalid name.') @@ -270,71 +241,44 @@ class AppConfig(dict): log.e('can not load configuration file: [{}]\n'.format(cfg_file)) return False - if 'common' not in _cfg: - log.e('invalid configuration file: [{}]\n'.format(cfg_file)) + if not self._on_load(_cfg): return False - _comm = _cfg['common'] - - _tmp_int = _comm.getint('port', -1) - if -1 != _tmp_int: - self.set_kv('common::port', _tmp_int) - - _tmp_str = _comm.get('log-file', None) - if _tmp_str is not None: - self.set_kv('common::log_file', _tmp_str) - - _tmp_int = _comm.getint('log-level', -1) - if LOG_DEBUG <= _tmp_int <= LOG_ERROR: - self.set_kv('common::log_level', _tmp_int) - - # self['server_port'] = _comm.getint('port', -1) - # self['log_file'] = _comm.get('log-file', None) - # if self['log_file'] is not None: - # self['log_path'] = os.path.dirname(self['log_file']) - - # log_level, ok = self.cfg_log_level() - # if ok: - # log.set_attribute(min_level=log_level) - self['_cfg_file'] = cfg_file - # self._make_final() return True def save(self, cfg_file=None): if cfg_file is None: cfg_file = self['_cfg_file'] - print('save to', cfg_file) - _save = [ - {'common': ['port', 'log_file', 'log_level']}, - # {'test': ['abc', 'def']} - ] + _save = self._on_get_save_info() cnt = ['; codec: utf-8\n'] is_first_section = True for sections in _save: for sec_name in sections: + sec_name = sec_name.replace('-', '_') if sec_name in self['_cfg_default'] or sec_name in self['_cfg_loaded']: if not is_first_section: cnt.append('\n') cnt.append('[{}]'.format(sec_name)) is_first_section = False for k in sections[sec_name]: + _k = k.replace('-', '_') have_comment = False - if sec_name in self['_cfg_default'] and k in self['_cfg_default'][sec_name] and 'comment' in self['_cfg_default'][sec_name][k]: - comments = self['_cfg_default'][sec_name][k]['comment'] + if sec_name in self['_cfg_default'] and _k in self['_cfg_default'][sec_name] and 'comment' in self['_cfg_default'][sec_name][_k]: + comments = self['_cfg_default'][sec_name][_k]['comment'] if comments is not None: - comments = self['_cfg_default'][sec_name][k]['comment'].split('\n') + comments = self['_cfg_default'][sec_name][_k]['comment'].split('\n') cnt.append('') have_comment = True for comment in comments: cnt.append('; {}'.format(comment)) - if sec_name in self['_cfg_loaded'] and k in self['_cfg_loaded'][sec_name]: + if sec_name in self['_cfg_loaded'] and _k in self['_cfg_loaded'][sec_name]: if not have_comment: cnt.append('') - cnt.append('{}={}'.format(k, self['_cfg_loaded'][sec_name][k])) + cnt.append('{}={}'.format(k, self['_cfg_loaded'][sec_name][_k])) cnt.append('\n') tmp_file = '{}.tmp'.format(cfg_file) @@ -420,30 +364,137 @@ class AppConfig(dict): return def_value, False -# def dump_var(obj, indent=' '): -# x = {'data': obj} -# y = json.dumps(x, indent=indent) -# t = y.split('\n') -# t = t[2:-2] -# for i in t: -# print(i[4:]) +class AppConfig(BaseAppConfig): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.core = AttrDict() + self.core.detected = False + + def _on_init(self): + self.set_default('common::ip', '0.0.0.0', 'ip=0.0.0.0') + self.set_default('common::port', 7190, 'port=7190') + self.set_default('common::log-file', None, + '`log-file` define the log file location. if not set, default location\n' + 'to %APPROOT%/log/web.log\n' + 'log-file=/var/log/teleport/tpweb.log' + ) + self.set_default('common::log-level', 2, + '`log-level` can be 0 ~ 4, default to 2.\n' + 'LOG_LEVEL_DEBUG 0 log every-thing.\n' + 'LOG_LEVEL_VERBOSE 1 log every-thing but without debug message.\n' + 'LOG_LEVEL_INFO 2 log information/warning/error message.\n' + 'LOG_LEVEL_WARN 3 log warning and error message.\n' + 'LOG_LEVEL_ERROR 4 log error message only.' + ) + self.set_default('common::debug-mode', 0, + 'default to `no`.\n' + 'in debug mode, `log-level` force to 0 and trace call stack when exception raised.' + ) + self.set_default('common::core-server-rpc', 'http://127.0.0.1:52080/rpc', + '`core-server-rpc` is the rpc interface of core server.\n' + 'DO NOT FORGET update this setting if you modified rpc::bind-port in core.ini.' + ) + + def _on_get_save_info(self): + return [ + {'common': ['ip', 'port', 'log-file', 'log-level', 'debug-mode', 'core-server-rpc']}, + ] + + def _on_load(self, cfg_parser): + if 'common' not in cfg_parser: + return False + + _comm = cfg_parser['common'] + + _tmp_int = _comm.getint('log-level', -1) + if log.LOG_DEBUG <= _tmp_int <= log.LOG_ERROR: + self.set_kv('common::log-level', _tmp_int) + log.set_attribute(min_level=self.common.log_level) + + _tmp_bool = _comm.getint('debug-mode', False) + self.set_kv('common::debug-mode', _tmp_bool) + if _tmp_bool: + log.set_attribute(min_level=log.LOG_DEBUG, trace_error=log.TRACE_ERROR_FULL) + + _tmp_str = _comm.get('ip', '0.0.0.0') + if _tmp_str is not None: + self.set_kv('common::ip', _tmp_str) + + _tmp_int = _comm.getint('port', -1) + if -1 != _tmp_int: + self.set_kv('common::port', _tmp_int) + + _tmp_str = _comm.get('log-file', None) + if _tmp_str is not None: + self.set_kv('common::log-file', _tmp_str) + + return True + + def update_core(self, conf_data): + self.core = AttrDict() + self.core.detected = False + + if conf_data is None: + log.w('core server config info is empty.\n') + return True + + try: + self.core.ssh = AttrDict() + self.core.ssh.enable = False + self.core.ssh.port = 52189 + if 'ssh' in conf_data: + self.core.ssh.enable = conf_data['ssh']['enable'] + self.core.ssh.port = conf_data['ssh']['port'] + + self.core.rdp = AttrDict() + self.core.rdp.enable = False + self.core.rdp.port = 52089 + if 'rdp' in conf_data: + self.core.rdp.enable = conf_data['rdp']['enable'] + self.core.rdp.port = conf_data['rdp']['port'] + + self.core.telnet = AttrDict() + self.core.telnet.enable = False + self.core.telnet.port = 52389 + if 'telnet' in conf_data: + self.core.telnet.enable = conf_data['telnet']['enable'] + self.core.telnet.port = conf_data['telnet']['port'] + + if 'replay-path' in conf_data: + self.core.replay_path = conf_data['replay-path'] + + if 'web-server-rpc' in conf_data: + self.core.web_server_rpc = conf_data['web-server-rpc'] + if 'version' in conf_data: + self.core.version = conf_data['version'] + + self.core.detected = True + + except IndexError: + log.e('invalid core config.\n') + return False + + return True def app_cfg(): import builtins - if '__web_config__' not in builtins.__dict__: - builtins.__dict__['__web_config__'] = ConfigFile() - return builtins.__dict__['__web_config__'] + if '__app_cfg__' not in builtins.__dict__: + builtins.__dict__['__app_cfg__'] = AppConfig() + return builtins.__dict__['__app_cfg__'] + + +# def app_cfg(): +# import builtins +# if '__web_config__' not in builtins.__dict__: +# builtins.__dict__['__web_config__'] = ConfigFile() +# return builtins.__dict__['__web_config__'] if __name__ == '__main__': cfg = AppConfig() - # cfg.load('/Users/apex/work/otc-tech/contract-demo/dashboard/config/web.ini') - cfg.set_default('common::log_file', 'E:/test/log/web.log') - cfg.set_default('test::abc', 'this is a test', 'abcd\ndefa\ntttt\n') - cfg.set_kv('test::abc', '1234') + cfg.set_default('common::log-file', 'E:/test/log/web.log') cfg.load('E:/test/config/web.ini') - # cfg = _cfg.config() cfg.aaa = 'this is aaa' cfg.bbb = 123 cfg.ccc = False @@ -469,4 +520,4 @@ if __name__ == '__main__': print(cfg.ccc) cfg.save('E:/test/config/web-new.ini') - # cfg.save() + cfg.save() diff --git a/server/www/teleport/app/eom_app/app/core.py b/server/www/teleport/app/eom_app/app/core.py index c1fc61c..d089edc 100644 --- a/server/www/teleport/app/eom_app/app/core.py +++ b/server/www/teleport/app/eom_app/app/core.py @@ -38,8 +38,13 @@ class WebServerCore: if not cfg.load(_cfg_file): return False - cfg.log_path = os.path.abspath(options['log_path']) - cfg.log_file = os.path.join(cfg.log_path, 'tpweb.log') + _log_file, ok = cfg.get_str('common::log-file') + if ok: + cfg.log_path = os.path.abspath(os.path.dirname(_log_file)) + else: + cfg.log_path = os.path.abspath(options['log_path']) + _log_file = os.path.join(cfg.log_path, 'tpweb.log') + cfg.set_default('common::log-file', _log_file) if not os.path.exists(cfg.log_path): utils.make_dir(cfg.log_path) @@ -47,15 +52,33 @@ class WebServerCore: log.e('Can not create log path:{}\n'.format(cfg.log_path)) return False - log.set_attribute(min_level=cfg.log_level, filename=cfg.log_file) - if cfg.debug: - log.set_attribute(trace_error=log.TRACE_ERROR_FULL) + # log.set_attribute(min_level=cfg.common.log_level, filename=cfg.common.log_file) + # if cfg.common.debug_mode: + # log.set_attribute(min_level=log.LOG_DEBUG, trace_error=log.TRACE_ERROR_FULL) - # 尝试通过CORE-JSON-RPC获取core服务的配置(主要是ssh/rdp/telnet的端口) + return True + + def _get_core_server_config(self): + try: + req = {'method': 'get_config', 'param': []} + req_data = json.dumps(req) + data = urllib.parse.quote(req_data).encode('utf-8') + req = urllib.request.Request(url=cfg.common.core_server_rpc, data=data) + rep = urllib.request.urlopen(req, timeout=3) + body = rep.read().decode() + x = json.loads(body) + log.d('connect core server and get config info succeeded.\n') + cfg.update_core(x['data']) + except: + log.w('can not connect to core server to get config, maybe it not start yet, ignore.\n') + + def run(self): + # 尝试通过CORE-JSON-RPC获取core服务的配置(主要是ssh/rdp/telnet的端口以及录像文件存放路径) self._get_core_server_config() if not web_session().init(): - return False + log.e('can not initialize session manager.\n') + return 0 # TODO: 根据配置文件来决定使用什么数据库(初始安装时还没有配置数据库信息) _db = get_db() @@ -67,24 +90,6 @@ class WebServerCore: else: cfg.app_mode = APP_MODE_NORMAL - return True - - def _get_core_server_config(self): - try: - req = {'method': 'get_config', 'param': []} - req_data = json.dumps(req) - data = urllib.parse.quote(req_data).encode('utf-8') - req = urllib.request.Request(url=cfg.core_server_rpc, data=data) - rep = urllib.request.urlopen(req, timeout=3) - body = rep.read().decode() - x = json.loads(body) - log.d('update core server config info.\n') - cfg.update_core(x['data']) - except: - log.w('can not connect to core server to get config, maybe it not start yet, ignore.\n') - - def run(self): - settings = { # 'cookie_secret': '8946svdABGD345fg98uhIaefEBePIfegOIakjFH43oETzK', @@ -114,11 +119,15 @@ class WebServerCore: web_app = tornado.web.Application(controllers, **settings) server = tornado.httpserver.HTTPServer(web_app) + try: - server.listen(cfg.server_port) - log.i('works on [http://127.0.0.1:{}]\n'.format(cfg.server_port)) + server.listen(cfg.common.port, address=cfg.common.ip) + if cfg.common.ip == '0.0.0.0': + log.i('works on [http://127.0.0.1:{}]\n'.format(cfg.common.port)) + else: + log.i('works on [http://{}:{}]\n'.format(cfg.common.ip, cfg.common.port)) except: - log.e('Can not listen on port {}, maybe it been used by another application.\n'.format(cfg.server_port)) + log.e('can not listen on port {}:{}, make sure it not been used by another application.\n'.format(cfg.common.ip, cfg.common.port)) return 0 # 启动session超时管理 diff --git a/server/www/teleport/app/eom_app/app/util.py b/server/www/teleport/app/eom_app/app/util.py index 6a46fef..dbfb311 100644 --- a/server/www/teleport/app/eom_app/app/util.py +++ b/server/www/teleport/app/eom_app/app/util.py @@ -1,159 +1,159 @@ -# -*- coding: utf-8 -*- - -import os -import random -import io -import hashlib - -import json -import urllib.parse -import tornado.gen -import tornado.httpclient - -from wheezy.captcha.image import background -from wheezy.captcha.image import captcha -from wheezy.captcha.image import curve -from wheezy.captcha.image import noise -from wheezy.captcha.image import offset -from wheezy.captcha.image import rotate -from wheezy.captcha.image import smooth -from wheezy.captcha.image import text -from wheezy.captcha.image import warp - -from .configs import app_cfg - -cfg = app_cfg() - -__all__ = ['async_post_http', 'async_enc', 'gen_captcha', 'sec_generate_password', 'sec_verify_password'] - - -@tornado.gen.coroutine -def async_post_http(post_data): - try: - v = json.dumps(post_data) - data = urllib.parse.quote(v).encode('utf-8') - - c = tornado.httpclient.AsyncHTTPClient() - r = yield c.fetch(cfg.core_server_rpc, body=data, method='POST') - - # print('async_post_http return:', r.body.decode()) - return json.loads(r.body.decode()) - except: - return None - - -@tornado.gen.coroutine -def async_enc(data): - # ts_server_rpc_ip = cfg.core.rpc.ip - # ts_server_rpc_port = cfg.core.rpc.port - - # url = 'http://{}:{}/rpc'.format(ts_server_rpc_ip, ts_server_rpc_port) - req = {'method': 'enc', 'param': {'p': data}} - - _yr = async_post_http(req) - return_data = yield _yr - if return_data is None: - return {'code': -2} - if 'code' not in return_data: - return {'code': -3} - if return_data['code'] != 0: - return {'code': return_data['code']} - - if 'data' not in return_data: - return {'code': -5} - - if 'c' not in return_data['data']: - return {'code': -6} - - return {'code': 0, 'data': return_data['data']['c']} - - -_captcha_chars = 'AaCDdEeFfHJjKkLMmNnPpQRTtVvWwXxYy34679' - - -def gen_captcha(): - captcha_image_t = captcha( - width=136, - height=36, - drawings=[ - background(color='#eeeeee'), - # curve(color='#4388d5', width=1, number=10), - curve(color='#4388d5', width=1, number=10), - curve(color='#af6fff', width=3, number=16), - noise(number=80, color='#eeeeee', level=3), - text(fonts=[ - os.path.join(cfg.res_path, 'fonts', '001.ttf') - ], - # font_sizes=(28, 34, 36, 32), - font_sizes=(34, 40, 32, 36), - color='#63a8f5', - # squeeze_factor=1.2, - squeeze_factor=0.9, - drawings=[ - # warp(dx_factor=0.05, dy_factor=0.05), - warp(dx_factor=0.03, dy_factor=0.03), - rotate(angle=20), - offset() - ]), - # curve(color='#af6fff', width=3, number=16), - noise(number=30, color='#eeeeee', level=2), - smooth(), - ]) - - chars_t = random.sample(_captcha_chars, 4) - image = captcha_image_t(chars_t) - - out = io.BytesIO() - image.save(out, "jpeg", quality=100) - # web.header('Content-Type','image/jpeg') - return ''.join(chars_t), out.getvalue() - - -_hex_chars = '0123456789abcdef' - - -def sec_generate_password(password): - """ - 根据设置的password,计算一个加盐的散列,用于保存到数据库 - @param password: string - @return: string - """ - - _hash_type = '3' # 1 = md5, 2 = sha1, 3 = sha256 - - _salt_data = list() - for i in range(16): - _salt_data.append(random.choice(_hex_chars)) - _salt = ''.join(_salt_data) - - h = hashlib.sha256() - h.update(_hash_type.encode()) - h.update(_salt.encode()) - h.update(password.encode()) - _val = h.hexdigest() - - ret = '{}:{}:{}'.format(_hash_type, _salt, _val) - - return ret - - -def sec_verify_password(password, sec_password): - _sec = sec_password.split(':') - if len(_sec) != 3: - return False - - if _sec[0] == '1': - h = hashlib.md5() - elif _sec[0] == '2': - h = hashlib.sha1() - elif _sec[0] == '3': - h = hashlib.sha256() - else: - return False - - h.update(_sec[0].encode()) - h.update(_sec[1].encode()) - h.update(password.encode()) - _val = h.hexdigest() - - return _val == _sec[2] +# -*- coding: utf-8 -*- + +import os +import random +import io +import hashlib + +import json +import urllib.parse +import tornado.gen +import tornado.httpclient + +from wheezy.captcha.image import background +from wheezy.captcha.image import captcha +from wheezy.captcha.image import curve +from wheezy.captcha.image import noise +from wheezy.captcha.image import offset +from wheezy.captcha.image import rotate +from wheezy.captcha.image import smooth +from wheezy.captcha.image import text +from wheezy.captcha.image import warp + +from .configs import app_cfg + +cfg = app_cfg() + +__all__ = ['async_post_http', 'async_enc', 'gen_captcha', 'sec_generate_password', 'sec_verify_password'] + + +@tornado.gen.coroutine +def async_post_http(post_data): + try: + v = json.dumps(post_data) + data = urllib.parse.quote(v).encode('utf-8') + + c = tornado.httpclient.AsyncHTTPClient() + r = yield c.fetch(cfg.common.core_server_rpc, body=data, method='POST') + + # print('async_post_http return:', r.body.decode()) + return json.loads(r.body.decode()) + except: + return None + + +@tornado.gen.coroutine +def async_enc(data): + # ts_server_rpc_ip = cfg.core.rpc.ip + # ts_server_rpc_port = cfg.core.rpc.port + + # url = 'http://{}:{}/rpc'.format(ts_server_rpc_ip, ts_server_rpc_port) + req = {'method': 'enc', 'param': {'p': data}} + + _yr = async_post_http(req) + return_data = yield _yr + if return_data is None: + return {'code': -2} + if 'code' not in return_data: + return {'code': -3} + if return_data['code'] != 0: + return {'code': return_data['code']} + + if 'data' not in return_data: + return {'code': -5} + + if 'c' not in return_data['data']: + return {'code': -6} + + return {'code': 0, 'data': return_data['data']['c']} + + +_captcha_chars = 'AaCDdEeFfHJjKkLMmNnPpQRTtVvWwXxYy34679' + + +def gen_captcha(): + captcha_image_t = captcha( + width=136, + height=36, + drawings=[ + background(color='#eeeeee'), + # curve(color='#4388d5', width=1, number=10), + curve(color='#4388d5', width=1, number=10), + curve(color='#af6fff', width=3, number=16), + noise(number=80, color='#eeeeee', level=3), + text(fonts=[ + os.path.join(cfg.res_path, 'fonts', '001.ttf') + ], + # font_sizes=(28, 34, 36, 32), + font_sizes=(34, 40, 32, 36), + color='#63a8f5', + # squeeze_factor=1.2, + squeeze_factor=0.9, + drawings=[ + # warp(dx_factor=0.05, dy_factor=0.05), + warp(dx_factor=0.03, dy_factor=0.03), + rotate(angle=20), + offset() + ]), + # curve(color='#af6fff', width=3, number=16), + noise(number=30, color='#eeeeee', level=2), + smooth(), + ]) + + chars_t = random.sample(_captcha_chars, 4) + image = captcha_image_t(chars_t) + + out = io.BytesIO() + image.save(out, "jpeg", quality=100) + # web.header('Content-Type','image/jpeg') + return ''.join(chars_t), out.getvalue() + + +_hex_chars = '0123456789abcdef' + + +def sec_generate_password(password): + """ + 根据设置的password,计算一个加盐的散列,用于保存到数据库 + @param password: string + @return: string + """ + + _hash_type = '3' # 1 = md5, 2 = sha1, 3 = sha256 + + _salt_data = list() + for i in range(16): + _salt_data.append(random.choice(_hex_chars)) + _salt = ''.join(_salt_data) + + h = hashlib.sha256() + h.update(_hash_type.encode()) + h.update(_salt.encode()) + h.update(password.encode()) + _val = h.hexdigest() + + ret = '{}:{}:{}'.format(_hash_type, _salt, _val) + + return ret + + +def sec_verify_password(password, sec_password): + _sec = sec_password.split(':') + if len(_sec) != 3: + return False + + if _sec[0] == '1': + h = hashlib.md5() + elif _sec[0] == '2': + h = hashlib.sha1() + elif _sec[0] == '3': + h = hashlib.sha256() + else: + return False + + h.update(_sec[0].encode()) + h.update(_sec[1].encode()) + h.update(password.encode()) + _val = h.hexdigest() + + return _val == _sec[2] diff --git a/server/www/teleport/app/eom_app/controller/config.py b/server/www/teleport/app/eom_app/controller/config.py index b9d35d3..7f32d10 100644 --- a/server/www/teleport/app/eom_app/controller/config.py +++ b/server/www/teleport/app/eom_app/controller/config.py @@ -45,7 +45,7 @@ class IndexHandler(TPBaseAdminAuthHandler): 'core': cfg.core, 'web': { 'version': TS_VER, - 'core_server_rpc': cfg['core_server_rpc'], + 'core_server_rpc': cfg.common.core_server_rpc, # 'database': database, 'db': db } diff --git a/server/www/teleport/app/eom_app/controller/record.py b/server/www/teleport/app/eom_app/controller/record.py index 361fdd6..b23358f 100644 --- a/server/www/teleport/app/eom_app/controller/record.py +++ b/server/www/teleport/app/eom_app/controller/record.py @@ -31,7 +31,11 @@ def get_free_space_bytes(folder): class LogHandler(TPBaseAdminAuthHandler): def get(self): - total_size, free_size = get_free_space_bytes(app_cfg().data_path) + if not app_cfg().core.detected: + total_size = 0 + free_size = 0 + else: + total_size, free_size = get_free_space_bytes(app_cfg().core.replay_path) param = { 'user_list': user.get_user_list(with_admin=True), diff --git a/server/www/teleport/app/eom_app/controller/rpc.py b/server/www/teleport/app/eom_app/controller/rpc.py index 33f2f1a..9f83000 100644 --- a/server/www/teleport/app/eom_app/controller/rpc.py +++ b/server/www/teleport/app/eom_app/controller/rpc.py @@ -110,7 +110,7 @@ class RpcHandler(TPBaseJsonHandler): if 'rpc' not in param: return self.write_json(-1, 'invalid param.') - app_cfg().core_server_rpc = param['rpc'] + app_cfg().common.core_server_rpc = param['rpc'] # 获取core服务的配置信息 req = {'method': 'get_config', 'param': []} diff --git a/server/www/teleport/app/eom_app/module/record.py b/server/www/teleport/app/eom_app/module/record.py index fd0c63c..dc0989b 100644 --- a/server/www/teleport/app/eom_app/module/record.py +++ b/server/www/teleport/app/eom_app/module/record.py @@ -53,6 +53,7 @@ def read_record_head(record_id): offset += 2 except Exception as e: + log.e(e) return None finally: if file is not None: diff --git a/server/www/teleport/app/eom_common/eomcore/logger.py b/server/www/teleport/app/eom_common/eomcore/logger.py index 7787c4e..999bb61 100644 --- a/server/www/teleport/app/eom_common/eomcore/logger.py +++ b/server/www/teleport/app/eom_common/eomcore/logger.py @@ -8,26 +8,19 @@ import threading # import time import traceback -__all__ = ['log', - 'CR_DEBUG', 'CR_VERBOSE', 'CR_INFO', 'CR_WARN', 'CR_ERROR', - 'LOG_DEBUG', 'LOG_VERBOSE', 'LOG_INFO', 'LOG_WARN', 'LOG_ERROR'] +__all__ = ['log'] -LOG_DEBUG = 0 -LOG_VERBOSE = 1 -LOG_INFO = 2 -LOG_WARN = 3 -LOG_ERROR = 4 +# LOG_DEBUG = 0 +# LOG_VERBOSE = 1 +# LOG_INFO = 2 +# LOG_WARN = 3 +# LOG_ERROR = 4 USE_TPWEB_LOG = False try: import tpweb USE_TPWEB_LOG = True - LOG_DEBUG = tpweb.EX_LOG_LEVEL_DEBUG - LOG_VERBOSE = tpweb.EX_LOG_LEVEL_VERBOSE - LOG_INFO = tpweb.EX_LOG_LEVEL_INFO - LOG_WARN = tpweb.EX_LOG_LEVEL_WARN - LOG_ERROR = tpweb.EX_LOG_LEVEL_ERROR except ImportError: pass @@ -83,13 +76,18 @@ COLORS = { } -class EomLogger: +class Logger: """ 日志记录模块,支持输出到控制台及文件。 :type _file_handle : file :type _win_color : Win32ColorConsole """ + LOG_DEBUG = 0 + LOG_VERBOSE = 1 + LOG_INFO = 2 + LOG_WARN = 3 + LOG_ERROR = 4 TRACE_ERROR_NONE = 0 TRACE_ERROR_FULL = 999999 @@ -97,23 +95,28 @@ class EomLogger: def __init__(self): atexit.register(self.finalize) + if USE_TPWEB_LOG: + self.LOG_DEBUG = tpweb.EX_LOG_LEVEL_DEBUG + self.LOG_VERBOSE = tpweb.EX_LOG_LEVEL_VERBOSE + self.LOG_INFO = tpweb.EX_LOG_LEVEL_INFO + self.LOG_WARN = tpweb.EX_LOG_LEVEL_WARN + self.LOG_ERROR = tpweb.EX_LOG_LEVEL_ERROR + self._do_log = self._do_log_tpweb + else: + self._do_log = self._do_log_local + self._locker = threading.RLock() # self._sep = ' ' # self._end = '\n' - self._min_level = LOG_INFO # 大于等于此值的日志信息才会记录 + self._min_level = self.LOG_INFO # 大于等于此值的日志信息才会记录 self._trace_error = self.TRACE_ERROR_NONE # 记录错误信息时,是否追加记录调用栈 self._log_datetime = True # 是否记录日志时间 self._file_handle = None # 日志文件的句柄,为None时表示不记录到文件 self._win_color = None - if USE_TPWEB_LOG: - self._do_log = self._do_log_tpweb - else: - self._do_log = self._do_log_local - self._set_console(True) self._set_level(self._min_level) @@ -157,18 +160,18 @@ class EomLogger: self.w = self._log_warn self.e = self._log_error - if LOG_DEBUG == level: + if self.LOG_DEBUG == level: pass - elif LOG_VERBOSE == level: + elif self.LOG_VERBOSE == level: self.d = self._log_pass - elif LOG_INFO == level: + elif self.LOG_INFO == level: self.d = self._log_pass self.v = self._log_pass - elif LOG_WARN == level: + elif self.LOG_WARN == level: self.d = self._log_pass self.v = self._log_pass self.i = self._log_pass - elif LOG_ERROR == level: + elif self.LOG_ERROR == level: self.d = self._log_pass self.v = self._log_pass self.i = self._log_pass @@ -191,7 +194,7 @@ class EomLogger: self._console_set_color = self._console_set_color_linux self._console_restore_color = self._console_restore_color_linux elif _platform == 'windows': - if 'TERM' in os.environ and os.environ['TERM'] in ['xterm', 'emacs']: + if 'TERM' in os.environ and os.environ['TERM'] in ['xterm', 'emacs', 'cygwin']: self._console_set_color = self._console_set_color_linux self._console_restore_color = self._console_restore_color_linux @@ -234,27 +237,27 @@ class EomLogger: def _log_debug(self, *args, **kwargs): self._console_set_color(CR_DEBUG) - self._do_log(LOG_DEBUG, *args, **kwargs) + self._do_log(self.LOG_DEBUG, *args, **kwargs) self._console_restore_color() def _log_verbose(self, *args, **kwargs): self._console_set_color(CR_VERBOSE) - self._do_log(LOG_VERBOSE, *args, **kwargs) + self._do_log(self.LOG_VERBOSE, *args, **kwargs) self._console_restore_color() def _log_info(self, *args, **kwargs): self._console_set_color(CR_INFO) - self._do_log(LOG_INFO, *args, **kwargs) + self._do_log(self.LOG_INFO, *args, **kwargs) self._console_restore_color() def _log_warn(self, *args, **kwargs): self._console_set_color(CR_WARN) - self._do_log(LOG_WARN, *args, **kwargs) + self._do_log(self.LOG_WARN, *args, **kwargs) self._console_restore_color() def _log_error(self, *args, **kwargs): self._console_set_color(CR_ERROR) - self._do_log(LOG_ERROR, *args, **kwargs) + self._do_log(self.LOG_ERROR, *args, **kwargs) if self._trace_error != self.TRACE_ERROR_NONE: s = traceback.extract_stack() @@ -264,14 +267,14 @@ class EomLogger: break if s[c - 2 - i][0].startswith(' LOG_DEBUG: + if self._min_level > self.LOG_DEBUG: return # 仅仅输出到控制台,不输出到日志文件 if self._log_console is None: @@ -514,19 +519,19 @@ class EomLogger: first = True for x in args: if not first: - log._do_log(LOG_VERBOSE, sep, show_datetime=show_datetime) + log._do_log(self.LOG_VERBOSE, sep, show_datetime=show_datetime) first = False if isinstance(x, str): - log._do_log(LOG_VERBOSE, x, show_datetime=show_datetime) + log._do_log(self.LOG_VERBOSE, x, show_datetime=show_datetime) show_datetime = False continue else: - log._do_log(LOG_VERBOSE, x.__str__(), show_datetime=show_datetime) + log._do_log(self.LOG_VERBOSE, x.__str__(), show_datetime=show_datetime) show_datetime = False - log._do_log(LOG_VERBOSE, end, show_datetime=show_datetime) + log._do_log(self.LOG_VERBOSE, end, show_datetime=show_datetime) # s = traceback.extract_stack() # c = len(s) @@ -540,8 +545,8 @@ class EomLogger: # break def _test(self): - self._set_level(LOG_DEBUG) - self._trace_error = TRACE_ERROR_FULL + self._set_level(self.LOG_DEBUG) + self._trace_error = self.TRACE_ERROR_FULL self.d('This is DEBUG message.\n') self.v('This is VERBOSE message.\n') @@ -622,8 +627,8 @@ class Win32ColorConsole: self.__SetConsoleTextAttribute(self.__stdout, color) -log = EomLogger() -del EomLogger +log = Logger() +del Logger # log._test() # print('test built-in `print` function.') diff --git a/server/www/teleport/static/js/ui/log.js b/server/www/teleport/static/js/ui/log.js index a18d2a3..ee3d6c7 100644 --- a/server/www/teleport/static/js/ui/log.js +++ b/server/www/teleport/static/js/ui/log.js @@ -7,8 +7,13 @@ ywl.on_init = function (cb_stack, cb_args) { // 创建页面控件对象 //=================================== // 表格数据 - var disk_rate = parseInt(ywl.page_options.free_size * 100 / ywl.page_options.total_size); - $('#disk-status').text('日志磁盘大小:' + size2str(ywl.page_options.total_size, 2) + ',剩余空间:' + size2str(ywl.page_options.free_size, 2) + ',空闲' + disk_rate + '%'); + var disk_rate = 0; + if(0 == ywl.page_options.total_size) { + $('#disk-status').text('未能连接到核心服务,无法获取操作日志路径'); + } else { + disk_rate = parseInt(ywl.page_options.free_size * 100 / ywl.page_options.total_size); + $('#disk-status').text('日志磁盘大小:' + size2str(ywl.page_options.total_size, 2) + ',剩余空间:' + size2str(ywl.page_options.free_size, 2) + ',空闲' + disk_rate + '%'); + } if (disk_rate < 10) { $('#disk-status').removeClass().addClass('badge badge-danger'); } else if (disk_rate < 30) {