dbus_manager: add initial implementation
The DBus manager is a core component that connects to the system bus, providing resources used to communicate with other processes on the the system through the DBus interface. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
0d6791a320
commit
73f0d5503d
|
@ -0,0 +1,122 @@
|
||||||
|
# DBus Connection Management
|
||||||
|
#
|
||||||
|
# Copyright (C) 2022 Eric Callahan <arksine.code@gmail.com>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
from __future__ import annotations
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import logging
|
||||||
|
import dbus_next
|
||||||
|
from dbus_next.aio import MessageBus, ProxyInterface
|
||||||
|
from dbus_next.constants import BusType
|
||||||
|
|
||||||
|
# Annotation imports
|
||||||
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from confighelper import ConfigHelper
|
||||||
|
|
||||||
|
class DbusManager:
|
||||||
|
Variant = dbus_next.Variant
|
||||||
|
DbusError = dbus_next.errors.DBusError
|
||||||
|
def __init__(self, config: ConfigHelper) -> None:
|
||||||
|
self.server = config.get_server()
|
||||||
|
self.bus: Optional[MessageBus] = None
|
||||||
|
self.polkit: Optional[ProxyInterface] = None
|
||||||
|
self.warned: bool = False
|
||||||
|
proc_data = pathlib.Path(f"/proc/self/stat").read_text()
|
||||||
|
start_clk_ticks = int(proc_data.split()[21])
|
||||||
|
self.polkit_subject = [
|
||||||
|
"unix-process",
|
||||||
|
{
|
||||||
|
"pid": dbus_next.Variant("u", os.getpid()),
|
||||||
|
"start-time": dbus_next.Variant("t", start_clk_ticks)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
return self.bus is not None and self.bus.connected
|
||||||
|
|
||||||
|
async def component_init(self) -> None:
|
||||||
|
try:
|
||||||
|
self.bus = MessageBus(bus_type=BusType.SYSTEM)
|
||||||
|
await self.bus.connect()
|
||||||
|
except Exception:
|
||||||
|
logging.info("Unable to Connect to D-Bus")
|
||||||
|
return
|
||||||
|
# Make sure that all required actions are register
|
||||||
|
try:
|
||||||
|
self.polkit = await self.get_interface(
|
||||||
|
"org.freedesktop.PolicyKit1",
|
||||||
|
"/org/freedesktop/PolicyKit1/Authority",
|
||||||
|
"org.freedesktop.PolicyKit1.Authority")
|
||||||
|
except self.DbusError:
|
||||||
|
self.server.add_warning(
|
||||||
|
"Unable to find DBus PolicyKit Interface")
|
||||||
|
|
||||||
|
async def check_permission(self,
|
||||||
|
action: str,
|
||||||
|
err_msg: str = ""
|
||||||
|
) -> bool:
|
||||||
|
if self.polkit is None:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
ret = await self.polkit.call_check_authorization( # type: ignore
|
||||||
|
self.polkit_subject, action, {}, 0, "")
|
||||||
|
except Exception as e:
|
||||||
|
self.server.add_warning(
|
||||||
|
f"Error checking authorization for action [{action}]: {e}"
|
||||||
|
", This may indicate that PolicyKit is not installed, "
|
||||||
|
f"{err_msg}")
|
||||||
|
return False
|
||||||
|
if not ret[0]:
|
||||||
|
if not self.warned:
|
||||||
|
self.server.add_warning(
|
||||||
|
"Missing PolicyKit permisions detected. See the "
|
||||||
|
"PolicyKit Permissions section of the install "
|
||||||
|
"documentation at https://moonraker.readthedocs.io/ "
|
||||||
|
"for details.")
|
||||||
|
self.warned = True
|
||||||
|
self.server.add_warning(
|
||||||
|
"Moonraker not authorized for PolicyKit action: "
|
||||||
|
f"[{action}], {err_msg}")
|
||||||
|
return ret[0]
|
||||||
|
|
||||||
|
async def get_interface(self,
|
||||||
|
bus_name: str,
|
||||||
|
bus_path: str,
|
||||||
|
interface_name: str
|
||||||
|
) -> ProxyInterface:
|
||||||
|
ret = await self.get_interfaces(bus_name, bus_path,
|
||||||
|
[interface_name])
|
||||||
|
return ret[0]
|
||||||
|
|
||||||
|
async def get_interfaces(self,
|
||||||
|
bus_name: str,
|
||||||
|
bus_path: str,
|
||||||
|
interface_names: List[str]
|
||||||
|
) -> List[ProxyInterface]:
|
||||||
|
if self.bus is None:
|
||||||
|
raise self.server.error("Bus not avaialable")
|
||||||
|
interfaces: List[ProxyInterface] = []
|
||||||
|
introspection = await self.bus.introspect(bus_name, bus_path)
|
||||||
|
proxy_obj = self.bus.get_proxy_object(bus_name, bus_path,
|
||||||
|
introspection)
|
||||||
|
for ifname in interface_names:
|
||||||
|
intf = proxy_obj.get_interface(ifname)
|
||||||
|
interfaces.append(intf)
|
||||||
|
return interfaces
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
if self.bus is not None and self.bus.connected:
|
||||||
|
self.bus.disconnect()
|
||||||
|
await self.bus.wait_for_disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
def load_component(config: ConfigHelper) -> DbusManager:
|
||||||
|
return DbusManager(config)
|
|
@ -51,9 +51,9 @@ MAX_LOG_ATTEMPTS = 10 * LOG_ATTEMPT_INTERVAL
|
||||||
UNIX_BUFFER_LIMIT = 2 * 1024 * 1024
|
UNIX_BUFFER_LIMIT = 2 * 1024 * 1024
|
||||||
|
|
||||||
CORE_COMPONENTS = [
|
CORE_COMPONENTS = [
|
||||||
'database', 'file_manager', 'klippy_apis', 'machine',
|
'dbus_manager', 'database', 'file_manager', 'klippy_apis',
|
||||||
'data_store', 'shell_command', 'proc_stats', 'job_state',
|
'machine', 'data_store', 'shell_command', 'proc_stats',
|
||||||
'job_queue'
|
'job_state', 'job_queue'
|
||||||
]
|
]
|
||||||
|
|
||||||
SENTINEL = SentinelClass.get_instance()
|
SENTINEL = SentinelClass.get_instance()
|
||||||
|
|
Loading…
Reference in New Issue