dsmq 0.6.0__py3-none-any.whl → 0.7.0__py3-none-any.whl
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.
dsmq/dsmq.py
CHANGED
@@ -5,15 +5,17 @@ import sys
|
|
5
5
|
from threading import Thread
|
6
6
|
import time
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
_default_host = "127.0.0.1"
|
9
|
+
_default_port = 30008
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
_message_length_offset = 1_000_000
|
12
|
+
_header_length = 23
|
13
|
+
_n_retries = 5
|
14
|
+
_first_retry = 0.01 # seconds
|
15
|
+
_time_to_live = 600.0 # seconds
|
14
16
|
|
15
17
|
|
16
|
-
def start_server(host=
|
18
|
+
def start_server(host=_default_host, port=_default_port):
|
17
19
|
"""
|
18
20
|
For best results, start this running in its own process and walk away.
|
19
21
|
"""
|
@@ -21,7 +23,7 @@ def start_server(host=DEFAULT_HOST, port=DEFAULT_PORT):
|
|
21
23
|
cursor = sqlite_conn.cursor()
|
22
24
|
|
23
25
|
cursor.execute("""
|
24
|
-
|
26
|
+
CREATE TABLE IF NOT EXISTS messages (timestamp DOUBLE, topic TEXT, message TEXT)
|
25
27
|
""")
|
26
28
|
|
27
29
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
@@ -46,7 +48,7 @@ def start_server(host=DEFAULT_HOST, port=DEFAULT_PORT):
|
|
46
48
|
sqlite_conn.close()
|
47
49
|
|
48
50
|
|
49
|
-
def connect_to_server(host=
|
51
|
+
def connect_to_server(host=_default_host, port=_default_port):
|
50
52
|
return DSMQClientSideConnection(host, port)
|
51
53
|
|
52
54
|
|
@@ -56,22 +58,55 @@ class DSMQClientSideConnection:
|
|
56
58
|
self.dsmq_conn.connect((host, port))
|
57
59
|
|
58
60
|
def get(self, topic):
|
59
|
-
|
60
|
-
self.dsmq_conn
|
61
|
+
msg_dict = {"action": "get", "topic": topic}
|
62
|
+
_send_message(self.dsmq_conn, msg_dict)
|
61
63
|
|
62
|
-
|
63
|
-
if
|
64
|
+
msg = _receive_message(self.dsmq_conn)
|
65
|
+
if msg is None:
|
64
66
|
raise RuntimeError("Connection terminated by server")
|
65
|
-
|
66
|
-
msg = json.loads(msg_str)
|
67
|
-
try:
|
68
|
-
return msg["message"]
|
69
|
-
except KeyError:
|
70
|
-
return ""
|
67
|
+
return msg["message"]
|
71
68
|
|
72
|
-
def put(self, topic,
|
73
|
-
|
74
|
-
self.dsmq_conn
|
69
|
+
def put(self, topic, msg_body):
|
70
|
+
msg_dict = {"action": "put", "topic": topic, "message": msg_body}
|
71
|
+
_send_message(self.dsmq_conn, msg_dict)
|
72
|
+
|
73
|
+
|
74
|
+
def _send_message(socket_conn, msg_dict):
|
75
|
+
msg = json.dumps(msg_dict)
|
76
|
+
msg_bytes = bytes(msg, "utf-8")
|
77
|
+
n_bytes = len(msg_bytes)
|
78
|
+
|
79
|
+
# Send a header first.
|
80
|
+
# Add a large number to ensure that the message is the same size each time.
|
81
|
+
header_dict = {"msg_length": n_bytes + _message_length_offset}
|
82
|
+
header = json.dumps(header_dict)
|
83
|
+
header_bytes = bytes(header, "utf-8")
|
84
|
+
socket_conn.sendall(header_bytes)
|
85
|
+
|
86
|
+
socket_conn.sendall(msg_bytes)
|
87
|
+
|
88
|
+
|
89
|
+
def _receive_message(socket_conn):
|
90
|
+
# First receive a header
|
91
|
+
header_data = socket_conn.recv(_header_length)
|
92
|
+
if header_data is None:
|
93
|
+
return None
|
94
|
+
if len(header_data) == 0:
|
95
|
+
return None
|
96
|
+
|
97
|
+
header_str = header_data.decode("utf-8")
|
98
|
+
header = json.loads(header_str)
|
99
|
+
msg_length = header["msg_length"] - _message_length_offset
|
100
|
+
|
101
|
+
data = socket_conn.recv(msg_length)
|
102
|
+
if data is None:
|
103
|
+
return None
|
104
|
+
if len(data) == 0:
|
105
|
+
return None
|
106
|
+
|
107
|
+
msg_str = data.decode("utf-8")
|
108
|
+
msg = json.loads(msg_str)
|
109
|
+
return msg
|
75
110
|
|
76
111
|
|
77
112
|
def _handle_client_connection(socket_conn):
|
@@ -83,19 +118,10 @@ def _handle_client_connection(socket_conn):
|
|
83
118
|
time_of_last_purge = time.time()
|
84
119
|
|
85
120
|
while True:
|
86
|
-
|
87
|
-
|
88
|
-
if not data:
|
121
|
+
msg = _receive_message(socket_conn)
|
122
|
+
if msg is None:
|
89
123
|
break
|
90
124
|
|
91
|
-
msg_str = data.decode("utf-8")
|
92
|
-
try:
|
93
|
-
msg = json.loads(msg_str)
|
94
|
-
except json.decoder.JSONDecodeError:
|
95
|
-
print("Message must be json-friendly")
|
96
|
-
print(f" Received: {msg}")
|
97
|
-
continue
|
98
|
-
|
99
125
|
topic = msg["topic"]
|
100
126
|
timestamp = time.time()
|
101
127
|
|
@@ -104,7 +130,7 @@ def _handle_client_connection(socket_conn):
|
|
104
130
|
|
105
131
|
# This block allows for multiple retries if the database
|
106
132
|
# is busy.
|
107
|
-
for i_retry in range(
|
133
|
+
for i_retry in range(_n_retries):
|
108
134
|
try:
|
109
135
|
cursor.execute(
|
110
136
|
"""
|
@@ -115,7 +141,7 @@ VALUES (:timestamp, :topic, :message)
|
|
115
141
|
)
|
116
142
|
sqlite_conn.commit()
|
117
143
|
except sqlite3.OperationalError:
|
118
|
-
wait_time =
|
144
|
+
wait_time = _first_retry * 2**i_retry
|
119
145
|
time.sleep(wait_time)
|
120
146
|
continue
|
121
147
|
break
|
@@ -130,7 +156,7 @@ VALUES (:timestamp, :topic, :message)
|
|
130
156
|
|
131
157
|
# This block allows for multiple retries if the database
|
132
158
|
# is busy.
|
133
|
-
for i_retry in range(
|
159
|
+
for i_retry in range(_n_retries):
|
134
160
|
try:
|
135
161
|
cursor.execute(
|
136
162
|
"""
|
@@ -149,7 +175,7 @@ AND timestamp = a.min_time
|
|
149
175
|
msg,
|
150
176
|
)
|
151
177
|
except sqlite3.OperationalError:
|
152
|
-
wait_time =
|
178
|
+
wait_time = _first_retry * 2**i_retry
|
153
179
|
time.sleep(wait_time)
|
154
180
|
continue
|
155
181
|
break
|
@@ -163,15 +189,14 @@ AND timestamp = a.min_time
|
|
163
189
|
# Handle the case where no results are returned
|
164
190
|
message = ""
|
165
191
|
|
166
|
-
|
167
|
-
socket_conn.sendall(bytes(msg, "utf-8"))
|
192
|
+
_send_message(socket_conn, {"message": message})
|
168
193
|
else:
|
169
194
|
print("Action must either be 'put' or 'get'")
|
170
195
|
|
171
196
|
# Periodically clean out messages from the queue that are
|
172
197
|
# past their sell buy date.
|
173
198
|
# This operation is pretty fast. I clock it at 12 us on my machine.
|
174
|
-
if time.time() - time_of_last_purge >
|
199
|
+
if time.time() - time_of_last_purge > _time_to_live:
|
175
200
|
cursor.execute(
|
176
201
|
"""
|
177
202
|
DELETE FROM messages
|
@@ -1,10 +1,10 @@
|
|
1
1
|
dsmq/__init__.py,sha256=YCgbnQAk8YbtHRyMcU0v2O7RdRhPhlT-vS_q40a7Q6g,50
|
2
2
|
dsmq/demo_linux.py,sha256=7yLglGmirDLuuyMxppYSK-dfx2Fg2Q0dIWB4cl2yV1c,622
|
3
|
-
dsmq/dsmq.py,sha256=
|
3
|
+
dsmq/dsmq.py,sha256=f-dR-Pjjn_gDx-EK1evYQWvDq8ypXbhx6DaCWHCInSc,6744
|
4
4
|
dsmq/example_get_client.py,sha256=chFfB2949PBENmgdUc3ASrATq1m4wvHGBzEnOC-o_Xs,296
|
5
5
|
dsmq/example_put_client.py,sha256=mUKCRhmUieMZEpHLFWFvzeKB6IR7A8l4tWN8TvPzdKU,348
|
6
6
|
dsmq/example_server.py,sha256=kkXOPaaTzVxf9_iIM76zU9pZhkPna_1vcGWkPrhCjus,61
|
7
|
-
dsmq-0.
|
8
|
-
dsmq-0.
|
9
|
-
dsmq-0.
|
10
|
-
dsmq-0.
|
7
|
+
dsmq-0.7.0.dist-info/METADATA,sha256=NFG4GQwX9RqIKLR3xvFelzuTVebieS4sJqZ9uFu24Lw,4006
|
8
|
+
dsmq-0.7.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
9
|
+
dsmq-0.7.0.dist-info/licenses/LICENSE,sha256=3Yu1mAp5VsKmnDtzkiOY7BdmrLeNwwZ3t6iWaLnlL0Y,1071
|
10
|
+
dsmq-0.7.0.dist-info/RECORD,,
|
File without changes
|