2019-07-08 13:52:41 +10:00
|
|
|
# Copyright 2019 miruka
|
|
|
|
# This file is part of harmonyqml, licensed under LGPLv3.
|
|
|
|
|
2019-06-27 16:31:03 +10:00
|
|
|
import asyncio
|
2019-07-04 14:24:21 +10:00
|
|
|
import random
|
2019-07-23 17:14:02 +10:00
|
|
|
from typing import Dict, Optional, Set, Tuple
|
2019-06-27 16:31:03 +10:00
|
|
|
|
|
|
|
from .app import App
|
2019-06-29 08:12:45 +10:00
|
|
|
from .events import users
|
2019-07-04 14:24:21 +10:00
|
|
|
from .html_filter import HTML_FILTER
|
2019-06-27 16:31:03 +10:00
|
|
|
from .matrix_client import MatrixClient
|
|
|
|
|
|
|
|
|
|
|
|
class Backend:
|
|
|
|
def __init__(self, app: App) -> None:
|
|
|
|
self.app = app
|
2019-07-05 16:45:30 +10:00
|
|
|
|
2019-07-19 10:30:41 +10:00
|
|
|
from . import config_files
|
|
|
|
self.saved_accounts = config_files.Accounts(self)
|
|
|
|
self.ui_settings = config_files.UISettings(self)
|
2019-07-21 21:14:16 +10:00
|
|
|
self.ui_state = config_files.UIState(self)
|
2019-07-19 10:30:41 +10:00
|
|
|
|
2019-06-27 16:31:03 +10:00
|
|
|
self.clients: Dict[str, MatrixClient] = {}
|
|
|
|
|
2019-07-05 16:45:30 +10:00
|
|
|
self.past_tokens: Dict[str, str] = {} # {room_id: token}
|
|
|
|
self.fully_loaded_rooms: Set[str] = set() # {room_id}
|
|
|
|
|
2019-07-07 15:37:13 +10:00
|
|
|
self.pending_profile_requests: Set[str] = set()
|
|
|
|
|
2019-06-27 16:31:03 +10:00
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
return f"{type(self).__name__}(clients={self.clients!r})"
|
|
|
|
|
|
|
|
|
|
|
|
# Clients management
|
|
|
|
|
|
|
|
async def login_client(self,
|
|
|
|
user: str,
|
|
|
|
password: str,
|
|
|
|
device_id: Optional[str] = None,
|
2019-07-03 03:59:52 +10:00
|
|
|
homeserver: str = "https://matrix.org") -> str:
|
2019-06-27 16:31:03 +10:00
|
|
|
client = MatrixClient(
|
2019-07-05 09:11:22 +10:00
|
|
|
backend=self, user=user, homeserver=homeserver, device_id=device_id
|
2019-06-27 16:31:03 +10:00
|
|
|
)
|
|
|
|
await client.login(password)
|
|
|
|
self.clients[client.user_id] = client
|
2019-06-29 08:12:45 +10:00
|
|
|
users.AccountUpdated(client.user_id)
|
2019-07-03 03:59:52 +10:00
|
|
|
return client.user_id
|
2019-06-27 16:31:03 +10:00
|
|
|
|
|
|
|
|
|
|
|
async def resume_client(self,
|
|
|
|
user_id: str,
|
|
|
|
token: str,
|
|
|
|
device_id: str,
|
|
|
|
homeserver: str = "https://matrix.org") -> None:
|
|
|
|
client = MatrixClient(
|
2019-07-05 09:11:22 +10:00
|
|
|
backend=self,
|
2019-06-27 16:31:03 +10:00
|
|
|
user=user_id, homeserver=homeserver, device_id=device_id
|
|
|
|
)
|
|
|
|
await client.resume(user_id=user_id, token=token, device_id=device_id)
|
|
|
|
self.clients[client.user_id] = client
|
2019-06-29 08:12:45 +10:00
|
|
|
users.AccountUpdated(client.user_id)
|
2019-06-27 16:31:03 +10:00
|
|
|
|
|
|
|
|
|
|
|
async def load_saved_accounts(self) -> Tuple[str, ...]:
|
|
|
|
async def resume(user_id: str, info: Dict[str, str]) -> str:
|
|
|
|
await self.resume_client(
|
|
|
|
user_id = user_id,
|
|
|
|
token = info["token"],
|
|
|
|
device_id = info["device_id"],
|
|
|
|
homeserver = info["homeserver"],
|
|
|
|
)
|
|
|
|
return user_id
|
|
|
|
|
|
|
|
return await asyncio.gather(*(
|
2019-07-19 10:30:41 +10:00
|
|
|
resume(uid, info)
|
|
|
|
for uid, info in (await self.saved_accounts.read()).items()
|
2019-06-27 16:31:03 +10:00
|
|
|
))
|
|
|
|
|
|
|
|
|
2019-07-19 10:30:41 +10:00
|
|
|
async def logout_client(self, user_id: str) -> None:
|
|
|
|
client = self.clients.pop(user_id, None)
|
|
|
|
if client:
|
|
|
|
await client.logout()
|
|
|
|
users.AccountDeleted(user_id)
|
2019-06-27 16:31:03 +10:00
|
|
|
|
|
|
|
|
2019-07-19 10:30:41 +10:00
|
|
|
async def logout_all_clients(self) -> None:
|
|
|
|
await asyncio.gather(*(
|
|
|
|
self.logout_client(user_id) for user_id in self.clients.copy()
|
|
|
|
))
|
2019-07-04 14:24:21 +10:00
|
|
|
|
|
|
|
|
2019-07-21 22:38:49 +10:00
|
|
|
async def wait_until_client_exists(self, user_id: str = "") -> None:
|
|
|
|
while True:
|
|
|
|
if user_id and user_id in self.clients:
|
|
|
|
return
|
|
|
|
|
|
|
|
if not user_id and self.clients:
|
|
|
|
return
|
|
|
|
|
|
|
|
await asyncio.sleep(0.1)
|
|
|
|
|
|
|
|
|
2019-07-04 14:24:21 +10:00
|
|
|
# General functions
|
|
|
|
|
2019-07-23 17:14:02 +10:00
|
|
|
async def load_settings(self) -> tuple:
|
|
|
|
from .config_files import Theme
|
|
|
|
settings = await self.ui_settings.read()
|
|
|
|
ui_state = await self.ui_state.read()
|
|
|
|
theme = await Theme(self, settings["theme"]).read()
|
|
|
|
|
|
|
|
return (settings, ui_state, theme)
|
2019-07-21 21:14:16 +10:00
|
|
|
|
|
|
|
|
2019-07-04 14:24:21 +10:00
|
|
|
async def request_user_update_event(self, user_id: str) -> None:
|
2019-07-21 21:14:16 +10:00
|
|
|
if not self.clients:
|
2019-07-21 22:38:49 +10:00
|
|
|
await self.wait_until_client_exists()
|
2019-07-21 21:14:16 +10:00
|
|
|
|
2019-07-19 10:30:41 +10:00
|
|
|
client = self.clients.get(
|
|
|
|
user_id,
|
|
|
|
random.choice(tuple(self.clients.values()))
|
|
|
|
)
|
2019-07-04 14:24:21 +10:00
|
|
|
await client.request_user_update_event(user_id)
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def inlinify(html: str) -> str:
|
|
|
|
return HTML_FILTER.filter_inline(html)
|