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.
- {dimples-0.5.3 → dimples-0.5.6}/PKG-INFO +1 -1
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/session.py +2 -2
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/state.py +4 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/terminal.py +8 -4
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/session.py +4 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/session.py +2 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/protocol/mars.py +4 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/session.py +10 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/octopus.py +3 -3
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/archivist.py +7 -3
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/dispatcher.py +96 -18
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/processor.py +9 -41
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/push.py +4 -5
- {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/__init__.py +2 -2
- {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/cache.py +4 -3
- {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/config.py +2 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/PKG-INFO +1 -1
- {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/requires.txt +3 -3
- {dimples-0.5.3 → dimples-0.5.6}/setup.py +4 -4
- {dimples-0.5.3 → dimples-0.5.6}/README.md +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/archivist.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/checkpoint.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/commands.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/creator.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/group.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_expel.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_invite.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_join.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_query.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_quit.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_reset.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/grp_resign.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/cpu/handshake.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/facebook.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/messenger.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/network/transition.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/packer.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/client/processor.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/anonymous.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/ans.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/archivist.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/btc.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/compatible.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/entity.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/meta.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/compat/network.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/account.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/dbi/message.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/facebook.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/messenger.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/packer.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/processer.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/ans.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/block.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/handshake.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/login.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/mute.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/protocol/report.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/common/register.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/gate.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/gatekeeper.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/mars.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/mtp.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/protocol/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/protocol/ws.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/queue.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/seeker.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/conn/ws.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/account.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/base.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/document.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/group.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/group_history.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/group_keys.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/login.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/meta.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/private.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/station.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/dos/user.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/message.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/session.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_cipherkey.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_document.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_group.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_group_history.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_group_keys.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_login.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_message.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_meta.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_private.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_station.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/database/t_user.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/shared.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/edge/start.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/admin.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/builder.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/delegate.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/emitter.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/helper.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/manager.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/group/packer.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/register/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/register/base.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/register/ext.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/register/run.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/register/shared.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/ans.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/document.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/handshake.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/login.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/cpu/report.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/messenger.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/packer.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/session.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/session_center.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/server/trace.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/station/__init__.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/station/handler.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/station/shared.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/station/start.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/dos.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/log.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples/utils/singleton.py +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/SOURCES.txt +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/dependency_links.txt +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/entry_points.txt +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/dimples.egg-info/top_level.txt +0 -0
- {dimples-0.5.3 → dimples-0.5.6}/setup.cfg +0 -0
|
@@ -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
|
|
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
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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.
|
|
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
|
|
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) ->
|
|
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
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return [
|
|
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
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
|
|
211
|
-
|
|
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
|
-
|
|
240
|
-
|
|
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
|
|
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
|
-
|
|
129
|
-
|
|
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
|
|
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)
|
|
@@ -14,7 +14,7 @@ import io
|
|
|
14
14
|
|
|
15
15
|
from setuptools import setup, find_packages
|
|
16
16
|
|
|
17
|
-
__version__ = '0.5.
|
|
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.
|
|
62
|
-
'tcp>=1.
|
|
63
|
-
'udp>=1.
|
|
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
|
|
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
|