Add sending, start work on --follow

This commit is contained in:
Midgard 2021-03-15 01:11:50 +01:00
parent 6a35ad2554
commit 65bfa726ca
Signed by: midgard
GPG key ID: 511C112F1331BBB4
3 changed files with 109 additions and 23 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
__pycache__/
*.pyc
*.pyo

View file

@ -10,8 +10,10 @@ import time
import json import json
from typing import Dict, Set, Generator, Optional, NamedTuple from typing import Dict, Set, Generator, Optional, NamedTuple
import mattermost import mattermost
import mattermost.ws
import re import re
from threading import Lock
from mmws import MMws
class NotFound(Exception): class NotFound(Exception):
@ -31,6 +33,14 @@ def yes_no(x):
return "yes" if x else "no" return "yes" if x else "no"
def http_to_ws(url):
"""
Transform url from http to ws and https to wss
"""
assert url.startswith("http://") or url.startswith("https://")
return "ws" + url[4:]
def get_posts_for_channel(self, channel_id: str, progress=lambda x: None, **kwargs) -> Generator[Dict, None, None]: def get_posts_for_channel(self, channel_id: str, progress=lambda x: None, **kwargs) -> Generator[Dict, None, None]:
""" """
@raises ApiException: Passed on from lower layers. @raises ApiException: Passed on from lower layers.
@ -117,30 +127,50 @@ def login(mm_api, parsed):
def cat(mm_api: mattermost.MMApi, parsed): def cat(mm_api: mattermost.MMApi, parsed):
channels = [ # channels = [
resolve_team_channel(mm_api, query) # resolve_team_channel(mm_api, query)
for query in parsed.channels # for query in parsed.channels
] # ]
team, channel = resolve_team_channel(mm_api, parsed.channel)
users = list(mm_api.get_users()) users = list(mm_api.get_users())
if not parsed.ids:
def attribute(key_value):
key, value = key_value
if key == "channel_id":
assert value == channel["id"]
return "channel", channel["name"]
if key == "user_id":
return "username", first(u["username"] for u in users if u["id"] == value)
return key_value
else:
def attribute(key_value):
return key_value
for team, channel in channels: # backlog = []
if not parsed.ids: # backlog_lock = Lock()
def attribute(key_value): if parsed.follow:
key, value = key_value raise NotImplementedError("--follow is not yet supported")
if key == "channel_id": # def webs_handler(mmws, event_data):
assert value == channel["id"] # if event_data["event"] == "posted":
return "channel", channel["name"] # with backlog_lock:
if key == "user_id": # if backlog is not None:
return "username", first(u["username"] for u in users if u["id"] == value) # backlog.append(event_data["data"])
return key_value # return
else: # print(post_str(attribute, event_data["data"], parsed))
def attribute(key_value):
return key_value
posts = get_posts_for_channel(mm_api, channel["id"], after=parsed.after) # ws_url = http_to_ws(mm_api._url) + "/v4/websocket"
for post in posts: # MMws(webs_handler, mm_api, ws_url)
print(post_str(attribute, post, parsed)) # return
posts = get_posts_for_channel(mm_api, channel["id"], after=parsed.after)
for post in posts:
print(post_str(attribute, post, parsed))
# with backlog_lock:
# for post in backlog:
# print(post_str(attribute, post, parsed))
# backlog = None
def send(mm_api: mattermost.MMApi, parsed): def send(mm_api: mattermost.MMApi, parsed):
@ -245,7 +275,7 @@ Hint: JSON output can be filtered on the command line with jq(1).
# --- # ---
parser_cat.add_argument("--after", help="all after post with ID") parser_cat.add_argument("--after", help="all after post with ID")
parser_cat.add_argument("--since", help="all after timestamp") parser_cat.add_argument("--since", help="all after timestamp")
parser_cat.add_argument("-f", "--follow", help="keep running, printing new posts as they come in") parser_cat.add_argument("-f", "--follow", action="store_true", help="keep running, printing new posts as they come in")
parser_send = subparsers.add_parser("send", help="send message(s)") parser_send = subparsers.add_parser("send", help="send message(s)")
parser_send.add_argument( parser_send.add_argument(
@ -268,7 +298,8 @@ Hint: JSON output can be filtered on the command line with jq(1).
f"`{prog_name} {parsed.action}` requires access token; get one with `{prog_name} login` " f"`{prog_name} {parsed.action}` requires access token; get one with `{prog_name} login` "
f"and set environment variable {ENVVAR_ACCESSTOKEN}") f"and set environment variable {ENVVAR_ACCESSTOKEN}")
mm_api = mattermost.MMApi(f"https://{parsed.server}/api") server = parsed.server if re.match(r"^[a-z]+://", parsed.server) else f"https://{parsed.server}"
mm_api = mattermost.MMApi(f"{server}/api")
if access_token: if access_token:
mm_api._headers.update({"Authorization": f"Bearer {access_token}"}) mm_api._headers.update({"Authorization": f"Bearer {access_token}"})

52
mmws.py Normal file
View file

@ -0,0 +1,52 @@
import sys
import json
import threading
import websocket
websocket.enableTrace(True)
class MMws:
"""
Websocket client.
"""
def __init__(self, ws_handler, api, ws_url):
self.api = api
self.ws_url = ws_url
self.ws_handler = ws_handler
self.ws_app = None
self.thread = threading.Thread(target=self._open_websocket)
self.thread.setName("websocket")
self.thread.setDaemon(False)
self.thread.start()
def _open_websocket(self):
def on_open(ws):
print("Opened")
ws.send(json.dumps({
"seq": 1, "action": "authentication_challenge", "data": {"token": self.api._bearer}
}))
def on_message(ws, msg):
print(msg)
self.ws_handler(self, msg)
def on_error(ws, error):
print(error, file=sys.stderr)
sys.exit(1)
self.ws_app = websocket.WebSocketApp(self.ws_url, on_open=on_open, on_message=on_message,
on_close=lambda ws: print("Closed"))
print("Start", flush=True)
self.ws_app.run_forever()
print("Done", flush=True)
def close_websocket(self):
self.ws_app.close()
self.thread.join()