anonstream/anonstream/control/commands/user.py

154 行
6.3 KiB
Python

import json
from quart import current_app
from anonstream.control.exceptions import BadArgument, Incomplete, Garbage, Failed
from anonstream.control.utils import json_dumps_contiguous
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
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'
' user eyes USER [show].............show a user\'s active video responses\n'
' user eyes USER delete EYES_ID.....end a video response to a user\n'
'Definitions:\n'
#' USER..............................={token TOKEN | hash HASH}\n'
' USER..............................=token TOKEN\n'
' TOKEN..............................a token\n'
#' HASH..............................a token hash\n'
' ATTR...............................a user attribute, re:[a-z0-9_]+\n'
' EYES_ID............................a user\'s eyes_id, base 10 integer\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_contiguous(token)]
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 {json_dumps_contiguous(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_contiguous(token), 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 {json_dumps_contiguous(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_contiguous(token), attr, json_dumps_contiguous(value)]
response = ''
case []:
raise Incomplete
case [*garbage]:
raise Garbage(garbage)
return normal_options, response
async def command_user_eyes(args):
match args:
case ['token', token_json, *subargs]:
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'")
match subargs:
case [] | ['show']:
normal_options = ['eyes', 'token', json_dumps_contiguous(token), 'show']
response = json.dumps(user['eyes']['current']) + '\n'
case ['delete', eyes_id_json]:
try:
eyes_id = json.loads(eyes_id_json)
except json.JSONDecodeError:
raise BadArgument('could not decode EYES_ID as json')
try:
user['eyes']['current'].pop(eyes_id)
except KeyError:
pass
normal_options = ['eyes', 'token', json_dumps_contiguous(token), 'delete', json_dumps_contiguous(eyes_id)]
response = ''
case []:
raise Incomplete
case [*garbage]:
raise Garbage(garbage)
return normal_options, response