webex-bot 0.6.1__tar.gz → 1.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.
- {webex_bot-0.6.1/webex_bot.egg-info → webex_bot-1.0.0}/PKG-INFO +10 -1
- {webex_bot-0.6.1 → webex_bot-1.0.0}/README.md +9 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/setup.cfg +1 -1
- {webex_bot-0.6.1 → webex_bot-1.0.0}/setup.py +1 -1
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/__init__.py +1 -1
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/webex_bot.py +2 -4
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/websockets/webex_websocket_client.py +44 -17
- {webex_bot-0.6.1 → webex_bot-1.0.0/webex_bot.egg-info}/PKG-INFO +10 -1
- {webex_bot-0.6.1 → webex_bot-1.0.0}/CONTRIBUTING.rst +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/LICENSE +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/MANIFEST.in +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/docs/Makefile +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/docs/conf.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/docs/contributing.rst +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/docs/index.rst +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/docs/installation.rst +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/docs/make.bat +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/docs/usage.rst +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/tests/__init__.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/tests/test_webex_bot.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/cards/__init__.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/commands/__init__.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/commands/echo.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/commands/help.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/exceptions.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/formatting.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/models/__init__.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/models/command.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/models/response.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot/websockets/__init__.py +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot.egg-info/SOURCES.txt +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot.egg-info/dependency_links.txt +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot.egg-info/not-zip-safe +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot.egg-info/requires.txt +0 -0
- {webex_bot-0.6.1 → webex_bot-1.0.0}/webex_bot.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: webex_bot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
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
|
|
@@ -443,6 +443,13 @@ bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
|
443
443
|
|
|
444
444
|
* Handle and retry on InvalidStatusCode in Websocket loop
|
|
445
445
|
|
|
446
|
+
### 0.6.2 (2025-May-23)
|
|
447
|
+
|
|
448
|
+
* Fix for [issue #48][i48] - Fix for `Commands not being received` issue.
|
|
449
|
+
|
|
450
|
+
### 0.7.0 (2025-Jun-04)
|
|
451
|
+
|
|
452
|
+
* Add connection headers to requests.
|
|
446
453
|
|
|
447
454
|
[1]: https://github.com/aaugustin/websockets
|
|
448
455
|
|
|
@@ -489,3 +496,5 @@ bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
|
489
496
|
[i13]: https://github.com/fbradyirl/webex_bot/issues/13
|
|
490
497
|
|
|
491
498
|
[i20]: https://github.com/fbradyirl/webex_bot/issues/20
|
|
499
|
+
|
|
500
|
+
[i48]: https://github.com/fbradyirl/webex_bot/issues/48
|
|
@@ -403,6 +403,13 @@ bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
|
403
403
|
|
|
404
404
|
* Handle and retry on InvalidStatusCode in Websocket loop
|
|
405
405
|
|
|
406
|
+
### 0.6.2 (2025-May-23)
|
|
407
|
+
|
|
408
|
+
* Fix for [issue #48][i48] - Fix for `Commands not being received` issue.
|
|
409
|
+
|
|
410
|
+
### 0.7.0 (2025-Jun-04)
|
|
411
|
+
|
|
412
|
+
* Add connection headers to requests.
|
|
406
413
|
|
|
407
414
|
[1]: https://github.com/aaugustin/websockets
|
|
408
415
|
|
|
@@ -449,3 +456,5 @@ bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
|
449
456
|
[i13]: https://github.com/fbradyirl/webex_bot/issues/13
|
|
450
457
|
|
|
451
458
|
[i20]: https://github.com/fbradyirl/webex_bot/issues/20
|
|
459
|
+
|
|
460
|
+
[i48]: https://github.com/fbradyirl/webex_bot/issues/48
|
|
@@ -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:
|
|
@@ -12,6 +12,8 @@ import websockets
|
|
|
12
12
|
from webexpythonsdk import WebexAPI
|
|
13
13
|
from websockets.exceptions import InvalidStatusCode
|
|
14
14
|
|
|
15
|
+
from webex_bot import __version__
|
|
16
|
+
|
|
15
17
|
try:
|
|
16
18
|
from websockets_proxy import Proxy, proxy_connect
|
|
17
19
|
except ImportError:
|
|
@@ -20,7 +22,7 @@ except ImportError:
|
|
|
20
22
|
|
|
21
23
|
logger = logging.getLogger(__name__)
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
DEFAULT_U2C_URL = "https://u2c.wbx2.com/u2c/api/v1/catalog"
|
|
24
26
|
|
|
25
27
|
DEVICE_DATA = {
|
|
26
28
|
"deviceName": "pywebsocket-client",
|
|
@@ -41,25 +43,37 @@ MAX_BACKOFF_TIME = 240
|
|
|
41
43
|
class WebexWebsocketClient(object):
|
|
42
44
|
def __init__(self,
|
|
43
45
|
access_token,
|
|
44
|
-
device_url=DEFAULT_DEVICE_URL,
|
|
45
46
|
on_message=None,
|
|
46
47
|
on_card_action=None,
|
|
47
48
|
proxies=None):
|
|
48
49
|
self.access_token = access_token
|
|
49
50
|
self.teams = WebexAPI(access_token=access_token, proxies=proxies)
|
|
50
|
-
self.
|
|
51
|
+
self.tracking_id = f"webex-bot_{uuid.uuid4()}"
|
|
52
|
+
self.session = requests.Session()
|
|
53
|
+
self.session.headers = self._get_headers()
|
|
54
|
+
# log the tracking ID
|
|
55
|
+
logger.info(f"Tracking ID: {self.tracking_id}")
|
|
51
56
|
self.device_info = None
|
|
57
|
+
self.device_url = self._get_device_url()
|
|
52
58
|
self.on_message = on_message
|
|
53
59
|
self.on_card_action = on_card_action
|
|
54
60
|
self.proxies = proxies
|
|
55
61
|
self.websocket = None
|
|
56
62
|
self.share_id = None
|
|
57
|
-
|
|
63
|
+
if self.proxies:
|
|
64
|
+
self.session.proxies = proxies
|
|
58
65
|
if self.proxies:
|
|
59
66
|
# Connecting through a proxy
|
|
60
67
|
if proxy_connect is None:
|
|
61
68
|
raise ImportError("Failed to load libraries for proxy, maybe forgot [proxy] option during installation.")
|
|
62
69
|
|
|
70
|
+
def _get_headers(self):
|
|
71
|
+
return {
|
|
72
|
+
"Authorization": f"Bearer {self.access_token}",
|
|
73
|
+
"User-Agent": f"webex_bot/{__version__}",
|
|
74
|
+
"trackingid": self.tracking_id
|
|
75
|
+
}
|
|
76
|
+
|
|
63
77
|
def _process_incoming_websocket_message(self, msg):
|
|
64
78
|
"""
|
|
65
79
|
Handle websocket data.
|
|
@@ -136,10 +150,7 @@ class WebexWebsocketClient(object):
|
|
|
136
150
|
logger.debug(f"activity_id={activity_id}")
|
|
137
151
|
conversation_message_url = conversation_url.replace(f"conversations/{conv_target_id}",
|
|
138
152
|
f"{verb}/{activity_id}")
|
|
139
|
-
|
|
140
|
-
conversation_message = requests.get(conversation_message_url,
|
|
141
|
-
headers=headers,
|
|
142
|
-
proxies=self.proxies).json()
|
|
153
|
+
conversation_message = self.session.get(conversation_message_url).json()
|
|
143
154
|
logger.debug(f"conversation_message={conversation_message}")
|
|
144
155
|
return conversation_message['id']
|
|
145
156
|
|
|
@@ -155,6 +166,22 @@ class WebexWebsocketClient(object):
|
|
|
155
166
|
asyncio.run(self.websocket.send(json.dumps(ack_message)))
|
|
156
167
|
logger.info(f"WebSocket ack message with id={message_id}. Complete.")
|
|
157
168
|
|
|
169
|
+
def _get_device_url(self):
|
|
170
|
+
params = {"format": "hostmap"}
|
|
171
|
+
response = self.session.get(DEFAULT_U2C_URL, params=params)
|
|
172
|
+
|
|
173
|
+
# check for 401 Unauthorized
|
|
174
|
+
if response.status_code == 401:
|
|
175
|
+
logger.error("Unauthorized access. Please check your access token.")
|
|
176
|
+
raise Exception("Unauthorized access. Please check your access token.")
|
|
177
|
+
|
|
178
|
+
data = response.json()
|
|
179
|
+
|
|
180
|
+
wdm_url = data["serviceLinks"].get("wdm") # or whatever key your hostmap uses
|
|
181
|
+
logging.info(f"wdm url: {wdm_url}")
|
|
182
|
+
return wdm_url
|
|
183
|
+
|
|
184
|
+
|
|
158
185
|
def _get_device_info(self, check_existing=True):
|
|
159
186
|
"""
|
|
160
187
|
Get device info from Webex Cloud.
|
|
@@ -164,8 +191,8 @@ class WebexWebsocketClient(object):
|
|
|
164
191
|
if check_existing:
|
|
165
192
|
logger.debug('Getting device list')
|
|
166
193
|
try:
|
|
167
|
-
resp = self.
|
|
168
|
-
for device in resp['devices']:
|
|
194
|
+
resp = self.session.get(f"{self.device_url}/devices")
|
|
195
|
+
for device in resp.json()['devices']:
|
|
169
196
|
if device['name'] == DEVICE_DATA['name']:
|
|
170
197
|
self.device_info = device
|
|
171
198
|
logger.debug(f"device_info: {self.device_info}")
|
|
@@ -175,12 +202,12 @@ class WebexWebsocketClient(object):
|
|
|
175
202
|
|
|
176
203
|
logger.info('Device does not exist, creating')
|
|
177
204
|
|
|
178
|
-
resp = self.
|
|
205
|
+
resp = self.session.post(f"{self.device_url}/devices", json=DEVICE_DATA)
|
|
179
206
|
if resp is None:
|
|
180
207
|
raise Exception("could not create WDM device")
|
|
181
|
-
self.device_info = resp
|
|
208
|
+
self.device_info = resp.json()
|
|
182
209
|
logger.debug(f"self.device_info: {self.device_info}")
|
|
183
|
-
return
|
|
210
|
+
return self.device_info
|
|
184
211
|
|
|
185
212
|
def stop(self):
|
|
186
213
|
def terminate():
|
|
@@ -226,14 +253,14 @@ class WebexWebsocketClient(object):
|
|
|
226
253
|
if self.proxies and "wss" in self.proxies:
|
|
227
254
|
logger.info(f"Using proxy for websocket connection: {self.proxies['wss']}")
|
|
228
255
|
proxy = Proxy.from_url(self.proxies["wss"])
|
|
229
|
-
connect = proxy_connect(ws_url, ssl=ssl_context, proxy=proxy)
|
|
256
|
+
connect = proxy_connect(ws_url, ssl=ssl_context, proxy=proxy, extra_headers=self._get_headers())
|
|
230
257
|
elif self.proxies and "https" in self.proxies:
|
|
231
258
|
logger.info(f"Using proxy for websocket connection: {self.proxies['https']}")
|
|
232
259
|
proxy = Proxy.from_url(self.proxies["https"])
|
|
233
|
-
connect = proxy_connect(ws_url, ssl=ssl_context, proxy=proxy)
|
|
260
|
+
connect = proxy_connect(ws_url, ssl=ssl_context, proxy=proxy, extra_headers=self._get_headers())
|
|
234
261
|
else:
|
|
235
262
|
logger.debug(f"Not using proxy for websocket connection.")
|
|
236
|
-
connect = websockets.connect(ws_url, ssl=ssl_context)
|
|
263
|
+
connect = websockets.connect(ws_url, ssl=ssl_context, extra_headers=self._get_headers())
|
|
237
264
|
|
|
238
265
|
async with connect as _websocket:
|
|
239
266
|
self.websocket = _websocket
|
|
@@ -264,4 +291,4 @@ class WebexWebsocketClient(object):
|
|
|
264
291
|
logger.error('could not create device info')
|
|
265
292
|
raise Exception("No WDM device info")
|
|
266
293
|
# trigger re-connect
|
|
267
|
-
asyncio.get_event_loop().run_until_complete(_connect_and_listen())
|
|
294
|
+
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.
|
|
3
|
+
Version: 1.0.0
|
|
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
|
|
@@ -443,6 +443,13 @@ bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
|
443
443
|
|
|
444
444
|
* Handle and retry on InvalidStatusCode in Websocket loop
|
|
445
445
|
|
|
446
|
+
### 0.6.2 (2025-May-23)
|
|
447
|
+
|
|
448
|
+
* Fix for [issue #48][i48] - Fix for `Commands not being received` issue.
|
|
449
|
+
|
|
450
|
+
### 0.7.0 (2025-Jun-04)
|
|
451
|
+
|
|
452
|
+
* Add connection headers to requests.
|
|
446
453
|
|
|
447
454
|
[1]: https://github.com/aaugustin/websockets
|
|
448
455
|
|
|
@@ -489,3 +496,5 @@ bot = WebexBot(teams_bot_token=os.getenv("WEBEX_ACCESS_TOKEN")
|
|
|
489
496
|
[i13]: https://github.com/fbradyirl/webex_bot/issues/13
|
|
490
497
|
|
|
491
498
|
[i20]: https://github.com/fbradyirl/webex_bot/issues/20
|
|
499
|
+
|
|
500
|
+
[i48]: https://github.com/fbradyirl/webex_bot/issues/48
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|