Control socket: view and change users' attributes
Changing things without thinking about it is probably going to cause weird undefined behaviour.
このコミットが含まれているのは:
コミット
31ce80b2bf
|
@ -1,8 +1,15 @@
|
|||
import asyncio
|
||||
import json
|
||||
|
||||
from quart import current_app
|
||||
|
||||
from anonstream.chat import delete_chat_messages
|
||||
from anonstream.stream import get_stream_title, set_stream_title
|
||||
from anonstream.utils.user import USER_WEBSOCKET_ATTRS
|
||||
|
||||
USERS_BY_TOKEN = current_app.users_by_token
|
||||
USERS = current_app.users
|
||||
USERS_UPDATE_BUFFER = current_app.users_update_buffer
|
||||
|
||||
class UnknownMethod(Exception):
|
||||
pass
|
||||
|
@ -218,6 +225,112 @@ async def command_title_set(args):
|
|||
raise Garbage(garbage)
|
||||
return normal_options, response
|
||||
|
||||
async def command_user_help(args):
|
||||
match args:
|
||||
case []:
|
||||
normal_options = ['help']
|
||||
response = (
|
||||
'Usage: user [show | attr USER | get USER ATTR | set USER ATTR VALUE]\n'
|
||||
'Commands:\n'
|
||||
' user [show]...........show all users\' tokens\n'
|
||||
' user attr USER........show names of a user\'s attributes\n'
|
||||
' user get USER ATTR....show an attribute of a user\n'
|
||||
' user set USER ATTR....set an attribute of a user\n'
|
||||
'Definitions:\n'
|
||||
' USER..................={token TOKEN | hash HASH}\n'
|
||||
' TOKEN.................a token\n'
|
||||
' HASH..................a token hash\n'
|
||||
' ATTR..................a user attribute, re:[a-z0-9_]+\n'
|
||||
)
|
||||
case [*garbage]:
|
||||
raise Garbage(garbage)
|
||||
return normal_options, response
|
||||
|
||||
async def command_user_show(args):
|
||||
match args:
|
||||
case []:
|
||||
normal_options = ['show']
|
||||
response = json.dumps(tuple(USERS_BY_TOKEN)) + '\n'
|
||||
case [*garbage]:
|
||||
raise Garbage(garbage)
|
||||
return normal_options, response
|
||||
|
||||
async def command_user_attr(args):
|
||||
match args:
|
||||
case []:
|
||||
raise Incomplete
|
||||
case ['token', token_json]:
|
||||
try:
|
||||
token = json.loads(token_json)
|
||||
except json.JSONDecodeError:
|
||||
raise BadArgument('could not decode token as json')
|
||||
try:
|
||||
user = USERS_BY_TOKEN[token]
|
||||
except KeyError:
|
||||
raise Failed(f"no user exists with token {token!r}, try 'user show'")
|
||||
normal_options = ['attr', 'token', json.dumps(token).replace(' ', r'\u0020')]
|
||||
response = json.dumps(tuple(user.keys())) + '\n'
|
||||
case [*garbage]:
|
||||
raise Garbage(garbage)
|
||||
return normal_options, response
|
||||
|
||||
async def command_user_get(args):
|
||||
match args:
|
||||
case ['token', token_json, attr]:
|
||||
try:
|
||||
token = json.loads(token_json)
|
||||
except json.JSONDecodeError:
|
||||
raise BadArgument('could not decode token as json')
|
||||
try:
|
||||
user = USERS_BY_TOKEN[token]
|
||||
except KeyError:
|
||||
raise Failed(f"no user exists with token {token!r}, try 'user show'")
|
||||
try:
|
||||
value = user[attr]
|
||||
except KeyError:
|
||||
raise Failed(f"user has no attribute {attr!r}, try 'user attr token {token}'")
|
||||
try:
|
||||
value_json = json.dumps(value)
|
||||
except TypeError:
|
||||
raise Failed(f'attribute {attr!r} is not JSON serializable')
|
||||
normal_options = ['get', 'token', json.dumps(token).replace(' ', r'\u0020'), attr]
|
||||
response = value_json + '\n'
|
||||
case []:
|
||||
raise Incomplete
|
||||
case [*garbage]:
|
||||
raise Garbage(garbage)
|
||||
return normal_options, response
|
||||
|
||||
async def command_user_set(args):
|
||||
match args:
|
||||
case ['token', token_json, attr, value_json]:
|
||||
try:
|
||||
token = json.loads(token_json)
|
||||
except json.JSONDecodeError:
|
||||
raise BadArgument('could not decode token as json')
|
||||
try:
|
||||
user = USERS_BY_TOKEN[token]
|
||||
except KeyError:
|
||||
raise Failed(f"no user exists with token {token!r}, try 'user show'")
|
||||
try:
|
||||
value = user[attr]
|
||||
except KeyError:
|
||||
raise Failed(f"user has no attribute {attr!r}, try 'user attr token {TOKEN}")
|
||||
try:
|
||||
value = json.loads(value_json)
|
||||
except JSON.JSONDecodeError:
|
||||
raise Failed('could not decode json')
|
||||
user[attr] = value
|
||||
if attr in USER_WEBSOCKET_ATTRS:
|
||||
USERS_UPDATE_BUFFER.add(token)
|
||||
normal_options = ['set', 'token', json.dumps(token).replace(' ', r'\u0020'), attr, json.dumps(value)]
|
||||
response = ''
|
||||
case []:
|
||||
raise Incomplete
|
||||
case [*garbage]:
|
||||
raise Garbage(garbage)
|
||||
return normal_options, response
|
||||
|
||||
async def command_chat_help(args):
|
||||
match args:
|
||||
case []:
|
||||
|
@ -254,6 +367,7 @@ METHOD_HELP = 'help'
|
|||
METHOD_EXIT = 'exit'
|
||||
METHOD_TITLE = 'title'
|
||||
METHOD_CHAT = 'chat'
|
||||
METHOD_USER = 'user'
|
||||
|
||||
METHOD_COMMAND_FUNCTIONS = {
|
||||
METHOD_HELP: {
|
||||
|
@ -274,5 +388,13 @@ METHOD_COMMAND_FUNCTIONS = {
|
|||
None: command_chat_help,
|
||||
'help': command_chat_help,
|
||||
'delete': command_chat_delete,
|
||||
}
|
||||
},
|
||||
METHOD_USER: {
|
||||
None: command_user_show,
|
||||
'help': command_user_help,
|
||||
'show': command_user_show,
|
||||
'attr': command_user_attr,
|
||||
'get': command_user_get,
|
||||
'set': command_user_set,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ from math import inf
|
|||
|
||||
from quart import escape, Markup
|
||||
|
||||
USER_WEBSOCKET_ATTRS = {'broadcaster', 'name', 'color', 'tripcode', 'tag'}
|
||||
|
||||
Presence = Enum(
|
||||
'Presence',
|
||||
names=(
|
||||
|
@ -44,8 +46,7 @@ def trilean(presence):
|
|||
return None
|
||||
|
||||
def get_user_for_websocket(user):
|
||||
keys = ('broadcaster', 'name', 'color', 'tripcode', 'tag')
|
||||
return {
|
||||
**{key: user[key] for key in keys},
|
||||
**{key: user[key] for key in USER_WEBSOCKET_ATTRS},
|
||||
'watching': trilean(user['presence']),
|
||||
}
|
||||
|
|
読み込み中…
新しいイシューから参照