pan: Move the dbus code into a separate file.

This commit is contained in:
Damir Jelić 2019-04-18 11:43:07 +02:00
parent 7038462e01
commit 1613a2fa5a
4 changed files with 170 additions and 73 deletions

View File

@ -9,6 +9,7 @@ from nio import (AsyncClient, ClientConfig, EncryptionError,
from nio.store import SqliteStore
from pantalaimon.log import logger
from pantalaimon.ui import DevicesMessage
class PanClient(AsyncClient):
@ -17,6 +18,7 @@ class PanClient(AsyncClient):
def __init__(
self,
homeserver,
queue=None,
user="",
device_id="",
store_path="",
@ -29,6 +31,7 @@ class PanClient(AsyncClient):
ssl, proxy)
self.task = None
self.queue = queue
self.loop_stopped = asyncio.Event()
self.synced = asyncio.Event()
@ -78,6 +81,12 @@ class PanClient(AsyncClient):
key_query_response = await self.keys_query()
if isinstance(key_query_response, KeysQueryResponse):
self.verify_devices(key_query_response.changed)
message = DevicesMessage(
self.user_id,
self.device_id,
key_query_response.changed
)
await self.queue.put(message)
if not isinstance(response, SyncResponse):
# TODO error handling

View File

@ -4,27 +4,20 @@ import asyncio
import json
import os
import sys
from enum import Enum, auto
from functools import partial
from ipaddress import ip_address
from json import JSONDecodeError
from queue import Empty
from urllib.parse import urlparse
import aiohttp
import attr
import click
import dbus
import dbus.exceptions
import dbus.service
import janus
import keyring
import logbook
from aiohttp import ClientSession, web
from aiohttp.client_exceptions import ContentTypeError
from appdirs import user_data_dir
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
from logbook import StderrHandler
from multidict import CIMultiDict
from nio import EncryptionError, GroupEncryptionError, LoginResponse
@ -32,69 +25,7 @@ from nio import EncryptionError, GroupEncryptionError, LoginResponse
from pantalaimon.client import PanClient
from pantalaimon.log import logger
from pantalaimon.store import ClientInfo, PanStore
class Tasks(Enum):
shutdown = auto()
class Devices(dbus.service.Object):
def __init__(self, bus_name, device_list):
super().__init__(bus_name, "/org/pantalaimon/Devices")
self.device_list = device_list
@dbus.service.method("org.pantalaimon.devices.list",
out_signature="a{sa{saa{ss}}}")
def list(self):
return self.device_list
class Users(dbus.service.Object):
def __init__(self, bus_name, user_list=None):
super().__init__(bus_name, "/org/pantalaimon/Users")
self.users = user_list
@dbus.service.method("org.pantalaimon.users.list",
out_signature="a(ss)")
def list(self):
return self.users
def dbus_loop(task_queue, data_dir):
DBusGMainLoop(set_as_default=True)
loop = GLib.MainLoop()
bus_name = dbus.service.BusName("org.pantalaimon",
bus=dbus.SessionBus(),
do_not_queue=True)
store = PanStore(data_dir)
users = store.load_all_users()
devices = store.load_all_devices()
# TODO update bus data if the asyncio thread tells us so.
Users(bus_name, users)
Devices(bus_name, devices)
def task_callback():
try:
task = task_queue.get_nowait()
except Empty:
return True
if task == Tasks.shutdown:
task_queue.task_done()
loop.quit()
return False
GLib.timeout_add(100, task_callback)
loop.run()
async def shutdown_dbus(future, queue, app):
await queue.put(Tasks.shutdown)
await future
from pantalaimon.ui import glib_loop, shutdown_glib_loop
@attr.s
@ -139,6 +70,7 @@ class ProxyDaemon:
pan_client = PanClient(
self.homeserver_url,
self.queue,
user_id,
device_id,
store_path=self.data_dir,
@ -248,6 +180,7 @@ class ProxyDaemon:
pan_client = PanClient(
self.homeserver_url,
self.queue,
user,
store_path=self.data_dir,
ssl=self.ssl,
@ -716,12 +649,12 @@ def start(
))
data_dir = user_data_dir("pantalaimon", "")
fut = loop.run_in_executor(None, dbus_loop, queue.sync_q, data_dir)
fut = loop.run_in_executor(None, glib_loop, queue.sync_q, data_dir)
kill_dbus_loop = partial(shutdown_dbus, fut, queue.async_q)
kill_glib = partial(shutdown_glib_loop, fut, queue.async_q)
app.on_shutdown.append(proxy.shutdown)
app.on_shutdown.append(kill_dbus_loop)
app.on_shutdown.append(kill_glib)
web.run_app(app, host=str(listen_address), port=listen_port)

View File

@ -223,6 +223,9 @@ class PanStore:
for d in account.device_keys:
if d.deleted:
continue
try:
trust_state = d.trust_state[0].state
except IndexError:

152
pantalaimon/ui.py Normal file
View File

@ -0,0 +1,152 @@
import attr
import dbus
import dbus.exceptions
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
from queue import Empty
from nio.store import TrustState
from pantalaimon.store import PanStore
from pantalaimon.log import logger
@attr.s
class Message:
pass
@attr.s
class ShutDownMessage(Message):
pass
@attr.s
class DevicesMessage(Message):
user_id = attr.ib()
device_id = attr.ib()
devices = attr.ib()
@attr.s
class DeviceVerifyMessage(Message):
user_id = attr.ib()
device_id = attr.ib()
device_user = attr.ib()
device_device_id = attr.ib()
class Devices(dbus.service.Object):
def __init__(self, bus_name, device_list):
super().__init__(bus_name, "/org/pantalaimon/Devices")
self.device_list = device_list
@dbus.service.method("org.pantalaimon.devices.list",
out_signature="a{sa{saa{ss}}}")
def list(self):
return self.device_list
@dbus.service.method("org.pantalaimon.devices.verify",
in_signature="ssss")
def verify(self, user_id, device_id, devices_user, devices_id):
device_store = self.device_list[user_id].get(device_id, None)
if not device_store:
logger.debug(f"Not verifying device, no store found for user "
f"{user_id}")
return
logger.debug(f"Verifying device {devices_user} {devices_id}")
return
@dbus.service.method("org.pantalaimon.devices.start_verification",
in_signature="ssss")
def start_verify(self, user_id, device_id, devices_user, devices_id):
device_store = self.device_list[user_id].get(device_id, None)
if not device_store:
logger.info(f"Not verifying device, no store found for user "
f"{user_id}")
return
logger.info(f"Verifying device {devices_user} {devices_id}")
return
def update_devices(self, message):
device_store = self.device_list[message.user_id][message.device_id]
for user_id, device_dict in message.devices.items():
for device in device_dict.values():
if device.deleted:
device_store[user_id].pop(device.id, None)
else:
device_store[user_id][device.id] = {
"user_id": device.user_id,
"device_id": device.id,
"fingerprint_key": device.ed25519,
"sender_key": device.curve25519,
"trust_state": TrustState.unset.name,
}
class Users(dbus.service.Object):
def __init__(self, bus_name, user_list=None):
super().__init__(bus_name, "/org/pantalaimon/Control")
self.users = user_list
@dbus.service.method("org.pantalaimon.control.list_users",
out_signature="a(ss)")
def list(self):
return self.users
@dbus.service.method("org.pantalaimon.control.export_keys",
in_signature="ss")
def export_keys(self, user, filepath):
return
def glib_loop(queue, data_dir):
DBusGMainLoop(set_as_default=True)
loop = GLib.MainLoop()
bus_name = dbus.service.BusName("org.pantalaimon",
bus=dbus.SessionBus(),
do_not_queue=True)
store = PanStore(data_dir)
users = store.load_all_users()
devices = store.load_all_devices()
# TODO update bus data if the asyncio thread tells us so.
Users(bus_name, users)
device_bus = Devices(bus_name, devices)
def message_callback():
try:
message = queue.get_nowait()
except Empty:
return True
logger.info(f"Dbus loop received message {message}")
if isinstance(message, ShutDownMessage):
queue.task_done()
loop.quit()
return False
elif isinstance(message, DevicesMessage):
device_bus.update_devices(message)
return True
GLib.timeout_add(100, message_callback)
loop.run()
async def shutdown_glib_loop(future, queue, app):
await queue.put(ShutDownMessage())
await future