dimples 0.3.3__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. {dimples-0.3.3 → dimples-0.3.4}/PKG-INFO +1 -1
  2. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/packer.py +44 -3
  3. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/packer.py +6 -42
  4. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/gatekeeper.py +8 -1
  5. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_login.py +1 -1
  6. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/emitter.py +1 -0
  7. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/broadcast.py +25 -4
  8. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/cpu/handshake.py +6 -2
  9. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/cpu/report.py +1 -0
  10. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/dispatcher.py +3 -0
  11. dimples-0.3.4/dimples/server/messenger.py +106 -0
  12. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/packer.py +2 -13
  13. dimples-0.3.4/dimples/server/processor.py +278 -0
  14. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/session.py +4 -5
  15. {dimples-0.3.3 → dimples-0.3.4}/dimples/utils/__init__.py +30 -2
  16. {dimples-0.3.3 → dimples-0.3.4}/dimples.egg-info/PKG-INFO +1 -1
  17. {dimples-0.3.3 → dimples-0.3.4}/setup.py +1 -1
  18. dimples-0.3.3/dimples/server/messenger.py +0 -185
  19. dimples-0.3.3/dimples/server/processor.py +0 -132
  20. {dimples-0.3.3 → dimples-0.3.4}/README.md +0 -0
  21. {dimples-0.3.3 → dimples-0.3.4}/dimples/__init__.py +0 -0
  22. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/__init__.py +0 -0
  23. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/archivist.py +0 -0
  24. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/checkpoint.py +0 -0
  25. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/__init__.py +0 -0
  26. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/commands.py +0 -0
  27. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/creator.py +0 -0
  28. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/group.py +0 -0
  29. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/grp_expel.py +0 -0
  30. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/grp_invite.py +0 -0
  31. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/grp_join.py +0 -0
  32. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/grp_query.py +0 -0
  33. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/grp_quit.py +0 -0
  34. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/grp_reset.py +0 -0
  35. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/grp_resign.py +0 -0
  36. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/cpu/handshake.py +0 -0
  37. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/facebook.py +0 -0
  38. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/messenger.py +0 -0
  39. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/network/__init__.py +0 -0
  40. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/network/session.py +0 -0
  41. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/network/state.py +0 -0
  42. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/network/transition.py +0 -0
  43. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/processor.py +0 -0
  44. {dimples-0.3.3 → dimples-0.3.4}/dimples/client/terminal.py +0 -0
  45. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/__init__.py +0 -0
  46. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/anonymous.py +0 -0
  47. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/ans.py +0 -0
  48. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/archivist.py +0 -0
  49. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/compat/__init__.py +0 -0
  50. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/compat/btc.py +0 -0
  51. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/compat/compatible.py +0 -0
  52. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/compat/entity.py +0 -0
  53. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/compat/meta.py +0 -0
  54. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/compat/network.py +0 -0
  55. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/dbi/__init__.py +0 -0
  56. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/dbi/account.py +0 -0
  57. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/dbi/message.py +0 -0
  58. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/dbi/session.py +0 -0
  59. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/facebook.py +0 -0
  60. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/messenger.py +0 -0
  61. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/protocol/__init__.py +0 -0
  62. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/protocol/ans.py +0 -0
  63. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/protocol/block.py +0 -0
  64. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/protocol/handshake.py +0 -0
  65. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/protocol/login.py +0 -0
  66. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/protocol/mute.py +0 -0
  67. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/protocol/report.py +0 -0
  68. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/register.py +0 -0
  69. {dimples-0.3.3 → dimples-0.3.4}/dimples/common/session.py +0 -0
  70. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/__init__.py +0 -0
  71. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/gate.py +0 -0
  72. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/mars.py +0 -0
  73. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/mtp.py +0 -0
  74. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/protocol/__init__.py +0 -0
  75. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/protocol/mars.py +0 -0
  76. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/protocol/ws.py +0 -0
  77. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/queue.py +0 -0
  78. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/seeker.py +0 -0
  79. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/session.py +0 -0
  80. {dimples-0.3.3 → dimples-0.3.4}/dimples/conn/ws.py +0 -0
  81. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/__init__.py +0 -0
  82. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/account.py +0 -0
  83. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/__init__.py +0 -0
  84. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/base.py +0 -0
  85. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/document.py +0 -0
  86. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/group.py +0 -0
  87. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/group_history.py +0 -0
  88. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/group_keys.py +0 -0
  89. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/login.py +0 -0
  90. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/meta.py +0 -0
  91. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/private.py +0 -0
  92. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/station.py +0 -0
  93. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/dos/user.py +0 -0
  94. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/message.py +0 -0
  95. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/session.py +0 -0
  96. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_cipherkey.py +0 -0
  97. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_document.py +0 -0
  98. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_group.py +0 -0
  99. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_group_history.py +0 -0
  100. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_group_keys.py +0 -0
  101. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_message.py +0 -0
  102. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_meta.py +0 -0
  103. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_private.py +0 -0
  104. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_station.py +0 -0
  105. {dimples-0.3.3 → dimples-0.3.4}/dimples/database/t_user.py +0 -0
  106. {dimples-0.3.3 → dimples-0.3.4}/dimples/edge/__init__.py +0 -0
  107. {dimples-0.3.3 → dimples-0.3.4}/dimples/edge/octopus.py +0 -0
  108. {dimples-0.3.3 → dimples-0.3.4}/dimples/edge/shared.py +0 -0
  109. {dimples-0.3.3 → dimples-0.3.4}/dimples/edge/start.py +0 -0
  110. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/__init__.py +0 -0
  111. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/admin.py +0 -0
  112. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/builder.py +0 -0
  113. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/delegate.py +0 -0
  114. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/helper.py +0 -0
  115. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/manager.py +0 -0
  116. {dimples-0.3.3 → dimples-0.3.4}/dimples/group/packer.py +0 -0
  117. {dimples-0.3.3 → dimples-0.3.4}/dimples/register/__init__.py +0 -0
  118. {dimples-0.3.3 → dimples-0.3.4}/dimples/register/base.py +0 -0
  119. {dimples-0.3.3 → dimples-0.3.4}/dimples/register/ext.py +0 -0
  120. {dimples-0.3.3 → dimples-0.3.4}/dimples/register/run.py +0 -0
  121. {dimples-0.3.3 → dimples-0.3.4}/dimples/register/shared.py +0 -0
  122. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/__init__.py +0 -0
  123. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/archivist.py +0 -0
  124. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/cpu/__init__.py +0 -0
  125. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/cpu/ans.py +0 -0
  126. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/cpu/document.py +0 -0
  127. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/cpu/login.py +0 -0
  128. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/push.py +0 -0
  129. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/session_center.py +0 -0
  130. {dimples-0.3.3 → dimples-0.3.4}/dimples/server/trace.py +0 -0
  131. {dimples-0.3.3 → dimples-0.3.4}/dimples/station/__init__.py +0 -0
  132. {dimples-0.3.3 → dimples-0.3.4}/dimples/station/handler.py +0 -0
  133. {dimples-0.3.3 → dimples-0.3.4}/dimples/station/shared.py +0 -0
  134. {dimples-0.3.3 → dimples-0.3.4}/dimples/station/start.py +0 -0
  135. {dimples-0.3.3 → dimples-0.3.4}/dimples/utils/cache.py +0 -0
  136. {dimples-0.3.3 → dimples-0.3.4}/dimples/utils/config.py +0 -0
  137. {dimples-0.3.3 → dimples-0.3.4}/dimples/utils/dos.py +0 -0
  138. {dimples-0.3.3 → dimples-0.3.4}/dimples/utils/log.py +0 -0
  139. {dimples-0.3.3 → dimples-0.3.4}/dimples/utils/singleton.py +0 -0
  140. {dimples-0.3.3 → dimples-0.3.4}/dimples.egg-info/SOURCES.txt +0 -0
  141. {dimples-0.3.3 → dimples-0.3.4}/dimples.egg-info/dependency_links.txt +0 -0
  142. {dimples-0.3.3 → dimples-0.3.4}/dimples.egg-info/entry_points.txt +0 -0
  143. {dimples-0.3.3 → dimples-0.3.4}/dimples.egg-info/requires.txt +0 -0
  144. {dimples-0.3.3 → dimples-0.3.4}/dimples.egg-info/top_level.txt +0 -0
  145. {dimples-0.3.3 → dimples-0.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimples
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: DIMP Library for Edges and Stations
5
5
  Home-page: https://github.com/dimchat/demo-py
6
6
  Author: Albert Moky
@@ -30,7 +30,7 @@
30
30
  from typing import Optional
31
31
 
32
32
  from dimsdk import ID
33
- from dimsdk import InstantMessage, ReliableMessage
33
+ from dimsdk import InstantMessage, SecureMessage, ReliableMessage
34
34
 
35
35
  from ..utils import get_msg_sig
36
36
  from ..common import CommonMessagePacker
@@ -40,14 +40,14 @@ from .checkpoint import Checkpoint
40
40
  class ClientMessagePacker(CommonMessagePacker):
41
41
 
42
42
  # Override
43
- def _check_instant_message_receiver(self, msg: InstantMessage) -> bool:
43
+ def _check_receiver(self, msg: InstantMessage) -> bool:
44
44
  receiver = msg.receiver
45
45
  if receiver.is_broadcast:
46
46
  # broadcast message
47
47
  return True
48
48
  elif receiver.is_user:
49
49
  # check user's meta & document
50
- return super()._check_instant_message_receiver(msg=msg)
50
+ return super()._check_receiver(msg=msg)
51
51
  #
52
52
  # check group's meta & members
53
53
  #
@@ -85,6 +85,47 @@ class ClientMessagePacker(CommonMessagePacker):
85
85
  # when the member's visa is responded, we should send the suspended message again.
86
86
  return len(waiting) < len(members)
87
87
 
88
+ # protected
89
+ def _check_group(self, msg: ReliableMessage) -> bool:
90
+ receiver = msg.receiver
91
+ # check group
92
+ group = ID.parse(identifier=msg.get('group'))
93
+ if group is None and receiver.is_group:
94
+ # Transform:
95
+ # (B) => (J)
96
+ # (D) => (G)
97
+ group = receiver
98
+ if group is None or group.is_broadcast:
99
+ # A, C - personal message (or hidden group message)
100
+ # the packer will call the facebook to select a user from local
101
+ # for this receiver, if no user matched (private key not found),
102
+ # this message will be ignored;
103
+ # E, F, G - broadcast group message
104
+ # broadcast message is not encrypted, so it can be read by anyone.
105
+ return True
106
+ # H, J, K - group message
107
+ # check for received group message
108
+ members = self._members(group=group)
109
+ if len(members) > 0:
110
+ # group is ready
111
+ return True
112
+ # group not ready, suspend message for waiting members
113
+ error = {
114
+ 'message': 'group not ready',
115
+ 'group': str(receiver),
116
+ }
117
+ self.suspend_reliable_message(msg=msg, error=error) # msg['error'] = error
118
+ return False
119
+
120
+ # Override
121
+ def verify_message(self, msg: ReliableMessage) -> Optional[SecureMessage]:
122
+ # check receiver/group with local user
123
+ if not self._check_group(msg=msg):
124
+ # receiver (group) not ready
125
+ self.warning(msg='receiver not ready: %s' % msg.receiver)
126
+ return None
127
+ return super().verify_message(msg=msg)
128
+
88
129
  # # Override
89
130
  # def serialize_message(self, msg: ReliableMessage) -> bytes:
90
131
  # attach_key_digest(msg=msg, messenger=self.messenger)
@@ -109,7 +109,7 @@ class CommonMessagePacker(MessagePacker, Logging, ABC):
109
109
  return self.facebook.members(identifier=group)
110
110
 
111
111
  # protected
112
- def _check_reliable_message_sender(self, msg: ReliableMessage) -> bool:
112
+ def _check_sender(self, msg: ReliableMessage) -> bool:
113
113
  """ Check sender before verifying received message """
114
114
  sender = msg.sender
115
115
  assert sender.is_user, 'sender error: %s' % sender
@@ -132,39 +132,7 @@ class CommonMessagePacker(MessagePacker, Logging, ABC):
132
132
  return False
133
133
 
134
134
  # protected
135
- def _check_reliable_message_receiver(self, msg: ReliableMessage) -> bool:
136
- receiver = msg.receiver
137
- # check group
138
- group = ID.parse(identifier=msg.get('group'))
139
- if group is None and receiver.is_group:
140
- # Transform:
141
- # (B) => (J)
142
- # (D) => (G)
143
- group = receiver
144
- if group is None or group.is_broadcast:
145
- # A, C - personal message (or hidden group message)
146
- # the packer will call the facebook to select a user from local
147
- # for this receiver, if no user matched (private key not found),
148
- # this message will be ignored;
149
- # E, F, G - broadcast group message
150
- # broadcast message is not encrypted, so it can be read by anyone.
151
- return True
152
- # H, J, K - group message
153
- # check for received group message
154
- members = self._members(group=group)
155
- if len(members) > 0:
156
- # group is ready
157
- return True
158
- # group not ready, suspend message for waiting members
159
- error = {
160
- 'message': 'group not ready',
161
- 'group': str(receiver),
162
- }
163
- self.suspend_reliable_message(msg=msg, error=error) # msg['error'] = error
164
- return False
165
-
166
- # protected
167
- def _check_instant_message_receiver(self, msg: InstantMessage) -> bool:
135
+ def _check_receiver(self, msg: InstantMessage) -> bool:
168
136
  """ Check receiver before encrypting message """
169
137
  receiver = msg.receiver
170
138
  if receiver.is_broadcast:
@@ -196,7 +164,7 @@ class CommonMessagePacker(MessagePacker, Logging, ABC):
196
164
  def encrypt_message(self, msg: InstantMessage) -> Optional[SecureMessage]:
197
165
  # 1. check contact info
198
166
  # 2. check group members info
199
- if not self._check_instant_message_receiver(msg=msg):
167
+ if not self._check_receiver(msg=msg):
200
168
  # receiver not ready
201
169
  self.warning(msg='receiver not ready: %s' % msg.receiver)
202
170
  return None
@@ -221,16 +189,12 @@ class CommonMessagePacker(MessagePacker, Logging, ABC):
221
189
 
222
190
  # Override
223
191
  def verify_message(self, msg: ReliableMessage) -> Optional[SecureMessage]:
224
- # 1. check sender's meta
225
- if not self._check_reliable_message_sender(msg=msg):
192
+ # 1. check receiver/group with local user
193
+ # 2. check sender's meta
194
+ if not self._check_sender(msg=msg):
226
195
  # sender not ready
227
196
  self.warning(msg='sender not ready: %s' % msg.sender)
228
197
  return None
229
- # 2. check receiver/group with local user
230
- if not self._check_reliable_message_receiver(msg=msg):
231
- # receiver (group) not ready
232
- self.warning(msg='receiver not ready: %s' % msg.receiver)
233
- return None
234
198
  return super().verify_message(msg=msg)
235
199
 
236
200
  # Override
@@ -30,6 +30,7 @@
30
30
 
31
31
  import socket
32
32
  import time
33
+ import traceback
33
34
  from typing import Optional, Tuple
34
35
 
35
36
  from dimsdk import ReliableMessage
@@ -44,12 +45,13 @@ from tcp import StreamChannel
44
45
  from tcp import ServerHub, ClientHub
45
46
 
46
47
  from ..utils import get_remote_address, get_local_address
48
+ from ..utils import get_msg_info
47
49
  from ..utils import Runner, Logging
48
50
 
49
51
  from .protocol import DeparturePacker
50
52
 
51
53
  from .gate import CommonGate, TCPServerGate, TCPClientGate
52
- from .queue import MessageQueue
54
+ from .queue import MessageQueue, MessageWrapper
53
55
 
54
56
 
55
57
  class StreamServerHub(ServerHub):
@@ -209,6 +211,7 @@ class GateKeeper(Runner, DockerDelegate, Logging):
209
211
  return True
210
212
  except Exception as e:
211
213
  self.error(msg='process error: %s' % e)
214
+ traceback.print_exc()
212
215
  return False
213
216
  if not self.active:
214
217
  # inactive, wait a while to check again
@@ -264,3 +267,7 @@ class GateKeeper(Runner, DockerDelegate, Logging):
264
267
  # Override
265
268
  def docker_error(self, error: IOError, ship: Departure, docker: Docker):
266
269
  self.error(msg='docker error while sending ship: %s, %s' % (ship, docker))
270
+ if isinstance(ship, MessageWrapper):
271
+ msg = ship.msg
272
+ if msg is not None:
273
+ self.error(msg='error message: %s' % get_msg_info(msg=msg))
@@ -60,7 +60,7 @@ class LoginTable(LoginDBI):
60
60
  old, _ = self.login_command_message(user=user)
61
61
  if old is not None and is_before(old_time=old.time, new_time=new_time):
62
62
  # command expired
63
- return False
63
+ return True
64
64
 
65
65
  #
66
66
  # Login DBI
@@ -155,6 +155,7 @@ class GroupEmitter(Logging):
155
155
  success = self.__split_send_message(msg=msg, members=members, group=group, priority=priority)
156
156
  self.info(msg='split %d message(s) for group: %s' % (success, group))
157
157
  else:
158
+ self.info(msg='splitting message for %d members of group: %s' % (len(members), group))
158
159
  # encrypt and sign this message first,
159
160
  # then split and send to all members one by one
160
161
  return self.__disperse_message(msg=msg, members=members, group=group, priority=priority)
@@ -43,7 +43,7 @@ from ..utils import Singleton, Log, Logging
43
43
  from ..common import StationInfo
44
44
 
45
45
  from .cpu import AnsCommandProcessor
46
- from .trace import TraceManager
46
+ from .trace import TraceNode, TraceList, TraceManager
47
47
  from .dispatcher import Dispatcher
48
48
  from .session_center import SessionCenter
49
49
 
@@ -173,6 +173,9 @@ def broadcast_reliable_message(msg: ReliableMessage, station: ID):
173
173
  # delivering via station bridge, should we mark 'sent_neighbors' in
174
174
  # only one message to the bridge, let the bridge to separate for other
175
175
  # neighbors which not connect to this station directly?
176
+ # set trace nodes
177
+ tm = TraceManager()
178
+ tm.set_nodes(msg=msg, nodes=recipients)
176
179
  # OK
177
180
  Log.info(msg='Broadcast message delivered: %s => %s' % (sender, recipients))
178
181
  return len(recipients)
@@ -186,13 +189,31 @@ def deliver_message(msg: ReliableMessage, receiver: ID, recipients: Set[ID], sta
186
189
  Log.warning(msg='skip sender: %s, %s' % (receiver, recipients))
187
190
  return None
188
191
  assert isinstance(recipients, set), 'recipients error: %s' % recipients
192
+ tm = TraceManager()
193
+ traces = tm.get_traces(msg=msg)
194
+ if traces.search(node=receiver) >= 0:
195
+ Log.warning(msg='skip cycled message: %s, %s' % (msg.sender, receiver))
196
+ return None
189
197
  # clone
190
198
  msg = ReliableMessage.parse(msg=msg.dictionary)
199
+ traces = copy_traces(traces=traces)
200
+ # add these recipients into traces, exclude current receiver
191
201
  recipients = recipients.copy()
192
202
  recipients.discard(receiver) # exclude receiver
193
203
  recipients.add(station) # include current station
194
- # set trace nodes
195
- tm = TraceManager()
196
- tm.set_nodes(msg=msg, nodes=recipients)
204
+ for mta in recipients:
205
+ node = TraceNode.create(identifier=mta)
206
+ traces.insert(node=node)
207
+ msg['traces'] = TraceNode.revert(nodes=traces.nodes)
197
208
  # deliver message with traces
198
209
  return dispatcher.deliver_message(msg=msg, receiver=receiver)
210
+
211
+
212
+ def copy_traces(traces: TraceList) -> TraceList:
213
+ when = traces.time
214
+ if when is None:
215
+ when = DateTime.now()
216
+ else:
217
+ when = DateTime.parse(value=when)
218
+ nodes = traces.nodes
219
+ return TraceList(msg_time=when, traces=nodes.copy())
@@ -67,11 +67,15 @@ class HandshakeCommandProcessor(BaseCommandProcessor):
67
67
  # set/update session in session server with new session key
68
68
  messenger = self.messenger
69
69
  session = messenger.session
70
+ sess_id = session.identifier
71
+ sender = r_msg.sender
72
+ if sess_id is not None:
73
+ assert sess_id == sender, 'sender error: %s, %s' % (sender, sess_id)
70
74
  if session.key == content.session:
71
75
  # session key match
72
- Log.info(msg='handshake accepted: %s, session: %s' % (r_msg.sender, session.key))
76
+ Log.info(msg='handshake accepted: %s, session: %s' % (sender, session.key))
73
77
  # verified success
74
- handshake_accepted(identifier=r_msg.sender, session=session, messenger=messenger)
78
+ handshake_accepted(identifier=sender, session=session, messenger=messenger)
75
79
  res = HandshakeCommand.success(session=session.key)
76
80
  else:
77
81
  # session key not match
@@ -59,6 +59,7 @@ class ReportCommandProcessor(BaseCommandProcessor, Logging):
59
59
  if session.identifier is None:
60
60
  self.error(msg='session not login, drop report command: %s => %s' % (sender, content))
61
61
  return []
62
+ # FIXME: send via bridge?
62
63
  assert sender == session.identifier, 'report sender error: %s not %s' % (sender, session.identifier)
63
64
  # check report title
64
65
  title = content.title
@@ -185,6 +185,9 @@ class Dispatcher(MessageDeliver):
185
185
  if receiver.type == EntityType.STATION or msg.sender.type == EntityType.STATION:
186
186
  # no need to save station message
187
187
  return False
188
+ elif msg.receiver.is_broadcast:
189
+ # no need to save broadcast message
190
+ return False
188
191
  db = self.__mdb
189
192
  return db.cache_reliable_message(msg=msg, receiver=receiver)
190
193
 
@@ -0,0 +1,106 @@
1
+ # -*- coding: utf-8 -*-
2
+ # ==============================================================================
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2019 Albert Moky
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+ # ==============================================================================
25
+
26
+ """
27
+ Messenger for request handler in station
28
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29
+
30
+ Transform and send message
31
+ """
32
+
33
+ from typing import List
34
+
35
+ from dimsdk import ID
36
+ from dimsdk import Station
37
+ from dimsdk import ReliableMessage
38
+ from dimsdk import MessageHelper
39
+
40
+ from ..common import CommonMessenger, CommonMessagePacker
41
+
42
+ from .dispatcher import Dispatcher
43
+
44
+
45
+ class ServerMessenger(CommonMessenger):
46
+
47
+ # Override
48
+ def handshake_success(self):
49
+ session = self.session
50
+ identifier = session.identifier
51
+ remote_address = session.remote_address
52
+ self.warning(msg='user login: %s, socket: %s' % (identifier, remote_address))
53
+ # process suspended messages
54
+ self._resume_reliable_messages()
55
+
56
+ def _resume_reliable_messages(self):
57
+ packer = self.packer
58
+ assert isinstance(packer, CommonMessagePacker), 'message packer error: %s' % packer
59
+ messages = packer.resume_reliable_messages()
60
+ for msg in messages:
61
+ self.info(msg='processing suspended message: %s -> %s' % (msg.sender, msg.receiver))
62
+ try:
63
+ responses = self.process_reliable_message(msg=msg)
64
+ for res in responses:
65
+ self.send_reliable_message(msg=res, priority=1)
66
+ except Exception as error:
67
+ self.error(msg='failed to process incoming message: %s' % error)
68
+
69
+ # Override
70
+ def process_reliable_message(self, msg: ReliableMessage) -> List[ReliableMessage]:
71
+ session = self.session
72
+ current = self.facebook.current_user
73
+ sid = current.identifier
74
+ receiver = msg.receiver
75
+ # call super
76
+ responses = super().process_reliable_message(msg=msg)
77
+ # check for first handshake
78
+ if receiver == Station.ANY or msg.group == Station.EVERY:
79
+ # if this message sent to 'station@anywhere', or with group ID 'stations@everywhere',
80
+ # it means the client doesn't have the station's meta (e.g.: first handshaking)
81
+ # or visa maybe expired, here attach them to the first response.
82
+ for res in responses:
83
+ if res.sender == sid:
84
+ # let the first responding message to carry the station's meta & visa
85
+ MessageHelper.set_meta(meta=current.meta, msg=res)
86
+ MessageHelper.set_visa(visa=current.visa, msg=res)
87
+ break
88
+ elif session.identifier == sid:
89
+ # station bridge
90
+ responses = pick_out(messages=responses, bridge=sid)
91
+ return responses
92
+
93
+
94
+ def pick_out(messages: List[ReliableMessage], bridge: ID) -> List[ReliableMessage]:
95
+ responses = []
96
+ dispatcher = Dispatcher()
97
+ for msg in messages:
98
+ receiver = msg.receiver
99
+ if receiver == bridge:
100
+ # respond to the bridge
101
+ responses.append(msg)
102
+ else:
103
+ # this message is not respond to the bridge, the receiver may be
104
+ # roaming to other station, so deliver it via dispatcher here.
105
+ dispatcher.deliver_message(msg=msg, receiver=receiver)
106
+ return responses
@@ -85,15 +85,13 @@ class ServerMessagePacker(CommonMessagePacker):
85
85
  # cycled message
86
86
  if sender.type == EntityType.STATION or receiver.type == EntityType.STATION:
87
87
  # ignore cycled station message
88
+ self.warning(msg='cycled station message: %s -> %s' % (sender, receiver))
88
89
  return None
89
90
  elif receiver.is_broadcast:
90
91
  # ignore cycled broadcast message
92
+ self.warning(msg='cycled broadcast message: %s -> %s' % (sender, receiver))
91
93
  return None
92
94
  self.warning(msg='cycled message: %s -> %s' % (sender, receiver))
93
- if not self.__check_reliable_message_receiver(msg=msg):
94
- # receiver (group) not ready
95
- self.warning(msg='receiver not ready: %s' % msg.receiver)
96
- return None
97
95
  # check session
98
96
  if self.__is_trusted(sender=msg.sender):
99
97
  # no need to verify message from this sender
@@ -102,15 +100,6 @@ class ServerMessagePacker(CommonMessagePacker):
102
100
  # verify after sender is OK
103
101
  return super().verify_message(msg=msg)
104
102
 
105
- # Override
106
- def _check_reliable_message_receiver(self, msg: ReliableMessage) -> bool:
107
- # skip for "super().verify_message(msg=msg)"
108
- return True
109
-
110
- def __check_reliable_message_receiver(self, msg: ReliableMessage) -> bool:
111
- # check for group
112
- return super()._check_reliable_message_receiver(msg=msg)
113
-
114
103
 
115
104
  def get_facebook(packer: CommonMessagePacker) -> CommonFacebook:
116
105
  barrack = packer.facebook