socket.d 2.4.10__tar.gz → 2.4.10.1__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {socket.d-2.4.10 → socket.d-2.4.10.1}/PKG-INFO +1 -1
- socket.d-2.4.10.1/README.md +42 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/setup.py +2 -2
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socket.d.egg-info/PKG-INFO +1 -1
- socket.d-2.4.10.1/socket.d.egg-info/SOURCES.txt +125 -0
- socket.d-2.4.10.1/socketd/broker/BrokerFragmentHandler.py +7 -0
- socket.d-2.4.10.1/socketd/broker/BrokerListener.py +93 -0
- socket.d-2.4.10.1/socketd/broker/BrokerListenerBase.py +82 -0
- socket.d-2.4.10.1/socketd/broker/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/cluster/ClusterClient.py +75 -0
- socket.d-2.4.10.1/socketd/cluster/ClusterClientSession.py +80 -0
- socket.d-2.4.10.1/socketd/cluster/LoadBalancer.py +65 -0
- socket.d-2.4.10.1/socketd/cluster/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/exception/SocketDExecption.py +38 -0
- socket.d-2.4.10.1/socketd/exception/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/client/Client.py +57 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientBase.py +97 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientChannel.py +192 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientConfig.py +96 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientConfigHandler.py +4 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientConnectHandler.py +10 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientConnector.py +23 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientConnectorBase.py +20 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientHandshakeResult.py +15 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientHeartbeatHandler.py +10 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientProvider.py +15 -0
- socket.d-2.4.10.1/socketd/transport/client/ClientSession.py +48 -0
- socket.d-2.4.10.1/socketd/transport/client/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/core/Asserts.py +35 -0
- socket.d-2.4.10.1/socketd/transport/core/Channel.py +112 -0
- socket.d-2.4.10.1/socketd/transport/core/ChannelAssistant.py +31 -0
- socket.d-2.4.10.1/socketd/transport/core/ChannelInternal.py +24 -0
- socket.d-2.4.10.1/socketd/transport/core/ChannelSupporter.py +21 -0
- socket.d-2.4.10.1/socketd/transport/core/Codec.py +72 -0
- socket.d-2.4.10.1/socketd/transport/core/Config.py +142 -0
- socket.d-2.4.10.1/socketd/transport/core/Costants.py +52 -0
- socket.d-2.4.10.1/socketd/transport/core/Entity.py +50 -0
- socket.d-2.4.10.1/socketd/transport/core/EntityMetas.py +22 -0
- socket.d-2.4.10.1/socketd/transport/core/Flags.py +74 -0
- socket.d-2.4.10.1/socketd/transport/core/FragmentAggregator.py +58 -0
- socket.d-2.4.10.1/socketd/transport/core/FragmentHandler.py +31 -0
- socket.d-2.4.10.1/socketd/transport/core/Frame.py +18 -0
- socket.d-2.4.10.1/socketd/transport/core/Frames.py +63 -0
- socket.d-2.4.10.1/socketd/transport/core/HandshakeDefault.py +92 -0
- socket.d-2.4.10.1/socketd/transport/core/IdGenerator.py +9 -0
- socket.d-2.4.10.1/socketd/transport/core/Listener.py +22 -0
- socket.d-2.4.10.1/socketd/transport/core/Message.py +37 -0
- socket.d-2.4.10.1/socketd/transport/core/Processor.py +33 -0
- socket.d-2.4.10.1/socketd/transport/core/Session.py +85 -0
- socket.d-2.4.10.1/socketd/transport/core/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/core/codec/Buffer.py +42 -0
- socket.d-2.4.10.1/socketd/transport/core/codec/ByteBufferCodecReader.py +33 -0
- socket.d-2.4.10.1/socketd/transport/core/codec/ByteBufferCodecWriter.py +24 -0
- socket.d-2.4.10.1/socketd/transport/core/codec/CodecDefault.py +116 -0
- socket.d-2.4.10.1/socketd/transport/core/codec/__init__.py +9 -0
- socket.d-2.4.10.1/socketd/transport/core/entity/EntityDefault.py +126 -0
- socket.d-2.4.10.1/socketd/transport/core/entity/FileEntity.py +28 -0
- socket.d-2.4.10.1/socketd/transport/core/entity/MessageBuilder.py +33 -0
- socket.d-2.4.10.1/socketd/transport/core/entity/MessageDefault.py +81 -0
- socket.d-2.4.10.1/socketd/transport/core/entity/StringEntity.py +10 -0
- socket.d-2.4.10.1/socketd/transport/core/entity/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/core/fragment/FragmentAggregatorDefault.py +56 -0
- socket.d-2.4.10.1/socketd/transport/core/fragment/FragmentHandlerBase.py +73 -0
- socket.d-2.4.10.1/socketd/transport/core/fragment/FragmentHandlerDefault.py +15 -0
- socket.d-2.4.10.1/socketd/transport/core/fragment/FragmentHolder.py +8 -0
- socket.d-2.4.10.1/socketd/transport/core/fragment/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/ChannelBase.py +80 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/ChannelDefault.py +172 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/ConfigBase.py +218 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/LogConfig.py +11 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/ProcessorDefault.py +181 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/SessionBase.py +51 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/SessionDefault.py +111 -0
- socket.d-2.4.10.1/socketd/transport/core/impl/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/core/listener/EventListener.py +57 -0
- socket.d-2.4.10.1/socketd/transport/core/listener/PathListener.py +32 -0
- socket.d-2.4.10.1/socketd/transport/core/listener/PathMapper.py +11 -0
- socket.d-2.4.10.1/socketd/transport/core/listener/PipelineListener.py +21 -0
- socket.d-2.4.10.1/socketd/transport/core/listener/SimpleListener.py +18 -0
- socket.d-2.4.10.1/socketd/transport/core/listener/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/server/Server.py +24 -0
- socket.d-2.4.10.1/socketd/transport/server/ServerBase.py +86 -0
- socket.d-2.4.10.1/socketd/transport/server/ServerConfig.py +53 -0
- socket.d-2.4.10.1/socketd/transport/server/ServerProvider.py +9 -0
- socket.d-2.4.10.1/socketd/transport/server/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/stream/RequestStream.py +36 -0
- socket.d-2.4.10.1/socketd/transport/stream/SendStream.py +14 -0
- socket.d-2.4.10.1/socketd/transport/stream/Stream.py +32 -0
- socket.d-2.4.10.1/socketd/transport/stream/StreamBase.py +62 -0
- socket.d-2.4.10.1/socketd/transport/stream/StreamManger.py +41 -0
- socket.d-2.4.10.1/socketd/transport/stream/StreamMangerDefault.py +32 -0
- socket.d-2.4.10.1/socketd/transport/stream/SubscribeStream.py +28 -0
- socket.d-2.4.10.1/socketd/transport/stream/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/utils/AsyncUtil.py +100 -0
- socket.d-2.4.10.1/socketd/transport/utils/CompletableFuture.py +63 -0
- socket.d-2.4.10.1/socketd/transport/utils/StrUtil.py +26 -0
- socket.d-2.4.10.1/socketd/transport/utils/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/utils/async_api/AtomicRefer.py +36 -0
- socket.d-2.4.10.1/socketd/transport/utils/async_api/__init__.py +0 -0
- socket.d-2.4.10.1/socketd/transport/utils/sync_api/AtomicRefer.py +36 -0
- socket.d-2.4.10.1/socketd/transport/utils/sync_api/__init__.py +0 -0
- socket.d-2.4.10.1/socketd_websocket/impl/AIOConnect.py +121 -0
- socket.d-2.4.10.1/socketd_websocket/impl/AIOServe.py +151 -0
- socket.d-2.4.10.1/socketd_websocket/impl/AIOWebSocketClientImpl.py +135 -0
- socket.d-2.4.10.1/socketd_websocket/impl/AIOWebSocketServerImpl.py +111 -0
- socket.d-2.4.10.1/socketd_websocket/impl/__init__.py +6 -0
- socket.d-2.4.10/README.md +0 -10
- socket.d-2.4.10/socket.d.egg-info/SOURCES.txt +0 -23
- {socket.d-2.4.10 → socket.d-2.4.10.1}/setup.cfg +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socket.d.egg-info/dependency_links.txt +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socket.d.egg-info/requires.txt +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socket.d.egg-info/top_level.txt +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socket.d.egg-info/zip-safe +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd/SocketD.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd/__init__.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_aio_tcp/TCPAIOServer.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_aio_tcp/TCPStreamIO.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_aio_tcp/TcpAIOChannelAssistant.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_aio_tcp/TcpAioClient.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_aio_tcp/TcpAioClientConnector.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_aio_tcp/TcpAioProvider.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_aio_tcp/__init__.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_websocket/WsAioChannelAssistant.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_websocket/WsAioClient.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_websocket/WsAioClientConnector.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_websocket/WsAioProvider.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_websocket/WsAioServer.py +0 -0
- {socket.d-2.4.10 → socket.d-2.4.10.1}/socketd_websocket/__init__.py +0 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
基于事件和语义消息流的网络应用层协议。
|
4
|
+
|
5
|
+
有用户说,“Socket.D 之于 Socket,尤如 Vue 之于 Js、Mvc 之于 Http”。支持 tcp, udp, ws, kcp 传输。
|
6
|
+
|
7
|
+
```
|
8
|
+
[len:int][flag:int][sid:str(<64)][\n][event:str(<512)][\n][metaString:str(<4k)][\n][data:byte(<16m)]
|
9
|
+
```
|
10
|
+
|
11
|
+
### 主要特性
|
12
|
+
|
13
|
+
* 基于事件,每个消息都可事件路由
|
14
|
+
* 所谓语义,通过元信息进行语义描述
|
15
|
+
* 流关联性,来回相关的消息会串成一个流
|
16
|
+
* 语言无关,使用二进制输传数据(支持 tcp, ws, udp)。支持多语言、多平台
|
17
|
+
* 断线重连,自动连接恢复
|
18
|
+
* 多路复用,一个连接便可允许多个请求和响应消息同时运行
|
19
|
+
* 双向通讯,单链接双向互听互发
|
20
|
+
* 自动分片,数据超出 16Mb(大小可配置),会自动分片、自动重组(udp 除外)
|
21
|
+
* 接口简单,是响应式但用回调接口
|
22
|
+
|
23
|
+
### 体验效果 (for python-client)
|
24
|
+
|
25
|
+
```python
|
26
|
+
#发送
|
27
|
+
session.send("/demo/hello", StringEntity("hi"));
|
28
|
+
#发送,且获取发送进度(如果有大数据发送,又需要显示进度)
|
29
|
+
session.send("/demo/upload", FileEntity(file)).then_progress(lambda isSend, val, max: ...)
|
30
|
+
|
31
|
+
#发送并请求,且同步等待
|
32
|
+
reply = await session.send_and_request("/demo/hello", EntityDefault());
|
33
|
+
#发送并请求,且取接收进度(如果有大数据获取,又需要显示进度)
|
34
|
+
session.send_and_request("/demo/download", EntityDefault())
|
35
|
+
.then_progress(lambda isSend, val, max: ...)
|
36
|
+
.thenReply(lambda reply: ...)
|
37
|
+
.thenError(lambda err: ...)
|
38
|
+
|
39
|
+
#发送并订阅
|
40
|
+
entity = EntityDefault().range(5,5).meta_put("videoId","1");
|
41
|
+
session.send_and_subscribe("/demo/stream", entity).then_reply(lambda reply: ...)
|
42
|
+
```
|
@@ -4,11 +4,11 @@ from setuptools import setup,find_packages
|
|
4
4
|
|
5
5
|
setup(
|
6
6
|
name='socket.d',
|
7
|
-
version='2.4.10',
|
7
|
+
version='2.4.10.1',
|
8
8
|
description='@noear/socket.d python project',
|
9
9
|
author='noear,bai',
|
10
10
|
url='https://socketd.noear.org/',
|
11
|
-
packages=[
|
11
|
+
packages=find_packages(exclude=['*test*']), # 包内不需要引用的文件夹
|
12
12
|
install_requires=[ # 依赖包
|
13
13
|
'loguru',
|
14
14
|
'websockets'
|
@@ -0,0 +1,125 @@
|
|
1
|
+
README.md
|
2
|
+
setup.py
|
3
|
+
socket.d.egg-info/PKG-INFO
|
4
|
+
socket.d.egg-info/SOURCES.txt
|
5
|
+
socket.d.egg-info/dependency_links.txt
|
6
|
+
socket.d.egg-info/requires.txt
|
7
|
+
socket.d.egg-info/top_level.txt
|
8
|
+
socket.d.egg-info/zip-safe
|
9
|
+
socketd/SocketD.py
|
10
|
+
socketd/__init__.py
|
11
|
+
socketd/broker/BrokerFragmentHandler.py
|
12
|
+
socketd/broker/BrokerListener.py
|
13
|
+
socketd/broker/BrokerListenerBase.py
|
14
|
+
socketd/broker/__init__.py
|
15
|
+
socketd/cluster/ClusterClient.py
|
16
|
+
socketd/cluster/ClusterClientSession.py
|
17
|
+
socketd/cluster/LoadBalancer.py
|
18
|
+
socketd/cluster/__init__.py
|
19
|
+
socketd/exception/SocketDExecption.py
|
20
|
+
socketd/exception/__init__.py
|
21
|
+
socketd/transport/__init__.py
|
22
|
+
socketd/transport/client/Client.py
|
23
|
+
socketd/transport/client/ClientBase.py
|
24
|
+
socketd/transport/client/ClientChannel.py
|
25
|
+
socketd/transport/client/ClientConfig.py
|
26
|
+
socketd/transport/client/ClientConfigHandler.py
|
27
|
+
socketd/transport/client/ClientConnectHandler.py
|
28
|
+
socketd/transport/client/ClientConnector.py
|
29
|
+
socketd/transport/client/ClientConnectorBase.py
|
30
|
+
socketd/transport/client/ClientHandshakeResult.py
|
31
|
+
socketd/transport/client/ClientHeartbeatHandler.py
|
32
|
+
socketd/transport/client/ClientProvider.py
|
33
|
+
socketd/transport/client/ClientSession.py
|
34
|
+
socketd/transport/client/__init__.py
|
35
|
+
socketd/transport/core/Asserts.py
|
36
|
+
socketd/transport/core/Channel.py
|
37
|
+
socketd/transport/core/ChannelAssistant.py
|
38
|
+
socketd/transport/core/ChannelInternal.py
|
39
|
+
socketd/transport/core/ChannelSupporter.py
|
40
|
+
socketd/transport/core/Codec.py
|
41
|
+
socketd/transport/core/Config.py
|
42
|
+
socketd/transport/core/Costants.py
|
43
|
+
socketd/transport/core/Entity.py
|
44
|
+
socketd/transport/core/EntityMetas.py
|
45
|
+
socketd/transport/core/Flags.py
|
46
|
+
socketd/transport/core/FragmentAggregator.py
|
47
|
+
socketd/transport/core/FragmentHandler.py
|
48
|
+
socketd/transport/core/Frame.py
|
49
|
+
socketd/transport/core/Frames.py
|
50
|
+
socketd/transport/core/HandshakeDefault.py
|
51
|
+
socketd/transport/core/IdGenerator.py
|
52
|
+
socketd/transport/core/Listener.py
|
53
|
+
socketd/transport/core/Message.py
|
54
|
+
socketd/transport/core/Processor.py
|
55
|
+
socketd/transport/core/Session.py
|
56
|
+
socketd/transport/core/__init__.py
|
57
|
+
socketd/transport/core/codec/Buffer.py
|
58
|
+
socketd/transport/core/codec/ByteBufferCodecReader.py
|
59
|
+
socketd/transport/core/codec/ByteBufferCodecWriter.py
|
60
|
+
socketd/transport/core/codec/CodecDefault.py
|
61
|
+
socketd/transport/core/codec/__init__.py
|
62
|
+
socketd/transport/core/entity/EntityDefault.py
|
63
|
+
socketd/transport/core/entity/FileEntity.py
|
64
|
+
socketd/transport/core/entity/MessageBuilder.py
|
65
|
+
socketd/transport/core/entity/MessageDefault.py
|
66
|
+
socketd/transport/core/entity/StringEntity.py
|
67
|
+
socketd/transport/core/entity/__init__.py
|
68
|
+
socketd/transport/core/fragment/FragmentAggregatorDefault.py
|
69
|
+
socketd/transport/core/fragment/FragmentHandlerBase.py
|
70
|
+
socketd/transport/core/fragment/FragmentHandlerDefault.py
|
71
|
+
socketd/transport/core/fragment/FragmentHolder.py
|
72
|
+
socketd/transport/core/fragment/__init__.py
|
73
|
+
socketd/transport/core/impl/ChannelBase.py
|
74
|
+
socketd/transport/core/impl/ChannelDefault.py
|
75
|
+
socketd/transport/core/impl/ConfigBase.py
|
76
|
+
socketd/transport/core/impl/LogConfig.py
|
77
|
+
socketd/transport/core/impl/ProcessorDefault.py
|
78
|
+
socketd/transport/core/impl/SessionBase.py
|
79
|
+
socketd/transport/core/impl/SessionDefault.py
|
80
|
+
socketd/transport/core/impl/__init__.py
|
81
|
+
socketd/transport/core/listener/EventListener.py
|
82
|
+
socketd/transport/core/listener/PathListener.py
|
83
|
+
socketd/transport/core/listener/PathMapper.py
|
84
|
+
socketd/transport/core/listener/PipelineListener.py
|
85
|
+
socketd/transport/core/listener/SimpleListener.py
|
86
|
+
socketd/transport/core/listener/__init__.py
|
87
|
+
socketd/transport/server/Server.py
|
88
|
+
socketd/transport/server/ServerBase.py
|
89
|
+
socketd/transport/server/ServerConfig.py
|
90
|
+
socketd/transport/server/ServerProvider.py
|
91
|
+
socketd/transport/server/__init__.py
|
92
|
+
socketd/transport/stream/RequestStream.py
|
93
|
+
socketd/transport/stream/SendStream.py
|
94
|
+
socketd/transport/stream/Stream.py
|
95
|
+
socketd/transport/stream/StreamBase.py
|
96
|
+
socketd/transport/stream/StreamManger.py
|
97
|
+
socketd/transport/stream/StreamMangerDefault.py
|
98
|
+
socketd/transport/stream/SubscribeStream.py
|
99
|
+
socketd/transport/stream/__init__.py
|
100
|
+
socketd/transport/utils/AsyncUtil.py
|
101
|
+
socketd/transport/utils/CompletableFuture.py
|
102
|
+
socketd/transport/utils/StrUtil.py
|
103
|
+
socketd/transport/utils/__init__.py
|
104
|
+
socketd/transport/utils/async_api/AtomicRefer.py
|
105
|
+
socketd/transport/utils/async_api/__init__.py
|
106
|
+
socketd/transport/utils/sync_api/AtomicRefer.py
|
107
|
+
socketd/transport/utils/sync_api/__init__.py
|
108
|
+
socketd_aio_tcp/TCPAIOServer.py
|
109
|
+
socketd_aio_tcp/TCPStreamIO.py
|
110
|
+
socketd_aio_tcp/TcpAIOChannelAssistant.py
|
111
|
+
socketd_aio_tcp/TcpAioClient.py
|
112
|
+
socketd_aio_tcp/TcpAioClientConnector.py
|
113
|
+
socketd_aio_tcp/TcpAioProvider.py
|
114
|
+
socketd_aio_tcp/__init__.py
|
115
|
+
socketd_websocket/WsAioChannelAssistant.py
|
116
|
+
socketd_websocket/WsAioClient.py
|
117
|
+
socketd_websocket/WsAioClientConnector.py
|
118
|
+
socketd_websocket/WsAioProvider.py
|
119
|
+
socketd_websocket/WsAioServer.py
|
120
|
+
socketd_websocket/__init__.py
|
121
|
+
socketd_websocket/impl/AIOConnect.py
|
122
|
+
socketd_websocket/impl/AIOServe.py
|
123
|
+
socketd_websocket/impl/AIOWebSocketClientImpl.py
|
124
|
+
socketd_websocket/impl/AIOWebSocketServerImpl.py
|
125
|
+
socketd_websocket/impl/__init__.py
|
@@ -0,0 +1,93 @@
|
|
1
|
+
from socketd.broker.BrokerListenerBase import BrokerListenerBase
|
2
|
+
from socketd.transport.core import Entity
|
3
|
+
from socketd.transport.core.Message import Message
|
4
|
+
from socketd.transport.core.Session import Session
|
5
|
+
|
6
|
+
|
7
|
+
# 经纪人监听器(为不同的玩家转发消息)
|
8
|
+
class BrokerListener(BrokerListenerBase):
|
9
|
+
def __init__(self):
|
10
|
+
super().__init__()
|
11
|
+
|
12
|
+
async def on_open(self, session: Session):
|
13
|
+
name = session.name()
|
14
|
+
self.add_player(name, session)
|
15
|
+
|
16
|
+
def on_close(self, session: Session):
|
17
|
+
name = session.name()
|
18
|
+
self.remove_player(name, session)
|
19
|
+
|
20
|
+
async def on_message(self, requester: Session, message: Message):
|
21
|
+
atName = message.at_name()
|
22
|
+
|
23
|
+
if atName is None:
|
24
|
+
await requester.send_alarm(message, "Broker message require '@' meta")
|
25
|
+
return
|
26
|
+
|
27
|
+
if atName.__eq__("*"):
|
28
|
+
# 广播模式(给所有玩家)
|
29
|
+
nameAll = self.get_name_all()
|
30
|
+
if nameAll is not None and len(nameAll) > 0:
|
31
|
+
for name in nameAll:
|
32
|
+
self.forward_to_name(requester, message, name)
|
33
|
+
elif atName.endswith("*"):
|
34
|
+
# 群发模式(给同名的所有玩家)
|
35
|
+
atName = atName[:-1]
|
36
|
+
if not self.forward_to_name(requester, message, atName):
|
37
|
+
await requester.send_alarm(message, "Broker don't have '@" + atName + "' player")
|
38
|
+
else:
|
39
|
+
responder = self.get_player_any(atName, requester, message)
|
40
|
+
if responder is not None:
|
41
|
+
self.forward_to_session(requester, message, responder)
|
42
|
+
else:
|
43
|
+
await requester.send_alarm(message, "Broker don't have '@" + atName + "' session")
|
44
|
+
|
45
|
+
# 批量转发消息
|
46
|
+
def forward_to_name(self, requester: Session, message: Message, name: str) -> bool:
|
47
|
+
playerAll = self.get_player_all(name)
|
48
|
+
|
49
|
+
if playerAll is not None and len(playerAll) > 0:
|
50
|
+
for responder in playerAll:
|
51
|
+
if responder != requester:
|
52
|
+
if responder.is_valid():
|
53
|
+
self.forward_to_session(requester, message, responder)
|
54
|
+
else:
|
55
|
+
self.on_close(responder)
|
56
|
+
return True
|
57
|
+
else:
|
58
|
+
return False
|
59
|
+
|
60
|
+
# 转发消息
|
61
|
+
def forward_to_session(self, requester: Session, message: Message, responder: Session):
|
62
|
+
if message.is_request():
|
63
|
+
def then_reply(reply: Entity):
|
64
|
+
if requester.is_valid():
|
65
|
+
requester.reply(message, reply)
|
66
|
+
|
67
|
+
def then_error(err: Exception):
|
68
|
+
if requester.is_valid():
|
69
|
+
requester.send_alarm(message, err)
|
70
|
+
|
71
|
+
responder.send_and_request(message.event(), message, -1).then_reply(then_reply).then_error(then_error)
|
72
|
+
return
|
73
|
+
|
74
|
+
if message.is_subscribe():
|
75
|
+
def then_reply(reply: Entity):
|
76
|
+
if requester.is_valid():
|
77
|
+
if message.is_end():
|
78
|
+
requester.reply_end(message, reply)
|
79
|
+
else:
|
80
|
+
requester.reply(message, reply)
|
81
|
+
|
82
|
+
def then_error(err: Exception):
|
83
|
+
if requester.is_valid():
|
84
|
+
requester.send_alarm(message, err)
|
85
|
+
|
86
|
+
responder.send_and_subscribe(message.event(), message, -1).then_reply(then_reply).then_error(then_error)
|
87
|
+
return
|
88
|
+
|
89
|
+
responder.send(message.event(), message)
|
90
|
+
|
91
|
+
def on_error(self, session: Session, error):
|
92
|
+
...
|
93
|
+
# log.warn("Broker error", error)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
from abc import ABC
|
2
|
+
from typing import Dict, List
|
3
|
+
from socketd.cluster.LoadBalancer import LoadBalancer
|
4
|
+
from socketd.transport.client.ClientSession import ClientSession
|
5
|
+
from socketd.transport.core.EntityMetas import EntityMetas
|
6
|
+
from socketd.transport.core.Listener import Listener
|
7
|
+
from socketd.transport.core.Message import Message
|
8
|
+
from socketd.transport.core.Session import Session
|
9
|
+
from socketd.transport.utils.StrUtil import StrUtil
|
10
|
+
|
11
|
+
|
12
|
+
# 经纪人监听器基类(实现玩家封闭管理)
|
13
|
+
class BrokerListenerBase(Listener, ABC):
|
14
|
+
def __init__(self):
|
15
|
+
self.__sessionAll: Dict[str, Session] = {}
|
16
|
+
self.__playerSessions: Dict[str, List[Session]] = {}
|
17
|
+
|
18
|
+
# 获取所有会话(包括没有名字的)
|
19
|
+
def get_session_all(self) -> List[Session]:
|
20
|
+
return list(self.__sessionAll.values())
|
21
|
+
|
22
|
+
# 获取任意会话(包括没有名字的)
|
23
|
+
def get_session_any(self) -> ClientSession:
|
24
|
+
return LoadBalancer.get_any(self.get_session_all(), LoadBalancer.round_counter_get())
|
25
|
+
|
26
|
+
# 获取会话数量
|
27
|
+
def get_session_count(self) -> int:
|
28
|
+
return len(self.__sessionAll)
|
29
|
+
|
30
|
+
# 获取所有玩家的名字
|
31
|
+
def get_name_all(self) -> List[str]:
|
32
|
+
return list(self.__sessionAll.keys())
|
33
|
+
|
34
|
+
# 获取所有玩家数量
|
35
|
+
def get_player_count(self, name: str) -> int:
|
36
|
+
return len(self.get_player_all(name))
|
37
|
+
|
38
|
+
# 获取所有玩家会话
|
39
|
+
def get_player_all(self, name: str) -> List[Session]:
|
40
|
+
return self.__playerSessions[name]
|
41
|
+
|
42
|
+
# 获取任意一个玩家会话
|
43
|
+
def get_player_any(self, atName: str, requester: Session | None, message: Message | None) -> ClientSession | None:
|
44
|
+
if StrUtil.is_empty(atName):
|
45
|
+
return None
|
46
|
+
|
47
|
+
if atName.endswith("!"):
|
48
|
+
atName = atName[:-1]
|
49
|
+
x_hash = None
|
50
|
+
|
51
|
+
if message is not None:
|
52
|
+
x_hash = message.meta(EntityMetas.META_X_Hash)
|
53
|
+
|
54
|
+
if StrUtil.is_empty(x_hash):
|
55
|
+
if requester is None:
|
56
|
+
return LoadBalancer.get_any_by_poll(self.get_player_all(atName))
|
57
|
+
else: # 使用请求者 ip 分流
|
58
|
+
return LoadBalancer.get_any_by_hash(self.get_player_all(atName), requester.remote_address())
|
59
|
+
else:
|
60
|
+
return LoadBalancer.get_any_by_hash(self.get_player_all(atName), x_hash)
|
61
|
+
else:
|
62
|
+
return LoadBalancer.get_any_by_poll(self.get_player_all(atName))
|
63
|
+
|
64
|
+
# 添加玩家会话
|
65
|
+
def add_player(self, name: str, session: Session):
|
66
|
+
if StrUtil.is_not_empty(name):
|
67
|
+
tmp: List[Session] = self.__playerSessions.get(name)
|
68
|
+
if tmp is None:
|
69
|
+
tmp = [session]
|
70
|
+
self.__playerSessions[name] = tmp
|
71
|
+
tmp.append(session)
|
72
|
+
|
73
|
+
self.__sessionAll[session.session_id()] = session
|
74
|
+
|
75
|
+
# 移除玩家会话
|
76
|
+
def remove_player(self, name: str, session: Session):
|
77
|
+
if StrUtil.is_not_empty(name):
|
78
|
+
tmp: list[Session] = self.get_player_all(name)
|
79
|
+
if tmp is not None:
|
80
|
+
tmp.remove(session)
|
81
|
+
|
82
|
+
self.__sessionAll.pop(session.session_id())
|
File without changes
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Optional, List, Awaitable, Any
|
3
|
+
|
4
|
+
from socketd import SocketD
|
5
|
+
from socketd.cluster.ClusterClientSession import ClusterClientSession
|
6
|
+
from socketd.transport.client.Client import Client, ClientInternal
|
7
|
+
from socketd.transport.client.ClientConfigHandler import ClientConfigHandler
|
8
|
+
from socketd.transport.client.ClientConnectHandler import ClientConnectHandler
|
9
|
+
from socketd.transport.client.ClientSession import ClientSession
|
10
|
+
from socketd.transport.core import Listener
|
11
|
+
from socketd.transport.core.Session import Session
|
12
|
+
from socketd.transport.client.ClientHeartbeatHandler import ClientHeartbeatHandler
|
13
|
+
|
14
|
+
|
15
|
+
class ClusterClient(Client):
|
16
|
+
|
17
|
+
def __init__(self, *serverUrls):
|
18
|
+
self.__serverUrls: Optional[tuple[Any, ...]] = serverUrls
|
19
|
+
|
20
|
+
self.__connectHandler: ClientConnectHandler = None
|
21
|
+
self.__heartbeatHandler: ClientHeartbeatHandler = None
|
22
|
+
self.__configHandler: ClientConfigHandler = None
|
23
|
+
|
24
|
+
self.__listener = None
|
25
|
+
|
26
|
+
def connect_handler(self, connectHandler: ClientConnectHandler) -> Client:
|
27
|
+
self.__connectHandler = connectHandler
|
28
|
+
return self
|
29
|
+
|
30
|
+
def heartbeat_handler(self, heartbeatHandler: ClientHeartbeatHandler) -> Client:
|
31
|
+
self.__heartbeatHandler = heartbeatHandler
|
32
|
+
return self
|
33
|
+
|
34
|
+
def config(self, configHandler: ClientConfigHandler) -> Client:
|
35
|
+
self.__configHandler = configHandler
|
36
|
+
return self
|
37
|
+
|
38
|
+
def listen(self, listener: Listener) -> Client:
|
39
|
+
self.__listener = listener
|
40
|
+
return self
|
41
|
+
|
42
|
+
def open(self) -> Awaitable[ClientSession]:
|
43
|
+
return self._open_do(False)
|
44
|
+
|
45
|
+
def open_or_throw(self) -> Awaitable[ClientSession]:
|
46
|
+
return self._open_do(True)
|
47
|
+
|
48
|
+
async def _open_do(self, is_throw):
|
49
|
+
sessions: List[Session] = []
|
50
|
+
exchangeExecutor = None
|
51
|
+
for urls in self.__serverUrls:
|
52
|
+
for url in urls.split(","):
|
53
|
+
client: ClientInternal = SocketD.create_client(url)
|
54
|
+
|
55
|
+
if self.__listener:
|
56
|
+
client.listen(self.__listener)
|
57
|
+
|
58
|
+
if self.__configHandler:
|
59
|
+
client.config(self.__configHandler)
|
60
|
+
|
61
|
+
if self.__connectHandler:
|
62
|
+
client.connect_handler(self.__connectHandler)
|
63
|
+
|
64
|
+
if self.__heartbeatHandler:
|
65
|
+
client.heartbeat_handler(self.__heartbeatHandler)
|
66
|
+
|
67
|
+
if exchangeExecutor is None:
|
68
|
+
exchangeExecutor = client.get_config().get_exchange_executor()
|
69
|
+
else:
|
70
|
+
client.get_config().exchange_executor(exchangeExecutor)
|
71
|
+
|
72
|
+
sessions.extend(await asyncio.gather(*[client.open_or_throw() if is_throw else client.open()]))
|
73
|
+
return ClusterClientSession(sessions)
|
74
|
+
|
75
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
from socketd.cluster.LoadBalancer import LoadBalancer
|
2
|
+
from socketd.exception.SocketDExecption import SocketDException
|
3
|
+
from socketd.transport.client.ClientSession import ClientSession
|
4
|
+
from socketd.transport.core import Entity
|
5
|
+
from socketd.transport.stream.RequestStream import RequestStream
|
6
|
+
from socketd.transport.stream.SendStream import SendStream
|
7
|
+
from socketd.transport.stream.SubscribeStream import SubscribeStream
|
8
|
+
from socketd.transport.utils.StrUtil import StrUtil
|
9
|
+
|
10
|
+
|
11
|
+
class ClusterClientSession(ClientSession):
|
12
|
+
|
13
|
+
def __init__(self, _sessionSet):
|
14
|
+
self.__sessionSet: list[ClientSession] = _sessionSet
|
15
|
+
self.__sessionId = StrUtil.guid()
|
16
|
+
|
17
|
+
def get_session_all(self) -> list[ClientSession]:
|
18
|
+
return self.__sessionSet
|
19
|
+
|
20
|
+
def get_session_any(self, diversionOrNull: str | None) -> ClientSession:
|
21
|
+
session: ClientSession
|
22
|
+
|
23
|
+
if diversionOrNull:
|
24
|
+
session = LoadBalancer.get_any_by_poll(self.__sessionSet)
|
25
|
+
else:
|
26
|
+
session = LoadBalancer.get_any_by_hash(self.__sessionSet, diversionOrNull)
|
27
|
+
|
28
|
+
if session:
|
29
|
+
return session
|
30
|
+
else:
|
31
|
+
raise SocketDException("No session is available!")
|
32
|
+
|
33
|
+
def is_valid(self) -> bool:
|
34
|
+
for session in self.__sessionSet:
|
35
|
+
if session.is_valid():
|
36
|
+
return True
|
37
|
+
return False
|
38
|
+
|
39
|
+
def is_closing(self) -> bool:
|
40
|
+
for session in self.__sessionSet:
|
41
|
+
if session.is_closing():
|
42
|
+
return True
|
43
|
+
return False
|
44
|
+
|
45
|
+
def session_id(self) -> str:
|
46
|
+
return self.__sessionId
|
47
|
+
|
48
|
+
async def send(self, event: str, content: Entity) -> SendStream:
|
49
|
+
sender = self.get_session_any(None)
|
50
|
+
|
51
|
+
return await sender.send(event, content)
|
52
|
+
|
53
|
+
async def send_and_request(self, event: str, content: Entity, timeout: int) -> RequestStream:
|
54
|
+
sender = self.get_session_any(None)
|
55
|
+
|
56
|
+
return await sender.send_and_request(event, content, timeout)
|
57
|
+
|
58
|
+
async def send_and_subscribe(self, event: str, content: Entity, timeout: int = 0) -> SubscribeStream:
|
59
|
+
sender = self.get_session_any(None)
|
60
|
+
|
61
|
+
return await sender.send_and_subscribe(event, content, timeout)
|
62
|
+
|
63
|
+
async def preclose(self):
|
64
|
+
for session in self.__sessionSet:
|
65
|
+
try:
|
66
|
+
await session.preclose()
|
67
|
+
except RuntimeError as e:
|
68
|
+
pass
|
69
|
+
|
70
|
+
async def close(self):
|
71
|
+
for session in self.__sessionSet:
|
72
|
+
try:
|
73
|
+
await session.close()
|
74
|
+
except RuntimeError as e:
|
75
|
+
pass
|
76
|
+
|
77
|
+
async def reconnect(self):
|
78
|
+
for session in self.__sessionSet:
|
79
|
+
if not session.is_valid():
|
80
|
+
await session.reconnect()
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from threading import RLock
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
from socketd.transport.client.ClientSession import ClientSession
|
5
|
+
from socketd.transport.utils.StrUtil import StrUtil
|
6
|
+
|
7
|
+
|
8
|
+
class LoadBalancer:
|
9
|
+
__roundCounter: int = 0 # 轮环计数器
|
10
|
+
__lock: RLock = RLock() # 计数锁
|
11
|
+
|
12
|
+
@staticmethod
|
13
|
+
def round_counter_get() -> int:
|
14
|
+
LoadBalancer.__lock.acquire()
|
15
|
+
|
16
|
+
try:
|
17
|
+
LoadBalancer.__roundCounter += 1
|
18
|
+
if LoadBalancer.__roundCounter > 999_999:
|
19
|
+
LoadBalancer.__roundCounter = 0
|
20
|
+
return LoadBalancer.__roundCounter
|
21
|
+
finally:
|
22
|
+
LoadBalancer.__lock.release()
|
23
|
+
|
24
|
+
# 根据 poll 获取任意一个
|
25
|
+
@staticmethod
|
26
|
+
def get_any_by_poll(coll: List[ClientSession]) -> ClientSession:
|
27
|
+
return LoadBalancer.get_any(coll, LoadBalancer.round_counter_get())
|
28
|
+
|
29
|
+
# 根据 hash 获取任意一个
|
30
|
+
@staticmethod
|
31
|
+
def get_any_by_hash(coll: List[ClientSession], diversion: str) -> ClientSession:
|
32
|
+
return LoadBalancer.get_any(coll, StrUtil.hash_code(diversion))
|
33
|
+
|
34
|
+
# 获取任意一个
|
35
|
+
@staticmethod
|
36
|
+
def get_any(coll: list[ClientSession], random: int) -> ClientSession | None:
|
37
|
+
if coll is None or coll.__len__() == 0:
|
38
|
+
return None
|
39
|
+
else:
|
40
|
+
sessions: List[ClientSession] = []
|
41
|
+
for s in coll:
|
42
|
+
if s.is_valid() and not s.is_closing():
|
43
|
+
sessions.append(s)
|
44
|
+
|
45
|
+
if sessions.__len__() == 0:
|
46
|
+
return None
|
47
|
+
|
48
|
+
if sessions.__len__() == 1:
|
49
|
+
return sessions[0]
|
50
|
+
|
51
|
+
random = abs(random)
|
52
|
+
idx = random % sessions.__len__()
|
53
|
+
return sessions[idx]
|
54
|
+
|
55
|
+
# 获取第一个
|
56
|
+
@staticmethod
|
57
|
+
def get_first(coll: List[ClientSession]):
|
58
|
+
if coll is None or coll.__len__() == 0:
|
59
|
+
return None
|
60
|
+
else:
|
61
|
+
for s in coll:
|
62
|
+
if s.is_valid() and not s.is_closing():
|
63
|
+
return s
|
64
|
+
|
65
|
+
return None
|
File without changes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class SocketDException(RuntimeError):
|
2
|
+
|
3
|
+
def __init__(self, message):
|
4
|
+
super().__init__(self)
|
5
|
+
self.message = message
|
6
|
+
|
7
|
+
def __str__(self):
|
8
|
+
return self.message
|
9
|
+
|
10
|
+
|
11
|
+
class SocketDAlarmException(SocketDException):
|
12
|
+
""" 告警"""
|
13
|
+
pass
|
14
|
+
|
15
|
+
|
16
|
+
class SocketDChannelException(SocketDException):
|
17
|
+
""" 通道"""
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
class SocketDCodecException(SocketDException):
|
22
|
+
""" 编码"""
|
23
|
+
pass
|
24
|
+
|
25
|
+
|
26
|
+
class SocketDConnectionException(SocketDException):
|
27
|
+
"""连接"""
|
28
|
+
pass
|
29
|
+
|
30
|
+
|
31
|
+
class SocketDSizeLimitException(SocketDException):
|
32
|
+
""" 超长"""
|
33
|
+
pass
|
34
|
+
|
35
|
+
|
36
|
+
class SocketDTimeoutException(SocketDException):
|
37
|
+
""" 超时"""
|
38
|
+
pass
|
File without changes
|
File without changes
|