dimples 0.5.3__tar.gz → 0.5.6__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 (143) hide show
  1. {dimples-0.5.3 → dimples-0.5.6}/PKG-INFO +1 -1
  2. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/session.py +2 -2
  3. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/state.py +4 -0
  4. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/terminal.py +8 -4
  5. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/session.py +4 -0
  6. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/session.py +2 -0
  7. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/protocol/mars.py +4 -0
  8. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/session.py +10 -0
  9. {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/octopus.py +3 -3
  10. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/archivist.py +7 -3
  11. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/dispatcher.py +96 -18
  12. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/processor.py +9 -41
  13. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/push.py +4 -5
  14. {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/__init__.py +2 -2
  15. {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/cache.py +4 -3
  16. {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/config.py +2 -0
  17. {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/PKG-INFO +1 -1
  18. {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/requires.txt +3 -3
  19. {dimples-0.5.3 → dimples-0.5.6}/setup.py +4 -4
  20. {dimples-0.5.3 → dimples-0.5.6}/README.md +0 -0
  21. {dimples-0.5.3 → dimples-0.5.6}/dimples/__init__.py +0 -0
  22. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/__init__.py +0 -0
  23. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/archivist.py +0 -0
  24. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/checkpoint.py +0 -0
  25. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/__init__.py +0 -0
  26. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/commands.py +0 -0
  27. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/creator.py +0 -0
  28. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/group.py +0 -0
  29. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_expel.py +0 -0
  30. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_invite.py +0 -0
  31. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_join.py +0 -0
  32. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_query.py +0 -0
  33. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_quit.py +0 -0
  34. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_reset.py +0 -0
  35. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_resign.py +0 -0
  36. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/handshake.py +0 -0
  37. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/facebook.py +0 -0
  38. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/messenger.py +0 -0
  39. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/__init__.py +0 -0
  40. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/transition.py +0 -0
  41. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/packer.py +0 -0
  42. {dimples-0.5.3 → dimples-0.5.6}/dimples/client/processor.py +0 -0
  43. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/__init__.py +0 -0
  44. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/anonymous.py +0 -0
  45. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/ans.py +0 -0
  46. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/archivist.py +0 -0
  47. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/__init__.py +0 -0
  48. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/btc.py +0 -0
  49. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/compatible.py +0 -0
  50. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/entity.py +0 -0
  51. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/meta.py +0 -0
  52. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/network.py +0 -0
  53. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/__init__.py +0 -0
  54. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/account.py +0 -0
  55. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/message.py +0 -0
  56. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/facebook.py +0 -0
  57. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/messenger.py +0 -0
  58. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/packer.py +0 -0
  59. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/processer.py +0 -0
  60. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/__init__.py +0 -0
  61. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/ans.py +0 -0
  62. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/block.py +0 -0
  63. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/handshake.py +0 -0
  64. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/login.py +0 -0
  65. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/mute.py +0 -0
  66. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/report.py +0 -0
  67. {dimples-0.5.3 → dimples-0.5.6}/dimples/common/register.py +0 -0
  68. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/__init__.py +0 -0
  69. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/gate.py +0 -0
  70. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/gatekeeper.py +0 -0
  71. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/mars.py +0 -0
  72. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/mtp.py +0 -0
  73. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/protocol/__init__.py +0 -0
  74. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/protocol/ws.py +0 -0
  75. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/queue.py +0 -0
  76. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/seeker.py +0 -0
  77. {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/ws.py +0 -0
  78. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/__init__.py +0 -0
  79. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/account.py +0 -0
  80. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/__init__.py +0 -0
  81. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/base.py +0 -0
  82. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/document.py +0 -0
  83. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/group.py +0 -0
  84. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/group_history.py +0 -0
  85. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/group_keys.py +0 -0
  86. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/login.py +0 -0
  87. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/meta.py +0 -0
  88. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/private.py +0 -0
  89. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/station.py +0 -0
  90. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/user.py +0 -0
  91. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/message.py +0 -0
  92. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/session.py +0 -0
  93. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_cipherkey.py +0 -0
  94. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_document.py +0 -0
  95. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_group.py +0 -0
  96. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_group_history.py +0 -0
  97. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_group_keys.py +0 -0
  98. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_login.py +0 -0
  99. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_message.py +0 -0
  100. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_meta.py +0 -0
  101. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_private.py +0 -0
  102. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_station.py +0 -0
  103. {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_user.py +0 -0
  104. {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/__init__.py +0 -0
  105. {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/shared.py +0 -0
  106. {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/start.py +0 -0
  107. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/__init__.py +0 -0
  108. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/admin.py +0 -0
  109. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/builder.py +0 -0
  110. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/delegate.py +0 -0
  111. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/emitter.py +0 -0
  112. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/helper.py +0 -0
  113. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/manager.py +0 -0
  114. {dimples-0.5.3 → dimples-0.5.6}/dimples/group/packer.py +0 -0
  115. {dimples-0.5.3 → dimples-0.5.6}/dimples/register/__init__.py +0 -0
  116. {dimples-0.5.3 → dimples-0.5.6}/dimples/register/base.py +0 -0
  117. {dimples-0.5.3 → dimples-0.5.6}/dimples/register/ext.py +0 -0
  118. {dimples-0.5.3 → dimples-0.5.6}/dimples/register/run.py +0 -0
  119. {dimples-0.5.3 → dimples-0.5.6}/dimples/register/shared.py +0 -0
  120. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/__init__.py +0 -0
  121. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/__init__.py +0 -0
  122. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/ans.py +0 -0
  123. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/document.py +0 -0
  124. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/handshake.py +0 -0
  125. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/login.py +0 -0
  126. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/report.py +0 -0
  127. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/messenger.py +0 -0
  128. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/packer.py +0 -0
  129. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/session.py +0 -0
  130. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/session_center.py +0 -0
  131. {dimples-0.5.3 → dimples-0.5.6}/dimples/server/trace.py +0 -0
  132. {dimples-0.5.3 → dimples-0.5.6}/dimples/station/__init__.py +0 -0
  133. {dimples-0.5.3 → dimples-0.5.6}/dimples/station/handler.py +0 -0
  134. {dimples-0.5.3 → dimples-0.5.6}/dimples/station/shared.py +0 -0
  135. {dimples-0.5.3 → dimples-0.5.6}/dimples/station/start.py +0 -0
  136. {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/dos.py +0 -0
  137. {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/log.py +0 -0
  138. {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/singleton.py +0 -0
  139. {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/SOURCES.txt +0 -0
  140. {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/dependency_links.txt +0 -0
  141. {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/entry_points.txt +0 -0
  142. {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/top_level.txt +0 -0
  143. {dimples-0.5.3 → dimples-0.5.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimples
3
- Version: 0.5.3
3
+ Version: 0.5.6
4
4
  Summary: DIMP Library for Edges and Stations
5
5
  Home-page: https://github.com/dimchat/demo-py
6
6
  Author: Albert Moky
@@ -40,11 +40,11 @@ from typing import Optional, List
40
40
 
41
41
  from dimsdk import Station
42
42
 
43
- from startrek.fsm import Daemon
44
43
  from startrek.fsm import Delegate as StateDelegate
45
44
  from startrek import Docker, DockerStatus
46
45
  from startrek import Arrival
47
46
 
47
+ from ...utils import Daemon
48
48
  from ...common import SessionDBI
49
49
  from ...conn import BaseSession
50
50
  from ...conn import MTPStreamArrival
@@ -84,7 +84,7 @@ class ClientSession(BaseSession):
84
84
  # state machine
85
85
  self.__fsm = StateMachine(session=self)
86
86
  # background thread to drive gate & hub processing
87
- self.__daemon = Daemon(target=self.run)
87
+ self.__daemon = Daemon(target=self)
88
88
 
89
89
  @property
90
90
  def station(self) -> Station:
@@ -136,12 +136,15 @@ class SessionState(BaseState[StateMachine, StateTransition]):
136
136
  def enter_time(self) -> float:
137
137
  return self.__time
138
138
 
139
+ # Override
139
140
  def __str__(self) -> str:
140
141
  return self.__name
141
142
 
143
+ # Override
142
144
  def __repr__(self) -> str:
143
145
  return self.__name
144
146
 
147
+ # Override
145
148
  def __eq__(self, other) -> bool:
146
149
  if isinstance(other, SessionState):
147
150
  if self is other:
@@ -156,6 +159,7 @@ class SessionState(BaseState[StateMachine, StateTransition]):
156
159
  else:
157
160
  return False
158
161
 
162
+ # Override
159
163
  def __ne__(self, other) -> bool:
160
164
  if isinstance(other, SessionState):
161
165
  if self is other:
@@ -30,12 +30,11 @@
30
30
  Client
31
31
  """
32
32
 
33
- import threading
34
33
  import time
35
34
 
36
35
  from dimples import EntityType
37
36
 
38
- from ..utils import Runner, Logging
37
+ from ..utils import Runner, Daemon, Logging
39
38
  from ..utils import StateDelegate
40
39
 
41
40
  from .network import ClientSession
@@ -59,6 +58,7 @@ class Terminal(Runner, DeviceMixin, Logging, StateDelegate):
59
58
  self.__messenger = messenger
60
59
  # default online time
61
60
  self.__last_time = time.time()
61
+ self.__daemon = Daemon(target=self)
62
62
 
63
63
  @property
64
64
  def messenger(self) -> ClientMessenger:
@@ -74,8 +74,12 @@ class Terminal(Runner, DeviceMixin, Logging, StateDelegate):
74
74
  return self.session.running
75
75
 
76
76
  def start(self):
77
- thread = threading.Thread(target=self.run, daemon=True)
78
- thread.start()
77
+ self.__daemon.start()
78
+
79
+ # Override
80
+ def stop(self):
81
+ self.__daemon.stop()
82
+ super().stop()
79
83
 
80
84
  # Override
81
85
  def setup(self):
@@ -63,10 +63,12 @@ class ProviderInfo:
63
63
  self.identifier = identifier
64
64
  self.chosen = chosen
65
65
 
66
+ # Override
66
67
  def __str__(self) -> str:
67
68
  clazz = self.__class__.__name__
68
69
  return '<%s ID="%s" chosen=%d />' % (clazz, self.identifier, self.chosen)
69
70
 
71
+ # Override
70
72
  def __repr__(self) -> str:
71
73
  clazz = self.__class__.__name__
72
74
  return '<%s ID="%s" chosen=%d />' % (clazz, self.identifier, self.chosen)
@@ -94,11 +96,13 @@ class StationInfo:
94
96
  self.provider = provider
95
97
  self.chosen = chosen
96
98
 
99
+ # Override
97
100
  def __str__(self) -> str:
98
101
  clazz = self.__class__.__name__
99
102
  return '<%s host="%s" port=%d ID="%s" SP="%s" chosen=%d />' % (clazz, self.host, self.port, self.identifier,
100
103
  self.provider, self.chosen)
101
104
 
105
+ # Override
102
106
  def __repr__(self) -> str:
103
107
  clazz = self.__class__.__name__
104
108
  return '<%s host="%s" port=%d ID="%s" SP="%s" chosen=%d />' % (clazz, self.host, self.port, self.identifier,
@@ -114,10 +114,12 @@ class Session(Transmitter, ABC):
114
114
  """ Update active flag and return True on changed """
115
115
  raise NotImplemented
116
116
 
117
+ # Override
117
118
  def __str__(self) -> str:
118
119
  clazz = self.__class__.__name__
119
120
  return '<%s:%s %s|%s active=%s />' % (clazz, self.key, self.remote_address, self.identifier, self.active)
120
121
 
122
+ # Override
121
123
  def __repr__(self) -> str:
122
124
  clazz = self.__class__.__name__
123
125
  return '<%s:%s %s|%s active=%s />' % (clazz, self.key, self.remote_address, self.identifier, self.active)
@@ -94,10 +94,12 @@ class NetMsgHead:
94
94
  self.__options = options
95
95
  self.__body_length = body_len
96
96
 
97
+ # Override
97
98
  def __str__(self) -> str:
98
99
  cname = self.__class__.__name__
99
100
  return '<%s: %d| cmd=%d, seq=%d, body_len=%d />' % (cname, self.version, self.cmd, self.seq, self.body_length)
100
101
 
102
+ # Override
101
103
  def __repr__(self) -> str:
102
104
  cname = self.__class__.__name__
103
105
  return '<%s: %d| cmd=%d, seq=%d, body_len=%d />' % (cname, self.version, self.cmd, self.seq, self.body_length)
@@ -198,11 +200,13 @@ class NetMsg:
198
200
  self.__head = head
199
201
  self.__body = body
200
202
 
203
+ # Override
201
204
  def __str__(self) -> str:
202
205
  mod = self.__module__
203
206
  cname = self.__class__.__name__
204
207
  return '<%s body_len=%d>%s</%s module="%s">' % (cname, self.body_length, self.head, cname, mod)
205
208
 
209
+ # Override
206
210
  def __repr__(self) -> str:
207
211
  mod = self.__module__
208
212
  cname = self.__class__.__name__
@@ -50,6 +50,16 @@ class BaseSession(GateKeeper, Session, ABC):
50
50
  self.__identifier: Optional[ID] = None
51
51
  self.__messenger: Optional[weakref.ReferenceType] = None
52
52
 
53
+ # Override
54
+ def __str__(self) -> str:
55
+ cname = self.__class__.__name__
56
+ return '<%s id="%s" remote="%s" key="%s" />' % (cname, self.identifier, self.remote_address, self.key)
57
+
58
+ # Override
59
+ def __repr__(self):
60
+ cname = self.__class__.__name__
61
+ return '<%s id="%s" remote="%s" key="%s" />' % (cname, self.identifier, self.remote_address, self.key)
62
+
53
63
  @property # Override
54
64
  def database(self) -> SessionDBI:
55
65
  return self.__database
@@ -41,7 +41,7 @@ from dimsdk import ReliableMessage
41
41
  from dimsdk import Station
42
42
 
43
43
  from ..utils import Log, Logging
44
- from ..utils import Runner
44
+ from ..utils import Runner, Daemon
45
45
  from ..utils import get_msg_sig
46
46
  from ..common import ProviderInfo
47
47
  from ..common import MessageDBI, SessionDBI
@@ -67,6 +67,7 @@ class Octopus(Runner, Logging):
67
67
  self.__outers: Set[Terminal] = set()
68
68
  self.__outer_map = weakref.WeakValueDictionary()
69
69
  self.__outer_lock = threading.Lock()
70
+ self.__daemon = Daemon(target=self, daemonic=False)
70
71
 
71
72
  @property
72
73
  def shared(self) -> GlobalVariable:
@@ -129,8 +130,7 @@ class Octopus(Runner, Logging):
129
130
  return terminal
130
131
 
131
132
  def start(self):
132
- thread = threading.Thread(target=self.run)
133
- thread.start()
133
+ self.__daemon.start()
134
134
 
135
135
  # Override
136
136
  def stop(self):
@@ -44,7 +44,6 @@ from ..common import CommonArchivist
44
44
  from ..common import CommonFacebook, CommonMessenger
45
45
  from ..common import StationInfo
46
46
 
47
- from .dispatcher import Dispatcher
48
47
  from .session_center import SessionCenter
49
48
 
50
49
 
@@ -62,6 +61,11 @@ def get_messenger(archivist: CommonArchivist):
62
61
  return messenger
63
62
 
64
63
 
64
+ def get_dispatcher():
65
+ from .dispatcher import Dispatcher
66
+ return Dispatcher()
67
+
68
+
65
69
  class ServerArchivist(CommonArchivist, ABC):
66
70
 
67
71
  # each respond will be expired after 10 minutes
@@ -95,7 +99,7 @@ class ServerArchivist(CommonArchivist, ABC):
95
99
  @property
96
100
  def all_stations(self) -> List[StationInfo]:
97
101
  """ get stations from database """
98
- dispatcher = Dispatcher()
102
+ dispatcher = get_dispatcher()
99
103
  db = dispatcher.sdb
100
104
  # TODO: get chosen provider
101
105
  providers = db.all_providers()
@@ -136,7 +140,7 @@ class ServerArchivist(CommonArchivist, ABC):
136
140
  s_msg = messenger.encrypt_message(msg=i_msg)
137
141
  r_msg = messenger.sign_message(msg=s_msg)
138
142
  # dispatch
139
- dispatcher = Dispatcher()
143
+ dispatcher = get_dispatcher()
140
144
  neighbors = self.all_neighbors
141
145
  # avoid the new recipients redirect it to same targets
142
146
  r_msg['recipients'] = ID.revert(neighbors)
@@ -32,15 +32,14 @@
32
32
 
33
33
  import threading
34
34
  from abc import ABC, abstractmethod
35
- from typing import Optional, List
35
+ from typing import Optional, Set, List
36
36
 
37
- from startrek.fsm import Daemon
38
-
39
- from dimsdk import EntityType, ID
37
+ from dimsdk import EntityType, ID, EVERYONE
38
+ from dimsdk import Station
40
39
  from dimsdk import Content, ReceiptCommand
41
40
  from dimsdk import ReliableMessage
42
41
 
43
- from ..utils import Singleton, Logging, Runner
42
+ from ..utils import Singleton, Log, Logging, Runner, Daemon
44
43
  from ..common import CommonFacebook
45
44
  from ..common import MessageDBI, SessionDBI
46
45
  from ..common import ReliableMessageDBI
@@ -48,6 +47,7 @@ from ..common import LoginCommand
48
47
 
49
48
  from .session_center import SessionCenter
50
49
  from .push import PushCenter
50
+ from .archivist import ServerArchivist
51
51
 
52
52
 
53
53
  class MessageDeliver(ABC):
@@ -66,7 +66,7 @@ class MessageDeliver(ABC):
66
66
 
67
67
 
68
68
  @Singleton
69
- class Dispatcher(MessageDeliver):
69
+ class Dispatcher(MessageDeliver, Logging):
70
70
 
71
71
  def __init__(self):
72
72
  super().__init__()
@@ -149,7 +149,11 @@ class Dispatcher(MessageDeliver):
149
149
  def deliver_message(self, msg: ReliableMessage, receiver: ID) -> List[Content]:
150
150
  """ Deliver message to destination """
151
151
  worker = self.deliver_worker
152
- if receiver.type == EntityType.STATION:
152
+ if receiver.is_group:
153
+ # broadcast message to neighbor stations
154
+ # e.g.: 'stations@everywhere', 'everyone@everywhere'
155
+ return self.__deliver_group_message(msg=msg, receiver=receiver)
156
+ elif receiver.type == EntityType.STATION:
153
157
  # message to other stations
154
158
  # station won't roam to other station, so just push for it directly
155
159
  responses = worker.redirect_message(msg=msg, neighbor=receiver)
@@ -183,6 +187,70 @@ class Dispatcher(MessageDeliver):
183
187
  # message delivered
184
188
  return responses
185
189
 
190
+ def __deliver_group_message(self, msg: ReliableMessage, receiver: ID) -> List[Content]:
191
+ if receiver == Station.EVERY or receiver == EVERYONE:
192
+ # broadcast message to neighbor stations
193
+ # e.g.: 'stations@everywhere', 'everyone@everywhere'
194
+ archivist = self.facebook.archivist
195
+ assert isinstance(archivist, ServerArchivist)
196
+ candidates = archivist.all_neighbors
197
+ if len(candidates) == 0:
198
+ self.warning(msg='failed to get neighbors: %s' % receiver)
199
+ return []
200
+ self.info(msg='forward to neighbor stations: %s -> %s' % (receiver, candidates))
201
+ return self.__broadcast_message(msg=msg, receiver=receiver, neighbors=candidates)
202
+ else:
203
+ self.warning(msg='unknown group: %s' % receiver)
204
+ text = 'Group message not allow for this station'
205
+ res = ReceiptCommand.create(text=text, envelope=msg.envelope)
206
+ return [res]
207
+
208
+ def __broadcast_message(self, msg: ReliableMessage, receiver: ID, neighbors: Set[ID]) -> List[Content]:
209
+ #
210
+ # 0. check recipients
211
+ #
212
+ new_recipients = neighbors.copy()
213
+ old_recipients = msg.get('recipients')
214
+ if old_recipients is None:
215
+ all_recipients = []
216
+ else:
217
+ all_recipients = ID.convert(old_recipients)
218
+ # check duplicated
219
+ self.info(msg='discard recipients: %s, new recipients: %s' % (old_recipients, new_recipients))
220
+ for item in all_recipients:
221
+ new_recipients.discard(item)
222
+ if len(new_recipients) == 0:
223
+ self.info(msg='new recipients empty: %s => %s' % (receiver, neighbors))
224
+ return []
225
+ self.info(msg='append new recipients: %s, %s => %s' % (receiver, new_recipients, all_recipients))
226
+ for item in new_recipients:
227
+ all_recipients.append(item)
228
+ # avoid the new recipients redirect it to same targets
229
+ msg['recipients'] = ID.revert(all_recipients)
230
+ #
231
+ # 1. push to neighbor stations directly
232
+ #
233
+ indirect_neighbors = set()
234
+ for target in new_recipients:
235
+ if session_push(msg=msg, receiver=target) == 0:
236
+ indirect_neighbors.add(target)
237
+ if len(indirect_neighbors) > 0:
238
+ for item in indirect_neighbors:
239
+ all_recipients.remove(item)
240
+ msg['recipients'] = ID.revert(all_recipients)
241
+ #
242
+ # 2. push to other neighbor stations via station bridge
243
+ #
244
+ worker = self.deliver_worker
245
+ worker.redirect_message(msg=msg, neighbor=None)
246
+ #
247
+ # OK
248
+ #
249
+ text = 'Message forwarded.'
250
+ cmd = ReceiptCommand.create(text=text, envelope=msg.envelope)
251
+ cmd['recipients'] = ID.revert(new_recipients)
252
+ return [cmd]
253
+
186
254
  def __save_reliable_message(self, msg: ReliableMessage, receiver: ID) -> bool:
187
255
  if receiver.type == EntityType.STATION or msg.sender.type == EntityType.STATION:
188
256
  # no need to save station message
@@ -211,7 +279,7 @@ class Roamer(Runner, Logging):
211
279
  # roaming (user id => station id)
212
280
  self.__queue: List[RoamingInfo] = []
213
281
  self.__lock = threading.Lock()
214
- self.__daemon = Daemon(target=self.run)
282
+ self.__daemon = Daemon(target=self)
215
283
 
216
284
  @property
217
285
  def database(self) -> Optional[MessageDBI]:
@@ -307,7 +375,7 @@ class DeliverWorker(Logging):
307
375
  # 3. redirect message to roaming station
308
376
  return self.redirect_message(msg=msg, neighbor=roaming)
309
377
 
310
- def redirect_message(self, msg: ReliableMessage, neighbor: ID) -> Optional[List[Content]]:
378
+ def redirect_message(self, msg: ReliableMessage, neighbor: Optional[ID]) -> Optional[List[Content]]:
311
379
  """
312
380
  Redirect message to neighbor station
313
381
 
@@ -327,7 +395,7 @@ class DeliverWorker(Logging):
327
395
  # return None to tell the push center to push notification for it.
328
396
  return None
329
397
  # 1. try to push message to neighbor station directly
330
- if session_push(msg=msg, receiver=neighbor) > 0:
398
+ if neighbor is not None and session_push(msg=msg, receiver=neighbor) > 0:
331
399
  text = 'Message redirected.'
332
400
  cmd = ReceiptCommand.create(text=text, envelope=msg.envelope)
333
401
  cmd['neighbor'] = str(neighbor)
@@ -336,9 +404,10 @@ class DeliverWorker(Logging):
336
404
  return bridge_message(msg=msg, neighbor=neighbor, bridge=current)
337
405
 
338
406
 
339
- def bridge_message(msg: ReliableMessage, neighbor: ID, bridge: ID) -> Optional[List[Content]]:
407
+ def bridge_message(msg: ReliableMessage, neighbor: Optional[ID], bridge: ID) -> List[Content]:
340
408
  """
341
409
  Redirect message to neighbor station via the station bridge
410
+ if neighbor is None, try to broadcast
342
411
 
343
412
  :param msg: network message
344
413
  :param neighbor: roaming station
@@ -350,16 +419,25 @@ def bridge_message(msg: ReliableMessage, neighbor: ID, bridge: ID) -> Optional[L
350
419
  # be changed to another value before pushing to the bridge.
351
420
  # clone = msg.copy_dictionary()
352
421
  # msg = ReliableMessage.parse(msg=clone)
353
- msg['neighbor'] = str(neighbor)
354
- if session_push(msg=msg, receiver=bridge) > 0:
355
- text = 'Message redirected.'
356
- cmd = ReceiptCommand.create(text=text, envelope=msg.envelope)
357
- cmd['neighbor'] = str(neighbor)
358
- return [cmd]
422
+ if neighbor is None:
423
+ # broadcast to all neighbor stations
424
+ # except that ones already in msg['recipients']
425
+ session_push(msg=msg, receiver=bridge)
426
+ # no need to respond receipt for this broadcast message
427
+ return []
359
428
  else:
429
+ assert neighbor != bridge, 'cannot bridge cycled message: %s' % neighbor
430
+ msg['neighbor'] = str(neighbor)
431
+ # push to the bridge
432
+ if session_push(msg=msg, receiver=bridge) == 0:
360
433
  # station bridge not found
361
- # return an empty array to avoid calling push center
434
+ Log.warning(msg='failed to push message to bridge: %s, drop message: %s -> %s'
435
+ % (bridge, msg.sender, msg.receiver))
362
436
  return []
437
+ text = 'Message redirected via station bridge.'
438
+ cmd = ReceiptCommand.create(text=text, envelope=msg.envelope)
439
+ cmd['neighbor'] = str(neighbor)
440
+ return [cmd]
363
441
 
364
442
 
365
443
  def session_push(msg: ReliableMessage, receiver: ID) -> int:
@@ -56,7 +56,6 @@ from .cpu import DocumentCommandProcessor
56
56
 
57
57
  from .packer import FilterManager
58
58
  from .dispatcher import Dispatcher
59
- from .archivist import ServerArchivist
60
59
 
61
60
 
62
61
  class ServerMessageProcessor(CommonMessageProcessor):
@@ -195,49 +194,18 @@ class ServerMessageProcessor(CommonMessageProcessor):
195
194
  if bot is None:
196
195
  self.warning(msg='failed to get receiver: %s' % receiver)
197
196
  return False
198
- candidates = set()
199
- candidates.add(bot)
200
- self.info(msg='forward to station bot: %s -> %s' % (name, bot))
201
- elif receiver == Station.EVERY or receiver == EVERYONE:
202
- # broadcast message to neighbor stations
203
- # e.g.: 'stations@everywhere', 'everyone@everywhere'
204
- archivist = self.facebook.archivist
205
- assert isinstance(archivist, ServerArchivist)
206
- candidates = archivist.all_neighbors
207
- if len(candidates) == 0:
208
- self.warning(msg='failed to get neighbors: %s' % receiver)
197
+ elif bot == sender:
198
+ self.warning(msg='skip cycled message: %s -> %s' % (sender, receiver))
209
199
  return False
210
- self.info(msg='forward to neighbor stations: %s -> %s' % (receiver, candidates))
211
- else:
212
- self.warning(msg='unknown receiver: %s' % receiver)
213
- return False
214
- # check recipients
215
- new_recipients = candidates.copy()
216
- old_recipients = msg.get('recipients')
217
- if old_recipients is None:
218
- all_recipients = []
219
- else:
220
- all_recipients = ID.convert(old_recipients)
221
- # check duplicated
222
- self.info(msg='discard recipients: %s, new recipients: %s' % (old_recipients, new_recipients))
223
- for item in all_recipients:
224
- new_recipients.discard(item)
225
- if len(new_recipients) == 0:
226
- self.info(msg='new recipients empty: %s => %s' % (receiver, candidates))
200
+ elif bot == station:
201
+ self.warning(msg='skip current station: %s -> %s' % (sender, receiver))
227
202
  return False
228
- self.info(msg='append new recipients: %s, %s => %s' % (receiver, new_recipients, all_recipients))
229
- for item in new_recipients:
230
- all_recipients.append(item)
231
- # avoid the new recipients redirect it to same targets
232
- msg['recipients'] = ID.revert(all_recipients)
233
- # dispatch
234
- dispatcher = Dispatcher()
235
- for target in new_recipients:
236
- if target == sender or target == station:
237
- self.info(msg='skip cycled message: %s -> %s, %s' % (sender, receiver, target))
238
203
  else:
239
- dispatcher.deliver_message(msg=msg, receiver=target)
240
- return True
204
+ self.info(msg='forward to bot: %s -> %s' % (name, bot))
205
+ receiver = bot
206
+ # deliver by dispatcher
207
+ dispatcher = Dispatcher()
208
+ dispatcher.deliver_message(msg=msg, receiver=receiver)
241
209
 
242
210
  def _split_group_message(self, msg: ReliableMessage, station: ID):
243
211
  """ redirect group message to assistant """
@@ -36,10 +36,10 @@ import time
36
36
  from abc import ABC, abstractmethod
37
37
  from typing import Optional, List, Dict
38
38
 
39
- from startrek.fsm import Daemon
40
39
  from dimsdk import ID, ReliableMessage
41
40
 
42
- from ..utils import Singleton, Logging, Runner
41
+ from ..utils import Runner, Daemon
42
+ from ..utils import Singleton, Logging
43
43
 
44
44
 
45
45
  class MessageQueue(Logging):
@@ -125,9 +125,8 @@ class PushCenter(Runner, Logging):
125
125
  self.__keeper = BadgeKeeper()
126
126
  self.__service: Optional[PushService] = None
127
127
  # background thread
128
- daemon = Daemon(target=self.run)
129
- daemon.start()
130
- self.__daemon = daemon
128
+ self.__daemon = Daemon(target=self)
129
+ self.__daemon.start()
131
130
 
132
131
  @property
133
132
  def service(self) -> Optional[PushService]:
@@ -50,7 +50,7 @@ from dimsdk import DocumentHelper
50
50
 
51
51
  from dimplugins.crypto.aes import random_bytes
52
52
 
53
- from startrek.fsm import Runnable, Runner
53
+ from startrek.fsm import Runnable, Runner, Daemon
54
54
  from startrek.fsm import Delegate as StateDelegate
55
55
  from startrek.net.channel import get_remote_address, get_local_address
56
56
 
@@ -122,7 +122,7 @@ __all__ = [
122
122
 
123
123
  'Converter',
124
124
 
125
- 'Runnable', 'Runner',
125
+ 'Runnable', 'Runner', 'Daemon',
126
126
  'StateDelegate',
127
127
 
128
128
  'get_remote_address', 'get_local_address',
@@ -32,7 +32,7 @@
32
32
  import time
33
33
  from typing import TypeVar, Generic, Optional, Dict, Set, Tuple
34
34
 
35
- from startrek.fsm import Daemon
35
+ from startrek.fsm import Daemon, Runnable
36
36
  from dimsdk import DateTime
37
37
 
38
38
  from .singleton import Singleton
@@ -135,12 +135,12 @@ class CachePool(Generic[K, V]):
135
135
 
136
136
 
137
137
  @Singleton
138
- class CacheManager:
138
+ class CacheManager(Runnable):
139
139
 
140
140
  def __init__(self):
141
141
  self.__pools: Dict[str, CachePool] = {} # name -> pool
142
142
  # thread for cleaning caches
143
- self.__daemon = Daemon(target=self.run)
143
+ self.__daemon = Daemon(target=self)
144
144
  self.__running = False
145
145
 
146
146
  @property
@@ -154,6 +154,7 @@ class CacheManager:
154
154
  def stop(self):
155
155
  self.__daemon.stop()
156
156
 
157
+ # Override
157
158
  def run(self):
158
159
  next_time = 0
159
160
  while self.running:
@@ -42,10 +42,12 @@ class Node(Dictionary):
42
42
  if port > 0:
43
43
  self['port'] = port
44
44
 
45
+ # Override
45
46
  def __str__(self) -> str:
46
47
  clazz = self.__class__.__name__
47
48
  return '<%s host="%s" port=%d name="%s" />' % (clazz, self.host, self.port, self.name)
48
49
 
50
+ # Override
49
51
  def __repr__(self) -> str:
50
52
  clazz = self.__class__.__name__
51
53
  return '<%s host="%s" port=%d name="%s" />' % (clazz, self.host, self.port, self.name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimples
3
- Version: 0.5.3
3
+ Version: 0.5.6
4
4
  Summary: DIMP Library for Edges and Stations
5
5
  Home-page: https://github.com/dimchat/demo-py
6
6
  Author: Albert Moky
@@ -3,6 +3,6 @@ dimsdk>=1.0.3
3
3
  dimp>=1.0.3
4
4
  dkd>=1.0.2
5
5
  mkm>=1.0.2
6
- startrek>=1.1.2
7
- tcp>=1.1.2
8
- udp>=1.1.2
6
+ startrek>=1.2.0
7
+ tcp>=1.2.0
8
+ udp>=1.2.0
@@ -14,7 +14,7 @@ import io
14
14
 
15
15
  from setuptools import setup, find_packages
16
16
 
17
- __version__ = '0.5.3'
17
+ __version__ = '0.5.6'
18
18
  __author__ = 'Albert Moky'
19
19
  __contact__ = 'albert.moky@gmail.com'
20
20
 
@@ -58,8 +58,8 @@ setup(
58
58
  'dkd>=1.0.2',
59
59
  'mkm>=1.0.2',
60
60
 
61
- 'startrek>=1.1.2',
62
- 'tcp>=1.1.2',
63
- 'udp>=1.1.2',
61
+ 'startrek>=1.2.0',
62
+ 'tcp>=1.2.0',
63
+ 'udp>=1.2.0',
64
64
  ]
65
65
  )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes