Skip to content

Commit 08218fa

Browse files
committed
add server component and requirement.txt etc.
1 parent 3b0b7d4 commit 08218fa

File tree

9 files changed

+194
-65
lines changed

9 files changed

+194
-65
lines changed

demos/jserver.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
File: jserver.py
6+
Author: jcppython(jcppython@outlook.com)
7+
Date: 2022/05/01 20:50:18
8+
"""
9+
10+
import argparse
11+
12+
import jserve.server
13+
14+
if __name__ == '__main__':
15+
parser = argparse.ArgumentParser(description='the demo of jserve')
16+
parser.add_argument('--conf', type=str, required=True)
17+
parser.add_argument('--workdir', type=str, required=True)
18+
args = parser.parse_args()
19+
20+
server = server.create(args.workdir, args.conf)
21+
server.run()
22+
23+

jserve/configure.py

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,22 @@
1313

1414
options = None
1515

16-
__fixed_sserver_conf = "conf/sserver.conf"
17-
__fixed_sserver_logname = "app"
16+
def init(workdir, conf):
17+
r""" 初始化配置
18+
"""
19+
global options
20+
21+
if options is not None:
22+
raise Exception("you can't init configure twice")
23+
24+
with open(conf) as f:
25+
options = json.load(f)
26+
27+
__buildin_option(workdir)
28+
1829

1930
def add_option(path, value):
20-
"""
21-
添加指定配置
31+
r""" 添加配置
2232
2333
Args:
2434
@@ -41,30 +51,13 @@ def add_option(path, value):
4151
p = p[key]
4252

4353

44-
def __buildin_option(workdir, category):
54+
def __buildin_option(workdir):
4555
"""
4656
填充内置配置项
4757
"""
4858
global options
4959

50-
options['app']['name'] = category
5160
add_option('env.workdir', workdir)
5261
options['log']['name'] = __fixed_sserver_logname
5362
options['log']['path'] = os.path.join(options['env']['workdir'], options['log']['path'])
5463
options['log']['level'] = getattr(logging, options['log']['level'].upper())
55-
56-
57-
def init(workdir, category):
58-
"""
59-
创建配置
60-
"""
61-
global options
62-
63-
if options is not None:
64-
raise Exception("you can't init configure twice")
65-
66-
with open("{}/{}/{}".format(workdir, category, __fixed_sserver_conf)) as f:
67-
options = json.load(f)
68-
69-
__buildin_option(workdir, category)
70-

jserve/http/http.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
File: http.py
6+
Author: jcppython(jcppython@outlook.com)
7+
Date: 2022/05/02 17:50:18
8+
"""
9+
10+
from abc import abstractmethod
11+
12+
class Http(object):
13+
r""" http 服务
14+
"""
15+
16+
def __init__(self):
17+
r""" 初始化服务
18+
"""
19+
self._routes = ()
20+
21+
@abstractmethod
22+
def add_route(self, route, handler):
23+
r""" 添加请求处理路由
24+
"""
25+
pass
26+
27+
@abstractmethod
28+
def run(self):
29+
r""" 运行服务
30+
"""
31+
pass
32+
Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# !/usr/bin/env python3
1+
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
33

44
"""
@@ -7,32 +7,38 @@
77
Date: 2022/05/02 01:50:18
88
"""
99

10-
import os
11-
import logging
12-
import asyncio
13-
import socketio
14-
import tornado
15-
import tornado.web
16-
import tornado.options
17-
import tornado.platform.asyncio
18-
1910
import log
20-
import configure
21-
import ssocketio
11+
import http
2212

23-
class Server(object):
24-
r""" App 服务
13+
class Tornado(http.Http):
14+
r""" 基于 tornado 的 http 服务
2515
"""
2616

27-
@classmethod
28-
def run(cls, port, routes):
17+
def __init__(self):
18+
r"""
19+
"""
20+
self.__enable_log()
21+
self._routes = ()
22+
23+
def add_route(self, route, handler):
24+
r""" 添加请求处理路由
25+
"""
26+
self._routes.append((route, handler))
27+
28+
def run(self):
2929
r""" 需要捕获异常
3030
"""
31+
3132
tornado.platform.asyncio.AsyncIOMainLoop().install()
3233

33-
cls.__enable_log()
34-
app = cls.__create_app(routes)
35-
app.listen(port)
34+
self._app = tornado.web.Application(
35+
self._routes,
36+
settings = dict(
37+
debug=True,
38+
autoescape=None
39+
)
40+
)
41+
self._app.listen(port)
3642

3743
loop = asyncio.get_event_loop()
3844
try:
@@ -45,11 +51,10 @@ def run(cls, port, routes):
4551
finally:
4652
loop.close()
4753

48-
@classmethod
49-
def __enable_log(cls):
50-
"""
51-
启用日志
54+
def __enable_log(self):
55+
r""" 设置日志
5256
"""
57+
5358
config = [
5459
{
5560
'logger': tornado.log.access_log,
@@ -70,19 +75,3 @@ def __enable_log(cls):
7075
d['logger'].addHandler(h)
7176
d['logger'].setLevel(configure.options['log']['level'])
7277

73-
@classmethod
74-
def __create_app(cls, routes):
75-
ssocketio.init(True, async_mode='tornado', cors_allowed_origins="*")
76-
ssocketio.load_event("./event/")
77-
78-
routes.append(
79-
(r"/socket.io/.*/", socketio.get_tornado_handler(ssocketio.sio))
80-
)
81-
82-
return tornado.web.Application(
83-
routes,
84-
settings = dict(
85-
debug=True,
86-
autoescape=None
87-
)
88-
)

jserve/server.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# !/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
File: jserve.py
6+
Author: jcppython(jcppython@outlook.com)
7+
Date: 2022/05/02 01:50:18
8+
"""
9+
10+
import os
11+
import logging
12+
import asyncio
13+
import socketio
14+
15+
import log
16+
import configure
17+
import sio
18+
import logging
19+
import traceback
20+
21+
import http
22+
23+
def create(workdir, conf):
24+
r""" 创建 server 服务
25+
"""
26+
27+
configure.init(workdir, conf)
28+
29+
logger = logging.getLogger()
30+
logger.setLevel(configure.options['log']['level'])
31+
log.logDecorateStandard(logger, configure.options['log']['path'], configure.options['log']['name'])
32+
33+
return Server()
34+
35+
36+
class Server(object):
37+
r""" jserve 服务接口
38+
"""
39+
40+
def __init__(self):
41+
r""" 创建一个 server
42+
43+
Args:
44+
45+
workdir: string 服务运行目录,决定 log 等产出位置
46+
conf: 服务配置文件
47+
"""
48+
49+
self._http_server = http.Http(conf['http'])
50+
51+
if 'sio' in kwargs:
52+
self._http_server.add_route(
53+
(r"/socket.io/.*/", sio.http_handler())
54+
)
55+
56+
def run(self):
57+
try:
58+
self._http_server.run()
59+
except Exception as e:
60+
logger.error("{}\n{}".format("app exit by some fatal error", traceback.format_exc()))
61+
finally:
62+
logger.warning("app exit")
63+

jserve/sio/jsocketio.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# !/usr/bin/env python3
1+
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
33

44
"""
@@ -31,6 +31,9 @@ def init(is_async=True, **kwargs):
3131

3232
sio = __create_async_server(**kwargs) if is_async else __create_sync_server(**kwargs)
3333

34+
ssocketio.init(True, async_mode='tornado', cors_allowed_origins="*")
35+
ssocketio.load_event("./event/")
36+
3437

3538
def load_event(path):
3639
r""" 遍历 path 目录 .py 模块,完成 @sio 事件的加载
@@ -54,10 +57,17 @@ def help_load(file):
5457
state, mod_name, path, file
5558
))
5659

60+
def http_handler(**kwargs):
61+
"""
62+
"""
63+
sio.http_handler()
64+
return socketio.get_tornado_handler(ssocketio.sio)
65+
5766

5867
def __config_server(kwargs, is_async=True):
5968
r""" 完成 server 创建的配置构建
6069
70+
https://python-socketio.readthedocs.io/en/latest/api.html#server-class
6171
https://python-socketio.readthedocs.io/en/latest/server.html#emitting-from-external-processes
6272
connect to the redis queue as an external process
6373
external_sio = socketio.RedisManager('redis://', write_only=True)

requirements-test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tox

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
socketio
1+
socketio
2+
tornado

setup.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def read(*parts):
1515
# intentionally *not* adding an encoding option to open
1616
return codecs.open(os.path.join(here, *parts), 'r').read()
1717

18+
1819
def find_version(*file_paths):
1920
version_file = read(*file_paths)
2021
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
@@ -23,6 +24,17 @@ def find_version(*file_paths):
2324
return version_match.group(1)
2425
raise RuntimeError("Unable to find version string.")
2526

27+
28+
def parse_requirements(filename):
29+
"""
30+
读取 requirements.txt
31+
"""
32+
with open(os.path.join(here, filename), 'r', encoding='utf-8') as file_:
33+
lines = map(lambda x: x.strip('\n'), file_.readlines())
34+
lines = filter(lambda x: x and not x.startswith('#') and not x.startswith('-'), lines)
35+
return list(lines)
36+
37+
2638
class Tox(TestCommand):
2739
def finalize_options(self):
2840
TestCommand.finalize_options(self)
@@ -35,10 +47,12 @@ def run_tests(self):
3547
errcode = tox.cmdline(self.test_args)
3648
sys.exit(errcode)
3749

50+
3851
# Get the long description from the README file
39-
with open(os.path.join(here, "README.md")) as in_file:
52+
with open(os.path.join(here, "README.md"), 'r') as in_file:
4053
long_description = in_file.read()
4154

55+
4256
setup(
4357
name="jserve",
4458
version=find_version('jserve', '__init__.py'),
@@ -50,7 +64,10 @@ def run_tests(self):
5064
url="https://github.com/jcppython/jserve-python",
5165
packages=["jserve"],
5266
python_requires=">=3.6",
53-
tests_require=['tox'],
67+
install_requires=parse_requirements('requirements.txt'),
68+
tests_require=(
69+
parse_requirements('requirements.txt') +
70+
parse_requirements('requirements-test.txt')),
5471
cmdclass = {'test': Tox},
5572
classifiers=[
5673
"Development Status :: 3 - Alpha",

0 commit comments

Comments
 (0)