ironflock 1.2.0__tar.gz → 1.3.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.
- {ironflock-1.2.0 → ironflock-1.3.0}/PKG-INFO +1 -1
- {ironflock-1.2.0 → ironflock-1.3.0}/pyproject.toml +1 -1
- {ironflock-1.2.0 → ironflock-1.3.0}/src/ironflock/CrossbarConnection.py +10 -10
- {ironflock-1.2.0 → ironflock-1.3.0}/src/ironflock/__init__.py +1 -1
- {ironflock-1.2.0 → ironflock-1.3.0}/src/ironflock/ironflock.py +79 -43
- {ironflock-1.2.0 → ironflock-1.3.0}/LICENSE +0 -0
- {ironflock-1.2.0 → ironflock-1.3.0}/README.md +0 -0
|
@@ -138,7 +138,7 @@ class CrossbarConnection:
|
|
|
138
138
|
self.session = session
|
|
139
139
|
self._is_connected = True
|
|
140
140
|
await self._resubscribe_all()
|
|
141
|
-
print(f"Connection to realm '{session._realm}' established")
|
|
141
|
+
print(f"Connection to IronFlock app realm '{session._realm}' established")
|
|
142
142
|
|
|
143
143
|
if self._first_connection_future and not self._first_connection_future.done():
|
|
144
144
|
self._first_connection_future.set_result(None)
|
|
@@ -147,7 +147,7 @@ class CrossbarConnection:
|
|
|
147
147
|
"""Handle session close event"""
|
|
148
148
|
self.session = None
|
|
149
149
|
self._is_connected = False
|
|
150
|
-
print(f"Connection to realm {self.realm} closed: {details.reason}")
|
|
150
|
+
print(f"Connection to IronFlock app realm {self.realm} closed: {details.reason}")
|
|
151
151
|
|
|
152
152
|
if self._first_connection_future and not self._first_connection_future.done():
|
|
153
153
|
self._first_connection_future.set_exception(
|
|
@@ -158,8 +158,8 @@ class CrossbarConnection:
|
|
|
158
158
|
"""Handle disconnect event"""
|
|
159
159
|
self.session = None
|
|
160
160
|
self._is_connected = False
|
|
161
|
-
print(f"Disconnected from realm {self.realm}, clean: {was_clean}")
|
|
162
|
-
|
|
161
|
+
print(f"Disconnected from IronFlock app realm {self.realm}, clean: {was_clean}")
|
|
162
|
+
|
|
163
163
|
async def _session_wait(self) -> None:
|
|
164
164
|
"""Wait for session to be available"""
|
|
165
165
|
start_time = time.time()
|
|
@@ -177,13 +177,13 @@ class CrossbarConnection:
|
|
|
177
177
|
"""Start the connection"""
|
|
178
178
|
if not self.component:
|
|
179
179
|
raise ValueError("Must call configure() before start()")
|
|
180
|
-
|
|
181
|
-
print(f'Starting connection for realm {self.realm}')
|
|
182
|
-
|
|
183
|
-
# Start the component
|
|
184
|
-
|
|
180
|
+
|
|
181
|
+
print(f'Starting connection for IronFlock app realm {self.realm}')
|
|
182
|
+
|
|
183
|
+
# Start the component (non-blocking in autobahn asyncio)
|
|
184
|
+
self.component.start()
|
|
185
185
|
|
|
186
|
-
# Wait for first connection
|
|
186
|
+
# Wait for first connection to be established
|
|
187
187
|
if self._first_connection_future:
|
|
188
188
|
await self._first_connection_future
|
|
189
189
|
|
|
@@ -3,6 +3,7 @@ import asyncio
|
|
|
3
3
|
from typing import Optional, Any
|
|
4
4
|
|
|
5
5
|
from ironflock.CrossbarConnection import CrossbarConnection, Stage, getSerialNumber
|
|
6
|
+
from autobahn.wamp.types import PublishOptions, RegisterOptions, SubscribeOptions, CallOptions
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class IronFlock:
|
|
@@ -106,8 +107,8 @@ class IronFlock:
|
|
|
106
107
|
# Merge device metadata with user kwargs
|
|
107
108
|
combined_kwargs = {**device_metadata, **kwargs}
|
|
108
109
|
|
|
109
|
-
# Use acknowledged publish
|
|
110
|
-
options =
|
|
110
|
+
# Use acknowledged publish with proper PublishOptions
|
|
111
|
+
options = PublishOptions(acknowledge=True)
|
|
111
112
|
|
|
112
113
|
try:
|
|
113
114
|
pub = await self._connection.publish(
|
|
@@ -159,60 +160,87 @@ class IronFlock:
|
|
|
159
160
|
print(f"Set location failed: {e}")
|
|
160
161
|
return None
|
|
161
162
|
|
|
162
|
-
async def register_function(self, topic: str,
|
|
163
|
-
"""Registers a function
|
|
164
|
-
|
|
163
|
+
async def register_function(self, topic: str, endpoint, options: Optional[dict] = None) -> Optional[Any]:
|
|
164
|
+
"""Registers a function with the IronFlock Platform Message Router
|
|
165
|
+
|
|
165
166
|
Args:
|
|
166
|
-
topic (str): The URI of the topic to register
|
|
167
|
-
|
|
167
|
+
topic (str): The URI of the topic to register, e.g. "com.myapp.myprocedure1"
|
|
168
|
+
endpoint: The function to register
|
|
169
|
+
options (dict, optional): Registration options
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Optional[Any]: Object representing a registration
|
|
168
173
|
"""
|
|
169
174
|
if not self.is_connected:
|
|
170
|
-
print("cannot register
|
|
175
|
+
print("cannot register, not connected")
|
|
171
176
|
return None
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
full_topic = f"{swarm_key}.{self._device_key}.{app_key}.{env_value}.{topic}"
|
|
178
|
-
|
|
177
|
+
|
|
178
|
+
# Convert options dict to RegisterOptions if provided
|
|
179
|
+
register_options = RegisterOptions(**options) if options else None
|
|
180
|
+
|
|
179
181
|
try:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
registration = await self._connection.register(full_topic, func)
|
|
183
|
-
return registration
|
|
182
|
+
reg = await self._connection.register(topic, endpoint, options=register_options)
|
|
183
|
+
return reg
|
|
184
184
|
except Exception as e:
|
|
185
|
-
print(f"Register
|
|
185
|
+
print(f"Register failed: {e}")
|
|
186
186
|
return None
|
|
187
187
|
|
|
188
|
-
async def
|
|
189
|
-
"""
|
|
188
|
+
async def register(self, topic: str, endpoint, options: Optional[dict] = None) -> Optional[Any]:
|
|
189
|
+
"""Alias for register_function() for backward compatibility"""
|
|
190
|
+
return await self.register_function(topic, endpoint, options)
|
|
191
|
+
|
|
192
|
+
async def subscribe(self, topic: str, handler, options: Optional[dict] = None) -> Optional[Any]:
|
|
193
|
+
"""Subscribes to a topic on the IronFlock Platform Message Router
|
|
190
194
|
|
|
191
195
|
Args:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
kwargs (dict): The keyword arguments to pass to the procedure.
|
|
196
|
+
topic (str): The URI of the topic to subscribe to, e.g. "com.myapp.mytopic1"
|
|
197
|
+
handler: The function to call when a message is received
|
|
198
|
+
options (dict, optional): Subscription options
|
|
196
199
|
|
|
197
200
|
Returns:
|
|
198
|
-
|
|
201
|
+
Optional[Any]: Object representing a subscription
|
|
202
|
+
"""
|
|
203
|
+
if not self.is_connected:
|
|
204
|
+
print("cannot subscribe, not connected")
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
# Convert options dict to SubscribeOptions if provided
|
|
208
|
+
subscribe_options = SubscribeOptions(**options) if options else None
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
sub = await self._connection.subscribe(topic, handler, options=subscribe_options)
|
|
212
|
+
return sub
|
|
213
|
+
except Exception as e:
|
|
214
|
+
print(f"Subscribe failed: {e}")
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
async def call(self, device_key: str, topic: str, args: list = None, kwargs: dict = None, options: Optional[dict] = None):
|
|
218
|
+
"""Calls a remote procedure registered by another IronFlock device
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
device_key (str): The device key of the target device
|
|
222
|
+
topic (str): The URI of the topic to call, e.g. "com.myapp.myprocedure1"
|
|
223
|
+
args (list, optional): Positional arguments for the call. Defaults to None.
|
|
224
|
+
kwargs (dict, optional): Keyword arguments for the call. Defaults to None.
|
|
225
|
+
options (dict, optional): Call options. Defaults to None.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Any: The result of the remote procedure call
|
|
199
229
|
"""
|
|
200
230
|
if not self.is_connected:
|
|
201
231
|
print("cannot call, not connected")
|
|
202
232
|
return None
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
233
|
+
|
|
234
|
+
args = args or []
|
|
235
|
+
kwargs = kwargs or {}
|
|
236
|
+
|
|
237
|
+
# Convert options dict to CallOptions if provided
|
|
238
|
+
call_options = CallOptions(**options) if options else None
|
|
239
|
+
|
|
240
|
+
call_topic = f"{device_key}.{topic}"
|
|
241
|
+
|
|
210
242
|
try:
|
|
211
|
-
result = await self._connection.call(
|
|
212
|
-
full_topic,
|
|
213
|
-
args=args or [],
|
|
214
|
-
kwargs=kwargs or {}
|
|
215
|
-
)
|
|
243
|
+
result = await self._connection.call(call_topic, args=args, kwargs=kwargs, options=call_options)
|
|
216
244
|
return result
|
|
217
245
|
except Exception as e:
|
|
218
246
|
print(f"Call failed: {e}")
|
|
@@ -275,9 +303,14 @@ class IronFlock:
|
|
|
275
303
|
pass
|
|
276
304
|
self._main_task = None
|
|
277
305
|
|
|
278
|
-
|
|
306
|
+
if self._connection:
|
|
307
|
+
await self._connection.stop()
|
|
279
308
|
|
|
280
|
-
|
|
309
|
+
def run(self):
|
|
310
|
+
"""Synchronous wrapper to run the IronFlock instance (original API)"""
|
|
311
|
+
asyncio.run(self.run_async())
|
|
312
|
+
|
|
313
|
+
async def run_async(self):
|
|
281
314
|
"""Start the connection and keep it running"""
|
|
282
315
|
await self.start()
|
|
283
316
|
|
|
@@ -291,9 +324,12 @@ class IronFlock:
|
|
|
291
324
|
await asyncio.sleep(1)
|
|
292
325
|
except KeyboardInterrupt:
|
|
293
326
|
print("Shutting down...")
|
|
327
|
+
except Exception as e:
|
|
328
|
+
print(f"Exception in run(): {e}")
|
|
329
|
+
raise
|
|
294
330
|
finally:
|
|
295
331
|
await self.stop()
|
|
296
332
|
|
|
297
333
|
def run_sync(self):
|
|
298
|
-
"""
|
|
299
|
-
|
|
334
|
+
"""Alias for run() method for clarity"""
|
|
335
|
+
return self.run()
|
|
File without changes
|
|
File without changes
|