Python backend "App" becomes QmlBridge
Is now strictly about setting up asyncio/uvloop and providing the functions for QML to interact with it and call backend coroutines. The appdirs attribute is moved to Backend.
This commit is contained in:
parent
5d7d66f99b
commit
9e372d01d5
|
@ -1 +1 @@
|
|||
from .app import APP # noqa
|
||||
from .qml_bridge import BRIDGE # noqa
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
import asyncio
|
||||
import logging as log
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, DefaultDict, Dict, List, Optional, Tuple
|
||||
|
||||
import hsluv
|
||||
from appdirs import AppDirs
|
||||
|
||||
import nio
|
||||
|
||||
from .app import App
|
||||
from . import __about__
|
||||
from .errors import MatrixError
|
||||
from .matrix_client import MatrixClient
|
||||
from .models.items import Account, Device, Event, Member, Room, Upload
|
||||
from .models.model_store import ModelStore
|
||||
|
||||
log.getLogger().setLevel(log.INFO)
|
||||
nio.logger_group.level = nio.log.logbook.ERROR
|
||||
nio.log.logbook.StreamHandler(sys.stderr).push_application()
|
||||
|
||||
|
||||
class Backend:
|
||||
def __init__(self, app: App) -> None:
|
||||
self.app = app
|
||||
def __init__(self) -> None:
|
||||
self.appdirs = AppDirs(appname=__about__.__pkg_name__, roaming=True)
|
||||
|
||||
from . import config_files
|
||||
self.saved_accounts = config_files.Accounts(self)
|
||||
|
@ -43,7 +49,7 @@ class Backend:
|
|||
DefaultDict(asyncio.Lock) # {room_id: lock}
|
||||
|
||||
from .media_cache import MediaCache
|
||||
cache_dir = Path(self.app.appdirs.user_cache_dir)
|
||||
cache_dir = Path(self.appdirs.user_cache_dir)
|
||||
self.media_cache = MediaCache(self, cache_dir)
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class ConfigFile:
|
|||
|
||||
@property
|
||||
def path(self) -> Path:
|
||||
return Path(self.backend.app.appdirs.user_config_dir) / self.filename
|
||||
return Path(self.backend.appdirs.user_config_dir) / self.filename
|
||||
|
||||
|
||||
async def default_data(self):
|
||||
|
@ -180,7 +180,7 @@ class UIState(JSONConfigFile):
|
|||
|
||||
@property
|
||||
def path(self) -> Path:
|
||||
return Path(self.backend.app.appdirs.user_data_dir) / self.filename
|
||||
return Path(self.backend.appdirs.user_data_dir) / self.filename
|
||||
|
||||
|
||||
async def default_data(self) -> JsonData:
|
||||
|
@ -198,7 +198,7 @@ class History(JSONConfigFile):
|
|||
|
||||
@property
|
||||
def path(self) -> Path:
|
||||
return Path(self.backend.app.appdirs.user_data_dir) / self.filename
|
||||
return Path(self.backend.appdirs.user_data_dir) / self.filename
|
||||
|
||||
|
||||
async def default_data(self) -> JsonData:
|
||||
|
@ -209,7 +209,7 @@ class History(JSONConfigFile):
|
|||
class Theme(ConfigFile):
|
||||
@property
|
||||
def path(self) -> Path:
|
||||
data_dir = Path(self.backend.app.appdirs.user_data_dir)
|
||||
data_dir = Path(self.backend.appdirs.user_data_dir)
|
||||
return data_dir / "themes" / self.filename
|
||||
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ class MatrixClient(nio.AsyncClient):
|
|||
f"homeserver is missing scheme (e.g. https://): {homeserver}",
|
||||
)
|
||||
|
||||
store = Path(backend.app.appdirs.user_data_dir) / "encryption"
|
||||
store = Path(backend.appdirs.user_data_dir) / "encryption"
|
||||
store.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
super().__init__(
|
||||
|
|
|
@ -1,56 +1,37 @@
|
|||
import asyncio
|
||||
import logging as log
|
||||
import signal
|
||||
import sys
|
||||
import traceback
|
||||
from concurrent.futures import Future
|
||||
from operator import attrgetter
|
||||
from threading import Thread
|
||||
from typing import Coroutine, Sequence
|
||||
|
||||
import nio
|
||||
from appdirs import AppDirs
|
||||
|
||||
from . import __about__
|
||||
from .backend import Backend
|
||||
from .pyotherside_events import CoroutineDone
|
||||
|
||||
log.getLogger().setLevel(log.INFO)
|
||||
nio.logger_group.level = nio.log.logbook.ERROR
|
||||
nio.log.logbook.StreamHandler(sys.stderr).push_application()
|
||||
|
||||
try:
|
||||
import uvloop
|
||||
except ModuleNotFoundError:
|
||||
UVLOOP = False
|
||||
log.info("uvloop not available, using default asyncio loop.")
|
||||
log.warning("uvloop module not found, using slower default asyncio loop")
|
||||
else:
|
||||
UVLOOP = True
|
||||
log.info("uvloop is available.")
|
||||
uvloop.install()
|
||||
|
||||
|
||||
class App:
|
||||
class QmlBridge:
|
||||
def __init__(self) -> None:
|
||||
self.appdirs = AppDirs(appname=__about__.__pkg_name__, roaming=True)
|
||||
self.backend = Backend()
|
||||
|
||||
from .backend import Backend
|
||||
self.backend = Backend(app=self)
|
||||
self.debug = False
|
||||
|
||||
self.loop = asyncio.get_event_loop()
|
||||
self.loop_thread = Thread(target=self._loop_starter)
|
||||
self.loop_thread.start()
|
||||
self.loop = asyncio.get_event_loop()
|
||||
Thread(target=self._start_loop_in_thread).start()
|
||||
|
||||
|
||||
def _loop_starter(self) -> None:
|
||||
def _start_loop_in_thread(self) -> None:
|
||||
asyncio.set_event_loop(self.loop)
|
||||
|
||||
if UVLOOP:
|
||||
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||
|
||||
self.loop.run_forever()
|
||||
|
||||
|
||||
def run_in_loop(self, coro: Coroutine) -> Future:
|
||||
def _run_coro_in_loop(self, coro: Coroutine) -> Future:
|
||||
return asyncio.run_coroutine_threadsafe(coro, self.loop)
|
||||
|
||||
|
||||
|
@ -66,37 +47,40 @@ class App:
|
|||
|
||||
CoroutineDone(uuid, result, exception, trace)
|
||||
|
||||
future = self.run_in_loop(coro)
|
||||
future = self._run_coro_in_loop(coro)
|
||||
future.add_done_callback(on_done)
|
||||
return future
|
||||
|
||||
|
||||
def call_backend_coro(self, name: str, uuid: str, args: Sequence[str] = (),
|
||||
) -> Future:
|
||||
def call_backend_coro(
|
||||
self, name: str, uuid: str, args: Sequence[str] = (),
|
||||
) -> Future:
|
||||
return self._call_coro(attrgetter(name)(self.backend)(*args), uuid)
|
||||
|
||||
|
||||
def call_client_coro(self,
|
||||
account_id: str,
|
||||
name: str,
|
||||
uuid: str,
|
||||
args: Sequence[str] = ()) -> Future:
|
||||
client = self.backend.clients[account_id]
|
||||
def call_client_coro(
|
||||
self, user_id: str, name: str, uuid: str, args: Sequence[str] = (),
|
||||
) -> Future:
|
||||
|
||||
client = self.backend.clients[user_id]
|
||||
return self._call_coro(attrgetter(name)(client)(*args), uuid)
|
||||
|
||||
|
||||
def pdb(self, additional_data: Sequence = ()) -> None:
|
||||
ad = additional_data # noqa
|
||||
rl = self.run_in_loop # noqa
|
||||
rc = self._run_coro_in_loop # noqa
|
||||
ba = self.backend # noqa
|
||||
mo = self.backend.models # noqa
|
||||
cl = self.backend.clients
|
||||
tcl = lambda user: cl[f"@{user}:matrix.org"] # noqa
|
||||
gcl = lambda user: cl[f"@{user}:matrix.org"] # noqa
|
||||
|
||||
from .models.items import Account, Room, Member, Event, Device # noqa
|
||||
|
||||
p = print # pdb's `p` doesn't print a class's __str__ # noqa
|
||||
from pprintpp import pprint as pp # noqa
|
||||
try:
|
||||
from pprintpp import pprint as pp # noqa
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
log.info("\n=> Run `socat readline tcp:127.0.0.1:4444` in a terminal "
|
||||
"to connect to pdb.")
|
||||
|
@ -107,4 +91,4 @@ class App:
|
|||
# Make CTRL-C work again
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
APP = App()
|
||||
BRIDGE = QmlBridge()
|
|
@ -24,7 +24,7 @@ Item {
|
|||
HShortcut {
|
||||
enabled: debugMode
|
||||
sequences: settings.keys.startPythonDebugger
|
||||
onActivated: py.call("APP.pdb")
|
||||
onActivated: py.call("BRIDGE.pdb")
|
||||
}
|
||||
|
||||
HShortcut {
|
||||
|
|
|
@ -12,7 +12,7 @@ Python {
|
|||
addImportPath("src")
|
||||
addImportPath("qrc:/src")
|
||||
|
||||
importNames("backend", ["APP"], () => {
|
||||
importNames("backend", ["BRIDGE"], () => {
|
||||
loadSettings(() => {
|
||||
callCoro("saved_accounts.any_saved", [], any => {
|
||||
if (any) { py.callCoro("load_saved_accounts", []) }
|
||||
|
@ -45,7 +45,7 @@ Python {
|
|||
|
||||
|
||||
function callSync(name, args=[]) {
|
||||
return call_sync("APP.backend." + name, args)
|
||||
return call_sync("BRIDGE.backend." + name, args)
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,7 +56,7 @@ Python {
|
|||
|
||||
let future = privates.makeFuture()
|
||||
|
||||
call("APP.call_backend_coro", [name, uuid, args], pyFuture => {
|
||||
call("BRIDGE.call_backend_coro", [name, uuid, args], pyFuture => {
|
||||
future.privates.pythonFuture = pyFuture
|
||||
})
|
||||
|
||||
|
@ -76,7 +76,7 @@ Python {
|
|||
|
||||
let call_args = [accountId, name, uuid, args]
|
||||
|
||||
call("APP.call_client_coro", call_args, pyFuture => {
|
||||
call("BRIDGE.call_client_coro", call_args, pyFuture => {
|
||||
future.privates.pythonFuture = pyFuture
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue
Block a user