dimples 0.4.0__tar.gz → 0.4.1__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.
- {dimples-0.4.0 → dimples-0.4.1}/PKG-INFO +1 -1
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/terminal.py +5 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/protocol/ws.py +1 -1
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/__init__.py +0 -4
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/archivist.py +73 -11
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/processor.py +44 -13
- {dimples-0.4.0 → dimples-0.4.1}/dimples/station/shared.py +0 -9
- {dimples-0.4.0 → dimples-0.4.1}/dimples.egg-info/PKG-INFO +1 -1
- {dimples-0.4.0 → dimples-0.4.1}/dimples.egg-info/SOURCES.txt +0 -1
- {dimples-0.4.0 → dimples-0.4.1}/setup.py +1 -1
- dimples-0.4.0/dimples/server/broadcast.py +0 -219
- {dimples-0.4.0 → dimples-0.4.1}/README.md +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/archivist.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/checkpoint.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/commands.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/creator.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/group.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/grp_expel.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/grp_invite.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/grp_join.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/grp_query.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/grp_quit.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/grp_reset.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/grp_resign.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/cpu/handshake.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/facebook.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/messenger.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/network/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/network/session.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/network/state.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/network/transition.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/packer.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/client/processor.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/anonymous.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/ans.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/archivist.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/compat/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/compat/btc.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/compat/compatible.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/compat/entity.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/compat/meta.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/compat/network.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/dbi/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/dbi/account.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/dbi/message.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/dbi/session.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/facebook.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/messenger.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/packer.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/protocol/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/protocol/ans.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/protocol/block.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/protocol/handshake.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/protocol/login.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/protocol/mute.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/protocol/report.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/register.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/common/session.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/gate.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/gatekeeper.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/mars.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/mtp.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/protocol/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/protocol/mars.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/queue.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/seeker.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/session.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/conn/ws.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/account.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/base.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/document.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/group.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/group_history.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/group_keys.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/login.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/meta.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/private.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/station.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/dos/user.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/message.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/session.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_cipherkey.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_document.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_group.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_group_history.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_group_keys.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_login.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_message.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_meta.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_private.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_station.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/database/t_user.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/edge/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/edge/octopus.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/edge/shared.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/edge/start.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/admin.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/builder.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/delegate.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/emitter.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/helper.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/manager.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/group/packer.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/register/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/register/base.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/register/ext.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/register/run.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/register/shared.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/cpu/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/cpu/ans.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/cpu/document.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/cpu/handshake.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/cpu/login.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/cpu/report.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/dispatcher.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/messenger.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/packer.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/push.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/session.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/session_center.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/server/trace.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/station/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/station/handler.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/station/start.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/utils/__init__.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/utils/cache.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/utils/config.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/utils/dos.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/utils/log.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples/utils/singleton.py +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples.egg-info/dependency_links.txt +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples.egg-info/entry_points.txt +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples.egg-info/requires.txt +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/dimples.egg-info/top_level.txt +0 -0
- {dimples-0.4.0 → dimples-0.4.1}/setup.cfg +0 -0
|
@@ -149,6 +149,11 @@ class Terminal(Runner, StateDelegate, Logging):
|
|
|
149
149
|
# broadcast current meta & visa document to all stations
|
|
150
150
|
messenger = self.messenger
|
|
151
151
|
messenger.handshake_success()
|
|
152
|
+
session = messenger.session
|
|
153
|
+
usr_id = session.identifier
|
|
154
|
+
if usr_id is not None and usr_id.type != EntityType.STATION:
|
|
155
|
+
# send login command to everyone to provide more information.
|
|
156
|
+
messenger.broadcast_login(sender=usr_id, user_agent=self.user_agent)
|
|
152
157
|
# update last online time
|
|
153
158
|
self.__last_time = time.time()
|
|
154
159
|
|
|
@@ -76,7 +76,7 @@ class WebSocket:
|
|
|
76
76
|
text = utf8_decode(data=stream).lower()
|
|
77
77
|
pos1 = text.find('sec-websocket-key:')
|
|
78
78
|
if pos1 > 0:
|
|
79
|
-
pos1 += len('sec-
|
|
79
|
+
pos1 += len('sec-websocket-key:')
|
|
80
80
|
pos2 = text.find('\r\n', pos1)
|
|
81
81
|
if pos2 > 0:
|
|
82
82
|
return stream[pos1:pos2].strip()
|
|
@@ -32,8 +32,6 @@
|
|
|
32
32
|
from .session import ServerSession
|
|
33
33
|
from .session_center import SessionCenter # SessionPool
|
|
34
34
|
|
|
35
|
-
from .broadcast import BroadcastRecipientManager
|
|
36
|
-
|
|
37
35
|
from .push import BadgeKeeper, PushService
|
|
38
36
|
from .push import PushCenter
|
|
39
37
|
|
|
@@ -56,8 +54,6 @@ __all__ = [
|
|
|
56
54
|
# Session
|
|
57
55
|
'ServerSession', 'SessionCenter', # 'SessionPool',
|
|
58
56
|
|
|
59
|
-
'BroadcastRecipientManager',
|
|
60
|
-
|
|
61
57
|
# Push Notification
|
|
62
58
|
'BadgeKeeper', 'PushService',
|
|
63
59
|
'PushCenter',
|
|
@@ -28,11 +28,13 @@
|
|
|
28
28
|
# SOFTWARE.
|
|
29
29
|
# ==============================================================================
|
|
30
30
|
|
|
31
|
+
import threading
|
|
31
32
|
from abc import ABC
|
|
32
|
-
from typing import Dict, List
|
|
33
|
+
from typing import Dict, List, Set
|
|
33
34
|
|
|
35
|
+
from dimsdk import DateTime
|
|
34
36
|
from dimsdk import FrequencyChecker
|
|
35
|
-
from dimsdk import ID, Document
|
|
37
|
+
from dimsdk import EntityType, ID, Document
|
|
36
38
|
from dimsdk import Envelope, InstantMessage
|
|
37
39
|
from dimsdk import Command, MetaCommand, DocumentCommand
|
|
38
40
|
from dimsdk import Station
|
|
@@ -40,8 +42,10 @@ from dimsdk import Station
|
|
|
40
42
|
from ..common import AccountDBI
|
|
41
43
|
from ..common import CommonArchivist
|
|
42
44
|
from ..common import CommonFacebook, CommonMessenger
|
|
45
|
+
from ..common import StationInfo
|
|
43
46
|
|
|
44
|
-
from .
|
|
47
|
+
from .dispatcher import Dispatcher
|
|
48
|
+
from .session_center import SessionCenter
|
|
45
49
|
|
|
46
50
|
|
|
47
51
|
def get_facebook(archivist: CommonArchivist):
|
|
@@ -67,21 +71,79 @@ class ServerArchivist(CommonArchivist, ABC):
|
|
|
67
71
|
super().__init__(database=database)
|
|
68
72
|
self.__document_responses = FrequencyChecker(expires=self.RESPOND_EXPIRES)
|
|
69
73
|
self.__last_active_members: Dict[ID, ID] = {} # group => member
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
# neighbor stations
|
|
75
|
+
self.__neighbors = set()
|
|
76
|
+
self.__lock = threading.Lock()
|
|
77
|
+
self.__expires = 0
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def active_stations(self) -> Set[ID]:
|
|
81
|
+
""" get neighbor stations connected to current station """
|
|
82
|
+
now = DateTime.now()
|
|
83
|
+
with self.__lock:
|
|
84
|
+
if self.__expires < now.timestamp:
|
|
85
|
+
neighbors = set()
|
|
86
|
+
center = SessionCenter()
|
|
87
|
+
all_users = center.all_users()
|
|
88
|
+
for item in all_users:
|
|
89
|
+
if item.type == EntityType.STATION:
|
|
90
|
+
neighbors.add(item)
|
|
91
|
+
self.__neighbors = neighbors
|
|
92
|
+
self.__expires = now.timestamp + 128
|
|
93
|
+
return self.__neighbors
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def all_stations(self) -> List[StationInfo]:
|
|
97
|
+
""" get stations from database """
|
|
98
|
+
dispatcher = Dispatcher()
|
|
99
|
+
db = dispatcher.sdb
|
|
100
|
+
# TODO: get chosen provider
|
|
101
|
+
providers = db.all_providers()
|
|
102
|
+
assert len(providers) > 0, 'service provider not found'
|
|
103
|
+
gsp = providers[0].identifier
|
|
104
|
+
return db.all_stations(provider=gsp)
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def all_neighbors(self) -> Set[ID]:
|
|
108
|
+
""" get all stations """
|
|
109
|
+
neighbors = set()
|
|
110
|
+
# get stations from chosen provider
|
|
111
|
+
chosen_stations = self.all_stations
|
|
112
|
+
for item in chosen_stations:
|
|
113
|
+
sid = item.identifier
|
|
114
|
+
if sid is None or sid.is_broadcast:
|
|
115
|
+
continue
|
|
116
|
+
neighbors.add(sid)
|
|
117
|
+
# get neighbor station from session server
|
|
118
|
+
proactive_neighbors = self.active_stations
|
|
119
|
+
for sid in proactive_neighbors:
|
|
120
|
+
if sid is None or sid.is_broadcast:
|
|
121
|
+
self.error(msg='neighbor station ID error: %s' % sid)
|
|
122
|
+
continue
|
|
123
|
+
neighbors.add(sid)
|
|
124
|
+
return neighbors
|
|
125
|
+
|
|
126
|
+
def _broadcast_command(self, command: Command) -> bool:
|
|
72
127
|
facebook = get_facebook(archivist=self)
|
|
73
128
|
messenger = get_messenger(archivist=self)
|
|
74
129
|
if facebook is None or messenger is None:
|
|
75
130
|
self.error(msg='twins not ready yet: %s, %s' % (facebook, messenger))
|
|
76
131
|
return False
|
|
77
132
|
sid = facebook.current_user.identifier
|
|
78
|
-
env = Envelope.create(sender=sid, receiver=
|
|
79
|
-
i_msg = InstantMessage.create(head=env, body=
|
|
133
|
+
env = Envelope.create(sender=sid, receiver=Station.EVERY)
|
|
134
|
+
i_msg = InstantMessage.create(head=env, body=command)
|
|
80
135
|
# pack & deliver message
|
|
81
136
|
s_msg = messenger.encrypt_message(msg=i_msg)
|
|
82
137
|
r_msg = messenger.sign_message(msg=s_msg)
|
|
83
|
-
|
|
84
|
-
|
|
138
|
+
# dispatch
|
|
139
|
+
dispatcher = Dispatcher()
|
|
140
|
+
neighbors = self.all_neighbors
|
|
141
|
+
for receiver in neighbors:
|
|
142
|
+
if receiver == sid:
|
|
143
|
+
self.debug(msg='skip cycled message: %s -> %s' % (sid, receiver))
|
|
144
|
+
continue
|
|
145
|
+
dispatcher.deliver_message(msg=r_msg, receiver=receiver)
|
|
146
|
+
return len(neighbors) > 0
|
|
85
147
|
|
|
86
148
|
# protected
|
|
87
149
|
def is_documents_respond_expired(self, identifier: ID, force: bool) -> bool:
|
|
@@ -98,7 +160,7 @@ class ServerArchivist(CommonArchivist, ABC):
|
|
|
98
160
|
return False
|
|
99
161
|
self.info(msg='querying meta for: %s' % identifier)
|
|
100
162
|
command = MetaCommand.query(identifier=identifier)
|
|
101
|
-
return self._broadcast_command(
|
|
163
|
+
return self._broadcast_command(command=command)
|
|
102
164
|
|
|
103
165
|
# Override
|
|
104
166
|
def query_documents(self, identifier: ID, documents: List[Document]) -> bool:
|
|
@@ -109,7 +171,7 @@ class ServerArchivist(CommonArchivist, ABC):
|
|
|
109
171
|
last_time = self.get_last_document_time(identifier=identifier, documents=documents)
|
|
110
172
|
self.info(msg='querying document for: %s, last time: %s' % (identifier, last_time))
|
|
111
173
|
command = DocumentCommand.query(identifier=identifier, last_time=last_time)
|
|
112
|
-
return self._broadcast_command(
|
|
174
|
+
return self._broadcast_command(command=command)
|
|
113
175
|
|
|
114
176
|
# Override
|
|
115
177
|
def query_members(self, group: ID, members: List[ID]) -> bool:
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
import time
|
|
32
32
|
from typing import Optional, Union, List, Dict
|
|
33
33
|
|
|
34
|
-
from dimsdk import EntityType, ID, ANYONE
|
|
34
|
+
from dimsdk import EntityType, ID, ANYONE, EVERYONE
|
|
35
35
|
from dimsdk import Station
|
|
36
36
|
from dimsdk import InstantMessage, ReliableMessage
|
|
37
37
|
from dimsdk import Envelope
|
|
@@ -58,7 +58,7 @@ from .cpu import DocumentCommandProcessor
|
|
|
58
58
|
|
|
59
59
|
from .packer import FilterManager
|
|
60
60
|
from .dispatcher import Dispatcher
|
|
61
|
-
from .
|
|
61
|
+
from .archivist import ServerArchivist
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
class ServerMessageProcessor(MessageProcessor, Logging):
|
|
@@ -95,8 +95,7 @@ class ServerMessageProcessor(MessageProcessor, Logging):
|
|
|
95
95
|
messenger = self.messenger
|
|
96
96
|
session = messenger.session
|
|
97
97
|
current = self.facebook.current_user
|
|
98
|
-
|
|
99
|
-
sender = msg.sender
|
|
98
|
+
station = current.identifier
|
|
100
99
|
receiver = msg.receiver
|
|
101
100
|
# 0. verify message
|
|
102
101
|
s_msg = messenger.verify_message(msg=msg)
|
|
@@ -104,7 +103,7 @@ class ServerMessageProcessor(MessageProcessor, Logging):
|
|
|
104
103
|
# TODO: suspend and waiting for sender's meta if not exists
|
|
105
104
|
return []
|
|
106
105
|
# 1. check receiver
|
|
107
|
-
if receiver ==
|
|
106
|
+
if receiver == station:
|
|
108
107
|
# message to this station
|
|
109
108
|
# maybe a meta command, document command, etc ...
|
|
110
109
|
pass
|
|
@@ -131,16 +130,22 @@ class ServerMessageProcessor(MessageProcessor, Logging):
|
|
|
131
130
|
# we can trust this message an no need to verify it;
|
|
132
131
|
# else if sender is a neighbor station,
|
|
133
132
|
# we can trust it too;
|
|
134
|
-
if receiver.
|
|
135
|
-
# broadcast message (to neighbor stations
|
|
136
|
-
# e.g.: 'stations@everywhere'
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
#
|
|
140
|
-
# broadcast message to multiple destinations,
|
|
133
|
+
if receiver == Station.EVERY or receiver == EVERYONE:
|
|
134
|
+
# broadcast message (to neighbor stations)
|
|
135
|
+
# e.g.: 'stations@everywhere'
|
|
136
|
+
self._broadcast_message(msg=msg, station=station)
|
|
137
|
+
# if receiver == 'everyone@everywhere':
|
|
138
|
+
# broadcast message to all destinations,
|
|
141
139
|
# current station is it's receiver too.
|
|
140
|
+
elif receiver.is_broadcast:
|
|
141
|
+
# broadcast message (to station bots)
|
|
142
|
+
# e.g.: 'archivist@anywhere', 'announcer@anywhere', 'monitor@anywhere'
|
|
143
|
+
self._broadcast_message(msg=msg, station=station)
|
|
144
|
+
return []
|
|
142
145
|
elif receiver.is_group:
|
|
143
|
-
|
|
146
|
+
# encrypted group messages should be sent to the group assistant,
|
|
147
|
+
# the station will never process these messages.
|
|
148
|
+
self._split_group_message(msg=msg, station=station)
|
|
144
149
|
return []
|
|
145
150
|
else:
|
|
146
151
|
# this message is not for current station,
|
|
@@ -180,6 +185,32 @@ class ServerMessageProcessor(MessageProcessor, Logging):
|
|
|
180
185
|
else:
|
|
181
186
|
return [r_msg]
|
|
182
187
|
|
|
188
|
+
def _broadcast_message(self, msg: ReliableMessage, station: ID):
|
|
189
|
+
""" broadcast message to neighbor stations """
|
|
190
|
+
archivist = self.facebook.archivist
|
|
191
|
+
assert isinstance(archivist, ServerArchivist)
|
|
192
|
+
neighbors = archivist.all_neighbors
|
|
193
|
+
sender = msg.sender
|
|
194
|
+
self.info(msg='broadcast message %s -> %s (%s): from station %s to %s'
|
|
195
|
+
% (sender, msg.receiver, msg.group, station, neighbors))
|
|
196
|
+
# dispatch
|
|
197
|
+
dispatcher = Dispatcher()
|
|
198
|
+
for receiver in neighbors:
|
|
199
|
+
if receiver == sender:
|
|
200
|
+
self.debug(msg='skip cycled message: %s -> %s' % (sender, receiver))
|
|
201
|
+
continue
|
|
202
|
+
elif receiver == station:
|
|
203
|
+
self.debug(msg='skip current station: %s -> %s' % (sender, receiver))
|
|
204
|
+
continue
|
|
205
|
+
dispatcher.deliver_message(msg=msg, receiver=receiver)
|
|
206
|
+
return len(neighbors) > 0
|
|
207
|
+
|
|
208
|
+
def _split_group_message(self, msg: ReliableMessage, station: ID):
|
|
209
|
+
""" redirect group message to assistant """
|
|
210
|
+
sender = msg.sender
|
|
211
|
+
receiver = msg.receiver
|
|
212
|
+
self.error(msg='group message should not send to station: %s, %s -> %s' % (station, sender, receiver))
|
|
213
|
+
|
|
183
214
|
def _deliver_message(self, msg: ReliableMessage) -> List[ReliableMessage]:
|
|
184
215
|
messenger = self.messenger
|
|
185
216
|
current = self.facebook.current_user
|
|
@@ -42,7 +42,6 @@ from ..server import ServerSession
|
|
|
42
42
|
from ..server import ServerMessenger
|
|
43
43
|
from ..server import ServerMessagePacker
|
|
44
44
|
from ..server import ServerMessageProcessor
|
|
45
|
-
from ..server import BroadcastRecipientManager
|
|
46
45
|
from ..server import Dispatcher
|
|
47
46
|
|
|
48
47
|
|
|
@@ -189,12 +188,4 @@ def create_ans(config: Config) -> AddressNameServer:
|
|
|
189
188
|
ans_records = config.ans_records
|
|
190
189
|
if ans_records is not None:
|
|
191
190
|
ans.fix(records=ans_records)
|
|
192
|
-
# set bots to receive message for 'everyone@everywhere'
|
|
193
|
-
bots = set()
|
|
194
|
-
se = ans.identifier(name='archivist') # Search Engine
|
|
195
|
-
if se is not None:
|
|
196
|
-
bots.add(se)
|
|
197
|
-
if len(bots) > 0:
|
|
198
|
-
manager = BroadcastRecipientManager()
|
|
199
|
-
manager.station_bots = bots
|
|
200
191
|
return ans
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# DIM-SDK : Decentralized Instant Messaging Software Development Kit
|
|
4
|
-
#
|
|
5
|
-
# ==============================================================================
|
|
6
|
-
# MIT License
|
|
7
|
-
#
|
|
8
|
-
# Copyright (c) 2023 Albert Moky
|
|
9
|
-
#
|
|
10
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
12
|
-
# in the Software without restriction, including without limitation the rights
|
|
13
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
15
|
-
# furnished to do so, subject to the following conditions:
|
|
16
|
-
#
|
|
17
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
18
|
-
# copies or substantial portions of the Software.
|
|
19
|
-
#
|
|
20
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
-
# SOFTWARE.
|
|
27
|
-
# ==============================================================================
|
|
28
|
-
|
|
29
|
-
"""
|
|
30
|
-
Broadcast Recipient Manager
|
|
31
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
import threading
|
|
35
|
-
from typing import Set, List
|
|
36
|
-
|
|
37
|
-
from dimsdk import DateTime
|
|
38
|
-
from dimsdk import EntityType, ID, EVERYONE
|
|
39
|
-
from dimsdk import Station
|
|
40
|
-
from dimsdk import ReliableMessage
|
|
41
|
-
|
|
42
|
-
from ..utils import Singleton, Log, Logging
|
|
43
|
-
from ..common import StationInfo
|
|
44
|
-
|
|
45
|
-
from .cpu import AnsCommandProcessor
|
|
46
|
-
from .trace import TraceNode, TraceList, TraceManager
|
|
47
|
-
from .dispatcher import Dispatcher
|
|
48
|
-
from .session_center import SessionCenter
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@Singleton
|
|
52
|
-
class BroadcastRecipientManager(Logging):
|
|
53
|
-
|
|
54
|
-
def __init__(self):
|
|
55
|
-
super().__init__()
|
|
56
|
-
self.__lock = threading.Lock()
|
|
57
|
-
self.__expires = 0
|
|
58
|
-
self.__neighbors = set()
|
|
59
|
-
self.__bots = set()
|
|
60
|
-
|
|
61
|
-
@property
|
|
62
|
-
def station_bots(self) -> Set[ID]:
|
|
63
|
-
""" get station bots """
|
|
64
|
-
return self.__bots
|
|
65
|
-
|
|
66
|
-
@station_bots.setter
|
|
67
|
-
def station_bots(self, bots: Set[ID]):
|
|
68
|
-
""" set station bots to receive message for 'everyone@everywhere' """
|
|
69
|
-
assert isinstance(bots, Set), 'bots error: %s' % bots
|
|
70
|
-
self.__bots = bots
|
|
71
|
-
|
|
72
|
-
@property
|
|
73
|
-
def proactive_neighbors(self) -> Set[ID]:
|
|
74
|
-
""" get neighbor stations connected to current station """
|
|
75
|
-
now = DateTime.now()
|
|
76
|
-
with self.__lock:
|
|
77
|
-
if self.__expires < now.timestamp:
|
|
78
|
-
neighbors = set()
|
|
79
|
-
center = SessionCenter()
|
|
80
|
-
all_users = center.all_users()
|
|
81
|
-
for item in all_users:
|
|
82
|
-
if item.type == EntityType.STATION:
|
|
83
|
-
neighbors.add(item)
|
|
84
|
-
self.__neighbors = neighbors
|
|
85
|
-
self.__expires = now.timestamp + 128
|
|
86
|
-
return self.__neighbors
|
|
87
|
-
|
|
88
|
-
@property
|
|
89
|
-
def all_stations(self) -> List[StationInfo]:
|
|
90
|
-
""" get stations from database """
|
|
91
|
-
dispatcher = Dispatcher()
|
|
92
|
-
db = dispatcher.sdb
|
|
93
|
-
# TODO: get chosen provider
|
|
94
|
-
providers = db.all_providers()
|
|
95
|
-
assert len(providers) > 0, 'service provider not found'
|
|
96
|
-
gsp = providers[0].identifier
|
|
97
|
-
return db.all_stations(provider=gsp)
|
|
98
|
-
|
|
99
|
-
@property
|
|
100
|
-
def all_neighbors(self) -> Set[ID]:
|
|
101
|
-
""" get all stations """
|
|
102
|
-
neighbors = set()
|
|
103
|
-
# get stations from chosen provider
|
|
104
|
-
stations = self.all_stations
|
|
105
|
-
for item in stations:
|
|
106
|
-
sid = item.identifier
|
|
107
|
-
if sid is None or sid.is_broadcast:
|
|
108
|
-
continue
|
|
109
|
-
neighbors.add(sid)
|
|
110
|
-
# get neighbor station from session server
|
|
111
|
-
proactive_neighbors = self.proactive_neighbors
|
|
112
|
-
for sid in proactive_neighbors:
|
|
113
|
-
if sid is None or sid.is_broadcast:
|
|
114
|
-
assert False, 'neighbor station ID error: %s' % sid
|
|
115
|
-
# continue
|
|
116
|
-
neighbors.add(sid)
|
|
117
|
-
return neighbors
|
|
118
|
-
|
|
119
|
-
def get_recipients(self, msg: ReliableMessage, receiver: ID, station: ID) -> Set[ID]:
|
|
120
|
-
""" get nodes passed through, includes current node which is just added before """
|
|
121
|
-
recipients = set()
|
|
122
|
-
tm = TraceManager()
|
|
123
|
-
traces = tm.get_traces(msg=msg)
|
|
124
|
-
# if this message is sending to 'stations@everywhere' or 'everyone@everywhere'
|
|
125
|
-
# get all neighbor stations to broadcast, but
|
|
126
|
-
# traced nodes should be ignored to avoid cycled delivering
|
|
127
|
-
if receiver == Station.EVERY or receiver == EVERYONE:
|
|
128
|
-
self.info(msg='forward to neighbors: %s' % receiver)
|
|
129
|
-
# get neighbor stations
|
|
130
|
-
neighbors = self.all_neighbors
|
|
131
|
-
for sid in neighbors:
|
|
132
|
-
if traces.search(node=sid) >= 0 or sid == station:
|
|
133
|
-
self.warning(msg='skip duplicated station: %s' % sid)
|
|
134
|
-
continue
|
|
135
|
-
recipients.add(sid)
|
|
136
|
-
# get station bots
|
|
137
|
-
if receiver == EVERYONE:
|
|
138
|
-
# include station bots as 'everyone@everywhere'
|
|
139
|
-
bots = self.station_bots
|
|
140
|
-
for bid in bots:
|
|
141
|
-
if traces.search(node=bid) >= 0:
|
|
142
|
-
self.warning(msg='skip duplicated bot: %s' % bid)
|
|
143
|
-
continue
|
|
144
|
-
recipients.add(bid)
|
|
145
|
-
elif receiver.is_user:
|
|
146
|
-
# 'archivist@anywhere', 'announcer@anywhere', 'monitor@anywhere'
|
|
147
|
-
name = receiver.name
|
|
148
|
-
if name is not None:
|
|
149
|
-
assert name != 'station' and name != 'anyone', 'receiver error: %s' % receiver
|
|
150
|
-
bot = AnsCommandProcessor.ans_id(name=name)
|
|
151
|
-
self.info(msg='forward to bot: %s -> %s' % (name, bot))
|
|
152
|
-
if bot is not None and traces.search(node=bot) < 0:
|
|
153
|
-
recipients.add(bot)
|
|
154
|
-
self.info(msg='recipients: %s -> %s' % (receiver, recipients))
|
|
155
|
-
return recipients
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def broadcast_reliable_message(msg: ReliableMessage, station: ID):
|
|
159
|
-
receiver = msg.receiver
|
|
160
|
-
# get other recipients for broadcast message
|
|
161
|
-
manager = BroadcastRecipientManager()
|
|
162
|
-
recipients = manager.get_recipients(msg=msg, receiver=receiver, station=station)
|
|
163
|
-
if len(recipients) == 0:
|
|
164
|
-
Log.warning('other recipients not found: %s' % receiver)
|
|
165
|
-
return 0
|
|
166
|
-
sender = msg.sender
|
|
167
|
-
# dispatch
|
|
168
|
-
dispatcher = Dispatcher()
|
|
169
|
-
for target in recipients:
|
|
170
|
-
assert not target.is_broadcast, 'recipient error: %s, %s' % (target, receiver)
|
|
171
|
-
deliver_message(msg=msg, receiver=target, recipients=recipients, station=station, dispatcher=dispatcher)
|
|
172
|
-
# TODO: after deliver to connected neighbors, the dispatcher will continue
|
|
173
|
-
# delivering via station bridge, should we mark 'sent_neighbors' in
|
|
174
|
-
# only one message to the bridge, let the bridge to separate for other
|
|
175
|
-
# neighbors which not connect to this station directly?
|
|
176
|
-
# set trace nodes
|
|
177
|
-
tm = TraceManager()
|
|
178
|
-
tm.set_nodes(msg=msg, nodes=recipients)
|
|
179
|
-
# OK
|
|
180
|
-
Log.info(msg='Broadcast message delivered: %s => %s' % (sender, recipients))
|
|
181
|
-
return len(recipients)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
def deliver_message(msg: ReliableMessage, receiver: ID, recipients: Set[ID], station: ID, dispatcher: Dispatcher):
|
|
185
|
-
if receiver == station:
|
|
186
|
-
Log.warning(msg='skip current node: %s, %s' % (receiver, recipients))
|
|
187
|
-
return None
|
|
188
|
-
elif receiver == msg.sender:
|
|
189
|
-
Log.warning(msg='skip sender: %s, %s' % (receiver, recipients))
|
|
190
|
-
return None
|
|
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
|
|
197
|
-
# clone
|
|
198
|
-
msg = ReliableMessage.parse(msg=msg.dictionary)
|
|
199
|
-
traces = copy_traces(traces=traces)
|
|
200
|
-
# add these recipients into traces, exclude current receiver
|
|
201
|
-
recipients = recipients.copy()
|
|
202
|
-
recipients.discard(receiver) # exclude receiver
|
|
203
|
-
recipients.add(station) # include current station
|
|
204
|
-
for mta in recipients:
|
|
205
|
-
node = TraceNode.create(identifier=mta)
|
|
206
|
-
traces.insert(node=node)
|
|
207
|
-
msg['traces'] = TraceNode.revert(nodes=traces.nodes)
|
|
208
|
-
# deliver message with traces
|
|
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())
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|