nolag 2.0.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.
nolag-2.0.0/PKG-INFO ADDED
@@ -0,0 +1,329 @@
1
+ Metadata-Version: 2.4
2
+ Name: nolag
3
+ Version: 2.0.0
4
+ Summary: NoLag real-time messaging SDK for Python
5
+ Project-URL: Homepage, https://nolag.app
6
+ Project-URL: Documentation, https://docs.nolag.app
7
+ Project-URL: Repository, https://github.com/NoLagApp/nolag-python
8
+ Author-email: NoLag <support@nolag.app>
9
+ License-Expression: MIT
10
+ Keywords: messaging,nolag,pubsub,real-time,websocket
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Framework :: AsyncIO
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Communications
20
+ Classifier: Topic :: Internet
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: aiohttp>=3.9.0
23
+ Requires-Dist: msgpack>=1.0.0
24
+ Requires-Dist: websockets>=12.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: black>=23.0.0; extra == 'dev'
27
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
28
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
31
+ Provides-Extra: webrtc
32
+ Requires-Dist: aiortc>=1.6.0; extra == 'webrtc'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # NoLag Python SDK
36
+
37
+ Real-time messaging SDK for Python applications.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install nolag
43
+ ```
44
+
45
+ ## Setup
46
+
47
+ Before using the SDK, you need to set up your NoLag project:
48
+
49
+ 1. **Create a Project** in the [NoLag Dashboard](https://app.nolag.app)
50
+ 2. **Create an App** with your desired topics
51
+ 3. **Create Topics** in your App schema (e.g., `messages`, `status`, `commands`)
52
+ 4. **Create Actors** to get access tokens (`at_xxx...`)
53
+
54
+ > **Note:** Topics must be defined in your App schema before you can subscribe or publish to them. Rooms are created dynamically at runtime.
55
+
56
+ ## Quick Start
57
+
58
+ ```python
59
+ import asyncio
60
+ from nolag import NoLag, NoLagOptions
61
+
62
+ async def main():
63
+ # Create client with your actor token
64
+ client = NoLag("your-actor-token")
65
+
66
+ # Connect to NoLag
67
+ await client.connect()
68
+
69
+ # Subscribe to a topic
70
+ def on_message(data, meta):
71
+ print(f"Received: {data}")
72
+
73
+ await client.subscribe("my-topic", on_message)
74
+
75
+ # Publish a message
76
+ await client.emit("my-topic", {"hello": "world"})
77
+
78
+ # Keep running
79
+ await asyncio.sleep(60)
80
+
81
+ # Disconnect when done
82
+ await client.disconnect()
83
+
84
+ asyncio.run(main())
85
+ ```
86
+
87
+ ## Configuration
88
+
89
+ ```python
90
+ from nolag import NoLag, NoLagOptions, QoS
91
+
92
+ options = NoLagOptions(
93
+ url="wss://broker.nolag.app/ws", # Custom broker URL
94
+ reconnect=True, # Auto-reconnect on disconnect
95
+ reconnect_interval=5.0, # Seconds between reconnect attempts
96
+ max_reconnect_attempts=10, # Max reconnect attempts (0 = infinite)
97
+ heartbeat_interval=30.0, # Heartbeat interval (0 to disable)
98
+ qos=QoS.AT_LEAST_ONCE, # Default QoS level
99
+ debug=True, # Enable debug logging
100
+ )
101
+
102
+ client = NoLag("your-actor-token", options)
103
+ ```
104
+
105
+ ## Subscribing to Topics
106
+
107
+ ```python
108
+ from nolag import SubscribeOptions, QoS
109
+
110
+ # Basic subscription
111
+ await client.subscribe("chat/messages", lambda data, meta: print(data))
112
+
113
+ # With options
114
+ options = SubscribeOptions(
115
+ qos=QoS.EXACTLY_ONCE,
116
+ load_balance=True,
117
+ load_balance_group="workers"
118
+ )
119
+ await client.subscribe("tasks", handler, options)
120
+
121
+ # Unsubscribe
122
+ await client.unsubscribe("chat/messages")
123
+ ```
124
+
125
+ ## Publishing Messages
126
+
127
+ ```python
128
+ from nolag import EmitOptions, QoS
129
+
130
+ # Publish any data (dict, list, string, bytes, etc.)
131
+ await client.emit("chat/messages", {"text": "Hello!"})
132
+
133
+ # With options
134
+ options = EmitOptions(
135
+ qos=QoS.EXACTLY_ONCE,
136
+ retain=True # Retain last message for new subscribers
137
+ )
138
+ await client.emit("status", {"online": True}, options)
139
+ ```
140
+
141
+ ## Connection Events
142
+
143
+ ```python
144
+ from nolag import ConnectionStatus
145
+
146
+ # Listen for connection events
147
+ client.on("connected", lambda: print("Connected!"))
148
+ client.on("disconnected", lambda: print("Disconnected"))
149
+ client.on("reconnecting", lambda attempt: print(f"Reconnecting... attempt {attempt}"))
150
+ client.on("error", lambda err: print(f"Error: {err}"))
151
+
152
+ # Check connection status
153
+ if client.status == ConnectionStatus.CONNECTED:
154
+ print("We're connected!")
155
+ ```
156
+
157
+ ## Presence
158
+
159
+ ```python
160
+ # Set your presence data
161
+ await client.set_presence({"status": "online", "typing": False})
162
+
163
+ # Get presence of all actors in a topic
164
+ presence_list = await client.get_presence("chat/room-1")
165
+ for actor in presence_list:
166
+ print(f"{actor.actor_token_id}: {actor.presence}")
167
+
168
+ # Listen for presence changes
169
+ client.on("presence", lambda topic, presence:
170
+ print(f"Presence update in {topic}: {presence}")
171
+ )
172
+ ```
173
+
174
+ ## Error Handling
175
+
176
+ ```python
177
+ import asyncio
178
+ from nolag import NoLag
179
+
180
+ async def main():
181
+ client = NoLag("your-actor-token")
182
+
183
+ try:
184
+ await client.connect()
185
+ except Exception as e:
186
+ print(f"Connection failed: {e}")
187
+ return
188
+
189
+ # Handle errors during operation
190
+ client.on("error", lambda err: print(f"Error: {err}"))
191
+
192
+ try:
193
+ await client.emit("topic", {"data": "value"})
194
+ except Exception as e:
195
+ print(f"Emit failed: {e}")
196
+
197
+ asyncio.run(main())
198
+ ```
199
+
200
+ ## QoS Levels
201
+
202
+ | Level | Name | Description |
203
+ |-------|------|-------------|
204
+ | 0 | AT_MOST_ONCE | Fire and forget, no acknowledgment |
205
+ | 1 | AT_LEAST_ONCE | Guaranteed delivery, may have duplicates |
206
+ | 2 | EXACTLY_ONCE | Guaranteed exactly one delivery |
207
+
208
+ ```python
209
+ from nolag import QoS
210
+
211
+ # Set default QoS in options
212
+ options = NoLagOptions(qos=QoS.EXACTLY_ONCE)
213
+
214
+ # Or per-message
215
+ await client.emit("important", data, EmitOptions(qos=QoS.EXACTLY_ONCE))
216
+ ```
217
+
218
+ ## Load Balancing
219
+
220
+ Distribute messages across multiple subscribers:
221
+
222
+ ```python
223
+ # Enable load balancing for a subscription
224
+ await client.subscribe(
225
+ "tasks",
226
+ process_task,
227
+ SubscribeOptions(
228
+ load_balance=True,
229
+ load_balance_group="task-workers"
230
+ )
231
+ )
232
+ ```
233
+
234
+ ## Type Definitions
235
+
236
+ ```python
237
+ from nolag import (
238
+ NoLag, # Main client class
239
+ NoLagOptions, # Connection options
240
+ SubscribeOptions, # Subscription options
241
+ EmitOptions, # Publish options
242
+ ConnectionStatus, # Connection status enum
243
+ ActorType, # Actor type enum
244
+ QoS, # QoS level enum
245
+ MessageMeta, # Message metadata
246
+ ActorPresence, # Presence info
247
+ )
248
+ ```
249
+
250
+ ## REST API Client
251
+
252
+ The SDK also includes a REST API client for managing apps, rooms, and actors.
253
+
254
+ ```python
255
+ import asyncio
256
+ from nolag import NoLagApi, AppCreate, RoomCreate, ActorCreate
257
+
258
+ async def main():
259
+ # Create API client with project-scoped API key
260
+ async with NoLagApi("nlg_live_xxx.secret") as api:
261
+ # List all apps in your project
262
+ apps = await api.apps.list()
263
+ print(f"Found {len(apps.data)} apps")
264
+
265
+ # Create a new app
266
+ app = await api.apps.create(AppCreate(
267
+ name="my-chat-app",
268
+ description="A real-time chat application"
269
+ ))
270
+ print(f"Created app: {app.app_id}")
271
+
272
+ # Create a room in the app
273
+ room = await api.rooms.create(app.app_id, RoomCreate(
274
+ name="general",
275
+ slug="general",
276
+ description="General chat room"
277
+ ))
278
+ print(f"Created room: {room.room_id}")
279
+
280
+ # Create an actor (IMPORTANT: save the access token!)
281
+ actor = await api.actors.create(ActorCreate(
282
+ name="web-client",
283
+ actor_type="device"
284
+ ))
285
+ print(f"Actor token (save this!): {actor.access_token}")
286
+
287
+ # Update an app
288
+ updated = await api.apps.update(app.app_id, AppUpdate(
289
+ description="Updated description"
290
+ ))
291
+
292
+ # Delete resources
293
+ await api.rooms.delete(app.app_id, room.room_id)
294
+ await api.actors.delete(actor.actor_token_id)
295
+ await api.apps.delete(app.app_id)
296
+
297
+ asyncio.run(main())
298
+ ```
299
+
300
+ ### API Types
301
+
302
+ ```python
303
+ from nolag import (
304
+ # API Client
305
+ NoLagApi, # REST API client
306
+ NoLagApiError, # API error class
307
+ NoLagApiOptions, # API client options
308
+
309
+ # Resources
310
+ App, AppCreate, AppUpdate,
311
+ Room, RoomCreate, RoomUpdate,
312
+ Actor, ActorWithToken, ActorCreate, ActorUpdate,
313
+
314
+ # Utilities
315
+ ListOptions, # Pagination options
316
+ PaginatedResult, # Paginated response
317
+ )
318
+ ```
319
+
320
+ ## Requirements
321
+
322
+ - Python 3.10+
323
+ - websockets >= 12.0
324
+ - msgpack >= 1.0.0
325
+ - aiohttp >= 3.9.0
326
+
327
+ ## License
328
+
329
+ MIT
nolag-2.0.0/README.md ADDED
@@ -0,0 +1,295 @@
1
+ # NoLag Python SDK
2
+
3
+ Real-time messaging SDK for Python applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install nolag
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ Before using the SDK, you need to set up your NoLag project:
14
+
15
+ 1. **Create a Project** in the [NoLag Dashboard](https://app.nolag.app)
16
+ 2. **Create an App** with your desired topics
17
+ 3. **Create Topics** in your App schema (e.g., `messages`, `status`, `commands`)
18
+ 4. **Create Actors** to get access tokens (`at_xxx...`)
19
+
20
+ > **Note:** Topics must be defined in your App schema before you can subscribe or publish to them. Rooms are created dynamically at runtime.
21
+
22
+ ## Quick Start
23
+
24
+ ```python
25
+ import asyncio
26
+ from nolag import NoLag, NoLagOptions
27
+
28
+ async def main():
29
+ # Create client with your actor token
30
+ client = NoLag("your-actor-token")
31
+
32
+ # Connect to NoLag
33
+ await client.connect()
34
+
35
+ # Subscribe to a topic
36
+ def on_message(data, meta):
37
+ print(f"Received: {data}")
38
+
39
+ await client.subscribe("my-topic", on_message)
40
+
41
+ # Publish a message
42
+ await client.emit("my-topic", {"hello": "world"})
43
+
44
+ # Keep running
45
+ await asyncio.sleep(60)
46
+
47
+ # Disconnect when done
48
+ await client.disconnect()
49
+
50
+ asyncio.run(main())
51
+ ```
52
+
53
+ ## Configuration
54
+
55
+ ```python
56
+ from nolag import NoLag, NoLagOptions, QoS
57
+
58
+ options = NoLagOptions(
59
+ url="wss://broker.nolag.app/ws", # Custom broker URL
60
+ reconnect=True, # Auto-reconnect on disconnect
61
+ reconnect_interval=5.0, # Seconds between reconnect attempts
62
+ max_reconnect_attempts=10, # Max reconnect attempts (0 = infinite)
63
+ heartbeat_interval=30.0, # Heartbeat interval (0 to disable)
64
+ qos=QoS.AT_LEAST_ONCE, # Default QoS level
65
+ debug=True, # Enable debug logging
66
+ )
67
+
68
+ client = NoLag("your-actor-token", options)
69
+ ```
70
+
71
+ ## Subscribing to Topics
72
+
73
+ ```python
74
+ from nolag import SubscribeOptions, QoS
75
+
76
+ # Basic subscription
77
+ await client.subscribe("chat/messages", lambda data, meta: print(data))
78
+
79
+ # With options
80
+ options = SubscribeOptions(
81
+ qos=QoS.EXACTLY_ONCE,
82
+ load_balance=True,
83
+ load_balance_group="workers"
84
+ )
85
+ await client.subscribe("tasks", handler, options)
86
+
87
+ # Unsubscribe
88
+ await client.unsubscribe("chat/messages")
89
+ ```
90
+
91
+ ## Publishing Messages
92
+
93
+ ```python
94
+ from nolag import EmitOptions, QoS
95
+
96
+ # Publish any data (dict, list, string, bytes, etc.)
97
+ await client.emit("chat/messages", {"text": "Hello!"})
98
+
99
+ # With options
100
+ options = EmitOptions(
101
+ qos=QoS.EXACTLY_ONCE,
102
+ retain=True # Retain last message for new subscribers
103
+ )
104
+ await client.emit("status", {"online": True}, options)
105
+ ```
106
+
107
+ ## Connection Events
108
+
109
+ ```python
110
+ from nolag import ConnectionStatus
111
+
112
+ # Listen for connection events
113
+ client.on("connected", lambda: print("Connected!"))
114
+ client.on("disconnected", lambda: print("Disconnected"))
115
+ client.on("reconnecting", lambda attempt: print(f"Reconnecting... attempt {attempt}"))
116
+ client.on("error", lambda err: print(f"Error: {err}"))
117
+
118
+ # Check connection status
119
+ if client.status == ConnectionStatus.CONNECTED:
120
+ print("We're connected!")
121
+ ```
122
+
123
+ ## Presence
124
+
125
+ ```python
126
+ # Set your presence data
127
+ await client.set_presence({"status": "online", "typing": False})
128
+
129
+ # Get presence of all actors in a topic
130
+ presence_list = await client.get_presence("chat/room-1")
131
+ for actor in presence_list:
132
+ print(f"{actor.actor_token_id}: {actor.presence}")
133
+
134
+ # Listen for presence changes
135
+ client.on("presence", lambda topic, presence:
136
+ print(f"Presence update in {topic}: {presence}")
137
+ )
138
+ ```
139
+
140
+ ## Error Handling
141
+
142
+ ```python
143
+ import asyncio
144
+ from nolag import NoLag
145
+
146
+ async def main():
147
+ client = NoLag("your-actor-token")
148
+
149
+ try:
150
+ await client.connect()
151
+ except Exception as e:
152
+ print(f"Connection failed: {e}")
153
+ return
154
+
155
+ # Handle errors during operation
156
+ client.on("error", lambda err: print(f"Error: {err}"))
157
+
158
+ try:
159
+ await client.emit("topic", {"data": "value"})
160
+ except Exception as e:
161
+ print(f"Emit failed: {e}")
162
+
163
+ asyncio.run(main())
164
+ ```
165
+
166
+ ## QoS Levels
167
+
168
+ | Level | Name | Description |
169
+ |-------|------|-------------|
170
+ | 0 | AT_MOST_ONCE | Fire and forget, no acknowledgment |
171
+ | 1 | AT_LEAST_ONCE | Guaranteed delivery, may have duplicates |
172
+ | 2 | EXACTLY_ONCE | Guaranteed exactly one delivery |
173
+
174
+ ```python
175
+ from nolag import QoS
176
+
177
+ # Set default QoS in options
178
+ options = NoLagOptions(qos=QoS.EXACTLY_ONCE)
179
+
180
+ # Or per-message
181
+ await client.emit("important", data, EmitOptions(qos=QoS.EXACTLY_ONCE))
182
+ ```
183
+
184
+ ## Load Balancing
185
+
186
+ Distribute messages across multiple subscribers:
187
+
188
+ ```python
189
+ # Enable load balancing for a subscription
190
+ await client.subscribe(
191
+ "tasks",
192
+ process_task,
193
+ SubscribeOptions(
194
+ load_balance=True,
195
+ load_balance_group="task-workers"
196
+ )
197
+ )
198
+ ```
199
+
200
+ ## Type Definitions
201
+
202
+ ```python
203
+ from nolag import (
204
+ NoLag, # Main client class
205
+ NoLagOptions, # Connection options
206
+ SubscribeOptions, # Subscription options
207
+ EmitOptions, # Publish options
208
+ ConnectionStatus, # Connection status enum
209
+ ActorType, # Actor type enum
210
+ QoS, # QoS level enum
211
+ MessageMeta, # Message metadata
212
+ ActorPresence, # Presence info
213
+ )
214
+ ```
215
+
216
+ ## REST API Client
217
+
218
+ The SDK also includes a REST API client for managing apps, rooms, and actors.
219
+
220
+ ```python
221
+ import asyncio
222
+ from nolag import NoLagApi, AppCreate, RoomCreate, ActorCreate
223
+
224
+ async def main():
225
+ # Create API client with project-scoped API key
226
+ async with NoLagApi("nlg_live_xxx.secret") as api:
227
+ # List all apps in your project
228
+ apps = await api.apps.list()
229
+ print(f"Found {len(apps.data)} apps")
230
+
231
+ # Create a new app
232
+ app = await api.apps.create(AppCreate(
233
+ name="my-chat-app",
234
+ description="A real-time chat application"
235
+ ))
236
+ print(f"Created app: {app.app_id}")
237
+
238
+ # Create a room in the app
239
+ room = await api.rooms.create(app.app_id, RoomCreate(
240
+ name="general",
241
+ slug="general",
242
+ description="General chat room"
243
+ ))
244
+ print(f"Created room: {room.room_id}")
245
+
246
+ # Create an actor (IMPORTANT: save the access token!)
247
+ actor = await api.actors.create(ActorCreate(
248
+ name="web-client",
249
+ actor_type="device"
250
+ ))
251
+ print(f"Actor token (save this!): {actor.access_token}")
252
+
253
+ # Update an app
254
+ updated = await api.apps.update(app.app_id, AppUpdate(
255
+ description="Updated description"
256
+ ))
257
+
258
+ # Delete resources
259
+ await api.rooms.delete(app.app_id, room.room_id)
260
+ await api.actors.delete(actor.actor_token_id)
261
+ await api.apps.delete(app.app_id)
262
+
263
+ asyncio.run(main())
264
+ ```
265
+
266
+ ### API Types
267
+
268
+ ```python
269
+ from nolag import (
270
+ # API Client
271
+ NoLagApi, # REST API client
272
+ NoLagApiError, # API error class
273
+ NoLagApiOptions, # API client options
274
+
275
+ # Resources
276
+ App, AppCreate, AppUpdate,
277
+ Room, RoomCreate, RoomUpdate,
278
+ Actor, ActorWithToken, ActorCreate, ActorUpdate,
279
+
280
+ # Utilities
281
+ ListOptions, # Pagination options
282
+ PaginatedResult, # Paginated response
283
+ )
284
+ ```
285
+
286
+ ## Requirements
287
+
288
+ - Python 3.10+
289
+ - websockets >= 12.0
290
+ - msgpack >= 1.0.0
291
+ - aiohttp >= 3.9.0
292
+
293
+ ## License
294
+
295
+ MIT
Binary file
@@ -0,0 +1,84 @@
1
+ """
2
+ NoLag Python SDK
3
+ Real-time messaging for Python applications
4
+ """
5
+
6
+ from .client import NoLag
7
+ from .types import (
8
+ NoLagOptions,
9
+ ConnectionStatus,
10
+ ActorType,
11
+ QoS,
12
+ SubscribeOptions,
13
+ EmitOptions,
14
+ MessageMeta,
15
+ ActorPresence,
16
+ LobbyPresenceEvent,
17
+ LobbyPresenceState,
18
+ LobbyPresenceHandler,
19
+ )
20
+ from .api import NoLagApi, NoLagApiError
21
+ from .api_types import (
22
+ NoLagApiOptions,
23
+ ListOptions,
24
+ PaginatedResult,
25
+ ApiError,
26
+ App,
27
+ AppCreate,
28
+ AppUpdate,
29
+ Room,
30
+ RoomCreate,
31
+ RoomUpdate,
32
+ Actor,
33
+ ActorWithToken,
34
+ ActorCreate,
35
+ ActorUpdate,
36
+ )
37
+
38
+ # WebRTC support (optional, requires aiortc)
39
+ try:
40
+ from .webrtc import WebRTCManager, WebRTCOptions, is_webrtc_available
41
+ _WEBRTC_AVAILABLE = True
42
+ except ImportError:
43
+ _WEBRTC_AVAILABLE = False
44
+ WebRTCManager = None
45
+ WebRTCOptions = None
46
+ is_webrtc_available = lambda: False
47
+
48
+ __version__ = "2.0.0"
49
+ __all__ = [
50
+ # WebSocket Client
51
+ "NoLag",
52
+ "NoLagOptions",
53
+ "ConnectionStatus",
54
+ "ActorType",
55
+ "QoS",
56
+ "SubscribeOptions",
57
+ "EmitOptions",
58
+ "MessageMeta",
59
+ "ActorPresence",
60
+ "LobbyPresenceEvent",
61
+ "LobbyPresenceState",
62
+ "LobbyPresenceHandler",
63
+ # REST API Client
64
+ "NoLagApi",
65
+ "NoLagApiError",
66
+ "NoLagApiOptions",
67
+ "ListOptions",
68
+ "PaginatedResult",
69
+ "ApiError",
70
+ "App",
71
+ "AppCreate",
72
+ "AppUpdate",
73
+ "Room",
74
+ "RoomCreate",
75
+ "RoomUpdate",
76
+ "Actor",
77
+ "ActorWithToken",
78
+ "ActorCreate",
79
+ "ActorUpdate",
80
+ # WebRTC (optional)
81
+ "WebRTCManager",
82
+ "WebRTCOptions",
83
+ "is_webrtc_available",
84
+ ]