dimples 0.4.2__tar.gz → 0.5.0__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 (142) hide show
  1. {dimples-0.4.2 → dimples-0.5.0}/PKG-INFO +1 -1
  2. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/network/session.py +28 -15
  3. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/network/state.py +55 -45
  4. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/network/transition.py +12 -12
  5. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/terminal.py +25 -33
  6. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/gate.py +84 -90
  7. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/gatekeeper.py +40 -37
  8. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/mars.py +3 -3
  9. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/mtp.py +3 -3
  10. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/protocol/ws.py +2 -1
  11. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/ws.py +11 -3
  12. {dimples-0.4.2 → dimples-0.5.0}/dimples/edge/octopus.py +25 -6
  13. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/dispatcher.py +6 -4
  14. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/push.py +5 -5
  15. {dimples-0.4.2 → dimples-0.5.0}/dimples/utils/cache.py +4 -15
  16. {dimples-0.4.2 → dimples-0.5.0}/dimples.egg-info/PKG-INFO +1 -1
  17. {dimples-0.4.2 → dimples-0.5.0}/dimples.egg-info/requires.txt +3 -3
  18. {dimples-0.4.2 → dimples-0.5.0}/setup.py +4 -4
  19. {dimples-0.4.2 → dimples-0.5.0}/README.md +0 -0
  20. {dimples-0.4.2 → dimples-0.5.0}/dimples/__init__.py +0 -0
  21. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/__init__.py +0 -0
  22. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/archivist.py +0 -0
  23. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/checkpoint.py +0 -0
  24. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/__init__.py +0 -0
  25. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/commands.py +0 -0
  26. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/creator.py +0 -0
  27. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/group.py +0 -0
  28. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/grp_expel.py +0 -0
  29. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/grp_invite.py +0 -0
  30. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/grp_join.py +0 -0
  31. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/grp_query.py +0 -0
  32. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/grp_quit.py +0 -0
  33. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/grp_reset.py +0 -0
  34. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/grp_resign.py +0 -0
  35. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/cpu/handshake.py +0 -0
  36. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/facebook.py +0 -0
  37. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/messenger.py +0 -0
  38. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/network/__init__.py +0 -0
  39. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/packer.py +0 -0
  40. {dimples-0.4.2 → dimples-0.5.0}/dimples/client/processor.py +0 -0
  41. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/__init__.py +0 -0
  42. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/anonymous.py +0 -0
  43. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/ans.py +0 -0
  44. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/archivist.py +0 -0
  45. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/compat/__init__.py +0 -0
  46. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/compat/btc.py +0 -0
  47. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/compat/compatible.py +0 -0
  48. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/compat/entity.py +0 -0
  49. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/compat/meta.py +0 -0
  50. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/compat/network.py +0 -0
  51. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/dbi/__init__.py +0 -0
  52. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/dbi/account.py +0 -0
  53. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/dbi/message.py +0 -0
  54. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/dbi/session.py +0 -0
  55. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/facebook.py +0 -0
  56. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/messenger.py +0 -0
  57. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/packer.py +0 -0
  58. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/protocol/__init__.py +0 -0
  59. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/protocol/ans.py +0 -0
  60. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/protocol/block.py +0 -0
  61. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/protocol/handshake.py +0 -0
  62. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/protocol/login.py +0 -0
  63. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/protocol/mute.py +0 -0
  64. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/protocol/report.py +0 -0
  65. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/register.py +0 -0
  66. {dimples-0.4.2 → dimples-0.5.0}/dimples/common/session.py +0 -0
  67. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/__init__.py +0 -0
  68. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/protocol/__init__.py +0 -0
  69. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/protocol/mars.py +0 -0
  70. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/queue.py +0 -0
  71. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/seeker.py +0 -0
  72. {dimples-0.4.2 → dimples-0.5.0}/dimples/conn/session.py +0 -0
  73. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/__init__.py +0 -0
  74. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/account.py +0 -0
  75. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/__init__.py +0 -0
  76. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/base.py +0 -0
  77. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/document.py +0 -0
  78. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/group.py +0 -0
  79. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/group_history.py +0 -0
  80. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/group_keys.py +0 -0
  81. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/login.py +0 -0
  82. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/meta.py +0 -0
  83. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/private.py +0 -0
  84. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/station.py +0 -0
  85. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/dos/user.py +0 -0
  86. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/message.py +0 -0
  87. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/session.py +0 -0
  88. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_cipherkey.py +0 -0
  89. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_document.py +0 -0
  90. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_group.py +0 -0
  91. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_group_history.py +0 -0
  92. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_group_keys.py +0 -0
  93. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_login.py +0 -0
  94. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_message.py +0 -0
  95. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_meta.py +0 -0
  96. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_private.py +0 -0
  97. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_station.py +0 -0
  98. {dimples-0.4.2 → dimples-0.5.0}/dimples/database/t_user.py +0 -0
  99. {dimples-0.4.2 → dimples-0.5.0}/dimples/edge/__init__.py +0 -0
  100. {dimples-0.4.2 → dimples-0.5.0}/dimples/edge/shared.py +0 -0
  101. {dimples-0.4.2 → dimples-0.5.0}/dimples/edge/start.py +0 -0
  102. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/__init__.py +0 -0
  103. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/admin.py +0 -0
  104. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/builder.py +0 -0
  105. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/delegate.py +0 -0
  106. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/emitter.py +0 -0
  107. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/helper.py +0 -0
  108. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/manager.py +0 -0
  109. {dimples-0.4.2 → dimples-0.5.0}/dimples/group/packer.py +0 -0
  110. {dimples-0.4.2 → dimples-0.5.0}/dimples/register/__init__.py +0 -0
  111. {dimples-0.4.2 → dimples-0.5.0}/dimples/register/base.py +0 -0
  112. {dimples-0.4.2 → dimples-0.5.0}/dimples/register/ext.py +0 -0
  113. {dimples-0.4.2 → dimples-0.5.0}/dimples/register/run.py +0 -0
  114. {dimples-0.4.2 → dimples-0.5.0}/dimples/register/shared.py +0 -0
  115. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/__init__.py +0 -0
  116. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/archivist.py +0 -0
  117. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/cpu/__init__.py +0 -0
  118. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/cpu/ans.py +0 -0
  119. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/cpu/document.py +0 -0
  120. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/cpu/handshake.py +0 -0
  121. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/cpu/login.py +0 -0
  122. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/cpu/report.py +0 -0
  123. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/messenger.py +0 -0
  124. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/packer.py +0 -0
  125. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/processor.py +0 -0
  126. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/session.py +0 -0
  127. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/session_center.py +0 -0
  128. {dimples-0.4.2 → dimples-0.5.0}/dimples/server/trace.py +0 -0
  129. {dimples-0.4.2 → dimples-0.5.0}/dimples/station/__init__.py +0 -0
  130. {dimples-0.4.2 → dimples-0.5.0}/dimples/station/handler.py +0 -0
  131. {dimples-0.4.2 → dimples-0.5.0}/dimples/station/shared.py +0 -0
  132. {dimples-0.4.2 → dimples-0.5.0}/dimples/station/start.py +0 -0
  133. {dimples-0.4.2 → dimples-0.5.0}/dimples/utils/__init__.py +0 -0
  134. {dimples-0.4.2 → dimples-0.5.0}/dimples/utils/config.py +0 -0
  135. {dimples-0.4.2 → dimples-0.5.0}/dimples/utils/dos.py +0 -0
  136. {dimples-0.4.2 → dimples-0.5.0}/dimples/utils/log.py +0 -0
  137. {dimples-0.4.2 → dimples-0.5.0}/dimples/utils/singleton.py +0 -0
  138. {dimples-0.4.2 → dimples-0.5.0}/dimples.egg-info/SOURCES.txt +0 -0
  139. {dimples-0.4.2 → dimples-0.5.0}/dimples.egg-info/dependency_links.txt +0 -0
  140. {dimples-0.4.2 → dimples-0.5.0}/dimples.egg-info/entry_points.txt +0 -0
  141. {dimples-0.4.2 → dimples-0.5.0}/dimples.egg-info/top_level.txt +0 -0
  142. {dimples-0.4.2 → dimples-0.5.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dimples
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: DIMP Library for Edges and Stations
5
5
  Home-page: https://github.com/dimchat/demo-py
6
6
  Author: Albert Moky
@@ -36,11 +36,12 @@
36
36
  """
37
37
 
38
38
  import traceback
39
- from threading import Thread
40
39
  from typing import Optional, List
41
40
 
42
41
  from dimsdk import Station
43
42
 
43
+ from startrek.fsm import Daemon
44
+ from startrek.fsm import Delegate as StateDelegate
44
45
  from startrek import Docker, DockerStatus
45
46
  from startrek import Arrival
46
47
 
@@ -48,6 +49,8 @@ from ...common import SessionDBI
48
49
  from ...conn import BaseSession
49
50
  from ...conn import MTPStreamArrival
50
51
 
52
+ from .state import StateMachine, SessionState
53
+
51
54
 
52
55
  class ClientSession(BaseSession):
53
56
  """
@@ -76,8 +79,12 @@ class ClientSession(BaseSession):
76
79
  def __init__(self, station: Station, database: SessionDBI):
77
80
  super().__init__(remote=(station.host, station.port), sock=None, database=database)
78
81
  self.__station = station
82
+ # session key
79
83
  self.__key: Optional[str] = None
80
- self.__thread: Optional[Thread] = None
84
+ # state machine
85
+ self.__fsm = StateMachine(session=self)
86
+ # background thread to drive gate & hub processing
87
+ self.__daemon = Daemon(target=self.run)
81
88
 
82
89
  @property
83
90
  def station(self) -> Station:
@@ -91,23 +98,29 @@ class ClientSession(BaseSession):
91
98
  def key(self, session_key: str):
92
99
  self.__key = session_key
93
100
 
94
- def start(self):
95
- self.__force_stop()
96
- t = Thread(target=self.run, daemon=True)
97
- self.__thread = t
98
- t.start()
99
-
100
- def __force_stop(self):
101
- t: Thread = self.__thread
102
- if t is not None:
103
- # waiting 2 seconds for stopping the thread
104
- self.__thread = None
105
- t.join(timeout=2.0)
101
+ @property
102
+ def state(self) -> SessionState:
103
+ ss = self.__fsm.current_state
104
+ assert ss is None or isinstance(ss, SessionState), 'session state error: %s' % ss
105
+ return ss
106
+
107
+ def start(self, delegate: StateDelegate):
108
+ if self.running:
109
+ self.stop()
110
+ # start a background thread
111
+ self.__daemon.start()
112
+ # start state machine
113
+ fsm = self.__fsm
114
+ fsm.delegate = delegate
115
+ fsm.start()
106
116
 
107
117
  # Override
108
118
  def stop(self):
109
119
  super().stop()
110
- self.__force_stop()
120
+ # stop state machine
121
+ self.__fsm.stop()
122
+ # wait for thread stop
123
+ self.__daemon.stop()
111
124
 
112
125
  # Override
113
126
  def setup(self):
@@ -25,32 +25,33 @@
25
25
 
26
26
  import weakref
27
27
  from abc import ABC
28
- from typing import Optional
28
+ from enum import IntEnum
29
+ from typing import Optional, Union
29
30
 
30
31
  from dimsdk import ID
31
32
 
32
33
  from startrek.fsm import Context, BaseTransition, BaseState, AutoMachine
33
34
  from startrek import DockerStatus
34
35
 
35
- from .session import ClientSession
36
+ # from .session import ClientSession
36
37
 
37
38
 
38
39
  class StateMachine(AutoMachine, Context):
39
40
 
40
- def __init__(self, session: ClientSession):
41
- super().__init__(default=SessionState.DEFAULT)
41
+ def __init__(self, session):
42
+ super().__init__()
42
43
  self.__session = weakref.ref(session)
43
44
  # init states
44
45
  builder = self._create_state_builder()
45
- self.__set_state(state=builder.get_default_state())
46
- self.__set_state(state=builder.get_connecting_state())
47
- self.__set_state(state=builder.get_connected_state())
48
- self.__set_state(state=builder.get_handshaking_state())
49
- self.__set_state(state=builder.get_running_state())
50
- self.__set_state(state=builder.get_error_state())
46
+ self.add_state(state=builder.get_default_state())
47
+ self.add_state(state=builder.get_connecting_state())
48
+ self.add_state(state=builder.get_connected_state())
49
+ self.add_state(state=builder.get_handshaking_state())
50
+ self.add_state(state=builder.get_running_state())
51
+ self.add_state(state=builder.get_error_state())
51
52
 
52
53
  @property
53
- def session(self) -> ClientSession:
54
+ def session(self): # -> ClientSession:
54
55
  return self.__session()
55
56
 
56
57
  # noinspection PyMethodMayBeStatic
@@ -58,9 +59,6 @@ class StateMachine(AutoMachine, Context):
58
59
  from .transition import TransitionBuilder
59
60
  return StateBuilder(transition_builder=TransitionBuilder())
60
61
 
61
- def __set_state(self, state):
62
- self.set_state(name=state.name, state=state)
63
-
64
62
  @property # Override
65
63
  def context(self) -> Context:
66
64
  return self
@@ -79,16 +77,31 @@ class StateMachine(AutoMachine, Context):
79
77
  def status(self) -> DockerStatus:
80
78
  session = self.session
81
79
  gate = session.gate
82
- docker = gate.fetch_docker(remote=session.remote_address, local=None, advance_party=[])
80
+ docker = gate.fetch_docker([], remote=session.remote_address, local=None)
83
81
  if docker is None:
84
82
  return DockerStatus.ERROR
85
83
  else:
86
84
  return docker.status
87
85
 
88
86
 
87
+ class StateOrder(IntEnum):
88
+ """ Connection State Order """
89
+ INIT = 0 # default
90
+ CONNECTING = 1
91
+ CONNECTED = 2
92
+ HANDSHAKING = 3
93
+ RUNNING = 4
94
+ ERROR = 5
95
+
96
+
89
97
  # noinspection PyAbstractClass
90
98
  class StateTransition(BaseTransition[StateMachine], ABC):
91
99
 
100
+ def __init__(self, target: Union[int, StateOrder]):
101
+ if isinstance(target, StateOrder):
102
+ target = target.value
103
+ super().__init__(target=target)
104
+
92
105
  # noinspection PyMethodMayBeStatic
93
106
  def is_expired(self, state, now: float) -> bool:
94
107
  assert isinstance(state, SessionState), 'state error: %s' % state
@@ -110,16 +123,9 @@ class SessionState(BaseState[StateMachine, StateTransition]):
110
123
  ERROR - network error
111
124
  """
112
125
 
113
- DEFAULT = 'default'
114
- CONNECTING = 'connecting'
115
- CONNECTED = 'connected'
116
- HANDSHAKING = 'handshaking'
117
- RUNNING = 'running'
118
- ERROR = 'error'
119
-
120
- def __init__(self, name: str):
121
- super().__init__()
122
- self.__name = name
126
+ def __init__(self, order: StateOrder):
127
+ super().__init__(index=order.value)
128
+ self.__name = str(order)
123
129
  self.__time: float = 0 # enter time
124
130
 
125
131
  @property
@@ -137,20 +143,28 @@ class SessionState(BaseState[StateMachine, StateTransition]):
137
143
  return self.__name
138
144
 
139
145
  def __eq__(self, other) -> bool:
140
- if self is other:
141
- return True
142
- elif isinstance(other, SessionState):
143
- return self.__name == other.name
146
+ if isinstance(other, SessionState):
147
+ if self is other:
148
+ return True
149
+ return self.index == other.index
150
+ elif isinstance(other, StateOrder):
151
+ return self.index == other.value
152
+ elif isinstance(other, int):
153
+ return self.index == other
144
154
  elif isinstance(other, str):
145
155
  return self.__name == other
146
156
  else:
147
157
  return False
148
158
 
149
159
  def __ne__(self, other) -> bool:
150
- if self is other:
151
- return False
152
- elif isinstance(other, SessionState):
153
- return self.__name != other.name
160
+ if isinstance(other, SessionState):
161
+ if self is other:
162
+ return False
163
+ return self.index != other.index
164
+ elif isinstance(other, StateOrder):
165
+ return self.index != other.value
166
+ elif isinstance(other, int):
167
+ return self.index != other
154
168
  elif isinstance(other, str):
155
169
  return self.__name != other
156
170
  else:
@@ -165,11 +179,11 @@ class SessionState(BaseState[StateMachine, StateTransition]):
165
179
  self.__time = 0
166
180
 
167
181
  # Override
168
- def on_pause(self, ctx: StateMachine):
182
+ def on_pause(self, ctx: StateMachine, now: float):
169
183
  pass
170
184
 
171
185
  # Override
172
- def on_resume(self, ctx: StateMachine):
186
+ def on_resume(self, ctx: StateMachine, now: float):
173
187
  pass
174
188
 
175
189
 
@@ -183,14 +197,10 @@ class StateBuilder:
183
197
  super().__init__()
184
198
  self.__builder = transition_builder
185
199
 
186
- # noinspection PyMethodMayBeStatic
187
- def get_named_state(self, name: str) -> SessionState:
188
- return SessionState(name=name)
189
-
190
200
  def get_default_state(self) -> SessionState:
191
201
  builder = self.__builder
192
202
  # assert isinstance(builder, TransitionBuilder)
193
- state = self.get_named_state(name=SessionState.DEFAULT)
203
+ state = SessionState(order=StateOrder.INIT)
194
204
  # Default -> Connecting
195
205
  state.add_transition(transition=builder.get_default_connecting_transition())
196
206
  return state
@@ -198,7 +208,7 @@ class StateBuilder:
198
208
  def get_connecting_state(self) -> SessionState:
199
209
  builder = self.__builder
200
210
  # assert isinstance(builder, TransitionBuilder)
201
- state = self.get_named_state(name=SessionState.CONNECTING)
211
+ state = SessionState(order=StateOrder.CONNECTING)
202
212
  # Connecting -> Connected
203
213
  state.add_transition(transition=builder.get_connecting_connected_transition())
204
214
  # Connecting -> Error
@@ -208,7 +218,7 @@ class StateBuilder:
208
218
  def get_connected_state(self) -> SessionState:
209
219
  builder = self.__builder
210
220
  # assert isinstance(builder, TransitionBuilder)
211
- state = self.get_named_state(name=SessionState.CONNECTED)
221
+ state = SessionState(order=StateOrder.CONNECTED)
212
222
  # Connected -> Handshaking
213
223
  state.add_transition(transition=builder.get_connected_handshaking_transition())
214
224
  # Connected -> Error
@@ -218,7 +228,7 @@ class StateBuilder:
218
228
  def get_handshaking_state(self) -> SessionState:
219
229
  builder = self.__builder
220
230
  # assert isinstance(builder, TransitionBuilder)
221
- state = self.get_named_state(name=SessionState.HANDSHAKING)
231
+ state = SessionState(order=StateOrder.HANDSHAKING)
222
232
  # Handshaking -> Running
223
233
  state.add_transition(transition=builder.get_handshaking_running_transition())
224
234
  # Handshaking -> Connected
@@ -230,7 +240,7 @@ class StateBuilder:
230
240
  def get_running_state(self) -> SessionState:
231
241
  builder = self.__builder
232
242
  # assert isinstance(builder, TransitionBuilder)
233
- state = self.get_named_state(name=SessionState.RUNNING)
243
+ state = SessionState(order=StateOrder.RUNNING)
234
244
  # Running -> Default
235
245
  state.add_transition(transition=builder.get_running_default_transition())
236
246
  # Running -> Error
@@ -240,7 +250,7 @@ class StateBuilder:
240
250
  def get_error_state(self) -> SessionState:
241
251
  builder = self.__builder
242
252
  # assert isinstance(builder, TransitionBuilder)
243
- state = self.get_named_state(name=SessionState.ERROR)
253
+ state = SessionState(order=StateOrder.ERROR)
244
254
  # Error -> Default
245
255
  state.add_transition(transition=builder.get_error_default_transition())
246
256
  return state
@@ -26,64 +26,64 @@
26
26
  from startrek import DockerStatus
27
27
 
28
28
  from .state import StateMachine, StateTransition
29
- from .state import SessionState
29
+ from .state import StateOrder
30
30
 
31
31
 
32
32
  class TransitionBuilder:
33
33
 
34
34
  # noinspection PyMethodMayBeStatic
35
35
  def get_default_connecting_transition(self):
36
- return DefaultConnectingTransition(target=SessionState.CONNECTING)
36
+ return DefaultConnectingTransition(target=StateOrder.CONNECTING)
37
37
 
38
38
  # Connecting
39
39
 
40
40
  # noinspection PyMethodMayBeStatic
41
41
  def get_connecting_connected_transition(self):
42
- return ConnectingConnectedTransition(target=SessionState.CONNECTED)
42
+ return ConnectingConnectedTransition(target=StateOrder.CONNECTED)
43
43
 
44
44
  # noinspection PyMethodMayBeStatic
45
45
  def get_connecting_error_transition(self):
46
- return ConnectingErrorTransition(target=SessionState.ERROR)
46
+ return ConnectingErrorTransition(target=StateOrder.ERROR)
47
47
 
48
48
  # Connected
49
49
 
50
50
  # noinspection PyMethodMayBeStatic
51
51
  def get_connected_handshaking_transition(self):
52
- return ConnectedHandshakingTransition(target=SessionState.HANDSHAKING)
52
+ return ConnectedHandshakingTransition(target=StateOrder.HANDSHAKING)
53
53
 
54
54
  # noinspection PyMethodMayBeStatic
55
55
  def get_connected_error_transition(self):
56
- return ConnectedErrorTransition(target=SessionState.ERROR)
56
+ return ConnectedErrorTransition(target=StateOrder.ERROR)
57
57
 
58
58
  # Handshaking
59
59
 
60
60
  # noinspection PyMethodMayBeStatic
61
61
  def get_handshaking_running_transition(self):
62
- return HandshakingRunningTransition(target=SessionState.RUNNING)
62
+ return HandshakingRunningTransition(target=StateOrder.RUNNING)
63
63
 
64
64
  # noinspection PyMethodMayBeStatic
65
65
  def get_handshaking_connected_transition(self):
66
- return HandshakingConnectedTransition(target=SessionState.CONNECTED)
66
+ return HandshakingConnectedTransition(target=StateOrder.CONNECTED)
67
67
 
68
68
  # noinspection PyMethodMayBeStatic
69
69
  def get_handshaking_error_transition(self):
70
- return HandshakingErrorTransition(target=SessionState.ERROR)
70
+ return HandshakingErrorTransition(target=StateOrder.ERROR)
71
71
 
72
72
  # Running
73
73
 
74
74
  # noinspection PyMethodMayBeStatic
75
75
  def get_running_default_transition(self):
76
- return RunningDefaultTransition(target=SessionState.DEFAULT)
76
+ return RunningDefaultTransition(target=StateOrder.INIT)
77
77
 
78
78
  # noinspection PyMethodMayBeStatic
79
79
  def get_running_error_transition(self):
80
- return RunningErrorTransition(target=SessionState.ERROR)
80
+ return RunningErrorTransition(target=StateOrder.ERROR)
81
81
 
82
82
  # Error
83
83
 
84
84
  # noinspection PyMethodMayBeStatic
85
85
  def get_error_default_transition(self):
86
- return ErrorDefaultTransition(target=SessionState.DEFAULT)
86
+ return ErrorDefaultTransition(target=StateOrder.INIT)
87
87
 
88
88
 
89
89
  #
@@ -40,26 +40,26 @@ from ..utils import StateDelegate
40
40
 
41
41
  from .network import ClientSession
42
42
  from .network import StateMachine, SessionState
43
+ from .network.state import StateOrder
43
44
 
44
45
  from .messenger import ClientMessenger
45
46
 
46
47
 
47
- class Terminal(Runner, StateDelegate, Logging):
48
+ class DeviceMixin:
49
+
50
+ @property
51
+ def user_agent(self) -> str:
52
+ return 'DIMP/0.4 (Client; Linux; en-US) DIMCoreKit/0.9 (Terminal) DIM-by-GSP/1.0'
53
+
54
+
55
+ class Terminal(Runner, DeviceMixin, Logging, StateDelegate):
48
56
 
49
57
  def __init__(self, messenger: ClientMessenger):
50
58
  super().__init__(interval=60)
51
59
  self.__messenger = messenger
52
- # session state
53
- fsm = StateMachine(session=messenger.session)
54
- fsm.delegate = self
55
- self.__fsm = fsm
56
60
  # default online time
57
61
  self.__last_time = time.time()
58
62
 
59
- @property
60
- def user_agent(self) -> str:
61
- return 'DIMP/0.4 (Client; Linux; en-US) DIMCoreKit/0.9 (Terminal) DIM-by-GSP/1.0'
62
-
63
63
  @property
64
64
  def messenger(self) -> ClientMessenger:
65
65
  return self.__messenger
@@ -68,18 +68,10 @@ class Terminal(Runner, StateDelegate, Logging):
68
68
  def session(self) -> ClientSession:
69
69
  return self.messenger.session
70
70
 
71
- @property
72
- def state(self) -> SessionState:
73
- ss = self.__fsm.current_state
74
- assert ss is None or isinstance(ss, SessionState), 'session state error: %s' % ss
75
- return ss
76
-
77
- @property
78
- def is_alive(self) -> bool:
79
- # if more than 10 minutes no online command sent
80
- # means this terminal is dead
81
- now = time.time()
82
- return now < (self.__last_time + 600)
71
+ @property # Override
72
+ def running(self) -> bool:
73
+ if super().running:
74
+ return self.session.running
83
75
 
84
76
  def start(self):
85
77
  thread = threading.Thread(target=self.run, daemon=True)
@@ -88,12 +80,10 @@ class Terminal(Runner, StateDelegate, Logging):
88
80
  # Override
89
81
  def setup(self):
90
82
  super().setup()
91
- self.session.start()
92
- self.__fsm.start()
83
+ self.session.start(delegate=self)
93
84
 
94
85
  # Override
95
86
  def finish(self):
96
- self.__fsm.stop()
97
87
  self.session.stop()
98
88
  super().finish()
99
89
 
@@ -107,7 +97,7 @@ class Terminal(Runner, StateDelegate, Logging):
107
97
  messenger = self.messenger
108
98
  session = messenger.session
109
99
  usr_id = session.identifier
110
- if usr_id is None or self.state != SessionState.RUNNING:
100
+ if usr_id is None or session.state != StateOrder.RUNNING:
111
101
  # handshake not accepted
112
102
  return False
113
103
  # report every 5 minutes to keep user online
@@ -128,24 +118,26 @@ class Terminal(Runner, StateDelegate, Logging):
128
118
  #
129
119
 
130
120
  # Override
131
- def enter_state(self, state: SessionState, ctx: StateMachine):
121
+ def enter_state(self, state: SessionState, ctx: StateMachine, now: float):
132
122
  # called before state changed
133
123
  session = self.session
134
124
  station = session.station
135
125
  self.info(msg='enter state: %s, %s => %s' % (state, session.identifier, station.identifier))
136
126
 
137
127
  # Override
138
- def exit_state(self, state: SessionState, ctx: StateMachine):
128
+ def exit_state(self, state: SessionState, ctx: StateMachine, now: float):
139
129
  # called after state changed
140
130
  current = ctx.current_state
141
131
  self.info(msg='server state changed: %s -> %s' % (state, current))
142
- if current is None:
143
- return
144
- elif current == SessionState.HANDSHAKING:
132
+ if isinstance(current, SessionState):
133
+ index = current.index
134
+ else:
135
+ index = -1
136
+ if index == StateOrder.HANDSHAKING:
145
137
  # start handshake
146
138
  messenger = self.messenger
147
139
  messenger.handshake(session_key=None)
148
- elif current == SessionState.RUNNING:
140
+ elif index == StateOrder.RUNNING:
149
141
  # broadcast current meta & visa document to all stations
150
142
  messenger = self.messenger
151
143
  messenger.handshake_success()
@@ -158,10 +150,10 @@ class Terminal(Runner, StateDelegate, Logging):
158
150
  self.__last_time = time.time()
159
151
 
160
152
  # Override
161
- def pause_state(self, state: SessionState, ctx: StateMachine):
153
+ def pause_state(self, state: SessionState, ctx: StateMachine, now: float):
162
154
  pass
163
155
 
164
156
  # Override
165
- def resume_state(self, state: SessionState, ctx: StateMachine):
157
+ def resume_state(self, state: SessionState, ctx: StateMachine, now: float):
166
158
  # TODO: clear session key for re-login?
167
159
  pass