Skip to content

Commit 84c7615

Browse files
committed
WIP
1 parent cef5e90 commit 84c7615

15 files changed

Lines changed: 1841 additions & 69 deletions

File tree

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ dependencies = [
3535
"Bug Tracker" = "https://github.com/tmunzer/mistapi_python/issues"
3636

3737
# UV-specific configuration
38+
[tool.uv.scripts]
39+
test = "pytest"
40+
lint = "ruff check src/"
41+
fmt = "ruff format src/"
42+
build = "python -m build"
43+
3844
[tool.uv]
3945
dev-dependencies = [
4046
# Testing dependencies

src/mistapi/api/v1/sites/devices.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,7 +1734,7 @@ def clearSiteDevicePendingVersion(
17341734

17351735

17361736
def clearSiteDevicePolicyHitCount(
1737-
mist_session: _APISession, site_id: str, device_id: str
1737+
mist_session: _APISession, site_id: str, device_id: str, body: dict
17381738
) -> _APIResponse:
17391739
"""
17401740
API doc: https://www.juniper.net/documentation/us/en/software/mist/api/http/api/utilities/common/clear-site-device-policy-hit-count
@@ -1756,7 +1756,7 @@ def clearSiteDevicePolicyHitCount(
17561756
"""
17571757

17581758
uri = f"/api/v1/sites/{site_id}/devices/{device_id}/clear_policy_hit_count"
1759-
resp = mist_session.mist_post(uri=uri)
1759+
resp = mist_session.mist_post(uri=uri, body=body)
17601760
return resp
17611761

17621762

@@ -2375,7 +2375,7 @@ def getSiteDeviceZtpPassword(
23752375

23762376

23772377
def testSiteSsrDnsResolution(
2378-
mist_session: _APISession, site_id: str, device_id: str
2378+
mist_session: _APISession, site_id: str, device_id: str, body: dict
23792379
) -> _APIResponse:
23802380
"""
23812381
API doc: https://www.juniper.net/documentation/us/en/software/mist/api/http/api/utilities/wan/test-site-ssr-dns-resolution
@@ -2397,7 +2397,7 @@ def testSiteSsrDnsResolution(
23972397
"""
23982398

23992399
uri = f"/api/v1/sites/{site_id}/devices/{device_id}/resolve_dns"
2400-
resp = mist_session.mist_post(uri=uri)
2400+
resp = mist_session.mist_post(uri=uri, body=body)
24012401
return resp
24022402

24032403

src/mistapi/websockets/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
ws.connect()
2222
"""
2323

24-
from mistapi.websockets import location, orgs, sites
24+
from mistapi.websockets import location, orgs, session, sites, utils

src/mistapi/websockets/__ws_client.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ class _MistWebsocket:
3939
def __init__(
4040
self,
4141
mist_session: "APISession",
42-
channel: str,
42+
channels: list[str],
4343
ping_interval: int = 30,
4444
ping_timeout: int = 10,
4545
) -> None:
4646
self._mist_session = mist_session
47-
self._channel = channel
47+
self._channels = channels
4848
self._ping_interval = ping_interval
4949
self._ping_timeout = ping_timeout
5050
self._ws: websocket.WebSocketApp | None = None
@@ -97,7 +97,8 @@ def on_close(self, callback: Callable[[int, str], None]) -> None:
9797
# Internal WebSocketApp handlers
9898

9999
def _handle_open(self, ws: websocket.WebSocketApp) -> None:
100-
ws.send(json.dumps({"subscribe": self._channel}))
100+
for channel in self._channels:
101+
ws.send(json.dumps({"subscribe": channel}))
101102
if self._on_open_cb:
102103
self._on_open_cb()
103104

src/mistapi/websockets/location.py

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from mistapi.websockets.__ws_client import _MistWebsocket
1616

1717

18-
class LocationBleAssetsEvents(_MistWebsocket):
18+
class BleAssetsEvents(_MistWebsocket):
1919
"""WebSocket stream for location BLE assets events.
2020
2121
Subscribes to the ``/sites/{site_id}/stats/maps/{map_id}/assets`` channel and delivers
@@ -27,8 +27,8 @@ class LocationBleAssetsEvents(_MistWebsocket):
2727
Authenticated API session.
2828
site_id : str
2929
UUID of the site to stream events from.
30-
map_id : str
31-
UUID of the map to stream events from.
30+
map_id : list[str]
31+
UUIDs of the maps to stream events from.
3232
ping_interval : int, default 30
3333
Interval in seconds to send WebSocket ping frames (keep-alive).
3434
ping_timeout : int, default 10
@@ -63,19 +63,20 @@ def __init__(
6363
self,
6464
mist_session: APISession,
6565
site_id: str,
66-
map_id: str,
66+
map_id: list[str],
6767
ping_interval: int = 30,
6868
ping_timeout: int = 10,
6969
) -> None:
70+
channels = [f"/sites/{site_id}/stats/maps/{mid}/assets" for mid in map_id]
7071
super().__init__(
7172
mist_session,
72-
channel=f"/sites/{site_id}/stats/maps/{map_id}/assets",
73+
channels=channels,
7374
ping_interval=ping_interval,
7475
ping_timeout=ping_timeout,
7576
)
7677

7778

78-
class LocationConnectedClientsEvents(_MistWebsocket):
79+
class ConnectedClientsEvents(_MistWebsocket):
7980
"""WebSocket stream for location connected clients events.
8081
8182
Subscribes to the ``/sites/{site_id}/stats/maps/{map_id}/clients`` channel and delivers
@@ -87,8 +88,8 @@ class LocationConnectedClientsEvents(_MistWebsocket):
8788
Authenticated API session.
8889
site_id : str
8990
UUID of the site to stream events from.
90-
map_id : str
91-
UUID of the map to stream events from.
91+
map_id : list[str]
92+
UUIDs of the maps to stream events from.
9293
ping_interval : int, default 30
9394
Interval in seconds to send WebSocket ping frames (keep-alive).
9495
ping_timeout : int, default 10
@@ -122,19 +123,20 @@ def __init__(
122123
self,
123124
mist_session: APISession,
124125
site_id: str,
125-
map_id: str,
126+
map_id: list[str],
126127
ping_interval: int = 30,
127128
ping_timeout: int = 10,
128129
) -> None:
130+
channels = [f"/sites/{site_id}/stats/maps/{mid}/clients" for mid in map_id]
129131
super().__init__(
130132
mist_session,
131-
channel=f"/sites/{site_id}/stats/maps/{map_id}/clients",
133+
channels=channels,
132134
ping_interval=ping_interval,
133135
ping_timeout=ping_timeout,
134136
)
135137

136138

137-
class LocationSdkClientsEvents(_MistWebsocket):
139+
class SdkClientsEvents(_MistWebsocket):
138140
"""WebSocket stream for location SDK clients events.
139141
140142
Subscribes to the ``/sites/{site_id}/stats/maps/{map_id}/sdkclients`` channel and delivers
@@ -146,8 +148,8 @@ class LocationSdkClientsEvents(_MistWebsocket):
146148
Authenticated API session.
147149
site_id : str
148150
UUID of the site to stream events from.
149-
map_id : str
150-
UUID of the map to stream events from.
151+
map_id : list[str]
152+
UUIDs of the maps to stream events from.
151153
ping_interval : int, default 30
152154
Interval in seconds to send WebSocket ping frames (keep-alive).
153155
ping_timeout : int, default 10
@@ -181,19 +183,20 @@ def __init__(
181183
self,
182184
mist_session: APISession,
183185
site_id: str,
184-
map_id: str,
186+
map_id: list[str],
185187
ping_interval: int = 30,
186188
ping_timeout: int = 10,
187189
) -> None:
190+
channels = [f"/sites/{site_id}/stats/maps/{mid}/sdkclients" for mid in map_id]
188191
super().__init__(
189192
mist_session,
190-
channel=f"/sites/{site_id}/stats/maps/{map_id}/sdkclients",
193+
channels=channels,
191194
ping_interval=ping_interval,
192195
ping_timeout=ping_timeout,
193196
)
194197

195198

196-
class LocationUnconnectedClientsEvents(_MistWebsocket):
199+
class UnconnectedClientsEvents(_MistWebsocket):
197200
"""WebSocket stream for location unconnected clients events.
198201
199202
Subscribes to the ``/sites/{site_id}/stats/maps/{map_id}/unconnected_clients`` channel and delivers
@@ -205,8 +208,8 @@ class LocationUnconnectedClientsEvents(_MistWebsocket):
205208
Authenticated API session.
206209
site_id : str
207210
UUID of the site to stream events from.
208-
map_id : str
209-
UUID of the map to stream events from.
211+
map_id : list[str]
212+
UUIDs of the maps to stream events from.
210213
ping_interval : int, default 30
211214
Interval in seconds to send WebSocket ping frames (keep-alive).
212215
ping_timeout : int, default 10
@@ -240,19 +243,22 @@ def __init__(
240243
self,
241244
mist_session: APISession,
242245
site_id: str,
243-
map_id: str,
246+
map_id: list[str],
244247
ping_interval: int = 30,
245248
ping_timeout: int = 10,
246249
) -> None:
250+
channels = [
251+
f"/sites/{site_id}/stats/maps/{mid}/unconnected_clients" for mid in map_id
252+
]
247253
super().__init__(
248254
mist_session,
249-
channel=f"/sites/{site_id}/stats/maps/{map_id}/unconnected_clients",
255+
channels=channels,
250256
ping_interval=ping_interval,
251257
ping_timeout=ping_timeout,
252258
)
253259

254260

255-
class LocationDiscoveredBleAssetsEvents(_MistWebsocket):
261+
class DiscoveredBleAssetsEvents(_MistWebsocket):
256262
"""WebSocket stream for location discovered BLE assets events.
257263
258264
Subscribes to the ``/sites/{site_id}/stats/maps/{map_id}/discovered_assets`` channel and delivers
@@ -264,8 +270,8 @@ class LocationDiscoveredBleAssetsEvents(_MistWebsocket):
264270
Authenticated API session.
265271
site_id : str
266272
UUID of the site to stream events from.
267-
map_id : str
268-
UUID of the map to stream events from.
273+
map_id : list[str]
274+
UUIDs of the maps to stream events from.
269275
ping_interval : int, default 30
270276
Interval in seconds to send WebSocket ping frames (keep-alive).
271277
ping_timeout : int, default 10
@@ -299,13 +305,16 @@ def __init__(
299305
self,
300306
mist_session: APISession,
301307
site_id: str,
302-
map_id: str,
308+
map_id: list[str],
303309
ping_interval: int = 30,
304310
ping_timeout: int = 10,
305311
) -> None:
312+
channels = [
313+
f"/sites/{site_id}/stats/maps/{mid}/discovered_assets" for mid in map_id
314+
]
306315
super().__init__(
307316
mist_session,
308-
channel=f"/sites/{site_id}/stats/maps/{map_id}/discovered_assets",
317+
channels=channels,
309318
ping_interval=ping_interval,
310319
ping_timeout=ping_timeout,
311320
)

src/mistapi/websockets/orgs.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from mistapi.websockets.__ws_client import _MistWebsocket
1616

1717

18-
class OrgInsightsEvents(_MistWebsocket):
18+
class InsightsEvents(_MistWebsocket):
1919
"""WebSocket stream for organization insights events.
2020
2121
Subscribes to the ``orgs/{org_id}/insights/summary`` channel and delivers
@@ -65,13 +65,13 @@ def __init__(
6565
) -> None:
6666
super().__init__(
6767
mist_session,
68-
channel=f"/orgs/{org_id}/insights/summary",
68+
channels=[f"/orgs/{org_id}/insights/summary"],
6969
ping_interval=ping_interval,
7070
ping_timeout=ping_timeout,
7171
)
7272

7373

74-
class OrgMxEdgesStatsEvents(_MistWebsocket):
74+
class MxEdgesStatsEvents(_MistWebsocket):
7575
"""WebSocket stream for organization MX edges stats events.
7676
7777
Subscribes to the ``orgs/{org_id}/stats/mxedges`` channel and delivers
@@ -121,13 +121,13 @@ def __init__(
121121
) -> None:
122122
super().__init__(
123123
mist_session,
124-
channel=f"/orgs/{org_id}/stats/mxedges",
124+
channels=[f"/orgs/{org_id}/stats/mxedges"],
125125
ping_interval=ping_interval,
126126
ping_timeout=ping_timeout,
127127
)
128128

129129

130-
class OrgMxEdgesUpgradesEvents(_MistWebsocket):
130+
class MxEdgesUpgradesEvents(_MistWebsocket):
131131
"""WebSocket stream for org MX edges upgrades events.
132132
133133
Subscribes to the ``orgs/{org_id}/mxedges`` channel and delivers
@@ -177,7 +177,7 @@ def __init__(
177177
) -> None:
178178
super().__init__(
179179
mist_session,
180-
channel=f"/orgs/{org_id}/mxedges",
180+
channels=[f"/orgs/{org_id}/mxedges"],
181181
ping_interval=ping_interval,
182182
ping_timeout=ping_timeout,
183183
)

src/mistapi/websockets/session.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
--------------------------------------------------------------------------------
3+
------------------------- Mist API Python CLI Session --------------------------
4+
5+
Written by: Thomas Munzer (tmunzer@juniper.net)
6+
Github : https://github.com/tmunzer/mistapi_python
7+
8+
This package is licensed under the MIT License.
9+
10+
--------------------------------------------------------------------------------
11+
WebSocket channel for Remote Commands events.
12+
"""
13+
14+
from mistapi import APISession
15+
from mistapi.websockets.__ws_client import _MistWebsocket
16+
17+
18+
class SessionWithUrl(_MistWebsocket):
19+
"""WebSocket stream for remote commands events.
20+
21+
Open a WebSocket connection to a custom channel URL for remote command events.
22+
This is a base class that can be used to implement specific remote command event streams by providing the
23+
appropriate channel URL.
24+
25+
PARAMS
26+
-----------
27+
mist_session : mistapi.APISession
28+
Authenticated API session.
29+
url : str
30+
URL of the WebSocket channel to connect to.
31+
ping_interval : int, default 30
32+
Interval in seconds to send WebSocket ping frames (keep-alive).
33+
ping_timeout : int, default 10
34+
Time in seconds to wait for a ping response before considering the connection dead.
35+
36+
EXAMPLE
37+
-----------
38+
Callback style (background thread)::
39+
40+
ws = sessionWithUrl(session, url="wss://example.com/channel")
41+
ws.on_message(lambda data: print(data))
42+
ws.connect()
43+
input("Press Enter to stop")
44+
ws.disconnect()
45+
46+
Generator style::
47+
48+
ws = sessionWithUrl(session, url="wss://example.com/channel")
49+
ws.connect(run_in_background=True)
50+
for msg in ws.receive():
51+
process(msg)
52+
53+
Context manager::
54+
55+
with sessionWithUrl(session, url="wss://example.com/channel") as ws:
56+
ws.on_message(my_handler)
57+
time.sleep(60)
58+
"""
59+
60+
def __init__(
61+
self,
62+
mist_session: APISession,
63+
url: str,
64+
ping_interval: int = 30,
65+
ping_timeout: int = 10,
66+
) -> None:
67+
super().__init__(
68+
mist_session,
69+
channels=[url],
70+
ping_interval=ping_interval,
71+
ping_timeout=ping_timeout,
72+
)

0 commit comments

Comments
 (0)