Log in/out and pm

This commit is contained in:
Joscha 2019-04-13 20:23:02 +00:00
parent 0d58f61652
commit 135640ca44
4 changed files with 117 additions and 23 deletions

View file

@ -2,6 +2,8 @@
## Next version ## Next version
- add login and logout command to room
- add pm command to room
- add cookie support - add cookie support
- add !restart to botrulez - add !restart to botrulez
- save (overwrite) `Bot` config file - save (overwrite) `Bot` config file

View file

@ -152,6 +152,12 @@ class Client:
async def on_edit(self, room: Room, message: LiveMessage) -> None: async def on_edit(self, room: Room, message: LiveMessage) -> None:
pass pass
async def on_login(self, room: Room, account_id: str) -> None:
pass
async def on_logout(self, room: Room) -> None:
pass
async def on_pm(self, async def on_pm(self,
room: Room, room: Room,
from_id: str, from_id: str,

View file

@ -1,6 +1,6 @@
import asyncio import asyncio
import logging import logging
from typing import Any, Awaitable, Callable, List, Optional, TypeVar from typing import Any, Awaitable, Callable, List, Optional, Tuple, TypeVar
from .connection import Connection from .connection import Connection
from .events import Events from .events import Events
@ -43,6 +43,12 @@ class Room:
"edit" - a message in the room has been modified or deleted "edit" - a message in the room has been modified or deleted
message: LiveMessage message: LiveMessage
"login" - this session has been logged in from another session
account_id: str
"logout" - this session has been logged out from another session
no parameters
"pm" - another session initiated a pm with you "pm" - another session initiated a pm with you
from: str - the id of the user inviting the client to chat privately from: str - the id of the user inviting the client to chat privately
from_nick: str - the nick of the inviting user from_nick: str - the nick of the inviting user
@ -117,11 +123,22 @@ class Room:
# Connecting, reconnecting and disconnecting # Connecting, reconnecting and disconnecting
def _set_connected(self) -> None: async def _try_set_connected(self) -> None:
packets_received = self._hello_received and self._snapshot_received packets_received = self._hello_received and self._snapshot_received
if packets_received and not self._connected.is_set(): if packets_received and not self._connected.is_set():
self._connected_successfully = True await self._set_nick_if_necessary()
self._connected.set() self._set_connected()
async def _set_nick_if_necessary(self) -> None:
nick_needs_updating = (self._session is None
or self._target_nick != self._session.nick)
if self._target_nick and nick_needs_updating:
await self._nick(self._target_nick)
def _set_connected(self) -> None:
self._connected_successfully = True
self._connected.set()
def _set_connected_failed(self) -> None: def _set_connected_failed(self) -> None:
if not self._connected.is_set(): if not self._connected.is_set():
@ -148,7 +165,7 @@ class Room:
self._account = Account.from_data(data) self._account = Account.from_data(data)
self._hello_received = True self._hello_received = True
self._set_connected() await self._try_set_connected()
async def _on_snapshot_event(self, packet: Any) -> None: async def _on_snapshot_event(self, packet: Any) -> None:
data = packet["data"] data = packet["data"]
@ -169,7 +186,7 @@ class Room:
self._events.fire("session", messages) self._events.fire("session", messages)
self._snapshot_received = True self._snapshot_received = True
self._set_connected() await self._try_set_connected()
async def _on_bounce_event(self, packet: Any) -> None: async def _on_bounce_event(self, packet: Any) -> None:
data = packet["data"] data = packet["data"]
@ -207,11 +224,6 @@ class Room:
if not self._connected_successfully: if not self._connected_successfully:
return False return False
nick_needs_updating = (self._session is None
or self._target_nick != self._session.nick)
if self._target_nick and nick_needs_updating:
await self._nick(self._target_nick)
self._events.fire("connected") self._events.fire("connected")
return True return True
@ -243,14 +255,34 @@ class Room:
session = LiveSession.from_data(self, data) session = LiveSession.from_data(self, data)
self._users = self.users.with_join(session) self._users = self.users.with_join(session)
logger.info(f"{session.atmention} joined") logger.info(f"&{self.name}: {session.atmention} joined")
self._events.fire("join", session) self._events.fire("join", session)
async def _on_login_event(self, packet: Any) -> None: async def _on_login_event(self, packet: Any) -> None:
pass # TODO implement once cookie support is here """
Just reconnect, see
https://github.com/euphoria-io/heim/blob/master/client/lib/stores/chat.js#L275-L276
"""
data = packet["data"]
account_id = data["account_id"]
self._events.fire("login", account_id)
logger.info(f"&{self.name}: Got logged in to {account_id}, reconnecting")
await self._connection.reconnect()
async def _on_logout_event(self, packet: Any) -> None: async def _on_logout_event(self, packet: Any) -> None:
pass # TODO implement once cookie support is here """
Just reconnect, see
https://github.com/euphoria-io/heim/blob/master/client/lib/stores/chat.js#L275-L276
"""
self._events.fire("logout")
logger.info(f"&{self.name}: Got logged out, reconnecting")
await self._connection.reconnect()
async def _on_network_event(self, packet: Any) -> None: async def _on_network_event(self, packet: Any) -> None:
data = packet["data"] data = packet["data"]
@ -264,7 +296,7 @@ class Room:
for user in self.users: for user in self.users:
if user.server_id == server_id and user.server_era == server_era: if user.server_id == server_id and user.server_era == server_era:
users = users.with_part(user) users = users.with_part(user)
logger.info(f"{user.atmention} left") logger.info(f"&{self.name}: {user.atmention} left")
self._events.fire("part", user) self._events.fire("part", user)
self._users = users self._users = users
@ -281,7 +313,7 @@ class Room:
else: else:
await self.who() # recalibrating self._users await self.who() # recalibrating self._users
logger.info(f"{atmention(nick_from)} is now called {atmention(nick_to)}") logger.info(f"&{self.name}: {atmention(nick_from)} is now called {atmention(nick_to)}")
self._events.fire("nick", session, nick_from, nick_to) self._events.fire("nick", session, nick_from, nick_to)
async def _on_edit_message_event(self, packet: Any) -> None: async def _on_edit_message_event(self, packet: Any) -> None:
@ -297,7 +329,7 @@ class Room:
session = LiveSession.from_data(self, data) session = LiveSession.from_data(self, data)
self._users = self.users.with_part(session) self._users = self.users.with_part(session)
logger.info(f"{session.atmention} left") logger.info(f"&{self.name}: {session.atmention} left")
self._events.fire("part", session) self._events.fire("part", session)
async def _on_pm_initiate_event(self, packet: Any) -> None: async def _on_pm_initiate_event(self, packet: Any) -> None:
@ -374,10 +406,6 @@ class Room:
# Functionality # Functionality
# These functions require cookie support and are thus not implemented yet:
#
# login, logout, pm
def _extract_data(self, packet: Any) -> Any: def _extract_data(self, packet: Any) -> Any:
error = packet.get("error") error = packet.get("error")
if error is not None: if error is not None:
@ -477,3 +505,55 @@ class Room:
self._users = users self._users = users
return self._users return self._users
async def login(self, email: str, password: str) -> Tuple[bool, str]:
"""
Since euphoria appears to only support email authentication, this way
of logging in is hardcoded here.
Returns whether the login was successful. If it was, the second
parameter is the account id. If it wasn't, the second parameter is the
reason why the login failed.
"""
data: Any = {
"namespace": "email",
"id": email,
"password": password,
}
reply = await self._connection.send("login", data)
data = self._extract_data(reply)
success: bool = data["success"]
account_id_or_reason = data.get("account_id") or data["reason"]
if success:
logger.info(f"&{self.name}: Logged in as {account_id_or_reason}")
else:
logger.info(f"&{self.name}: Failed to log in with {email} because {account_id_or_reason}")
await self._connection.reconnect()
return success, account_id_or_reason
async def logout(self) -> None:
await self._connection.send("logout", {})
logger.info(f"&{self.name}: Logged out")
await self._connection.reconnect()
async def pm(self, user_id: str) -> Tuple[str, str]:
"""
Returns the pm_id of the pm and the nick of the person being pinged.
"""
data = {"user_id": user_id}
reply = await self._connection.send("pm-initiate", data)
data = self._extract_data(reply)
pm_id = data["pm_id"]
to_nick = data["to_nick"]
return pm_id, to_nick

View file

@ -1,5 +1,6 @@
import re import re
from typing import TYPE_CHECKING, Any, Dict, Iterable, Iterator, List, Optional from typing import (TYPE_CHECKING, Any, Dict, Iterable, Iterator, List,
Optional, Tuple)
from .util import mention, normalize from .util import mention, normalize
@ -238,7 +239,12 @@ class LiveSession(Session):
# Live stuff # Live stuff
# TODO pm, once pm support is there. async def pm(self) -> Tuple[str, str]:
"""
See Room.pm
"""
return await self.room.pm(self.user_id)
class LiveSessionListing: class LiveSessionListing:
def __init__(self, room: "Room", sessions: Iterable[LiveSession]) -> None: def __init__(self, room: "Room", sessions: Iterable[LiveSession]) -> None: