Browse Source

Streamline messaging

master
Roderic Day 5 years ago
parent
commit
01967df09c
2 changed files with 56 additions and 52 deletions
  1. +14
    -12
      pico.py
  2. +42
    -40
      test.py

+ 14
- 12
pico.py View File

return {} return {}




async def core(ws, path, server_name):
async def handle(ws, path, server_name):
room = rooms[path] room = rooms[path]
usernames = room.keys() usernames = room.keys()
sockets = room.values() sockets = room.values()
while True: while True:
data = await recv_json(ws) data = await recv_json(ws)
ts = datetime.datetime.now().isoformat() + 'Z' ts = datetime.datetime.now().isoformat() + 'Z'
emit = partial(send_json_many, kind=data['kind'], value=data.get('value'), ts=ts)

emit = partial(send_json_many, kind=data['kind'], ts=ts)
broadcast = partial(emit, targets=sockets) broadcast = partial(emit, targets=sockets)
reply = partial(emit, targets=[ws]) reply = partial(emit, targets=[ws])
error = partial(reply, kind='error') error = partial(reply, kind='error')
await error(value='Username taken') await error(value='Username taken')
break break


others = list(sockets)
room[username] = ws room[username] = ws
online = list(usernames) online = list(usernames)
await reply(online=online)
await broadcast(kind='post', value=f'{username} joined', online=online, targets=others)
await reply(kind='post', value=f'Welcome to {path}')
await reply(kind='state', username=username)
await broadcast(kind='state', online=online)


elif username not in room: elif username not in room:
await error(value='Login required') await error(value='Login required')
elif data['kind'] == 'logout': elif data['kind'] == 'logout':
del room[username] del room[username]
online = list(usernames) online = list(usernames)
await broadcast(kind='post', value=f'{username} left', online=online)
await broadcast(kind='state', online=online)
break break


else: else:
value = data.get('value')
if 'target' in data: if 'target' in data:
targets = {v for k, v in room.items() if k in {username, data['target']}}
await broadcast(source=username, targets=targets)
recipients = {username, data['target']}
targets = {v for k, v in room.items() if k in recipients}
await broadcast(source=username, value=value, targets=targets)
else: else:
await broadcast(source=username)
await broadcast(source=username, value=value)




async def start_server(host, port, server_name): async def start_server(host, port, server_name):
bound_core = partial(core, server_name=server_name)
return await websockets.serve(bound_core, host, port, create_protocol=PicoProtocol)
bound_handle = partial(handle, server_name=server_name)
bound_serve = partial(websockets.serve, create_protocol=PicoProtocol)
return await bound_serve(bound_handle, host, port)




if __name__ == '__main__': if __name__ == '__main__':

+ 42
- 40
test.py View File

if kind == 'recv': if kind == 'recv':
A, B = message, await recv_json(websocket) A, B = message, await recv_json(websocket)
B.pop('ts') B.pop('ts')
if B['kind'] == 'login':
username = B['value']
state.update(message)
if B['kind'] == 'state':
state.update(B)
if A != B: if A != B:
error = True error = True
print('-', A) print('-', A)
await send_json(websocket, **message) await send_json(websocket, **message)


while 'online' in state: while 'online' in state:
if state['online'][0] == username:
if state['online'][0] == state['username']:
break break
message = await recv_json(websocket) message = await recv_json(websocket)
message.pop('ts') message.pop('ts')
def test_happy_path(): def test_happy_path():
client = _make_client('ws://localhost:8642/A', 0.1, Script() client = _make_client('ws://localhost:8642/A', 0.1, Script()
+ {'kind': 'login', 'value': 'TestUser'} + {'kind': 'login', 'value': 'TestUser'}
- {'kind': 'login', 'value': 'TestUser', 'online': ['TestUser']}
- {'kind': 'post', 'value': 'Welcome to /A'}
- {'kind': 'state', 'username': 'TestUser'}
- {'kind': 'state', 'online': ['TestUser']}
+ {'kind': 'post', 'value': 'Hello World!'} + {'kind': 'post', 'value': 'Hello World!'}
- {'kind': 'post', 'value': 'Hello World!', 'source': 'TestUser'} - {'kind': 'post', 'value': 'Hello World!', 'source': 'TestUser'}
) )
def test_name_taken(): def test_name_taken():
client1 = _make_client('ws://localhost:8642/', 0.10, Script() client1 = _make_client('ws://localhost:8642/', 0.10, Script()
+ {'kind': 'login', 'value': 'A'} + {'kind': 'login', 'value': 'A'}
- {'kind': 'login', 'value': 'A', 'online': ['A']}
- {'kind': 'post', 'value': 'Welcome to /'}
- {'kind': 'post', 'value': 'B joined', 'online': ['A', 'B']}
- {'kind': 'state', 'username': 'A'}
- {'kind': 'state', 'online': ['A']}
- {'kind': 'state', 'online': ['A', 'B']}
) )
client2 = _make_client('ws://localhost:8642/', 0.11, Script() client2 = _make_client('ws://localhost:8642/', 0.11, Script()
+ {'kind': 'login', 'value': 'A'} + {'kind': 'login', 'value': 'A'}
) )
client3 = _make_client('ws://localhost:8642/', 0.12, Script() client3 = _make_client('ws://localhost:8642/', 0.12, Script()
+ {'kind': 'login', 'value': 'B'} + {'kind': 'login', 'value': 'B'}
- {'kind': 'login', 'value': 'B', 'online': ['A', 'B']}
- {'kind': 'post', 'value': 'Welcome to /'}
- {'kind': 'post', 'value': 'A left', 'online': ['B']}
- {'kind': 'state', 'username': 'B'}
- {'kind': 'state', 'online': ['A', 'B']}
- {'kind': 'state', 'online': ['B']}
) )
return _test(client1, client2, client3) return _test(client1, client2, client3)


def test_interaction(): def test_interaction():
client1 = _make_client('ws://localhost:8642/', 0.10, Script() client1 = _make_client('ws://localhost:8642/', 0.10, Script()
+ {'kind': 'login', 'value': 'Alice'} + {'kind': 'login', 'value': 'Alice'}
- {'kind': 'login', 'value': 'Alice', 'online': ['Alice']}
- {'kind': 'post', 'value': 'Welcome to /'}
- {'kind': 'post', 'value': 'Bob joined', 'online': ['Alice', 'Bob']}
- {'kind': 'state', 'username': 'Alice'}
- {'kind': 'state', 'online': ['Alice']}
- {'kind': 'state', 'online': ['Alice', 'Bob']}
+ {'kind': 'post', 'value': 'Hey Bob!'} + {'kind': 'post', 'value': 'Hey Bob!'}
- {'kind': 'post', 'value': 'Hey Bob!', 'source': 'Alice'} - {'kind': 'post', 'value': 'Hey Bob!', 'source': 'Alice'}
- {'kind': 'post', 'value': 'Howdy!', 'source': 'Bob'} - {'kind': 'post', 'value': 'Howdy!', 'source': 'Bob'}
) )
client2 = _make_client('ws://localhost:8642/', 0.11, Script() client2 = _make_client('ws://localhost:8642/', 0.11, Script()
+ {'kind': 'login', 'value': 'Bob'} + {'kind': 'login', 'value': 'Bob'}
- {'kind': 'login', 'value': 'Bob', 'online': ['Alice', 'Bob']}
- {'kind': 'post', 'value': 'Welcome to /'}
- {'kind': 'state', 'username': 'Bob'}
- {'kind': 'state', 'online': ['Alice', 'Bob']}
- {'kind': 'post', 'value': 'Hey Bob!', 'source': 'Alice'} - {'kind': 'post', 'value': 'Hey Bob!', 'source': 'Alice'}
+ {'kind': 'post', 'value': 'Howdy!'} + {'kind': 'post', 'value': 'Howdy!'}
- {'kind': 'post', 'value': 'Howdy!', 'source': 'Bob'} - {'kind': 'post', 'value': 'Howdy!', 'source': 'Bob'}
- {'kind': 'post', 'value': 'Alice left', 'online': ['Bob']}
- {'kind': 'state', 'online': ['Bob']}
) )
return _test(client1, client2) return _test(client1, client2)


def test_rooms(): def test_rooms():
client1 = _make_client('ws://localhost:8642/A', 0.10, Script() client1 = _make_client('ws://localhost:8642/A', 0.10, Script()
+ {'kind': 'login', 'value': 'Dandy'} + {'kind': 'login', 'value': 'Dandy'}
- {'kind': 'login', 'value': 'Dandy', 'online': ['Dandy']}
- {'kind': 'post', 'value': 'Welcome to /A'}
- {'kind': 'state', 'username': 'Dandy'}
- {'kind': 'state', 'online': ['Dandy']}
+ {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'} + {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'}
- {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'} - {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'}
) )
client2 = _make_client('ws://localhost:8642/B', 0.10, Script() client2 = _make_client('ws://localhost:8642/B', 0.10, Script()
+ {'kind': 'login', 'value': 'Dandy'} + {'kind': 'login', 'value': 'Dandy'}
- {'kind': 'login', 'value': 'Dandy', 'online': ['Dandy']}
- {'kind': 'post', 'value': 'Welcome to /B'}
- {'kind': 'state', 'username': 'Dandy'}
- {'kind': 'state', 'online': ['Dandy']}
+ {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'} + {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'}
- {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'} - {'kind': 'post', 'value': 'Hi', 'source': 'Dandy'}
) )
def test_private_message(): def test_private_message():
client1 = _make_client('ws://localhost:8642/', 0.10, Script() client1 = _make_client('ws://localhost:8642/', 0.10, Script()
+ {'kind': 'login', 'value': 'Norman'} + {'kind': 'login', 'value': 'Norman'}
- {'kind': 'login', 'value': 'Norman', 'online': ['Norman']}
- {'kind': 'post', 'value': 'Welcome to /'}
- {'kind': 'post', 'value': 'Ray joined', 'online': ['Norman', 'Ray']}
- {'kind': 'post', 'value': 'Emma joined', 'online': ['Norman', 'Ray', 'Emma']}
+ {'kind': 'post', 'value': 'なに?', 'target': 'Emma'}
- {'kind': 'post', 'value': 'なに?', 'source': 'Norman'}
- {'kind': 'state', 'username': 'Norman'}
- {'kind': 'state', 'online': ['Norman']}
- {'kind': 'state', 'online': ['Norman', 'Ray']}
- {'kind': 'state', 'online': ['Norman', 'Ray', 'Emma']}
+ {'kind': 'post', 'value': '1', 'target': 'Ray'}
- {'kind': 'post', 'value': '1', 'source': 'Norman'}
- {'kind': 'post', 'value': '3', 'source': 'Emma'}
) )
client2 = _make_client('ws://localhost:8642/', 0.11, Script() client2 = _make_client('ws://localhost:8642/', 0.11, Script()
+ {'kind': 'login', 'value': 'Ray'} + {'kind': 'login', 'value': 'Ray'}
- {'kind': 'login', 'value': 'Ray', 'online': ['Norman', 'Ray']}
- {'kind': 'post', 'value': 'Welcome to /'}
- {'kind': 'post', 'value': 'Emma joined', 'online': ['Norman', 'Ray', 'Emma']}
- {'kind': 'post', 'value': '秘密!', 'source': 'Emma'}
- {'kind': 'post', 'value': 'Norman left', 'online': ['Ray', 'Emma']}
- {'kind': 'state', 'username': 'Ray'}
- {'kind': 'state', 'online': ['Norman', 'Ray']}
- {'kind': 'state', 'online': ['Norman', 'Ray', 'Emma']}
- {'kind': 'post', 'value': '1', 'source': 'Norman'}
+ {'kind': 'post', 'value': '2', 'target': 'Emma'}
- {'kind': 'post', 'value': '2', 'source': 'Ray'}
- {'kind': 'state', 'online': ['Ray', 'Emma']}
) )
client3 = _make_client('ws://localhost:8642/', 0.12, Script() client3 = _make_client('ws://localhost:8642/', 0.12, Script()
+ {'kind': 'login', 'value': 'Emma'} + {'kind': 'login', 'value': 'Emma'}
- {'kind': 'login', 'value': 'Emma', 'online': ['Norman', 'Ray', 'Emma']}
- {'kind': 'post', 'value': 'Welcome to /'}
- {'kind': 'post', 'value': 'なに?', 'source': 'Norman'}
+ {'kind': 'post', 'value': '秘密!', 'target': 'Ray'}
- {'kind': 'post', 'value': '秘密!', 'source': 'Emma'}
- {'kind': 'post', 'value': 'Norman left', 'online': ['Ray', 'Emma']}
- {'kind': 'post', 'value': 'Ray left', 'online': ['Emma']}
- {'kind': 'state', 'username': 'Emma'}
- {'kind': 'state', 'online': ['Norman', 'Ray', 'Emma']}
- {'kind': 'post', 'value': '2', 'source': 'Ray'}
+ {'kind': 'post', 'value': '3', 'target': 'Norman'}
- {'kind': 'post', 'value': '3', 'source': 'Emma'}
- {'kind': 'state', 'online': ['Ray', 'Emma']}
- {'kind': 'state', 'online': ['Emma']}
) )
return _test(client1, client2, client3) return _test(client1, client2, client3)



Loading…
Cancel
Save