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
- add login and logout command to room
- add pm command to room
- add cookie support
- add !restart to botrulez
- save (overwrite) `Bot` config file

View file

@ -152,6 +152,12 @@ class Client:
async def on_edit(self, room: Room, message: LiveMessage) -> None:
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,
room: Room,
from_id: str,

View file

@ -1,6 +1,6 @@
import asyncio
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 .events import Events
@ -43,6 +43,12 @@ class Room:
"edit" - a message in the room has been modified or deleted
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
from: str - the id of the user inviting the client to chat privately
from_nick: str - the nick of the inviting user
@ -117,11 +123,22 @@ class Room:
# 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
if packets_received and not self._connected.is_set():
self._connected_successfully = True
self._connected.set()
await self._set_nick_if_necessary()
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:
if not self._connected.is_set():
@ -148,7 +165,7 @@ class Room:
self._account = Account.from_data(data)
self._hello_received = True
self._set_connected()
await self._try_set_connected()
async def _on_snapshot_event(self, packet: Any) -> None:
data = packet["data"]
@ -169,7 +186,7 @@ class Room:
self._events.fire("session", messages)
self._snapshot_received = True
self._set_connected()
await self._try_set_connected()
async def _on_bounce_event(self, packet: Any) -> None:
data = packet["data"]
@ -207,11 +224,6 @@ class Room:
if not self._connected_successfully:
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")
return True
@ -243,14 +255,34 @@ class Room:
session = LiveSession.from_data(self, data)
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)
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:
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:
data = packet["data"]
@ -264,7 +296,7 @@ class Room:
for user in self.users:
if user.server_id == server_id and user.server_era == server_era:
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._users = users
@ -281,7 +313,7 @@ class Room:
else:
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)
async def _on_edit_message_event(self, packet: Any) -> None:
@ -297,7 +329,7 @@ class Room:
session = LiveSession.from_data(self, data)
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)
async def _on_pm_initiate_event(self, packet: Any) -> None:
@ -374,10 +406,6 @@ class Room:
# Functionality
# These functions require cookie support and are thus not implemented yet:
#
# login, logout, pm
def _extract_data(self, packet: Any) -> Any:
error = packet.get("error")
if error is not None:
@ -477,3 +505,55 @@ class Room:
self._users = 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
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
@ -238,7 +239,12 @@ class LiveSession(Session):
# 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:
def __init__(self, room: "Room", sessions: Iterable[LiveSession]) -> None: