diff --git a/HACKING.md b/HACKING.md index f2136b2..fd88c66 100644 --- a/HACKING.md +++ b/HACKING.md @@ -32,31 +32,21 @@ on chat, e.g. text-to-speech or Twitch Plays Pokémon. View events like this: ```sh -socat UNIX-CONNECT:event.sock STDOUT +socat -u UNIX-CONNECT:event.sock STDOUT ``` -Sidenote, this will still read from stdin, and if you send anything on -stdin the event socket will close itself. If you want to ignore stdin, -I couldn't figure out how to get `socat` to do it so you can do it like -this: -```sh -cat > /dev/null | socat UNIX-CONNECT:event.sock STDOUT -``` -If you do this `cat` will not exit when the connection is closed so you -will probably have to interrupt it with `^C`. - #### Examples If you have `jq` you can view prettified events like this: ```sh -socat UNIX-CONNECT:event.sock STDOUT | jq +socat -u UNIX-CONNECT:event.sock STDOUT | jq ``` (On older versions of `jq` you have to say `jq .` when reading from stdin.) Use this to get each new chat message on a new line: ```sh -socat UNIX-CONNECT:event.sock STDOUT | jq 'select(.type == "message") | .event.nomarkup' +socat -u UNIX-CONNECT:event.sock STDOUT | jq 'select(.type == "message") | .event.nomarkup' ``` ##### Text-to-speech @@ -65,7 +55,7 @@ This command will take each new chat message with the prefix "!say ", strip the prefix, and synthesize the rest of the message as speech using `espeak`: ```sh -socat UNIX-CONNECT:event.sock STDOUT \ +socat -u UNIX-CONNECT:event.sock STDOUT \ | jq --unbuffered 'select(.type == "message") | .event.nomarkup' \ | grep -E --line-buffered '^"!say ' \ | sed -Eu 's/^"!say /"/' \ diff --git a/anonstream/__init__.py b/anonstream/__init__.py index f918218..a6f34c0 100644 --- a/anonstream/__init__.py +++ b/anonstream/__init__.py @@ -75,7 +75,7 @@ def create_app(toml_config): from anonstream.events import start_event_server_at async def start_event_server(): return await start_event_server_at( - app.config['SOCKET_EVENT_ADDRESS'] + app.config['SOCKET_EVENT_ADDRESS'] ) app.add_background_task(start_event_server) diff --git a/anonstream/control/spec/methods/chat.py b/anonstream/control/spec/methods/chat.py index a77f822..a95cae7 100644 --- a/anonstream/control/spec/methods/chat.py +++ b/anonstream/control/spec/methods/chat.py @@ -31,7 +31,7 @@ class ArgsSeqs(Args): async def cmd_chat_help(): normal = ['chat', 'help'] response = ( - 'Usage: chat {show [MESSAGES] | delete SEQS}\n' + 'Usage: chat delete SEQS\n' 'Commands:\n' #' chat show [MESSAGES]......show chat messages\n' ' chat delete SEQS..........delete chat messages\n' diff --git a/anonstream/helpers/user.py b/anonstream/helpers/user.py index b4d8346..7bc6e63 100644 --- a/anonstream/helpers/user.py +++ b/anonstream/helpers/user.py @@ -23,7 +23,8 @@ def generate_token_hash_and_tag(token): return token_hash, tag def generate_user( - timestamp, token, broadcaster, verified=False, presence=Presence.NOTWATCHING, + timestamp, token, broadcaster, + verified=False, presence=Presence.NOTWATCHING, headers=None, ): colour = generate_colour( seed='name\0' + token, @@ -54,6 +55,7 @@ def generate_user( 'total': 0, 'current': {}, }, + 'headers': headers, } def get_default_name(user): diff --git a/anonstream/routes/__init__.py b/anonstream/routes/__init__.py index b537c93..d081546 100644 --- a/anonstream/routes/__init__.py +++ b/anonstream/routes/__init__.py @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2022 n9k # SPDX-License-Identifier: AGPL-3.0-or-later -import anonstream.routes.errors +import anonstream.routes.error import anonstream.routes.core import anonstream.routes.websocket import anonstream.routes.nojs diff --git a/anonstream/routes/core.py b/anonstream/routes/core.py index fb9630a..bebd50a 100644 --- a/anonstream/routes/core.py +++ b/anonstream/routes/core.py @@ -47,7 +47,7 @@ async def stream(timestamp, user): raise NotFound('The stream is offline.') else: try: - eyes_id = create_eyes(user, dict(request.headers)) + eyes_id = create_eyes(user, tuple(request.headers)) except RatelimitedEyes as e: retry_after, *_ = e.args error = TooManyRequests( diff --git a/anonstream/routes/errors.py b/anonstream/routes/error.py similarity index 100% rename from anonstream/routes/errors.py rename to anonstream/routes/error.py diff --git a/anonstream/routes/nojs.py b/anonstream/routes/nojs.py index 0ce8d12..412ffbe 100644 --- a/anonstream/routes/nojs.py +++ b/anonstream/routes/nojs.py @@ -151,7 +151,7 @@ async def nojs_submit_message(timestamp, user): else: state_id = None if message_was_added: - deverify(user) + deverify(user, timestamp=timestamp) url = url_for( 'nojs_chat_form', diff --git a/anonstream/routes/wrappers.py b/anonstream/routes/wrappers.py index cd184ae..04ff2db 100644 --- a/anonstream/routes/wrappers.py +++ b/anonstream/routes/wrappers.py @@ -72,7 +72,7 @@ def auth_required(f): return wrapper def generate_and_add_user( - timestamp, token=None, broadcaster=False, verified=False, + timestamp, token=None, broadcaster=False, verified=False, headers=None, ): token = token or generate_token() user = generate_user( @@ -80,6 +80,7 @@ def generate_and_add_user( token=token, broadcaster=broadcaster, verified=verified, + headers=headers, ) USERS_BY_TOKEN[token] = user USERS_UPDATE_BUFFER.add(token) @@ -132,6 +133,7 @@ def with_user_from(context, fallback_to_token=False): if CONFIG['ACCESS_CAPTCHA'] and not broadcaster: if user is not None: user['last']['seen'] = timestamp + user['headers'] = tuple(context.headers) response = await f(timestamp, user, *args, **kwargs) elif fallback_to_token: #assert not broadcaster @@ -146,8 +148,14 @@ def with_user_from(context, fallback_to_token=False): else: if user is not None: user['last']['seen'] = timestamp + user['headers'] = tuple(context.headers) else: - user = generate_and_add_user(timestamp, token, broadcaster) + user = generate_and_add_user( + timestamp, + token, + broadcaster, + headers=tuple(context.headers), + ) response = await f(timestamp, user, *args, **kwargs) # Set cookie diff --git a/anonstream/static/anonstream.js b/anonstream/static/anonstream.js index 4b071ff..6a9c9db 100644 --- a/anonstream/static/anonstream.js +++ b/anonstream/static/anonstream.js @@ -851,6 +851,7 @@ const connect_websocket = () => { } chat_live_ball.style.borderColor = "gold"; chat_live_status.innerHTML = "Connecting to chat...···"; + ws = null; ws = new WebSocket(`ws://${document.domain}:${location.port}/live?token=${encodeURIComponent(TOKEN)}`); ws.addEventListener("open", (event) => { console.log("websocket open", event); diff --git a/anonstream/tasks.py b/anonstream/tasks.py index 565e4e1..fe92fee 100644 --- a/anonstream/tasks.py +++ b/anonstream/tasks.py @@ -9,7 +9,7 @@ from quart import current_app, websocket from anonstream.broadcast import broadcast, broadcast_users_update from anonstream.stream import is_online, get_stream_title, get_stream_uptime_and_viewership -from anonstream.user import get_sunsettable_users +from anonstream.user import get_absent_users, get_sunsettable_users, deverify from anonstream.wrappers import with_timestamp CONFIG = current_app.config @@ -64,6 +64,12 @@ async def t_sunset_users(timestamp, iteration): if iteration == 0: return + # Deverify absent users + for user in get_absent_users(timestamp): + deverify(user, timestamp=timestamp) + + # Remove as many absent users as possible + # Broadcast a users update, in case any users being # removed have been mutated or are new. broadcast_users_update() diff --git a/anonstream/templates/captcha.html b/anonstream/templates/captcha.html index 6a6058b..0894b4e 100644 --- a/anonstream/templates/captcha.html +++ b/anonstream/templates/captcha.html @@ -2,6 +2,7 @@ +