pull/32/merge
Apex Liu 2017-01-16 21:28:13 +08:00
parent 3ec1bea6ea
commit b6e3448792
22 changed files with 515 additions and 385 deletions

2
.gitignore vendored
View File

@ -38,6 +38,7 @@ __pycache__
/external/openssl
/external/python
/build/config.py
# for dist folder
/dist/*.zip
@ -60,3 +61,4 @@ __pycache__
/client/tp_rdp
/external/libssh-win-static/lib
/server/share/log
/config.ini

5
build.bat.in Normal file
View File

@ -0,0 +1,5 @@
@echo off
SET PYEXEC=C:\Python\Python34-x86\python.exe
%PYEXEC% -B build/build.py %1 %2 %3 %4 %5

1
build/.gitignore vendored
View File

@ -1 +0,0 @@
/config.py

View File

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/builder" />
<orderEntry type="jdk" jdkName="3.4 x64" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="py34-x86" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">

View File

@ -8,6 +8,7 @@ import platform
import sys
THIS_PATH = os.path.abspath(os.path.dirname(__file__))
ROOT_PATH = os.path.abspath(os.path.join(THIS_PATH, '..'))
BUILDER_PATH = os.path.join(THIS_PATH, 'builder')
sys.path.append(os.path.join(BUILDER_PATH))
@ -139,16 +140,12 @@ def do_opt(opt):
# arg = 'installer'
arg = '%s %s installer' % (ctx.dist, opt['bits'])
elif 'installer-ubuntu' == opt['name']:
script = 'build-installer.py'
arg = '%s %s installer' % ('ubuntu', opt['bits'])
elif 'assist-exe' == opt['name']:
script = 'build-assist.py'
arg = '%s %s exe' % (ctx.target_path, opt['bits'])
elif 'assist-rdp' == opt['name']:
script = 'build-assist.py'
arg = '%s rdp' % (opt['bits'])
# elif 'assist-rdp' == opt['name']:
# script = 'build-assist.py'
# arg = '%s rdp' % (opt['bits'])
elif 'assist-installer' == opt['name']:
script = 'build-assist.py'
arg = '%s %s installer' % (ctx.dist, opt['bits'])
@ -157,9 +154,8 @@ def do_opt(opt):
cc.e('unknown option: ', opt['name'])
return
cmd = '"%s" -B "%s/%s" %s' % (utils.cfg.py_exec, BUILDER_PATH, script, arg)
cc.i(cmd)
cc.v('')
# cmd = '"%s" -B "%s" %s' % (utils.cfg.py_exec, os.path.join(BUILDER_PATH, script), arg)
cmd = '%s -B %s %s' % (utils.cfg.py_exec, os.path.join(BUILDER_PATH, script), arg)
os.system(cmd)
@ -176,13 +172,13 @@ def select_option_by_name(name):
return None
def select_option_by_id(id):
def select_option_by_id(_id):
global options
for o in range(len(options)):
if options[o] is None:
continue
if options[o]['id'] == id:
if options[o]['id'] == _id:
return options[o]
return None

View File

@ -31,8 +31,8 @@ class BuilderWin(BuilderBase):
def build_exe(self):
cc.n('build tp_assist...')
sln_file = os.path.join(ROOT_PATH, 'tp_assist', 'tp_assist.vs2015.sln')
out_file = os.path.join(ROOT_PATH, 'out', 'tp_assist', ctx.bits_path, ctx.target_path, 'tp_assist.exe')
sln_file = os.path.join(ROOT_PATH, 'client', 'tp_assist', 'tp_assist.vs2015.sln')
out_file = os.path.join(ROOT_PATH, 'out', 'client', ctx.bits_path, ctx.target_path, 'tp_assist.exe')
if os.path.exists(out_file):
utils.remove(out_file)
utils.msvc_build(sln_file, 'tp_assist', ctx.target_path, ctx.bits_path, False)

View File

@ -27,13 +27,30 @@ class BuilderWin(BuilderBase):
super().__init__()
def build_server(self):
cc.n('build eom_ts...')
sln_file = os.path.join(ROOT_PATH, 'teleport-server', 'src', 'eom_ts.vs2015.sln')
out_file = os.path.join(ROOT_PATH, 'out', 'eom_ts', ctx.bits_path, ctx.target_path, 'eom_ts.exe')
cc.n('build web server ...')
sln_file = os.path.join(ROOT_PATH, 'server', 'tp_web', 'src', 'tp_web.vs2015.sln')
out_file = os.path.join(ROOT_PATH, 'out', 'server', ctx.bits_path, ctx.target_path, 'tp_web.exe')
if os.path.exists(out_file):
utils.remove(out_file)
utils.msvc_build(sln_file, 'eom_ts', ctx.target_path, ctx.bits_path, False)
utils.msvc_build(sln_file, 'tp_web', ctx.target_path, ctx.bits_path, False)
utils.ensure_file_exists(out_file)
cc.n('build core server ...')
sln_file = os.path.join(ROOT_PATH, 'server', 'tp_core', 'core', 'tp_core.vs2015.sln')
out_file = os.path.join(ROOT_PATH, 'out', 'server', ctx.bits_path, ctx.target_path, 'tp_core.exe')
if os.path.exists(out_file):
utils.remove(out_file)
utils.msvc_build(sln_file, 'tp_core', ctx.target_path, ctx.bits_path, False)
utils.ensure_file_exists(out_file)
cc.n('build SSH protocol ...')
sln_file = os.path.join(ROOT_PATH, 'server', 'tp_core', 'protocol', 'ssh', 'tpssh.vs2015.sln')
out_file = os.path.join(ROOT_PATH, 'out', 'server', ctx.bits_path, ctx.target_path, 'tpssh.dll')
if os.path.exists(out_file):
utils.remove(out_file)
utils.msvc_build(sln_file, 'tpssh', ctx.target_path, ctx.bits_path, False)
utils.ensure_file_exists(out_file)
#
# s = os.path.join(ROOT_PATH, 'out', 'console', ctx.bits_path, ctx.target_path, 'console.exe')
# t = os.path.join(ROOT_PATH, 'out', 'eom_agent', ctx.target_path, ctx.dist_path, 'eom_agent.com')

View File

@ -3,12 +3,13 @@
import os
import sys
import platform
import configparser
from . import colorconsole as cc
__all__ = ['cfg']
class TpDict(dict):
class AttrDict(dict):
"""
可以像属性一样访问字典的 Keyvar.key 等同于 var['key']
"""
@ -24,17 +25,11 @@ class TpDict(dict):
self[name] = val
class ConfigFile(TpDict):
class ConfigFile(AttrDict):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# self.__file_name = None
# self.__save_indent = 0
# self.__loaded = False
def init(self, cfg_file):
if not self.load(cfg_file, True):
return False
self['ROOT_PATH'] = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
self['py_exec'] = sys.executable
@ -55,70 +50,47 @@ class ConfigFile(TpDict):
_os = platform.system().lower()
self['is_win'] = False
self['is_linux'] = False
self['is_macos'] = False
self['dist'] = ''
if _os == 'windows':
self['is_win'] = True
self['dist'] = 'windows'
elif _os == 'linux':
self['is_linux'] = True
self['dist'] = 'linux'
elif _os == 'darwin':
self['is_macos'] = True
self['dist'] = 'macos'
else:
cc.e('not support this OS: {}'.format(platform.system()))
return False
return True
def load_str(self, module, code):
m = type(sys)(module)
m.__module_class__ = type(sys)
m.__file__ = module
try:
exec(compile(code, module, 'exec'), m.__dict__)
except Exception as e:
cc.e('%s\n' % str(e))
# print(str(e))
# if eom_dev_conf.debug:
# raise
_cfg = configparser.ConfigParser()
_cfg.read(cfg_file)
if 'external_ver' not in _cfg.sections() or 'toolchain' not in _cfg.sections():
cc.e('invalid configuration file: need `external_ver` and `toolchain` section.')
return False
for y in m.__dict__:
if '__' == y[:2]:
continue
if isinstance(m.__dict__[y], dict):
self[y] = TpDict()
self._assign_dict(m.__dict__[y], self[y])
else:
self[y] = m.__dict__[y]
return True
def load(self, full_path, must_exists=True):
try:
f = open(full_path, encoding='utf8')
code = f.read()
f.close()
self.__loaded = True
except IOError:
if must_exists:
cc.e('Can not load config file: %s\n' % full_path)
_tmp = _cfg['external_ver']
if 'libuv' not in _tmp or 'mbedtls' not in _tmp or 'sqlite' not in _tmp:
cc.e('invalid configuration file: external version not set.')
return False
module = os.path.basename(full_path)
if not self.load_str(module, code):
return False
self['ver'] = AttrDict()
for k in _tmp:
self['ver'][k] = _tmp[k]
_tmp = _cfg['toolchain']
if self.is_win:
self['nsis'] = _tmp.get('nsis', None)
self['msbuild'] = None # msbuild always read from register.
else:
self['cmake'] = _tmp.get('cmake', '/usr/bin/cmake')
self.__file_name = full_path
return True
def _assign_dict(self, _from, _to):
for y in _from:
if isinstance(_from[y], dict):
_to[y] = TpDict()
self._assign_dict(_from[y], _to[y])
else:
_to[y] = _from[y]
cfg = ConfigFile()
del ConfigFile

View File

@ -11,18 +11,15 @@ import time
from . import colorconsole as cc
from .configs import cfg
try:
CONFIG_FILE = os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')), 'config.py')
CONFIG_FILE = os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')), 'config.ini')
if not cfg.init(CONFIG_FILE):
sys.exit(1)
except:
cc.e('can not load configuration.\n\nplease copy `config.py.in` into `config.py` and modify it to fit your condition and try again.')
sys.exit(1)
# PY_VER = platform.python_version_tuple()
#IS_PY2 = sys.version_info[0] == 2
#IS_PY3 = sys.version_info[0] == 3
if cfg.is_py2:
import imp
elif cfg.is_py3:
@ -222,13 +219,9 @@ def python_exec():
return sys.executable
g_msbuild_path = None
def msbuild_path():
global g_msbuild_path
if g_msbuild_path is not None:
return g_msbuild_path
if cfg.msbuild is not None:
return cfg.msbuild
# 14.0 = VS2015
# 12.0 = VS2012
@ -248,21 +241,13 @@ def msbuild_path():
if not os.path.exists(msb):
raise RuntimeError('Can not locate MSBuild at {}'.format(msp))
g_msbuild_path = msb
cfg.msbuild = msb
return msb
g_nsis_path = None
def nsis_path():
global g_nsis_path
if g_nsis_path is not None:
return g_nsis_path
if 'nsis' in cfg:
g_nsis_path = cfg['nsis']
return g_nsis_path
if cfg.nsis is not None:
return cfg.nsis
p = winreg_read_wow64_32(r'SOFTWARE\NSIS\Unicode', '')
if p is None:
@ -272,7 +257,7 @@ def nsis_path():
if not os.path.exists(p):
raise RuntimeError('Can not locate NSIS at {}'.format(p))
g_nsis_path = p
cfg.nsis = p
return p
@ -355,7 +340,7 @@ def nsis_build(nsi_file, _define=''):
def cmake(work_path, target, force_rebuild, cmake_define=''):
# because cmake v2.8 shipped with Ubuntu 14.04LTS, but we need 3.5.
# so we copy a v3.5 cmake from CLion and put to $WORK/eomsoft/toolchain/cmake.
#CMAKE = os.path.abspath(os.path.join(root_path(), 'toolchain', 'cmake', 'bin', 'cmake'))
# CMAKE = os.path.abspath(os.path.join(root_path(), 'toolchain', 'cmake', 'bin', 'cmake'))
if 'cmake' not in cfg:
raise RuntimeError('please set `cmake` path.')
if not os.path.exists(cfg['cmake']):

View File

@ -1,23 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
OPENSSL_VER = '1.0.2h'
LIBUV_VER = '1.9.1'
MBEDTLS_VER = '2.3.0'
SQLITE_VER = '3160200'
# ============================================
# for windows
# ============================================
# if not set nsis path, builder will try to get it by read register.
nsis = 'C:\\Program Files (x86)\\NSIS\\Unicode\\makensis.exe'
# ============================================
# for linux
# ============================================
cmake = '/opt/cmake/bin/cmake'
# pyexec = os.path.join(ROOT_PATH, 'external', 'linux', 'release', 'bin', 'python3.4')

26
config.ini.in Normal file
View File

@ -0,0 +1,26 @@
[toolchain]
#============================================
# for windows
#============================================
# if not set nsis path, default to get it by register.
#nsis = "C:\Program Files (x86)\NSIS\Unicode\makensis.exe"
# if not set msbuild path, default to get it by register.
#msbuild = "C:\Program Files (x86)\MSBuild\14.0\bin\MSBuild.exe"
# ============================================
# for linux
# ============================================
# if not set cmake path, default to '/usr/bin/cmake'
cmake = "/opt/cmake/bin/cmake"
[external_ver]
# openssl = 1.0.2h
libuv = 1.9.1
mbedtls = 2.3.0
sqlite = 3160200

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tpssh", "tpssh.vcxproj", "{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tpssh", "tpssh.vs2015.vcxproj", "{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -23,6 +23,7 @@
<Keyword>Win32Proj</Keyword>
<RootNamespace>tpssh</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<ProjectName>tpssh</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

View File

@ -40,6 +40,10 @@ static ex_u8 g_run_type = RUN_UNKNOWN;
static bool _run_daemon(void);
// 导出函数给Python脚本使用主要是为了记录日志
// Windows平台上tp_web程序打开日志文件写之后Python脚本尝试写入方式打开此日志文件时会失败。
PyObject* init_web_builtin_module(void);
#ifdef EX_OS_WIN32
static int service_install()
{
@ -227,6 +231,13 @@ static int _main_loop(void)
pys_add_arg(pysh, it->c_str());
}
if (!pys_add_builtin_module(pysh, "tpweb", init_web_builtin_module))
{
EXLOGE("[tpweb] can not add builtin module for python script.\n");
return 1;
}
return pys_run(pysh);
}
@ -417,9 +428,9 @@ VOID WINAPI service_main(DWORD argc, wchar_t** argv)
}
}
#else
// not EX_OS_WIN32
//#include "ts_util.h"
//======================================================
#else // Linux or MacOS
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
@ -500,3 +511,130 @@ static bool _run_daemon(void)
}
#endif
//===============================================================
// 演示如何加入内建模块供脚本调用
//===============================================================
PyObject* _py_log_output(PyObject* self, PyObject* args)
{
// UNUSED(self);
// UNUSED(args);
int level = 0;
const char* msg = NULL;
if (!pylib_PyArg_ParseTuple(args, "is", &level, &msg))
{
EXLOGE("invalid args for _py_log_output().\n");
PYLIB_RETURN_FALSE;
}
ex_wstr tmp;
ex_astr2wstr(msg, tmp, EX_CODEPAGE_UTF8);
//EXLOGV(msg);
switch (level)
{
case EX_LOG_LEVEL_DEBUG:
ex_printf_d(tmp.c_str());
break;
case EX_LOG_LEVEL_VERBOSE:
ex_printf_v(tmp.c_str());
break;
case EX_LOG_LEVEL_INFO:
ex_printf_i(tmp.c_str());
break;
case EX_LOG_LEVEL_WARN:
ex_printf_w(tmp.c_str());
break;
case EX_LOG_LEVEL_ERROR:
ex_printf_e(tmp.c_str());
break;
default:
PYLIB_RETURN_FALSE;
break;
}
//return pylib_PyLong_FromLong(0x010001);
PYLIB_RETURN_TRUE;
}
PyObject* _py_log_level(PyObject* self, PyObject* args)
{
int level = 0;
if (!pylib_PyArg_ParseTuple(args, "i", &level))
{
EXLOGE("invalid args for _py_log_level().\n");
PYLIB_RETURN_FALSE;
}
EXLOG_LEVEL(level);
PYLIB_RETURN_TRUE;
}
PyObject* _py_log_console(PyObject* self, PyObject* args)
{
bool to_console = false;
if (!pylib_PyArg_ParseTuple(args, "p", &to_console))
{
EXLOGE("invalid args for _py_log_console().\n");
PYLIB_RETURN_FALSE;
}
EXLOG_CONSOLE(to_console);
PYLIB_RETURN_TRUE;
}
PYS_BUILTIN_FUNC _demo_funcs[] = {
{
"log_output", // 脚本函数名,在脚本中使用
_py_log_output, // 对应的C代码函数名
PYS_TRUE, // 函数的基本信息(是否需要参数,等等)
"write log." // 函数的说明文档,可选(可以是空字符串)
},
{
"log_level",
_py_log_level,
PYS_TRUE,
"set log level."
},
{
"log_console",
_py_log_console,
PYS_TRUE,
"set log to console or not."
},
// 最后一组,第一个成员为空指针,表示结束
{ NULL, NULL, 0, NULL }
};
PyObject* init_web_builtin_module(void)
{
PyObject* mod = NULL;
mod = pys_create_module("_tpweb", _demo_funcs);
pys_builtin_const_long(mod, "EX_LOG_LEVEL_DEBUG", EX_LOG_LEVEL_DEBUG);
pys_builtin_const_long(mod, "EX_LOG_LEVEL_VERBOSE", EX_LOG_LEVEL_VERBOSE);
pys_builtin_const_long(mod, "EX_LOG_LEVEL_INFO", EX_LOG_LEVEL_INFO);
pys_builtin_const_long(mod, "EX_LOG_LEVEL_WARN", EX_LOG_LEVEL_WARN);
pys_builtin_const_long(mod, "EX_LOG_LEVEL_ERROR", EX_LOG_LEVEL_ERROR);
// pys_builtin_const_bool(mod, "DEMO_CONST_2", PYS_TRUE);
// //pys_builtin_const_wcs(mod, "DEMO_CONST_3", L"STRING 中文测试 this is string.");
// pys_builtin_const_wcs(mod, "DEMO_CONST_3", L"STRING this is string.");
// pys_builtin_const_utf8(mod, "DEMO_CONST_4", "this is string.");
//
// ex_u8 test_buf[12] = { 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d, 0x12, 0x34, 0xab, 0xcd };
// pys_builtin_const_bin(mod, "DEMO_CONST_5", test_buf, 12);
return mod;
}

View File

@ -69,7 +69,6 @@
<ClInclude Include="ts_env.h">
<Filter>main app</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
<ClInclude Include="..\..\..\common\libex\include\ex\ex_const.h">
<Filter>libex\header</Filter>
</ClInclude>
@ -115,6 +114,9 @@
<ClInclude Include="..\..\..\common\pyshell\include\pys.h">
<Filter>pyshell\header</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Resource Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="tp_web.rc">

View File

@ -24,7 +24,7 @@ bool TsEnv::init(void)
ex_path_join(base_path, true, L"..", NULL);
ex_wstr conf_file = base_path;
ex_path_join(conf_file, false, L"etc", L"web.conf", NULL);
ex_path_join(conf_file, false, L"etc", L"web.ini", NULL);
if (ex_is_file_exists(conf_file.c_str()))
{
@ -38,7 +38,7 @@ bool TsEnv::init(void)
ex_path_join(base_path, true, L"..", L"..", L"..", L"..", L"server", L"share", NULL);
conf_file = base_path;
ex_path_join(conf_file, false, L"etc", L"web.conf", NULL);
ex_path_join(conf_file, false, L"etc", L"web.ini", NULL);
m_www_path = m_exec_path;
ex_path_join(m_www_path, true, L"..", L"..", L"..", L"..", L"server", L"www", NULL);
@ -53,7 +53,7 @@ bool TsEnv::init(void)
ExIniFile cfg;
if (!cfg.LoadFromFile(conf_file))
{
EXLOGE("[tpweb] can not load web.conf.\n");
EXLOGE("[tpweb] can not load web.ini.\n");
return false;
}

View File

@ -11,7 +11,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/app" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="py34-x86" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">

View File

@ -2,13 +2,14 @@
import os
import sys
import configparser
from eom_common.eomcore.logger import log
__all__ = ['app_cfg']
class SwxDict(dict):
class AttrDict(dict):
"""
可以像属性一样访问字典的 Keyvar.key 等同于 var['key']
"""
@ -24,154 +25,112 @@ class SwxDict(dict):
self[name] = val
def swx_dict(obj):
"""
将一个对象中的dict转变为EomDict类型
"""
if isinstance(obj, dict):
ret = SwxDict()
for k in obj:
# ret[k] = obj[k]
if isinstance(obj[k], dict):
ret[k] = swx_dict(obj[k])
else:
ret[k] = obj[k]
else:
ret = obj
return ret
# def attr_dict(obj):
# """
# 将一个对象中的dict转变为AttrDict类型
# """
# if isinstance(obj, dict):
# ret = AttrDict()
# for k in obj:
# # ret[k] = obj[k]
# if isinstance(obj[k], dict):
# ret[k] = attr_dict(obj[k])
# else:
# ret[k] = obj[k]
# else:
# ret = obj
# return ret
class ConfigFile(SwxDict):
class ConfigFile(AttrDict):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# self.__file_name = None
# self.__save_indent = 0
# self.__loaded = False
def load_str(self, module, code):
m = type(sys)(module)
m.__module_class__ = type(sys)
m.__file__ = module
def load(self, cfg_file):
if not os.path.exists(cfg_file):
log.e('configuration file does not exists.')
return False
try:
exec(compile(code, module, 'exec'), m.__dict__)
except Exception as e:
log.e('%s\n' % str(e))
# print(str(e))
# if eom_dev_conf.debug:
# raise
_cfg = configparser.ConfigParser()
_cfg.read(cfg_file)
except:
log.e('can not load configuration file.')
return False
for y in m.__dict__:
if '__' == y[:2]:
continue
if isinstance(m.__dict__[y], dict):
self[y] = SwxDict()
self._assign_dict(m.__dict__[y], self[y])
else:
self[y] = m.__dict__[y]
if 'common' not in _cfg:
log.e('invalid configuration file.')
return False
_comm = _cfg['common']
self['server_port'] = _comm.getint('port', 7190)
self['log_file'] = _comm.get('log-file', None)
if self['log_file'] is not None:
self['log_path'] = os.path.dirname(self['log_file'])
return True
def load(self, full_path, must_exists=True):
try:
f = open(full_path, encoding='utf8')
code = f.read()
f.close()
self.__loaded = True
except IOError:
if must_exists:
log.e('Can not load config file: %s\n' % full_path)
return False
# def load_str(self, module, code):
# m = type(sys)(module)
# m.__module_class__ = type(sys)
# m.__file__ = module
#
# try:
# exec(compile(code, module, 'exec'), m.__dict__)
# except Exception as e:
# log.e('%s\n' % str(e))
# # print(str(e))
# # if eom_dev_conf.debug:
# # raise
# return False
#
# for y in m.__dict__:
# if '__' == y[:2]:
# continue
# if isinstance(m.__dict__[y], dict):
# self[y] = AttrDict()
# self._assign_dict(m.__dict__[y], self[y])
# else:
# self[y] = m.__dict__[y]
#
# return True
#
# def _load(self, full_path, must_exists=True):
# try:
# f = open(full_path, encoding='utf8')
# code = f.read()
# f.close()
# self.__loaded = True
# except IOError:
# if must_exists:
# log.e('Can not load config file: %s\n' % full_path)
# return False
#
# module = os.path.basename(full_path)
# if not self.load_str(module, code):
# return False
#
# self.__file_name = full_path
# return True
#
# def _assign_dict(self, _from, _to):
# for y in _from:
# if isinstance(_from[y], dict):
# _to[y] = AttrDict()
# self._assign_dict(_from[y], _to[y])
# else:
# _to[y] = _from[y]
#
module = os.path.basename(full_path)
if not self.load_str(module, code):
return False
self.__file_name = full_path
return True
"""
def save(self, filename=None):
if filename is None and not self.__loaded:
# log.w('Can not save config file without file name.\n')
return False
_file_name = filename
if _file_name is None:
_file_name = self.__file_name
if _file_name is None:
log.e('Do not known which file to save to.\n')
return False
# 排序后保存
m = [(k, self[k]) for k in sorted(self.keys())]
self.__save_indent = 0
s = self._save(m)
# 尝试加载生成的要保存的配置字符串,如果加载成功,则保存到文件,否则报错
x = ConfigFile()
if not x.load_str('_eom_tmp_cfg_data_', s):
log.e('Cannot generate config for save.\n')
return False
f = open(_file_name, 'w')
f.write('# -*- coding: utf-8 -*-\n\n')
f.write(s)
f.close()
return True
def _save(self, var):
s = ''
for (k, v) in var:
if self.__save_indent == 0 and k.find('_ConfigFile__') == 0:
# 本类的成员变量不用保存
continue
if isinstance(v, dict):
if self.__save_indent > 0:
s += "\n%s'%s' : {\n" % ('\t' * self.__save_indent, k)
else:
s += "\n%s%s = {\n" % ('\t' * self.__save_indent, k)
self.__save_indent += 1
m = [(x, v[x]) for x in sorted(v.keys())]
s += self._save(m)
self.__save_indent -= 1
if self.__save_indent > 0:
s += "%s},\n\n" % ('\t' * self.__save_indent)
else:
s += "%s}\n\n" % ('\t' * self.__save_indent)
else:
if isinstance(v, str):
val = "'%s'" % v.replace("'", "\\'")
else:
val = v
if self.__save_indent > 0:
s += "%s'%s' : %s,\n" % ('\t' * self.__save_indent, k, val)
else:
s += "%s%s = %s\n" % ('\t' * self.__save_indent, k, val)
return s
"""
def _assign_dict(self, _from, _to):
for y in _from:
if isinstance(_from[y], dict):
_to[y] = SwxDict()
self._assign_dict(_from[y], _to[y])
else:
_to[y] = _from[y]
_cfg = ConfigFile()
_g_cfg = ConfigFile()
del ConfigFile
def app_cfg():
global _cfg
return _cfg
global _g_cfg
return _g_cfg
if __name__ == '__main__':

View File

@ -7,7 +7,6 @@ import tornado.ioloop
import tornado.netutil
import tornado.process
import tornado.web
# from eom_app.controller import controllers
# from eom_common.eomcore.eom_mysql import get_mysql_pool
from eom_common.eomcore.eom_sqlite import get_sqlite_pool
@ -15,6 +14,7 @@ import eom_common.eomcore.utils as utils
from eom_common.eomcore.logger import log
from .configs import app_cfg
from .session import swx_session
cfg = app_cfg()
@ -28,10 +28,16 @@ class SwxCore:
cfg.dev_mode = options['dev_mode']
if 'log_path' not in options:
if not self._load_config(options):
return False
else:
cfg.log_path = options['log_path']
if cfg.log_file is None:
if 'log_path' not in options:
return False
else:
cfg.log_path = options['log_path']
cfg.log_file = os.path.join(cfg.log_path, 'tpweb.log')
if not os.path.exists(cfg.log_path):
utils.make_dir(cfg.log_path)
@ -39,14 +45,13 @@ class SwxCore:
log.e('Can not create log path.\n')
return False
log.set_attribute(filename=cfg.log_file)
if 'app_path' not in options:
return False
else:
cfg.app_path = options['app_path']
if not self._load_config(options):
return False
if 'static_path' in options:
cfg.static_path = options['static_path']
else:
@ -92,7 +97,7 @@ class SwxCore:
else:
_cfg_path = os.path.join(options['app_path'], 'conf')
_cfg_file = os.path.join(_cfg_path, 'web.conf')
_cfg_file = os.path.join(_cfg_path, 'web.ini')
if not cfg.load(_cfg_file):
return False
@ -238,9 +243,9 @@ class SwxCore:
log.e('Can not listen on port {}, maybe it been used by another application.\n'.format(cfg.server_port))
return 0
if not cfg.dev_mode:
log_file = os.path.join(cfg.log_path, 'ts-web.log')
log.set_attribute(console=False, filename=log_file)
# if not cfg.dev_mode:
# log_file = os.path.join(cfg.log_path, 'ts-web.log')
# log.set_attribute(console=False, filename=log_file)
tornado.ioloop.IOLoop.instance().start()
return 0

View File

@ -10,11 +10,25 @@ __all__ = ['log',
'CR_DEBUG', 'CR_VERBOSE', 'CR_INFO', 'CR_WARN', 'CR_ERROR',
'LOG_DEBUG', 'LOG_VERBOSE', 'LOG_INFO', 'LOG_WARN', 'LOG_ERROR', 'TRACE_ERROR_NONE', 'TRACE_ERROR_FULL']
LOG_DEBUG = 1
LOG_VERBOSE = 10
LOG_INFO = 20
LOG_WARN = 30
LOG_ERROR = 99
LOG_DEBUG = 0
LOG_VERBOSE = 1
LOG_INFO = 2
LOG_WARN = 3
LOG_ERROR = 4
USE_TPWEB_LOG = True
try:
import tpweb
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:
print('can not import tpweb.')
USE_TPWEB_LOG = False
TRACE_ERROR_NONE = 0
TRACE_ERROR_FULL = 999999
@ -71,9 +85,6 @@ COLORS = {
}
# env = eomcore.env.get_env()
class EomLogger:
"""
日志记录模块支持输出到控制台及文件
@ -83,8 +94,13 @@ class EomLogger:
"""
def __init__(self):
atexit.register(self.finalize)
self._locker = threading.RLock()
# self._sep = ' '
# self._end = '\n'
self._min_level = LOG_INFO # 大于等于此值的日志信息才会记录
self._trace_error = TRACE_ERROR_NONE # 记录错误信息时,是否追加记录调用栈
self._log_datetime = True # 是否记录日志时间
@ -93,17 +109,20 @@ class EomLogger:
self._win_color = None
self.d = self._func_debug
self.v = self._func_verbose
self.i = self._func_info
self.w = self._func_warn
self.e = self._func_error
if USE_TPWEB_LOG:
self._do_log = self._do_log_tpweb
else:
self._do_log = self._do_log_local
# self.d = self._log_debug
# self.v = self._log_verbose
# self.i = self._log_info
# self.w = self._log_warn
# self.e = self._log_error
self._set_console(True)
self._set_level(self._min_level)
atexit.register(self.finalize)
def initialize(self):
pass
@ -138,28 +157,28 @@ class EomLogger:
return True
def _set_level(self, level):
self.d = self._func_debug
self.v = self._func_verbose
self.i = self._func_info
self.w = self._func_warn
# self.e = self._func_error
self.d = self._log_debug
self.v = self._log_verbose
self.i = self._log_info
self.w = self._log_warn
self.e = self._log_error
if LOG_DEBUG == level:
pass
elif LOG_VERBOSE == level:
self.d = self._func_pass
self.d = self._log_pass
elif LOG_INFO == level:
self.d = self._func_pass
self.v = self._func_pass
self.d = self._log_pass
self.v = self._log_pass
elif LOG_WARN == level:
self.d = self._func_pass
self.v = self._func_pass
self.i = self._func_pass
self.d = self._log_pass
self.v = self._log_pass
self.i = self._log_pass
elif LOG_ERROR == level:
self.d = self._func_pass
self.v = self._func_pass
self.i = self._func_pass
self.w = self._func_pass
self.d = self._log_pass
self.v = self._log_pass
self.i = self._log_pass
self.w = self._log_pass
pass
else:
pass
@ -218,33 +237,92 @@ class EomLogger:
return True
def _log_pass(self, *args, **kwargs):
pass
def _log_debug(self, *args, **kwargs):
self._do_log(LOG_DEBUG, *args, **kwargs)
def _log_verbose(self, *args, **kwargs):
self._do_log(LOG_VERBOSE, *args, **kwargs)
def _log_info(self, *args, **kwargs):
self._do_log(LOG_INFO, *args, **kwargs)
def _log_warn(self, *args, **kwargs):
self._do_log(LOG_WARN, *args, **kwargs)
def _log_error(self, *args, **kwargs):
self._do_log(LOG_ERROR, *args, **kwargs)
def _do_log_tpweb(self, level, *args, **kwargs):
# sep = kwargs['sep'] if 'sep' in kwargs else self._sep
# end = kwargs['end'] if 'end' in kwargs else self._end
# first = True
for x in args:
# if not first:
# tpweb.log_output(level, sep)
first = False
if isinstance(x, str):
tpweb.log_output(level, x)
continue
else:
tpweb.log_output(level, x.__str__())
# tpweb.log_output(level, end)
def _do_log_local(self, level, *args, **kwargs):
if level < self._min_level:
return
# sep = kwargs['sep'] if 'sep' in kwargs else self._sep
# end = kwargs['end'] if 'end' in kwargs else self._end
# first = True
for x in args:
# if not first:
# sys.stdout.writelines(sep)
first = False
if isinstance(x, str):
sys.stdout.writelines(x)
continue
else:
sys.stdout.writelines(x.__str__())
# sys.stdout.writelines(end)
sys.stdout.flush()
def log(self, msg, color=None):
"""
自行指定颜色输出到控制台不会输出到日志文件且输出时不含时间信息
"""
self._do_log(msg, color=color, show_datetime=False)
def _func_pass(self, msg, color=None):
# do nothing.
pass
def _func_debug(self, msg):
# 调试输出的数据,在正常运行中不会输出
self._do_log(msg, CR_DEBUG)
# 普通的日志数据
def _func_verbose(self, msg):
# pass
self._do_log(msg, None)
# 重要信息
def _func_info(self, msg):
self._do_log(msg, CR_INFO)
# 警告
def _func_warn(self, msg):
self._do_log(msg, CR_WARN)
# def _func_pass(self, msg, color=None):
# # do nothing.
# pass
#
# def _func_debug(self, msg):
# # 调试输出的数据,在正常运行中不会输出
# self._do_log(msg, CR_DEBUG)
# # 普通的日志数据
# def _func_verbose(self, msg):
# # pass
# self._do_log(msg, None)
#
# # 重要信息
# def _func_info(self, msg):
# self._do_log(msg, CR_INFO)
#
# # 警告
# def _func_warn(self, msg):
# self._do_log(msg, CR_WARN)
#
def _func_error(self, msg):
"""错误
"""
@ -315,7 +393,7 @@ class EomLogger:
m += '.'
m += '\n'
self.log(m, CR_DEBUG)
self._log_debug(m)
if loop > 0:
x += 1
@ -342,25 +420,25 @@ class EomLogger:
m += '.'
m += '\n'
self.log(m, CR_DEBUG)
self._log_debug(m)
def _do_log(self, msg, color=None, show_datetime=True):
with self._locker:
now = time.localtime(time.time())
_log_time = '[{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}] '.format(now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec)
try:
if show_datetime and self._log_datetime:
msg = '{}{}'.format(_log_time, msg)
self._log_console(msg, color)
else:
self._log_console(msg, color)
msg = '{}{}'.format(_log_time, msg)
self._log_file(msg)
except IOError:
pass
# def _do_log(self, msg, color=None, show_datetime=True):
# with self._locker:
# now = time.localtime(time.time())
# _log_time = '[{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}] '.format(now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec)
#
# try:
# if show_datetime and self._log_datetime:
# msg = '{}{}'.format(_log_time, msg)
# self._log_console(msg, color)
# else:
# self._log_console(msg, color)
# msg = '{}{}'.format(_log_time, msg)
#
# self._log_file(msg)
#
# except IOError:
# pass
def _console_default(self, msg, color=None):
"""
@ -482,46 +560,6 @@ class EomLogger:
self._set_level(LOG_DEBUG)
self._trace_error = TRACE_ERROR_FULL
self.log('###################', CR_NORMAL)
self.log(' CR_NORMAL\n')
self.log('###################', CR_BLACK)
self.log(' CR_BLACK\n')
self.log('###################', CR_LIGHT_GRAY)
self.log(' CR_LIGHT_GRAY\n')
self.log('###################', CR_GRAY)
self.log(' CR_GRAY\n')
self.log('###################', CR_WHITE)
self.log(' CR_WHITE\n')
self.log('###################', CR_RED)
self.log(' CR_RED\n')
self.log('###################', CR_GREEN)
self.log(' CR_GREEN\n')
self.log('###################', CR_YELLOW)
self.log(' CR_YELLOW\n')
self.log('###################', CR_BLUE)
self.log(' CR_BLUE\n')
self.log('###################', CR_MAGENTA)
self.log(' CR_MAGENTA\n')
self.log('###################', CR_CYAN)
self.log(' CR_CYAN\n')
self.log('###################', CR_LIGHT_RED)
self.log(' CR_LIGHT_RED\n')
self.log('###################', CR_LIGHT_GREEN)
self.log(' CR_LIGHT_GREEN\n')
self.log('###################', CR_LIGHT_YELLOW)
self.log(' CR_LIGHT_YELLOW\n')
self.log('###################', CR_LIGHT_BLUE)
self.log(' CR_LIGHT_BLUE\n')
self.log('###################', CR_LIGHT_MAGENTA)
self.log(' CR_LIGHT_MAGENTA\n')
self.log('###################', CR_LIGHT_CYAN)
self.log(' CR_LIGHT_CYAN\n')
data = b'This is a test string and you can see binary format data here.'
self.bin('Binary Data:\n', data)
data = b''
self.bin('Empty binary\n', data)
self.bin('This is string\n\n', 'data')
self.d('This is DEBUG message.\n')
self.v('This is VERBOSE message.\n')
self.i('This is INFORMATION message.\n')
@ -530,6 +568,12 @@ class EomLogger:
self.v('test auto\nsplited lines.\nYou should see\nmulti-lines.\n')
data = b'This is a test string and you can see binary format data here.'
self.bin('Binary Data:\n', data)
data = b''
self.bin('Empty binary\n', data)
self.bin('This is string\n\n', 'data')
class Win32DebugView:
def __init__(self):
@ -615,6 +659,8 @@ class Win32ColorConsole:
log = EomLogger()
del EomLogger
log._test()
import builtins
builtins.__dict__['print'] = log._log_print

View File

@ -10,18 +10,18 @@
<%block name="breadcrumb">
<ol class="breadcrumb">
<li><i class="fa fa-server fa-fw"></i> 录像回放</li>
<li><i class="fa fa-server"></i> 录像回放</li>
</ol>
</%block>
<div class="page-content">
<div ng-controller="TerminalRecordCtrl">
<button id="btn-play" type="button" class="btn btn-primary btn-sm"><i class="fa fa-pause"> 暂停</i></button>
<button id="btn-restart" type="button" class="btn btn-success btn-sm"><i class="fa fa-refresh"> 重新播放</i></button>
<button id="btn-play" type="button" class="btn btn-primary btn-sm" style="width:80px;"><i class="fa fa-pause"> 暂停</i></button>
<button id="btn-restart" type="button" class="btn btn-success btn-sm"><i class="fa fa-refresh"></i> 重新播放</button>
<button id="btn-speed" type="button" class="btn btn-warning btn-sm">正常速度</button>
<span id="play-status" class="badge badge-danger" style="margin-left:5px;">状态:正在获取数据</span>
<button id="btn-speed" type="button" class="btn btn-warning btn-sm" style="width:80px;">正常速度</button>
<span id="play-status" class="badge badge-normal" style="margin-left:5px;">状态:正在获取数据</span>
<span id="play-time" class="badge badge-success" style="margin-left:5px;">总时长:未知</span>
<input id="progress" type="range" value="0" min=0 max=100 style="margin-top: 10px;"/>
<div id="terminal" style="margin-top: 10px;"></div>