dimples 0.5.1__tar.gz → 0.5.3__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.1 → dimples-0.5.3}/PKG-INFO +1 -1
  2. {dimples-0.5.1 → dimples-0.5.3}/dimples/__init__.py +2 -1
  3. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/messenger.py +15 -2
  4. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/processor.py +18 -12
  5. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/__init__.py +2 -0
  6. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/messenger.py +38 -7
  7. dimples-0.5.3/dimples/common/processer.py +70 -0
  8. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/emitter.py +10 -4
  9. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/cpu/handshake.py +5 -4
  10. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/cpu/login.py +1 -1
  11. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/packer.py +21 -15
  12. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/processor.py +2 -7
  13. {dimples-0.5.1 → dimples-0.5.3}/dimples.egg-info/PKG-INFO +1 -1
  14. {dimples-0.5.1 → dimples-0.5.3}/dimples.egg-info/SOURCES.txt +1 -0
  15. {dimples-0.5.1 → dimples-0.5.3}/setup.py +1 -1
  16. {dimples-0.5.1 → dimples-0.5.3}/README.md +0 -0
  17. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/__init__.py +0 -0
  18. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/archivist.py +0 -0
  19. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/checkpoint.py +0 -0
  20. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/__init__.py +0 -0
  21. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/commands.py +0 -0
  22. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/creator.py +0 -0
  23. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/group.py +0 -0
  24. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/grp_expel.py +0 -0
  25. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/grp_invite.py +0 -0
  26. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/grp_join.py +0 -0
  27. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/grp_query.py +0 -0
  28. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/grp_quit.py +0 -0
  29. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/grp_reset.py +0 -0
  30. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/grp_resign.py +0 -0
  31. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/cpu/handshake.py +0 -0
  32. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/facebook.py +0 -0
  33. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/network/__init__.py +0 -0
  34. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/network/session.py +0 -0
  35. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/network/state.py +0 -0
  36. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/network/transition.py +0 -0
  37. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/packer.py +0 -0
  38. {dimples-0.5.1 → dimples-0.5.3}/dimples/client/terminal.py +0 -0
  39. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/anonymous.py +0 -0
  40. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/ans.py +0 -0
  41. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/archivist.py +0 -0
  42. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/compat/__init__.py +0 -0
  43. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/compat/btc.py +0 -0
  44. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/compat/compatible.py +0 -0
  45. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/compat/entity.py +0 -0
  46. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/compat/meta.py +0 -0
  47. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/compat/network.py +0 -0
  48. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/dbi/__init__.py +0 -0
  49. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/dbi/account.py +0 -0
  50. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/dbi/message.py +0 -0
  51. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/dbi/session.py +0 -0
  52. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/facebook.py +0 -0
  53. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/packer.py +0 -0
  54. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/protocol/__init__.py +0 -0
  55. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/protocol/ans.py +0 -0
  56. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/protocol/block.py +0 -0
  57. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/protocol/handshake.py +0 -0
  58. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/protocol/login.py +0 -0
  59. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/protocol/mute.py +0 -0
  60. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/protocol/report.py +0 -0
  61. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/register.py +0 -0
  62. {dimples-0.5.1 → dimples-0.5.3}/dimples/common/session.py +0 -0
  63. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/__init__.py +0 -0
  64. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/gate.py +0 -0
  65. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/gatekeeper.py +0 -0
  66. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/mars.py +0 -0
  67. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/mtp.py +0 -0
  68. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/protocol/__init__.py +0 -0
  69. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/protocol/mars.py +0 -0
  70. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/protocol/ws.py +0 -0
  71. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/queue.py +0 -0
  72. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/seeker.py +0 -0
  73. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/session.py +0 -0
  74. {dimples-0.5.1 → dimples-0.5.3}/dimples/conn/ws.py +0 -0
  75. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/__init__.py +0 -0
  76. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/account.py +0 -0
  77. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/__init__.py +0 -0
  78. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/base.py +0 -0
  79. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/document.py +0 -0
  80. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/group.py +0 -0
  81. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/group_history.py +0 -0
  82. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/group_keys.py +0 -0
  83. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/login.py +0 -0
  84. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/meta.py +0 -0
  85. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/private.py +0 -0
  86. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/station.py +0 -0
  87. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/dos/user.py +0 -0
  88. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/message.py +0 -0
  89. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/session.py +0 -0
  90. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_cipherkey.py +0 -0
  91. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_document.py +0 -0
  92. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_group.py +0 -0
  93. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_group_history.py +0 -0
  94. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_group_keys.py +0 -0
  95. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_login.py +0 -0
  96. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_message.py +0 -0
  97. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_meta.py +0 -0
  98. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_private.py +0 -0
  99. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_station.py +0 -0
  100. {dimples-0.5.1 → dimples-0.5.3}/dimples/database/t_user.py +0 -0
  101. {dimples-0.5.1 → dimples-0.5.3}/dimples/edge/__init__.py +0 -0
  102. {dimples-0.5.1 → dimples-0.5.3}/dimples/edge/octopus.py +0 -0
  103. {dimples-0.5.1 → dimples-0.5.3}/dimples/edge/shared.py +0 -0
  104. {dimples-0.5.1 → dimples-0.5.3}/dimples/edge/start.py +0 -0
  105. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/__init__.py +0 -0
  106. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/admin.py +0 -0
  107. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/builder.py +0 -0
  108. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/delegate.py +0 -0
  109. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/helper.py +0 -0
  110. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/manager.py +0 -0
  111. {dimples-0.5.1 → dimples-0.5.3}/dimples/group/packer.py +0 -0
  112. {dimples-0.5.1 → dimples-0.5.3}/dimples/register/__init__.py +0 -0
  113. {dimples-0.5.1 → dimples-0.5.3}/dimples/register/base.py +0 -0
  114. {dimples-0.5.1 → dimples-0.5.3}/dimples/register/ext.py +0 -0
  115. {dimples-0.5.1 → dimples-0.5.3}/dimples/register/run.py +0 -0
  116. {dimples-0.5.1 → dimples-0.5.3}/dimples/register/shared.py +0 -0
  117. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/__init__.py +0 -0
  118. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/archivist.py +0 -0
  119. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/cpu/__init__.py +0 -0
  120. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/cpu/ans.py +0 -0
  121. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/cpu/document.py +0 -0
  122. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/cpu/report.py +0 -0
  123. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/dispatcher.py +0 -0
  124. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/messenger.py +0 -0
  125. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/push.py +0 -0
  126. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/session.py +0 -0
  127. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/session_center.py +0 -0
  128. {dimples-0.5.1 → dimples-0.5.3}/dimples/server/trace.py +0 -0
  129. {dimples-0.5.1 → dimples-0.5.3}/dimples/station/__init__.py +0 -0
  130. {dimples-0.5.1 → dimples-0.5.3}/dimples/station/handler.py +0 -0
  131. {dimples-0.5.1 → dimples-0.5.3}/dimples/station/shared.py +0 -0
  132. {dimples-0.5.1 → dimples-0.5.3}/dimples/station/start.py +0 -0
  133. {dimples-0.5.1 → dimples-0.5.3}/dimples/utils/__init__.py +0 -0
  134. {dimples-0.5.1 → dimples-0.5.3}/dimples/utils/cache.py +0 -0
  135. {dimples-0.5.1 → dimples-0.5.3}/dimples/utils/config.py +0 -0
  136. {dimples-0.5.1 → dimples-0.5.3}/dimples/utils/dos.py +0 -0
  137. {dimples-0.5.1 → dimples-0.5.3}/dimples/utils/log.py +0 -0
  138. {dimples-0.5.1 → dimples-0.5.3}/dimples/utils/singleton.py +0 -0
  139. {dimples-0.5.1 → dimples-0.5.3}/dimples.egg-info/dependency_links.txt +0 -0
  140. {dimples-0.5.1 → dimples-0.5.3}/dimples.egg-info/entry_points.txt +0 -0
  141. {dimples-0.5.1 → dimples-0.5.3}/dimples.egg-info/requires.txt +0 -0
  142. {dimples-0.5.1 → dimples-0.5.3}/dimples.egg-info/top_level.txt +0 -0
  143. {dimples-0.5.1 → dimples-0.5.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimples
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Summary: DIMP Library for Edges and Stations
5
5
  Home-page: https://github.com/dimchat/demo-py
6
6
  Author: Albert Moky
@@ -333,7 +333,8 @@ __all__ = [
333
333
  'AddressNameServer', 'ANSFactory',
334
334
  'CommonArchivist',
335
335
  'CommonFacebook', 'CommonMessenger',
336
- 'CommonMessagePacker', 'Transmitter',
336
+ 'CommonMessagePacker', 'CommonMessageProcessor',
337
+ 'Transmitter',
337
338
  'Session',
338
339
 
339
340
  ####################################
@@ -62,14 +62,27 @@ class ClientMessenger(CommonMessenger):
62
62
  facebook = self.facebook
63
63
  user = facebook.current_user
64
64
  assert user is not None, 'current user not found'
65
+ meta = user.meta
66
+ visa = user.visa
67
+ if visa is None:
68
+ self.warning(msg='user visa not found: %s' % user)
69
+ else:
70
+ device = {
71
+ 'os': 'Linux',
72
+ }
73
+ visa.set_property(key='sys', value=device)
74
+ # sign to update
75
+ pri_key = facebook.private_key_for_visa_signature(identifier=user.identifier)
76
+ assert pri_key is not None, 'failed to get private key for visa: %s' % visa
77
+ visa.sign(private_key=pri_key)
65
78
  env = Envelope.create(sender=user.identifier, receiver=srv_id)
66
79
  cmd = HandshakeCommand.start()
67
80
  # send first handshake command as broadcast message
68
81
  cmd.group = Station.EVERY
69
82
  # create instant message with meta & visa
70
83
  i_msg = InstantMessage.create(head=env, body=cmd)
71
- i_msg.set_map(key='meta', value=user.meta)
72
- i_msg.set_map(key='visa', value=user.visa)
84
+ i_msg.set_map(key='meta', value=meta)
85
+ i_msg.set_map(key='visa', value=visa)
73
86
  self.send_instant_message(msg=i_msg, priority=-1)
74
87
  else:
75
88
  # handshake again
@@ -37,18 +37,17 @@ from dimsdk import ReliableMessage
37
37
  from dimsdk import Content, TextContent
38
38
  from dimsdk import ReceiptCommand
39
39
  from dimsdk import ContentProcessorCreator
40
- from dimsdk import MessageProcessor
41
40
 
42
- from ..utils import Logging
43
41
  from ..common import HandshakeCommand
44
42
  from ..common import CommonMessenger
43
+ from ..common import CommonMessageProcessor
45
44
 
46
45
  from .cpu import ClientContentProcessorCreator
47
46
 
48
47
  from .archivist import ClientArchivist
49
48
 
50
49
 
51
- class ClientMessageProcessor(MessageProcessor, Logging):
50
+ class ClientMessageProcessor(CommonMessageProcessor):
52
51
 
53
52
  @property
54
53
  def messenger(self) -> CommonMessenger:
@@ -56,10 +55,11 @@ class ClientMessageProcessor(MessageProcessor, Logging):
56
55
  assert isinstance(transceiver, CommonMessenger), 'messenger error: %s' % transceiver
57
56
  return transceiver
58
57
 
59
- def __check_group_times(self, content: Content, r_msg: ReliableMessage):
58
+ # private
59
+ def _check_group_times(self, content: Content, r_msg: ReliableMessage) -> bool:
60
60
  group = content.group
61
61
  if group is None:
62
- return
62
+ return False
63
63
  facebook = self.facebook
64
64
  archivist = facebook.archivist
65
65
  assert isinstance(archivist, ClientArchivist), 'client archivist error: %s' % archivist
@@ -70,27 +70,33 @@ class ClientMessageProcessor(MessageProcessor, Logging):
70
70
  last_doc_time = r_msg.get_datetime(key='GDT', default=None)
71
71
  if last_doc_time is not None:
72
72
  if last_doc_time.after(now):
73
+ # calibrate the clock
73
74
  last_doc_time = now
74
75
  doc_updated = archivist.set_last_document_time(identifier=group, last_time=last_doc_time)
76
+ # check whether needs update
77
+ if doc_updated:
78
+ self.info(msg='checking for new bulletin: %s' % group)
79
+ facebook.documents(identifier=group)
75
80
  # check group history time
76
81
  last_his_time = r_msg.get_datetime(key='GHT', default=None)
77
82
  if last_his_time is not None:
78
83
  if last_his_time.after(now):
84
+ # calibrate the clock
79
85
  last_his_time = now
80
86
  mem_updated = archivist.set_last_group_history_time(group=group, last_time=last_his_time)
81
- # check whether needs update
82
- if doc_updated:
83
- facebook.documents(identifier=group)
84
- if mem_updated:
85
- archivist.set_last_active_member(member=r_msg.sender, group=group)
86
- facebook.members(identifier=group)
87
+ # check whether needs update
88
+ if mem_updated:
89
+ archivist.set_last_active_member(member=r_msg.sender, group=group)
90
+ self.info(msg='checking for group members: %s' % group)
91
+ facebook.members(identifier=group)
92
+ return doc_updated or mem_updated
87
93
 
88
94
  # Override
89
95
  def process_content(self, content: Content, r_msg: ReliableMessage) -> List[Content]:
90
96
  responses = super().process_content(content=content, r_msg=r_msg)
91
97
  # check group document & history times from the message
92
98
  # to make sure the group info synchronized
93
- self.__check_group_times(content=content, r_msg=r_msg)
99
+ self._check_group_times(content=content, r_msg=r_msg)
94
100
  # check responses
95
101
  if len(responses) == 0:
96
102
  # respond nothing
@@ -40,6 +40,7 @@ from .archivist import CommonArchivist
40
40
  from .facebook import CommonFacebook
41
41
  from .messenger import CommonMessenger
42
42
  from .packer import CommonMessagePacker
43
+ from .processer import CommonMessageProcessor
43
44
  from .session import Transmitter, Session
44
45
 
45
46
  from .compat import register_compatible_factories
@@ -87,6 +88,7 @@ __all__ = [
87
88
  'CommonFacebook',
88
89
  'CommonMessenger',
89
90
  'CommonMessagePacker',
91
+ 'CommonMessageProcessor',
90
92
  'Transmitter',
91
93
  'Session',
92
94
 
@@ -41,7 +41,7 @@ from typing import Optional, Union, Tuple
41
41
  from dimsdk import SymmetricKey
42
42
  from dimsdk import ID
43
43
  from dimsdk import Content, Envelope
44
- from dimsdk import Command
44
+ from dimsdk import Command, DocumentCommand
45
45
  from dimsdk import InstantMessage, SecureMessage, ReliableMessage
46
46
  from dimsdk import EntityDelegate, CipherKeyDelegate
47
47
  from dimsdk import Messenger, Packer, Processor
@@ -168,26 +168,57 @@ class CommonMessenger(Messenger, Transmitter, Logging, ABC):
168
168
  r_msg = self.send_instant_message(msg=i_msg, priority=priority)
169
169
  return i_msg, r_msg
170
170
 
171
+ # private
172
+ def _attach_visa_time(self, sender: ID, msg: InstantMessage) -> bool:
173
+ if isinstance(msg.content, DocumentCommand):
174
+ # no need to attach times for command
175
+ return True
176
+ doc = self.facebook.visa(identifier=sender)
177
+ if doc is None:
178
+ self.error(msg='failed to get visa document for sender: %s' % sender)
179
+ return False
180
+ # attach sender document time
181
+ last_doc_time = doc.time
182
+ if last_doc_time is None:
183
+ self.error(msg='document error: %s' % doc)
184
+ return False
185
+ else:
186
+ msg.set_datetime(key='SDT', value=last_doc_time)
187
+ return True
188
+
171
189
  # Override
172
190
  def send_instant_message(self, msg: InstantMessage, priority: int = 0) -> Optional[ReliableMessage]:
173
191
  """ send instant message with priority """
192
+ sender = msg.sender
174
193
  # 0. check cycled message
175
- if msg.sender == msg.receiver:
176
- self.warning(msg='drop cycled message: %s => %s, %s' % (msg.sender, msg.receiver, msg.group))
194
+ if sender == msg.receiver:
195
+ self.warning(msg='drop cycled message: %s => %s, %s' % (sender, msg.receiver, msg.group))
196
+ # return None
177
197
  else:
178
198
  self.debug(msg='send instant message message (type=%d): %s => %s, %s'
179
- % (msg.content.type, msg.sender, msg.receiver, msg.group))
180
- # 1. encrypt message
199
+ % (msg.content.type, sender, msg.receiver, msg.group))
200
+ # attach sender's document times
201
+ # for the receiver to check whether user info synchronized
202
+ ok = self._attach_visa_time(sender=sender, msg=msg)
203
+ if not ok:
204
+ self.warning(msg='failed to attach document time: %s => %s' % (sender, msg.content))
205
+ #
206
+ # 1. encrypt message
207
+ #
181
208
  s_msg = self.encrypt_message(msg=msg)
182
209
  if s_msg is None:
183
210
  # public key not found?
184
211
  return None
185
- # 2. sign message
212
+ #
213
+ # 2. sign message
214
+ #
186
215
  r_msg = self.sign_message(msg=s_msg)
187
216
  if r_msg is None:
188
217
  # TODO: set msg.state = error
189
218
  raise AssertionError('failed to sign message: %s' % s_msg)
190
- # 3. send message
219
+ #
220
+ # 3. send message
221
+ #
191
222
  if self.send_reliable_message(msg=r_msg, priority=priority):
192
223
  return r_msg
193
224
  # failed
@@ -0,0 +1,70 @@
1
+ # -*- coding: utf-8 -*-
2
+ # ==============================================================================
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2023 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
+ from abc import ABC
27
+ from typing import List
28
+
29
+ from dimsdk import DateTime
30
+ from dimsdk import Content
31
+ from dimsdk import ReliableMessage
32
+ from dimsdk import MessageProcessor
33
+
34
+ from ..utils import Logging
35
+
36
+ from .archivist import CommonArchivist
37
+
38
+
39
+ # noinspection PyAbstractClass
40
+ class CommonMessageProcessor(MessageProcessor, Logging, ABC):
41
+
42
+ # private
43
+ # noinspection PyUnusedLocal
44
+ def _check_visa_time(self, content: Content, r_msg: ReliableMessage) -> bool:
45
+ facebook = self.facebook
46
+ archivist = facebook.archivist
47
+ assert isinstance(archivist, CommonArchivist), 'archivist error: %s' % archivist
48
+ doc_updated = False
49
+ # check sender document time
50
+ last_doc_time = r_msg.get_datetime(key='SDT', default=None)
51
+ if last_doc_time is not None:
52
+ now = DateTime.now()
53
+ if last_doc_time.after(now):
54
+ # calibrate the clock
55
+ last_doc_time = now
56
+ sender = r_msg.sender
57
+ doc_updated = archivist.set_last_document_time(identifier=sender, last_time=last_doc_time)
58
+ # check whether needs update
59
+ if doc_updated:
60
+ self.info(msg='checking for new visa: %s' % sender)
61
+ facebook.documents(identifier=sender)
62
+ return doc_updated
63
+
64
+ # Override
65
+ def process_content(self, content: Content, r_msg: ReliableMessage) -> List[Content]:
66
+ responses = super().process_content(content=content, r_msg=r_msg)
67
+ # check sender's document times from the message
68
+ # to make sure the user info synchronized
69
+ self._check_visa_time(content=content, r_msg=r_msg)
70
+ return responses
@@ -93,19 +93,21 @@ class GroupEmitter(Logging):
93
93
  def messenger(self) -> CommonMessenger:
94
94
  return self.delegate.messenger
95
95
 
96
- def __attach_group_times(self, group: ID, msg: InstantMessage):
96
+ # private
97
+ def _attach_group_times(self, group: ID, msg: InstantMessage) -> bool:
97
98
  if isinstance(msg.content, GroupCommand):
98
99
  # no need to attach times for group command
99
- return
100
+ return True
100
101
  facebook = self.facebook
101
102
  doc = facebook.bulletin(identifier=group)
102
103
  if doc is None:
103
104
  self.error(msg='failed to get bulletin document for group: %s' % group)
104
- return
105
+ return False
105
106
  # attach group document time
106
107
  last_doc_time = doc.time
107
108
  if last_doc_time is None:
108
109
  self.error(msg='document error: %s' % doc)
110
+ return False
109
111
  else:
110
112
  msg.set_datetime(key='GDT', value=last_doc_time)
111
113
  # attach group history time
@@ -113,8 +115,10 @@ class GroupEmitter(Logging):
113
115
  last_his_time = archivist.get_last_group_history_time(group=group)
114
116
  if last_his_time is None:
115
117
  self.error(msg='failed to get history time: %s' % group)
118
+ return False
116
119
  else:
117
120
  msg.set_datetime(key='GHT', value=last_his_time)
121
+ return True
118
122
 
119
123
  def send_message(self, msg: InstantMessage, priority: int = 0) -> Optional[ReliableMessage]:
120
124
  content = msg.content
@@ -125,7 +129,9 @@ class GroupEmitter(Logging):
125
129
  assert msg.receiver == group, 'group message error: %s' % msg
126
130
  # attach group document & history times
127
131
  # for the receiver to check whether group info synchronized
128
- self.__attach_group_times(group=group, msg=msg)
132
+ ok = self._attach_group_times(group=group, msg=msg)
133
+ if not ok:
134
+ self.warning(msg='failed to attach group times: %s => %s' % (group, content))
129
135
  # TODO: if it's a file message
130
136
  # please upload the file data first
131
137
  # before calling this
@@ -30,8 +30,9 @@
30
30
  Handshake Protocol
31
31
  """
32
32
 
33
- from typing import List
33
+ from typing import Optional, List
34
34
 
35
+ from dimsdk import DateTime
35
36
  from dimsdk import ID, Content, ReliableMessage
36
37
 
37
38
  from dimsdk.cpu import BaseCommandProcessor
@@ -75,7 +76,7 @@ class HandshakeCommandProcessor(BaseCommandProcessor):
75
76
  # session key match
76
77
  Log.info(msg='handshake accepted: %s, session: %s' % (sender, session.key))
77
78
  # verified success
78
- handshake_accepted(identifier=sender, session=session, messenger=messenger)
79
+ handshake_accepted(identifier=sender, when=content.time, session=session, messenger=messenger)
79
80
  res = HandshakeCommand.success(session=session.key)
80
81
  else:
81
82
  # session key not match
@@ -85,12 +86,12 @@ class HandshakeCommandProcessor(BaseCommandProcessor):
85
86
  return [res]
86
87
 
87
88
 
88
- def handshake_accepted(identifier: ID, session: Session, messenger: CommonMessenger):
89
+ def handshake_accepted(identifier: ID, when: Optional[DateTime], session: Session, messenger: CommonMessenger):
89
90
  from ..session_center import SessionCenter
90
91
  center = SessionCenter()
91
92
  # 1. update session ID
92
93
  center.update_session(session=session, identifier=identifier)
93
94
  # 2. update session flag
94
- session.set_active(active=True)
95
+ session.set_active(active=True, when=when)
95
96
  # 3. callback
96
97
  messenger.handshake_success()
@@ -85,7 +85,7 @@ class LoginCommandProcessor(BaseCommandProcessor, Logging):
85
85
  self.info(msg='user login: %s -> %s, forwarded by %s' % (sender, roaming, session.identifier))
86
86
  return []
87
87
  # 3. update session flag
88
- session.set_active(active=True)
88
+ session.set_active(active=True, when=content.time)
89
89
  # only respond the user login to this station
90
90
  self.info(msg='user login: %s -> %s' % (sender, roaming))
91
91
  text = 'Login received.'
@@ -76,23 +76,29 @@ class ServerMessagePacker(CommonMessagePacker):
76
76
  # TODO: trusted station list
77
77
  return True
78
78
 
79
+ # Override
80
+ def deserialize_message(self, data: bytes) -> Optional[ReliableMessage]:
81
+ msg = super().deserialize_message(data=data)
82
+ if msg is not None:
83
+ sender = msg.sender
84
+ receiver = msg.receiver
85
+ # check duplicated
86
+ if self.__is_traced(msg=msg):
87
+ # cycled message
88
+ if sender.type == EntityType.STATION or receiver.type == EntityType.STATION:
89
+ # ignore cycled station message
90
+ self.warning(msg='drop cycled station message: %s -> %s' % (sender, receiver))
91
+ return None
92
+ elif receiver.is_broadcast:
93
+ # ignore cycled broadcast message
94
+ self.warning(msg='drop cycled broadcast message: %s -> %s' % (sender, receiver))
95
+ return None
96
+ self.warning(msg='cycled message: %s -> %s' % (sender, receiver))
97
+ return msg
98
+
79
99
  # Override
80
100
  def verify_message(self, msg: ReliableMessage) -> Optional[SecureMessage]:
81
- sender = msg.sender
82
- receiver = msg.receiver
83
- # check duplicated
84
- if self.__is_traced(msg=msg):
85
- # cycled message
86
- if sender.type == EntityType.STATION or receiver.type == EntityType.STATION:
87
- # ignore cycled station message
88
- self.warning(msg='cycled station message: %s -> %s' % (sender, receiver))
89
- return None
90
- elif receiver.is_broadcast:
91
- # ignore cycled broadcast message
92
- self.warning(msg='cycled broadcast message: %s -> %s' % (sender, receiver))
93
- return None
94
- self.warning(msg='cycled message: %s -> %s' % (sender, receiver))
95
- # check session
101
+ # check session ready
96
102
  if self.__is_trusted(sender=msg.sender):
97
103
  # no need to verify message from this sender
98
104
  self.debug(msg='trusted sender: %s' % msg.sender)
@@ -38,16 +38,14 @@ from dimsdk import Envelope
38
38
  from dimsdk import Content, ContentType, Command
39
39
  from dimsdk import TextContent, ReceiptCommand
40
40
  from dimsdk import ContentProcessor, ContentProcessorCreator
41
- from dimsdk import MessageProcessor
42
41
 
43
42
  from dimsdk.cpu import BaseContentProcessor, BaseContentProcessorCreator
44
43
 
45
- from ..utils import get_msg_info
46
- from ..utils import Logging
47
44
  from ..common import HandshakeCommand, LoginCommand
48
45
  from ..common import ReportCommand, AnsCommand
49
46
  from ..common import CommonFacebook, CommonMessenger
50
47
  from ..common import CommonMessagePacker
48
+ from ..common import CommonMessageProcessor
51
49
 
52
50
  from .cpu import HandshakeCommandProcessor
53
51
  from .cpu import LoginCommandProcessor
@@ -61,7 +59,7 @@ from .dispatcher import Dispatcher
61
59
  from .archivist import ServerArchivist
62
60
 
63
61
 
64
- class ServerMessageProcessor(MessageProcessor, Logging):
62
+ class ServerMessageProcessor(CommonMessageProcessor):
65
63
 
66
64
  @property
67
65
  def messenger(self) -> CommonMessenger:
@@ -166,9 +164,6 @@ class ServerMessageProcessor(MessageProcessor, Logging):
166
164
  # TODO: override to deliver to the receiver when catch exception "receiver error ..."
167
165
 
168
166
  def _force_handshake(self, msg: ReliableMessage) -> List[ReliableMessage]:
169
- if self.messenger.verify_message(msg=msg) is None:
170
- assert False, 'failed to verify message: %s' % get_msg_info(msg=msg)
171
- # return []
172
167
  session = self.messenger.session
173
168
  sess_id = session.identifier
174
169
  current = self.facebook.current_user
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimples
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Summary: DIMP Library for Edges and Stations
5
5
  Home-page: https://github.com/dimchat/demo-py
6
6
  Author: Albert Moky
@@ -38,6 +38,7 @@ dimples/common/archivist.py
38
38
  dimples/common/facebook.py
39
39
  dimples/common/messenger.py
40
40
  dimples/common/packer.py
41
+ dimples/common/processer.py
41
42
  dimples/common/register.py
42
43
  dimples/common/session.py
43
44
  dimples/common/compat/__init__.py
@@ -14,7 +14,7 @@ import io
14
14
 
15
15
  from setuptools import setup, find_packages
16
16
 
17
- __version__ = '0.5.1'
17
+ __version__ = '0.5.3'
18
18
  __author__ = 'Albert Moky'
19
19
  __contact__ = 'albert.moky@gmail.com'
20
20
 
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
File without changes
File without changes
File without changes
File without changes