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