dsmq 1.3.1__py3-none-any.whl → 1.4.1__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/client.py +33 -2
- dsmq/demo.py +12 -3
- dsmq/server.py +95 -42
- dsmq/tests/integration_test.py +44 -17
- dsmq/tests/performance_suite.py +10 -2
- {dsmq-1.3.1.dist-info → dsmq-1.4.1.dist-info}/METADATA +13 -2
- dsmq-1.4.1.dist-info/RECORD +13 -0
- dsmq-1.3.1.dist-info/RECORD +0 -13
- {dsmq-1.3.1.dist-info → dsmq-1.4.1.dist-info}/WHEEL +0 -0
- {dsmq-1.3.1.dist-info → dsmq-1.4.1.dist-info}/licenses/LICENSE +0 -0
dsmq/client.py
CHANGED
@@ -18,6 +18,7 @@ def connect(host=_default_host, port=_default_port, verbose=False):
|
|
18
18
|
class DSMQClientSideConnection:
|
19
19
|
def __init__(self, host, port, verbose=False):
|
20
20
|
self.uri = f"ws://{host}:{port}"
|
21
|
+
self.port = port
|
21
22
|
self.verbose = verbose
|
22
23
|
if self.verbose:
|
23
24
|
print(f"Connecting to dsmq server at {self.uri}")
|
@@ -40,7 +41,11 @@ class DSMQClientSideConnection:
|
|
40
41
|
|
41
42
|
def get(self, topic):
|
42
43
|
msg = {"action": "get", "topic": topic}
|
43
|
-
|
44
|
+
try:
|
45
|
+
self.websocket.send(json.dumps(msg))
|
46
|
+
except ConnectionClosedError:
|
47
|
+
return ""
|
48
|
+
|
44
49
|
try:
|
45
50
|
msg_text = self.websocket.recv()
|
46
51
|
except ConnectionClosedError:
|
@@ -50,6 +55,29 @@ class DSMQClientSideConnection:
|
|
50
55
|
msg = json.loads(msg_text)
|
51
56
|
return msg["message"]
|
52
57
|
|
58
|
+
def get_latest(self, topic):
|
59
|
+
"""
|
60
|
+
A variant of `get()` that grabs the latest available message
|
61
|
+
(if there is one) rather than grabbing the oldest unread message.
|
62
|
+
It will not go back to read older ones on subsequent calls;
|
63
|
+
it will leave them unread.
|
64
|
+
"""
|
65
|
+
msg = {"action": "get_latest", "topic": topic}
|
66
|
+
try:
|
67
|
+
self.websocket.send(json.dumps(msg))
|
68
|
+
except ConnectionClosedError:
|
69
|
+
return ""
|
70
|
+
|
71
|
+
try:
|
72
|
+
msg_text = self.websocket.recv()
|
73
|
+
except ConnectionClosedError:
|
74
|
+
self.close()
|
75
|
+
return ""
|
76
|
+
|
77
|
+
msg = json.loads(msg_text)
|
78
|
+
|
79
|
+
return msg["message"]
|
80
|
+
|
53
81
|
def get_wait(self, topic):
|
54
82
|
"""
|
55
83
|
A variant of `get()` that retries a few times until it gets
|
@@ -65,7 +93,10 @@ class DSMQClientSideConnection:
|
|
65
93
|
|
66
94
|
def put(self, topic, msg_body):
|
67
95
|
msg_dict = {"action": "put", "topic": topic, "message": msg_body}
|
68
|
-
|
96
|
+
try:
|
97
|
+
self.websocket.send(json.dumps(msg_dict))
|
98
|
+
except ConnectionClosedError:
|
99
|
+
return
|
69
100
|
|
70
101
|
def shutdown_server(self):
|
71
102
|
msg_dict = {"action": "shutdown", "topic": ""}
|
dsmq/demo.py
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
import multiprocessing as mp
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
|
3
|
+
# spawn is the default method on macOS,
|
4
|
+
# starting in Python 3.14 it will be the default in Linux too.
|
5
|
+
try:
|
6
|
+
mp.set_start_method("spawn")
|
7
|
+
except RuntimeError:
|
8
|
+
# Will throw an error if the start method has alraedy been set.
|
9
|
+
pass
|
10
|
+
|
11
|
+
from dsmq.server import serve # noqa: E402
|
12
|
+
import dsmq.example_get_client # noqa: E402
|
13
|
+
import dsmq.example_put_client # noqa: E402
|
5
14
|
|
6
15
|
HOST = "127.0.0.1"
|
7
16
|
PORT = 25252
|
dsmq/server.py
CHANGED
@@ -9,10 +9,12 @@ from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK
|
|
9
9
|
|
10
10
|
_default_host = "127.0.0.1"
|
11
11
|
_default_port = 30008
|
12
|
-
_n_retries = 20
|
13
|
-
_first_retry = 0.005 # seconds
|
14
|
-
_time_between_cleanup = 0.05 # seconds
|
15
12
|
_max_queue_length = 10
|
13
|
+
_shutdown_pause = 1.0 # seconds
|
14
|
+
_time_between_cleanup = 3.0 # seconds
|
15
|
+
_time_to_keep = 0.3 # seconds
|
16
|
+
# _time_between_cleanup = 60.0 # seconds
|
17
|
+
# _time_to_keep = 10.0 # seconds
|
16
18
|
|
17
19
|
# Make this global so it's easy to share
|
18
20
|
dsmq_server = None
|
@@ -42,10 +44,15 @@ def serve(
|
|
42
44
|
# and keep long-term latency more predictable.
|
43
45
|
# These also make it more susceptible to corruption during shutdown,
|
44
46
|
# but since dsmq is meant to be ephemeral, that's not a concern.
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
cursor.execute("PRAGMA
|
47
|
+
# See https://www.sqlite.org/pragma.html
|
48
|
+
# After playing around with them, I'm not sure these have any noticeable effect.
|
49
|
+
#
|
50
|
+
# cursor.execute("PRAGMA journal_mode = OFF")
|
51
|
+
# cursor.execute("PRAGMA journal_mode = MEMORY")
|
52
|
+
# cursor.execute("PRAGMA synchronous = NORMAL")
|
53
|
+
# cursor.execute("PRAGMA synchronous = OFF")
|
54
|
+
# cursor.execute("PRAGMA secure_delete = OFF")
|
55
|
+
# cursor.execute("PRAGMA temp_store = MEMORY")
|
49
56
|
|
50
57
|
cursor.execute("""
|
51
58
|
CREATE TABLE IF NOT EXISTS messages (timestamp DOUBLE, topic TEXT, message TEXT)
|
@@ -56,36 +63,33 @@ CREATE TABLE IF NOT EXISTS messages (timestamp DOUBLE, topic TEXT, message TEXT)
|
|
56
63
|
# and a method of last resort.
|
57
64
|
global dsmq_server
|
58
65
|
|
59
|
-
|
60
|
-
|
66
|
+
try:
|
67
|
+
with ws_serve(request_handler, host, port) as dsmq_server:
|
68
|
+
dsmq_server.serve_forever()
|
69
|
+
|
70
|
+
except OSError:
|
71
|
+
# Catch the case where the address is already in use
|
72
|
+
if verbose:
|
73
|
+
print()
|
74
|
+
print(f"Found a dsmq server already running on {host} on port {port}.")
|
75
|
+
print(" Closing it down.")
|
76
|
+
|
77
|
+
def shutdown_gracefully(server_to_shutdown):
|
78
|
+
server_to_shutdown.shutdown()
|
79
|
+
|
80
|
+
Thread(target=shutdown_gracefully, args=(dsmq_server,)).start()
|
81
|
+
time.sleep(_shutdown_pause)
|
82
|
+
|
61
83
|
with ws_serve(request_handler, host, port) as dsmq_server:
|
62
84
|
dsmq_server.serve_forever()
|
63
85
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
break
|
70
|
-
|
71
|
-
except OSError:
|
72
|
-
# Catch the case where the address is already in use
|
73
|
-
if verbose:
|
74
|
-
print()
|
75
|
-
if i_retry < _n_retries - 1:
|
76
|
-
print(f"Couldn't start dsmq server on {host} on port {port}.")
|
77
|
-
print(f" Trying again ({i_retry}) ...")
|
78
|
-
else:
|
79
|
-
print()
|
80
|
-
print(f"Failed to start dsmq server on {host} on port {port}.")
|
81
|
-
print()
|
82
|
-
raise
|
83
|
-
|
84
|
-
wait_time = _first_retry * 2**i_retry
|
85
|
-
time.sleep(wait_time)
|
86
|
+
if verbose:
|
87
|
+
print()
|
88
|
+
print(f"Server started at {host} on port {port}.")
|
89
|
+
print("Waiting for clients...")
|
86
90
|
|
87
91
|
sqlite_conn.close()
|
88
|
-
time.sleep(
|
92
|
+
time.sleep(_shutdown_pause)
|
89
93
|
cleanup_temp_files()
|
90
94
|
|
91
95
|
|
@@ -121,9 +125,10 @@ def request_handler(websocket):
|
|
121
125
|
for msg_text in websocket:
|
122
126
|
msg = json.loads(msg_text)
|
123
127
|
topic = msg["topic"]
|
128
|
+
action = msg["action"]
|
124
129
|
timestamp = time.time()
|
125
130
|
|
126
|
-
if
|
131
|
+
if action == "put":
|
127
132
|
msg["timestamp"] = timestamp
|
128
133
|
|
129
134
|
try:
|
@@ -138,7 +143,7 @@ def request_handler(websocket):
|
|
138
143
|
except sqlite3.OperationalError:
|
139
144
|
pass
|
140
145
|
|
141
|
-
elif
|
146
|
+
elif action == "get":
|
142
147
|
try:
|
143
148
|
last_read_time = last_read_times[topic]
|
144
149
|
except KeyError:
|
@@ -151,15 +156,46 @@ def request_handler(websocket):
|
|
151
156
|
"""
|
152
157
|
SELECT message,
|
153
158
|
timestamp
|
154
|
-
FROM messages,
|
155
|
-
(
|
156
|
-
SELECT MIN(timestamp) AS min_time
|
157
159
|
FROM messages
|
158
160
|
WHERE topic = :topic
|
159
161
|
AND timestamp > :last_read_time
|
160
|
-
|
162
|
+
ORDER BY timestamp ASC
|
163
|
+
LIMIT 1
|
164
|
+
""",
|
165
|
+
msg,
|
166
|
+
)
|
167
|
+
except sqlite3.OperationalError:
|
168
|
+
pass
|
169
|
+
|
170
|
+
try:
|
171
|
+
result = cursor.fetchall()[0]
|
172
|
+
message = result[0]
|
173
|
+
timestamp = result[1]
|
174
|
+
last_read_times[topic] = timestamp
|
175
|
+
except IndexError:
|
176
|
+
# Handle the case where no results are returned
|
177
|
+
message = ""
|
178
|
+
|
179
|
+
websocket.send(json.dumps({"message": message}))
|
180
|
+
|
181
|
+
elif action == "get_latest":
|
182
|
+
try:
|
183
|
+
last_read_time = last_read_times[topic]
|
184
|
+
except KeyError:
|
185
|
+
last_read_times[topic] = client_creation_time
|
186
|
+
last_read_time = last_read_times[topic]
|
187
|
+
msg["last_read_time"] = last_read_time
|
188
|
+
|
189
|
+
try:
|
190
|
+
cursor.execute(
|
191
|
+
"""
|
192
|
+
SELECT message,
|
193
|
+
timestamp
|
194
|
+
FROM messages
|
161
195
|
WHERE topic = :topic
|
162
|
-
AND timestamp
|
196
|
+
AND timestamp > :last_read_time
|
197
|
+
ORDER BY timestamp DESC
|
198
|
+
LIMIT 1;
|
163
199
|
""",
|
164
200
|
msg,
|
165
201
|
)
|
@@ -177,25 +213,41 @@ def request_handler(websocket):
|
|
177
213
|
|
178
214
|
websocket.send(json.dumps({"message": message}))
|
179
215
|
|
180
|
-
elif
|
216
|
+
elif action == "shutdown":
|
181
217
|
# Run this from a separate thread to prevent deadlock
|
182
218
|
global dsmq_server
|
183
219
|
|
184
220
|
def shutdown_gracefully(server_to_shutdown):
|
185
221
|
server_to_shutdown.shutdown()
|
186
|
-
# cleanup_temp_files()
|
187
222
|
|
188
223
|
Thread(target=shutdown_gracefully, args=(dsmq_server,)).start()
|
189
224
|
break
|
190
225
|
else:
|
191
226
|
raise RuntimeWarning(
|
192
|
-
"dsmq client action must either be
|
227
|
+
"dsmq client action must either be\n"
|
228
|
+
+ "'put', 'get', 'get_wait', 'get_latest', or 'shutdown'"
|
193
229
|
)
|
194
230
|
|
195
231
|
# Periodically clean out messages to keep individual queues at
|
196
232
|
# a manageable length and the overall mq small.
|
197
233
|
if time.time() - time_of_last_purge > _time_between_cleanup:
|
234
|
+
cutoff_time = time.time() - _time_to_keep
|
198
235
|
try:
|
236
|
+
cursor.execute(
|
237
|
+
"""
|
238
|
+
DELETE
|
239
|
+
FROM messages
|
240
|
+
WHERE topic = :topic
|
241
|
+
AND timestamp < :cutoff_time
|
242
|
+
""",
|
243
|
+
{
|
244
|
+
"cutoff_time": cutoff_time,
|
245
|
+
"topic": topic,
|
246
|
+
},
|
247
|
+
)
|
248
|
+
sqlite_conn.commit()
|
249
|
+
time_of_last_purge = time.time()
|
250
|
+
|
199
251
|
cursor.execute(
|
200
252
|
"""
|
201
253
|
DELETE
|
@@ -219,6 +271,7 @@ def request_handler(websocket):
|
|
219
271
|
)
|
220
272
|
sqlite_conn.commit()
|
221
273
|
time_of_last_purge = time.time()
|
274
|
+
|
222
275
|
except sqlite3.OperationalError:
|
223
276
|
# Database may be locked. Try again next time.
|
224
277
|
pass
|
dsmq/tests/integration_test.py
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
import multiprocessing as mp
|
2
|
+
|
3
|
+
try:
|
4
|
+
# spawn is the default method on macOS,
|
5
|
+
# starting in Python 3.14 it will be the default in Linux too.
|
6
|
+
mp.set_start_method("spawn")
|
7
|
+
except RuntimeError:
|
8
|
+
# Will throw an error if the start method has alraedy been set.
|
9
|
+
pass
|
10
|
+
|
2
11
|
import time
|
3
12
|
from dsmq.server import serve
|
4
13
|
from dsmq.client import connect
|
5
14
|
|
6
|
-
# spawn is the default method on macOS
|
7
|
-
# mp.set_start_method('spawn')
|
8
15
|
|
9
16
|
host = "127.0.0.1"
|
10
17
|
port = 30303
|
@@ -53,6 +60,10 @@ def test_write_one_read_one():
|
|
53
60
|
write_client = connect(host, port)
|
54
61
|
read_client = connect(host, port)
|
55
62
|
|
63
|
+
msg = read_client.get("test")
|
64
|
+
|
65
|
+
assert msg == ""
|
66
|
+
|
56
67
|
write_client.put("test", "test_msg")
|
57
68
|
|
58
69
|
# It takes a moment for the write to complete
|
@@ -61,6 +72,10 @@ def test_write_one_read_one():
|
|
61
72
|
|
62
73
|
assert msg == "test_msg"
|
63
74
|
|
75
|
+
msg = read_client.get("test")
|
76
|
+
|
77
|
+
assert msg == ""
|
78
|
+
|
64
79
|
write_client.shutdown_server()
|
65
80
|
write_client.close()
|
66
81
|
read_client.close()
|
@@ -83,6 +98,29 @@ def test_get_wait():
|
|
83
98
|
read_client.close()
|
84
99
|
|
85
100
|
|
101
|
+
def test_get_latest():
|
102
|
+
p_server = mp.Process(target=serve, args=(host, port))
|
103
|
+
p_server.start()
|
104
|
+
write_client = connect(host, port)
|
105
|
+
read_client = connect(host, port)
|
106
|
+
|
107
|
+
for i in range(5):
|
108
|
+
write_client.put("test", f"test_msg {i}")
|
109
|
+
|
110
|
+
time.sleep(_pause)
|
111
|
+
msg = read_client.get_latest("test")
|
112
|
+
|
113
|
+
assert msg == "test_msg 4"
|
114
|
+
|
115
|
+
msg = read_client.get_latest("test")
|
116
|
+
|
117
|
+
assert msg == ""
|
118
|
+
|
119
|
+
write_client.shutdown_server()
|
120
|
+
write_client.close()
|
121
|
+
read_client.close()
|
122
|
+
|
123
|
+
|
86
124
|
def test_multitopics():
|
87
125
|
p_server = mp.Process(target=serve, args=(host, port))
|
88
126
|
p_server.start()
|
@@ -183,15 +221,8 @@ def test_speed_writing():
|
|
183
221
|
p_speed_write.start()
|
184
222
|
time.sleep(_pause)
|
185
223
|
|
186
|
-
# time_a = time.time()
|
187
224
|
write_client.put("test", "test_msg")
|
188
|
-
# time_b = time.time()
|
189
225
|
msg = read_client.get_wait("test")
|
190
|
-
# time_c = time.time()
|
191
|
-
|
192
|
-
# write_time = int((time_b - time_a) * 1e6)
|
193
|
-
# read_time = int((time_c - time_b) * 1e6)
|
194
|
-
# print(f"write time: {write_time} us, read time: {read_time} us")
|
195
226
|
|
196
227
|
assert msg == "test_msg"
|
197
228
|
|
@@ -221,15 +252,8 @@ def test_speed_reading():
|
|
221
252
|
p_speed_read = mp.Process(target=speed_read, args=(stop_flag,))
|
222
253
|
p_speed_read.start()
|
223
254
|
|
224
|
-
# time_a = time.time()
|
225
255
|
write_client.put("test", "test_msg")
|
226
|
-
# time_b = time.time()
|
227
256
|
msg = read_client.get_wait("test")
|
228
|
-
# time_c = time.time()
|
229
|
-
|
230
|
-
# write_time = int((time_b - time_a) * 1e6)
|
231
|
-
# read_time = int((time_c - time_b) * 1e6)
|
232
|
-
# print(f"write time: {write_time} us, read time: {read_time} us")
|
233
257
|
|
234
258
|
assert msg == "test_msg"
|
235
259
|
|
@@ -238,5 +262,8 @@ def test_speed_reading():
|
|
238
262
|
p_speed_read.kill()
|
239
263
|
read_client.close()
|
240
264
|
write_client.shutdown_server()
|
241
|
-
# time.sleep(_pause)
|
242
265
|
write_client.close()
|
266
|
+
|
267
|
+
|
268
|
+
if __name__ == "__main__":
|
269
|
+
test_get_latest()
|
dsmq/tests/performance_suite.py
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
import multiprocessing as mp
|
2
|
+
|
3
|
+
# spawn is the default method on macOS,
|
4
|
+
# starting in Python 3.14 it will be the default in Linux too.
|
5
|
+
try:
|
6
|
+
mp.set_start_method("spawn")
|
7
|
+
except RuntimeError:
|
8
|
+
pass
|
9
|
+
|
2
10
|
import time
|
3
11
|
|
4
12
|
from dsmq.server import serve
|
@@ -11,8 +19,8 @@ verbose = False
|
|
11
19
|
_pause = 0.01
|
12
20
|
_very_long_pause = 1.0
|
13
21
|
|
14
|
-
_n_iter = int(
|
15
|
-
_n_long_char = int(
|
22
|
+
_n_iter = int(1e4)
|
23
|
+
_n_long_char = int(1e5)
|
16
24
|
|
17
25
|
_short_msg = "q"
|
18
26
|
_long_msg = str(["q"] * _n_long_char)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dsmq
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.4.1
|
4
4
|
Summary: A dead simple message queue
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.10
|
@@ -102,7 +102,8 @@ a queue before it connected.
|
|
102
102
|
- A client will get the oldest message available on a requested topic.
|
103
103
|
Queues are first-in-first-out.
|
104
104
|
|
105
|
-
- Messages older than
|
105
|
+
- Messages older than a certain age (typically 600 seconds)
|
106
|
+
will be deleted from the queue.
|
106
107
|
|
107
108
|
- Put and get operations are fairly quick--less than 100 $`\mu`$s of processing
|
108
109
|
time plus any network latency--so it can comfortably handle requests at rates of
|
@@ -152,6 +153,16 @@ connected to the server.
|
|
152
153
|
in the topic, or the topic doesn't yet exist,
|
153
154
|
returns `""`.
|
154
155
|
|
156
|
+
### `get_latest(topic)`
|
157
|
+
|
158
|
+
Get the *most recent* eligible message from the queue named `topic`.
|
159
|
+
All the messages older than that in the queue become ineligible and never
|
160
|
+
get seen by the client.
|
161
|
+
- `topic` (str)
|
162
|
+
- returns str, the content of the message. If there was no eligble message
|
163
|
+
in the topic, or the topic doesn't yet exist,
|
164
|
+
returns `""`.
|
165
|
+
|
155
166
|
### `get_wait(topic)`
|
156
167
|
|
157
168
|
A variant of `get()` that retries a few times until it gets
|
@@ -0,0 +1,13 @@
|
|
1
|
+
dsmq/__init__.py,sha256=YCgbnQAk8YbtHRyMcU0v2O7RdRhPhlT-vS_q40a7Q6g,50
|
2
|
+
dsmq/client.py,sha256=a4_6jcF7RAC58And0OlR3vL42FgZ24q2BECS-VF4Ri4,3438
|
3
|
+
dsmq/demo.py,sha256=HCnoucawZ2CU0rGipLgsZjVUpP7232mUcugmhf_DjBQ,825
|
4
|
+
dsmq/example_get_client.py,sha256=PvAsDGEAH1kVBifLVg2rx8ZxnAZmvzVCvZq13VgpLds,301
|
5
|
+
dsmq/example_put_client.py,sha256=QxDc3i7KAjjhpwxRRpI0Ke5KTNSPuBf9kkcGyTvUEaw,353
|
6
|
+
dsmq/server.py,sha256=PbmbW95VunRrQM24AdzX9HbqWPixt7XrAINV1yiHpxo,10210
|
7
|
+
dsmq/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
dsmq/tests/integration_test.py,sha256=zF6v_3UHt5KqveX22gEpCSLcoeOyEWLSy_gMLoytg2U,6303
|
9
|
+
dsmq/tests/performance_suite.py,sha256=g95jm0u2sa-1hm6m10aoRgN7_tynXFxU-bimy3V2wZM,5391
|
10
|
+
dsmq-1.4.1.dist-info/METADATA,sha256=LuoL1eb8_zH2bDCY7QRlKrZ3ndK0UJ1gXJKZ-4miWYc,5229
|
11
|
+
dsmq-1.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
+
dsmq-1.4.1.dist-info/licenses/LICENSE,sha256=3Yu1mAp5VsKmnDtzkiOY7BdmrLeNwwZ3t6iWaLnlL0Y,1071
|
13
|
+
dsmq-1.4.1.dist-info/RECORD,,
|
dsmq-1.3.1.dist-info/RECORD
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
dsmq/__init__.py,sha256=YCgbnQAk8YbtHRyMcU0v2O7RdRhPhlT-vS_q40a7Q6g,50
|
2
|
-
dsmq/client.py,sha256=ZsbuvsWX6_4-tkp7i3ixYAPEyvoebKX8qFtW38DHdXE,2569
|
3
|
-
dsmq/demo.py,sha256=K53cC5kN7K4kNJlPq7c5OTIMHRCKTo9hYX2aIos57rU,542
|
4
|
-
dsmq/example_get_client.py,sha256=PvAsDGEAH1kVBifLVg2rx8ZxnAZmvzVCvZq13VgpLds,301
|
5
|
-
dsmq/example_put_client.py,sha256=QxDc3i7KAjjhpwxRRpI0Ke5KTNSPuBf9kkcGyTvUEaw,353
|
6
|
-
dsmq/server.py,sha256=HXPH9-nSzz2Iy2UzIWqgUVbL174jq1VBzs7im9vRLqk,8268
|
7
|
-
dsmq/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
dsmq/tests/integration_test.py,sha256=dLsQGCmpXv4zRb93TriccH7TbUyD9MHcLckAQqfDOK4,5980
|
9
|
-
dsmq/tests/performance_suite.py,sha256=E59zB2ZvM8V5f8RxaB7p-Kehqyhrgsl0sXuy7g74BaI,5218
|
10
|
-
dsmq-1.3.1.dist-info/METADATA,sha256=K6fqrudTKsXR2xlHDlTNkrjepNcsKn5kX9I5yjpzxPk,4859
|
11
|
-
dsmq-1.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
-
dsmq-1.3.1.dist-info/licenses/LICENSE,sha256=3Yu1mAp5VsKmnDtzkiOY7BdmrLeNwwZ3t6iWaLnlL0Y,1071
|
13
|
-
dsmq-1.3.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|