From 7be2620c28dfa056c67bf71eea0cdb67e0213d73 Mon Sep 17 00:00:00 2001 From: Midgard Date: Wed, 26 Oct 2022 13:53:14 +0200 Subject: [PATCH] Add tail command --- mmcli.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/mmcli.py b/mmcli.py index b4b61fa..4e19535 100755 --- a/mmcli.py +++ b/mmcli.py @@ -244,6 +244,80 @@ def cat(mm_api: mattermost.MMApi, cmdline_args): print_initial_messages() +def tail(mm_api: mattermost.MMApi, cmdline_args): + + team, channel = resolve_team_channel(mm_api, cmdline_args.channel) + + if not cmdline_args.ids: + users = list(mm_api.get_users()) + 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 + + + # In a list to allow overwriting from within print_initial_messages without using global + backlog = [ [] ] + backlog_lock = threading.Lock() + + def print_initial_messages(): + data_page = mm_api._get(f"/v4/channels/{channel['id']}/posts") + order = data_page["order"] + posts = [ + data_page["posts"][post_id] + for post_id in reversed(order) + ] + + for post in posts: + print(str_for_post(attribute, post, cmdline_args)) + + with backlog_lock: + for post in backlog[0]: + print(str_for_post(attribute, post, cmdline_args)) + backlog[0] = None + + if cmdline_args.follow: + def simple_websocket_callback(_mmws, event_data): + if event_data.get("event") == "posted": + post = json.loads(event_data["data"]["post"]) + if post["channel_id"] != channel["id"]: + return + print(str_for_post(attribute, post, cmdline_args), flush=True) + + def initial_websocket_callback(mmws: MMws, event_data): + if event_data.get("event") == "posted": + post = json.loads(event_data["data"]["post"]) + if post["channel_id"] != channel["id"]: + return + with backlog_lock: + if backlog[0] is not None: + backlog[0].append(post) + return + else: + mmws.ws_handler = simple_websocket_callback + simple_websocket_callback(mmws, event_data) + + ws_url = http_to_ws(mm_api._url) + "/v4/websocket" + mmws = MMws(initial_websocket_callback, mm_api.access_token, ws_url) + + thread = threading.Thread(target=print_initial_messages) + thread.setDaemon(True) + thread.start() + + mmws.run_websocket() + + else: + print_initial_messages() + + + def ls(mm_api: mattermost.MMApi, cmdline_args): # TODO --follow doesn't work for channel creation and deletion yet @@ -407,6 +481,7 @@ def str_for_chan(attribute, channel, cmdline_args): ACTIONS = { "login": {"function": login, "accesstoken_required": False}, "cat": {"function": cat}, + "tail": {"function": tail}, "ls": {"function": ls}, "send": {"function": send}, "rm": {"function": rm}, @@ -477,6 +552,10 @@ Security note: Other programs and users can typically read which arguments you g parser_cat.add_argument("--since", help="all after timestamp") parser_cat.add_argument("-f", "--follow", action="store_true", help="keep running, printing new posts as they come in") + parser_tail = subparsers.add_parser("tail", help="list newest messages in channel") + parser_tail.add_argument("channel", help="URL names of team and channel: '/'") + parser_tail.add_argument("-f", "--follow", action="store_true", help="keep running, printing new posts as they come in") + parser_ls = subparsers.add_parser("ls", help="list channels") parser_ls.add_argument("team", help="URL name of team") parser_ls.add_argument("-f", "--follow", action="store_true", help="keep running, printing changes to channels as they come in")