dsmq 0.2.0__py3-none-any.whl → 0.3.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/demo_linux.py CHANGED
@@ -11,7 +11,7 @@ PORT = 25252
11
11
 
12
12
 
13
13
  def test_server_with_clients():
14
- p_server = mp.Process(target=dsmq.run, args=(HOST, PORT))
14
+ p_server = mp.Process(target=dsmq.start_server, args=(HOST, PORT))
15
15
  p_server.start()
16
16
 
17
17
  p_putter = mp.Process(target=example_put_client.run, args=(HOST, PORT, 20))
dsmq/dsmq.py CHANGED
@@ -5,11 +5,19 @@ import sys
5
5
  from threading import Thread
6
6
  import time
7
7
 
8
+ DEFAULT_HOST = "127.0.0.1"
9
+ DEFAULT_PORT = 30008
10
+
8
11
  N_RETRIES = 5
9
12
  FIRST_RETRY = 0.01 # seconds
10
13
 
11
14
 
12
- def run(host="127.0.0.1", port=30008):
15
+ def start_server(host=DEFAULT_HOST, port=DEFAULT_PORT):
16
+ """
17
+ For best results, start this running in its own process and walk away.
18
+
19
+
20
+ """
13
21
  sqlite_conn = sqlite3.connect("file:mem1?mode=memory&cache=shared")
14
22
  cursor = sqlite_conn.cursor()
15
23
 
@@ -34,12 +42,37 @@ def run(host="127.0.0.1", port=30008):
34
42
  while True:
35
43
  socket_conn, addr = s.accept()
36
44
  print(f"Connected by {addr}")
37
- Thread(target=handle_socket, args=(socket_conn,)).start()
45
+ Thread(target=_handle_client_connection, args=(socket_conn,)).start()
38
46
 
39
47
  sqlite_conn.close()
40
48
 
41
49
 
42
- def handle_socket(socket_conn):
50
+ def connect_to_server(host=DEFAULT_HOST, port=DEFAULT_PORT):
51
+ return DSMQClientSideConnection(host, port)
52
+
53
+
54
+ class DSMQClientSideConnection:
55
+ def __init__(self, host, port):
56
+ self.dsmq_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
57
+ self.dsmq_conn.connect((host, port))
58
+
59
+ def get(self, topic):
60
+ msg = json.dumps({"action": "get", "topic": topic})
61
+ self.dsmq_conn.sendall(bytes(msg, "utf-8"))
62
+
63
+ data = self.dsmq_conn.recv(1024)
64
+ if not data:
65
+ raise RuntimeError("Connection terminated by server")
66
+ msg_str = data.decode("utf-8")
67
+ msg = json.loads(msg_str)
68
+ return msg
69
+
70
+ def put(self, topic, msg):
71
+ msg = json.dumps({"action": "put", "topic": topic, "message": msg})
72
+ self.dsmq_conn.sendall(bytes(msg, "utf-8"))
73
+
74
+
75
+ def _handle_client_connection(socket_conn):
43
76
  sqlite_conn = sqlite3.connect("file:mem1?mode=memory&cache=shared")
44
77
  cursor = sqlite_conn.cursor()
45
78
 
@@ -140,12 +173,12 @@ if __name__ == "__main__":
140
173
  if len(sys.argv) == 3:
141
174
  host = sys.argv[1]
142
175
  port = int(sys.argv[2])
143
- run(host=host, port=port)
176
+ start_server(host=host, port=port)
144
177
  elif len(sys.argv) == 2:
145
178
  host = sys.argv[1]
146
- run(host=host)
179
+ start_server(host=host)
147
180
  elif len(sys.argv) == 1:
148
- run()
181
+ start_server()
149
182
  else:
150
183
  print(
151
184
  """
@@ -1,21 +1,15 @@
1
1
  import json
2
- import socket
3
2
  import time
3
+ import dsmq
4
4
 
5
5
 
6
6
  def run(host="127.0.0.1", port=30008, n_iter=1000):
7
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
8
- s.connect((host, port))
7
+ mq = dsmq.connect_to_server(host=host, port=port)
9
8
 
10
- for i in range(n_iter):
11
- time.sleep(1)
12
- msg = json.dumps({"action": "get", "topic": "greetings"})
13
- s.sendall(bytes(msg, "utf-8"))
14
- data = s.recv(1024)
15
- if not data:
16
- raise RuntimeError("Connection terminated by server")
17
- msg_str = data.decode("utf-8")
18
- print(f"client received {json.loads(msg_str)}")
9
+ for i in range(n_iter):
10
+ time.sleep(1)
11
+ msg = mq.get("greetings")
12
+ print(f"client received {msg}")
19
13
 
20
14
 
21
15
  if __name__ == "__main__":
@@ -1,18 +1,18 @@
1
1
  import json
2
2
  import socket
3
3
  import time
4
+ import dsmq
4
5
 
5
6
 
6
7
  def run(host="127.0.0.1", port=30008, n_iter=1000):
7
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
8
- s.connect((host, port))
8
+ mq = dsmq.connect_to_server(host=host, port=port)
9
9
 
10
- for i in range(n_iter):
11
- time.sleep(1)
12
- note = f"{i}. Hello, world"
13
- msg = json.dumps({"action": "put", "topic": "greetings", "message": note})
14
- s.sendall(bytes(msg, "utf-8"))
15
- print(f"client sent {msg}")
10
+ for i in range(n_iter):
11
+ time.sleep(1)
12
+ msg = f"{i}. Hello, world"
13
+ topic = "greetings"
14
+ mq.put(topic, msg)
15
+ print(f"client sent {msg}")
16
16
 
17
17
 
18
18
  if __name__ == "__main__":
dsmq/example_server.py CHANGED
@@ -1,3 +1,3 @@
1
- from dsmq import dsmq
1
+ import dsmq
2
2
 
3
- dsmq.run(host="127.0.0.1", port=12345)
3
+ dsmq.start_server(host="127.0.0.1", port=30008)
@@ -0,0 +1,129 @@
1
+ Metadata-Version: 2.3
2
+ Name: dsmq
3
+ Version: 0.3.0
4
+ Summary: A dead simple message queue
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+
9
+ # Dead Simple Message Queue
10
+
11
+ ## What it does
12
+
13
+ Part mail room, part bulletin board, dsmq is a central location for sharing messages
14
+ between processes, even when they are running on computers scattered around the world.
15
+
16
+ Its defining characteristic is bare-bones simplicity.
17
+
18
+ ## How to use it
19
+
20
+ ### Install
21
+
22
+ ```bash
23
+ pip install dsmq
24
+ ```
25
+ ### Create a dsmq server
26
+
27
+ As in `src/dsmq/example_server.py`
28
+
29
+ ```python
30
+ from dsmq import dsmq
31
+
32
+ dsmq.start_server(host="127.0.0.1", port=30008)
33
+ ```
34
+
35
+ ### Connect a client to a dsmq server
36
+
37
+ As in `src/dsmq/example_put_client.py`
38
+
39
+ ```python
40
+ mq = dsmq.connect_to_server(host="127.0.0.1", port=12345)
41
+ ```
42
+ ### Add a message to a queue
43
+
44
+ As in `src/dsmq/example_put_client.py`
45
+
46
+ ```python
47
+ topic = "greetings"
48
+ msg = "hello world!"
49
+ mq.put(topic, msg)
50
+ ```
51
+
52
+ ### Read a message from a queue
53
+
54
+ As in `src/dsmq/example_get_client.py`
55
+
56
+ ```python
57
+ topic = "greetings"
58
+ msg = mq.get(topic)
59
+ ```
60
+
61
+ ### Demo
62
+
63
+ 1. Open 3 separate terminal windows.
64
+ 1. In the first, run `src/dsmq/dsmq.py`.
65
+ 1. In the second, run `src/dsmq/example_put_client.py`.
66
+ 1. In the third, run `src/dsmq/example_get_client.py`.
67
+
68
+ Alternatively, if you're on Linux just run `src/dsmq/demo_linux.py`.
69
+
70
+ ## How it works
71
+
72
+ ### Expected behavior and limitations
73
+
74
+ - Many clients can read messages of the same topic. It is a one-to-many
75
+ publication model.
76
+
77
+ - A client will not be able to read any of the messages that were put into
78
+ a queue before it connected.
79
+
80
+ - A client will get the oldest message available on a requested topic.
81
+ Queues are first-in-first-out.
82
+
83
+ - Put and get operations are fairly quick--less than 100 $`\mu`$s of processing
84
+ time plus any network latency--so it can comfortably handle requests at rates of
85
+ hundreds of times per second. But if you have several clients reading and writing
86
+ at 1 kHz or more, you may overload the queue.
87
+
88
+ - The queue is backed by an in-memory SQLite database. If your message volumes
89
+ get larger than your RAM, you will reach an out-of-memory condition.
90
+
91
+
92
+ # API Reference
93
+ [[source](https://github.com/brohrer/dsmq/blob/main/src/dsmq/dsmq.py)]
94
+
95
+ ### `start_server(host="127.0.0.1", port=30008)`
96
+
97
+ Kicks off the mesage queue server. This process will be the central exchange
98
+ for all incoming and outgoing messages.
99
+ - `host` (str), IP address on which the server will be visible and
100
+ - `port` (int), port. These will be used by all clients.
101
+ Non-privileged ports are numbered 1024 and higher.
102
+
103
+ ### `connect_to_server(host="127.0.0.1", port=30008)`
104
+
105
+ Connects to an existing message queue server.
106
+ - `host` (str), IP address of the *server*.
107
+ - `port` (int), port on which the server is listening.
108
+ - returns a `DSMQClientSideConnection` object.
109
+
110
+ ## `DSMQClientSideConnection` class
111
+
112
+ This is a convenience wrapper, to make the `get()` and `put()` functions
113
+ easy to write and remember.
114
+
115
+ ### `put(topic, msg)`
116
+
117
+ Puts `msg` into the queue named `topic`. If the queue doesn't exist yet, it is created.
118
+ - msg (str), the content of the message.
119
+ - topic (str), name of the message queue in which to put this message.
120
+
121
+ ### `get(topic)`
122
+
123
+ Get the oldest eligible message from the queue named `topic`.
124
+ The client is only elgibile to receive messages that were added after it
125
+ connected to the server.
126
+ - `topic` (str)
127
+ - returns str, the content of the message. If there was no eligble message
128
+ in the topic, or the topic doesn't yet exist,
129
+ returns "".
@@ -0,0 +1,11 @@
1
+ dsmq/__init__.py,sha256=YCgbnQAk8YbtHRyMcU0v2O7RdRhPhlT-vS_q40a7Q6g,50
2
+ dsmq/demo_linux.py,sha256=7yLglGmirDLuuyMxppYSK-dfx2Fg2Q0dIWB4cl2yV1c,622
3
+ dsmq/dsmq.py,sha256=7s-e2dmbaPMfmkrbY-CXZ5y9DmOQ9xBvoWATYGAKgGY,5483
4
+ dsmq/example_get_client.py,sha256=VwL7Z7KdSDzbpdAhetcOY8KHVPjb6_OB5rtbI30CjJ0,308
5
+ dsmq/example_put_client.py,sha256=CRVQhZTYXDawXSiJP997A0ttBwKuNf8QvSpvPmEP7ng,374
6
+ dsmq/example_server.py,sha256=kkXOPaaTzVxf9_iIM76zU9pZhkPna_1vcGWkPrhCjus,61
7
+ dsmq/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ dsmq-0.3.0.dist-info/METADATA,sha256=8Mxc1JRyO8BrRiT5eLeszE5zVYUDuwJvrqXq6HW6g2s,3513
9
+ dsmq-0.3.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
10
+ dsmq-0.3.0.dist-info/licenses/LICENSE,sha256=3Yu1mAp5VsKmnDtzkiOY7BdmrLeNwwZ3t6iWaLnlL0Y,1071
11
+ dsmq-0.3.0.dist-info/RECORD,,
@@ -1,156 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: dsmq
3
- Version: 0.2.0
4
- Summary: A dead simple message queue
5
- License-File: LICENSE
6
- Requires-Python: >=3.10
7
- Description-Content-Type: text/markdown
8
-
9
- # Dead Simple Message Queue
10
-
11
- ## What it does
12
-
13
- Part mail room, part bulletin board, dsmq is a central location for sharing messages
14
- between processes, even when they are running on computers scattered around the world.
15
-
16
- Its defining characteristic is its bare-bones simplicity.
17
-
18
- ## How to use it
19
-
20
- ### Install
21
-
22
- ```bash
23
- pip install dsmq
24
- ```
25
- ### Create a dsmq server
26
-
27
- As in `src/dsmq/example_server.py`
28
-
29
- ```python
30
- from dsmq import dsmq
31
-
32
- dsmq.run(host="127.0.0.1", port=12345)
33
- ```
34
-
35
- ### Add a message to a queue
36
-
37
- As in `src/dsmq/example_put_client.py`
38
-
39
- ```python
40
- import json
41
- import socket
42
-
43
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
44
- s.connect(("127.0.0.1", 12345))
45
- message_content = {"action": "put", "topic": "greetings", "message": "Hello!"}
46
- msg = json.dumps(message_content)
47
- s.sendall(bytes(msg, "utf-8"))
48
- ```
49
-
50
- ### Read a message from a queue
51
-
52
- As in `src/dsmq/example_get_client.py`
53
-
54
- ```python
55
- import json
56
- import socket
57
-
58
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
59
- s.connect(("127.0.0.1", 12345))
60
-
61
- for i in range(n_iter):
62
- request_message_content = {"action": "get", "topic": "greetings"}
63
- request_msg = json.dumps(request_message_content)
64
- s.sendall(bytes(reequest_msg, "utf-8"))
65
-
66
- reply_msg = s.recv(1024)
67
- if not reply_msg:
68
- raise RuntimeError("Connection terminated by server")
69
- reply_msg_content = reply_msg.decode("utf-8")
70
- ```
71
-
72
- ### Demo
73
-
74
- 1. Open 3 separate terminal windows.
75
- 1. In the first, run `src/dsmq/dsmq.py`.
76
- 1. In the second, run `src/dsmq/example_put_client.py`.
77
- 1. In the third, run `src/dsmq/example_get_client.py`.
78
-
79
-
80
- ## How it works
81
-
82
- ### Expected behavior and limitations
83
-
84
- - Many clients can read messages of the same topic. It is a one-to-many
85
- pulication model.
86
-
87
- - A client will not be able to read any of the messages that were put into
88
- a queue before it connected.
89
-
90
- - A client will get the oldest message available on a requested topic.
91
- Queues are first-in-first-out.
92
-
93
- - Put and get operations are fairly quick--less than 100 $`\mu`$s of processing
94
- time plus any network latency--so it can comfortably handle operations at
95
- hundreds of Hz. But if you try to have several clients reading and writing
96
- at 1 kHz or more, you may overload the queue.
97
-
98
- - The queue is backed by an in-memory SQLite database. If your message volumes
99
- get larger than your RAM, you may reach an out-of-memory condition.
100
-
101
-
102
- # API Reference and Cookbook
103
- [[source](https://github.com/brohrer/dsmq/blob/main/src/dsmq/dsmq.py)]
104
-
105
- ### Start a server
106
-
107
- ```python
108
- run(host="127.0.0.1", port=30008)
109
- ```
110
-
111
- Kicks off the mesage queue server. This process will be the central exchange
112
- for all incoming and outgoing messages.
113
- - `host` (str), IP address on which the server will be visible and
114
- - `port` (int), port. These will be used by all clients.
115
- Non-privileged ports are numbered 1024 and higher.
116
-
117
- ### Open a connection from a client
118
-
119
- ```python
120
- import socket
121
-
122
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
123
- s.connect((host, port ))
124
- ```
125
-
126
- ### Add a message to a queue
127
-
128
- ```python
129
- import json
130
- msg = json.dumps({
131
- "action": "put",
132
- "topic": <queue-name>,
133
- "message": <message-content>
134
- })
135
- s.sendall(bytes(msg, "utf-8"))
136
- ```
137
-
138
- - `s`, the socket connection to the server
139
- - `<queue-name>` (str), a name for the queue where the message will be added
140
- - `<message-content>` (str), whatever message content you want
141
-
142
- Place `message-content` into the queue named `queue-name`.
143
- If the queue doesn't exist yet, create it.
144
-
145
- ### Get a message from a queue
146
-
147
- ```python
148
- request_msg = json.dumps({"action": "get", "topic": <queue-name>})
149
- s.sendall(bytes(request_msg, "utf-8"))
150
- data = s.recv(1024)
151
- msg_str = data.decode("utf-8")
152
- ```
153
-
154
- Get the oldest eligible message from the queue named `<queue-name>`.
155
- The client is only elgibile to receive messages added after it
156
- connected to the server.
@@ -1,11 +0,0 @@
1
- dsmq/__init__.py,sha256=YCgbnQAk8YbtHRyMcU0v2O7RdRhPhlT-vS_q40a7Q6g,50
2
- dsmq/demo_linux.py,sha256=D5NjEvPG-fTGRRbYzMJXgtwfrigOt_eaR6D0AozBNbA,613
3
- dsmq/dsmq.py,sha256=EJW6tMeG57QYBneqBEM4R_5CrtG-Lx2qz0D1BM0YtjI,4452
4
- dsmq/example_get_client.py,sha256=ZWZrAu7sIEn8VwCK09cTwsm1XnF3Jkor3r7Gl4ljUMw,630
5
- dsmq/example_put_client.py,sha256=bSjSJZsFZB6inVGUlTnJn0jgrpVNXvrN46STTvgwCzs,497
6
- dsmq/example_server.py,sha256=UM69GN7uORDetXQM8LlW68nrA-1i7Jgp2dZREVEqxaU,62
7
- dsmq/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- dsmq-0.2.0.dist-info/METADATA,sha256=TW6tM_oF2LuyRrmOBSBTHFCkJvNDA8O3QfuEtgD1-S8,4055
9
- dsmq-0.2.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
10
- dsmq-0.2.0.dist-info/licenses/LICENSE,sha256=3Yu1mAp5VsKmnDtzkiOY7BdmrLeNwwZ3t6iWaLnlL0Y,1071
11
- dsmq-0.2.0.dist-info/RECORD,,
File without changes