webex-bot 0.6.0__py2.py3-none-any.whl → 0.6.2__py2.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.
- webex_bot/__init__.py +1 -1
- webex_bot/webex_bot.py +2 -4
- webex_bot/websockets/webex_websocket_client.py +47 -8
- {webex_bot-0.6.0.dist-info → webex_bot-0.6.2.dist-info}/METADATA +12 -1
- {webex_bot-0.6.0.dist-info → webex_bot-0.6.2.dist-info}/RECORD +8 -8
- {webex_bot-0.6.0.dist-info → webex_bot-0.6.2.dist-info}/WHEEL +1 -1
- {webex_bot-0.6.0.dist-info → webex_bot-0.6.2.dist-info}/licenses/LICENSE +0 -0
- {webex_bot-0.6.0.dist-info → webex_bot-0.6.2.dist-info}/top_level.txt +0 -0
webex_bot/__init__.py
CHANGED
webex_bot/webex_bot.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Main module."""
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
-
|
|
5
4
|
import types
|
|
5
|
+
|
|
6
6
|
import backoff
|
|
7
7
|
import coloredlogs
|
|
8
8
|
import requests
|
|
@@ -14,7 +14,7 @@ from webex_bot.exceptions import BotException
|
|
|
14
14
|
from webex_bot.formatting import quote_info
|
|
15
15
|
from webex_bot.models.command import CALLBACK_KEYWORD_KEY, Command, COMMAND_KEYWORD_KEY
|
|
16
16
|
from webex_bot.models.response import Response
|
|
17
|
-
from webex_bot.websockets.webex_websocket_client import WebexWebsocketClient
|
|
17
|
+
from webex_bot.websockets.webex_websocket_client import WebexWebsocketClient
|
|
18
18
|
|
|
19
19
|
log = logging.getLogger(__name__)
|
|
20
20
|
|
|
@@ -26,7 +26,6 @@ class WebexBot(WebexWebsocketClient):
|
|
|
26
26
|
approved_users=[],
|
|
27
27
|
approved_domains=[],
|
|
28
28
|
approved_rooms=[],
|
|
29
|
-
device_url=DEFAULT_DEVICE_URL,
|
|
30
29
|
include_demo_commands=False,
|
|
31
30
|
bot_name="Webex Bot",
|
|
32
31
|
bot_help_subtitle="Here are my available commands. Click one to begin.",
|
|
@@ -60,7 +59,6 @@ class WebexBot(WebexWebsocketClient):
|
|
|
60
59
|
teams_bot_token,
|
|
61
60
|
on_message=self.process_incoming_message,
|
|
62
61
|
on_card_action=self.process_incoming_card_action,
|
|
63
|
-
device_url=device_url,
|
|
64
62
|
proxies=proxies)
|
|
65
63
|
|
|
66
64
|
if help_command is None:
|
|
@@ -10,6 +10,7 @@ import certifi
|
|
|
10
10
|
import requests
|
|
11
11
|
import websockets
|
|
12
12
|
from webexpythonsdk import WebexAPI
|
|
13
|
+
from websockets.exceptions import InvalidStatusCode
|
|
13
14
|
|
|
14
15
|
try:
|
|
15
16
|
from websockets_proxy import Proxy, proxy_connect
|
|
@@ -19,7 +20,7 @@ except ImportError:
|
|
|
19
20
|
|
|
20
21
|
logger = logging.getLogger(__name__)
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
DEFAULT_U2C_URL = "https://u2c.wbx2.com/u2c/api/v1/catalog"
|
|
23
24
|
|
|
24
25
|
DEVICE_DATA = {
|
|
25
26
|
"deviceName": "pywebsocket-client",
|
|
@@ -40,14 +41,13 @@ MAX_BACKOFF_TIME = 240
|
|
|
40
41
|
class WebexWebsocketClient(object):
|
|
41
42
|
def __init__(self,
|
|
42
43
|
access_token,
|
|
43
|
-
device_url=DEFAULT_DEVICE_URL,
|
|
44
44
|
on_message=None,
|
|
45
45
|
on_card_action=None,
|
|
46
46
|
proxies=None):
|
|
47
47
|
self.access_token = access_token
|
|
48
48
|
self.teams = WebexAPI(access_token=access_token, proxies=proxies)
|
|
49
|
-
self.device_url = device_url
|
|
50
49
|
self.device_info = None
|
|
50
|
+
self.device_url = self._get_device_url()
|
|
51
51
|
self.on_message = on_message
|
|
52
52
|
self.on_card_action = on_card_action
|
|
53
53
|
self.proxies = proxies
|
|
@@ -154,6 +154,25 @@ class WebexWebsocketClient(object):
|
|
|
154
154
|
asyncio.run(self.websocket.send(json.dumps(ack_message)))
|
|
155
155
|
logger.info(f"WebSocket ack message with id={message_id}. Complete.")
|
|
156
156
|
|
|
157
|
+
def _get_device_url(self):
|
|
158
|
+
headers = {}
|
|
159
|
+
headers["Authorization"] = 'Bearer ' + self.access_token
|
|
160
|
+
|
|
161
|
+
params = {"format": "hostmap"}
|
|
162
|
+
response = requests.get(DEFAULT_U2C_URL, headers=headers, params=params)
|
|
163
|
+
|
|
164
|
+
# check for 401 Unauthorized
|
|
165
|
+
if response.status_code == 401:
|
|
166
|
+
logger.error("Unauthorized access. Please check your access token.")
|
|
167
|
+
raise Exception("Unauthorized access. Please check your access token.")
|
|
168
|
+
|
|
169
|
+
data = response.json()
|
|
170
|
+
|
|
171
|
+
wdm_url = data["serviceLinks"].get("wdm") # or whatever key your hostmap uses
|
|
172
|
+
logging.info(f"wdm url: {wdm_url}")
|
|
173
|
+
return wdm_url
|
|
174
|
+
|
|
175
|
+
|
|
157
176
|
def _get_device_info(self, check_existing=True):
|
|
158
177
|
"""
|
|
159
178
|
Get device info from Webex Cloud.
|
|
@@ -193,6 +212,9 @@ class WebexWebsocketClient(object):
|
|
|
193
212
|
logger.error('could not get/create device info')
|
|
194
213
|
raise Exception("No WDM device info")
|
|
195
214
|
|
|
215
|
+
# Pull out URL now so we can log it on failure
|
|
216
|
+
ws_url = self.device_info.get('webSocketUrl')
|
|
217
|
+
|
|
196
218
|
async def _websocket_recv():
|
|
197
219
|
message = await self.websocket.recv()
|
|
198
220
|
logger.debug("WebSocket Received Message(raw): %s\n" % message)
|
|
@@ -204,10 +226,17 @@ class WebexWebsocketClient(object):
|
|
|
204
226
|
logger.warning(
|
|
205
227
|
f"An exception occurred while processing message. Ignoring. {messageProcessingException}")
|
|
206
228
|
|
|
207
|
-
@backoff.on_exception(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
229
|
+
@backoff.on_exception(
|
|
230
|
+
backoff.expo,
|
|
231
|
+
(
|
|
232
|
+
websockets.ConnectionClosedError,
|
|
233
|
+
websockets.ConnectionClosedOK,
|
|
234
|
+
websockets.ConnectionClosed,
|
|
235
|
+
socket.gaierror,
|
|
236
|
+
InvalidStatusCode,
|
|
237
|
+
),
|
|
238
|
+
max_time=MAX_BACKOFF_TIME
|
|
239
|
+
)
|
|
211
240
|
async def _connect_and_listen():
|
|
212
241
|
ws_url = self.device_info['webSocketUrl']
|
|
213
242
|
logger.info(f"Opening websocket connection to {ws_url}")
|
|
@@ -237,10 +266,20 @@ class WebexWebsocketClient(object):
|
|
|
237
266
|
|
|
238
267
|
try:
|
|
239
268
|
asyncio.get_event_loop().run_until_complete(_connect_and_listen())
|
|
269
|
+
except InvalidStatusCode as e:
|
|
270
|
+
logger.error(f"WebSocket handshake to {ws_url} failed with status {e.status_code}")
|
|
271
|
+
if e.status_code == 404:
|
|
272
|
+
logger.info("Refreshing WDM device info and retrying...")
|
|
273
|
+
self._get_device_info(check_existing=False)
|
|
274
|
+
# update ws_url before retry
|
|
275
|
+
ws_url = self.device_info.get('webSocketUrl')
|
|
276
|
+
asyncio.get_event_loop().run_until_complete(_connect_and_listen())
|
|
277
|
+
else:
|
|
278
|
+
raise
|
|
240
279
|
except Exception as runException:
|
|
241
280
|
logger.error(f"runException: {runException}")
|
|
242
281
|
if self._get_device_info(check_existing=False) is None:
|
|
243
282
|
logger.error('could not create device info')
|
|
244
283
|
raise Exception("No WDM device info")
|
|
245
284
|
# trigger re-connect
|
|
246
|
-
asyncio.get_event_loop().run_until_complete(_connect_and_listen())
|
|
285
|
+
asyncio.get_event_loop().run_until_complete(_connect_and_listen())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: webex_bot
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Python package for a Webex Bot based on websockets.
|
|
5
5
|
Home-page: https://github.com/fbradyirl/webex_bot
|
|
6
6
|
Author: Finbarr Brady
|
|
@@ -438,6 +438,15 @@ to
|
|
|
438
438
|
bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
439
439
|
```
|
|
440
440
|
|
|
441
|
+
|
|
442
|
+
### 0.6.1 (2025-May-19)
|
|
443
|
+
|
|
444
|
+
* Handle and retry on InvalidStatusCode in Websocket loop
|
|
445
|
+
|
|
446
|
+
### 0.6.2 (2025-May-23)
|
|
447
|
+
|
|
448
|
+
* Fix for [issue #48][i48] - Fix for `Commands not being received` issue.
|
|
449
|
+
|
|
441
450
|
[1]: https://github.com/aaugustin/websockets
|
|
442
451
|
|
|
443
452
|
[2]: https://github.com/WebexCommunity/WebexPythonSDK
|
|
@@ -483,3 +492,5 @@ bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
|
483
492
|
[i13]: https://github.com/fbradyirl/webex_bot/issues/13
|
|
484
493
|
|
|
485
494
|
[i20]: https://github.com/fbradyirl/webex_bot/issues/20
|
|
495
|
+
|
|
496
|
+
[i48]: https://github.com/fbradyirl/webex_bot/issues/48
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
webex_bot/__init__.py,sha256=
|
|
1
|
+
webex_bot/__init__.py,sha256=EP4VtizaH3ugEVwSp88ObjRczYV5ZlL4rNJ1vMC9BkA,95
|
|
2
2
|
webex_bot/exceptions.py,sha256=qs9yVitfJtvxwBMC8uCvTDOxUQ_oZjWFf1dU8Oaue14,740
|
|
3
3
|
webex_bot/formatting.py,sha256=jvPKym-z8CIJygpPVTVbt6vFXQo9_HQHpRDJB-nh-SI,382
|
|
4
|
-
webex_bot/webex_bot.py,sha256=
|
|
4
|
+
webex_bot/webex_bot.py,sha256=np5uGnVJc-l9jrbD9UPeoZU5JeuD8THLWd6Ml9HTlJ4,21153
|
|
5
5
|
webex_bot/cards/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
webex_bot/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
webex_bot/commands/echo.py,sha256=STY-MikBRjUteDK-g8G4GPB0V-Yi7siPN1DRMXrT-QU,3399
|
|
@@ -10,9 +10,9 @@ webex_bot/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
|
10
10
|
webex_bot/models/command.py,sha256=MyThlDaEkGlj1fDE_i_wr79O3QboakimRme8yI744yo,5327
|
|
11
11
|
webex_bot/models/response.py,sha256=d4k2ohR5SUVzvuQzcnm7jQQVTMB0gH9Kz9y09vkoAaU,2545
|
|
12
12
|
webex_bot/websockets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
webex_bot/websockets/webex_websocket_client.py,sha256=
|
|
14
|
-
webex_bot-0.6.
|
|
15
|
-
webex_bot-0.6.
|
|
16
|
-
webex_bot-0.6.
|
|
17
|
-
webex_bot-0.6.
|
|
18
|
-
webex_bot-0.6.
|
|
13
|
+
webex_bot/websockets/webex_websocket_client.py,sha256=byESKbgWa4x-tGX0DboWGfB3cpCAmPVyiL19V4FGVAc,11903
|
|
14
|
+
webex_bot-0.6.2.dist-info/licenses/LICENSE,sha256=93eGb10xmgkBP2Fh_n0E9YDXe0c0oz-FsnAimXG0S4Y,1072
|
|
15
|
+
webex_bot-0.6.2.dist-info/METADATA,sha256=HjomyzkjM0IFLrU7KD-eOCudzO2RtSLATk_9xcWjtgM,14590
|
|
16
|
+
webex_bot-0.6.2.dist-info/WHEEL,sha256=egKm5cKfE6OqlHwodY8Jjp4yqZDBXgsj09UsV5ojd_U,109
|
|
17
|
+
webex_bot-0.6.2.dist-info/top_level.txt,sha256=q1Y0RtYYinR7oXSwL93cK59c2KN_CbMVca8MLWeF63M,10
|
|
18
|
+
webex_bot-0.6.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|