1 package org
.asamk
.signal
.dbus
;
3 import org
.asamk
.signal
.DbusConfig
;
4 import org
.asamk
.signal
.commands
.exceptions
.CommandException
;
5 import org
.asamk
.signal
.commands
.exceptions
.UnexpectedErrorException
;
6 import org
.asamk
.signal
.commands
.exceptions
.UserErrorException
;
7 import org
.asamk
.signal
.manager
.Manager
;
8 import org
.asamk
.signal
.manager
.MultiAccountManager
;
9 import org
.freedesktop
.dbus
.connections
.impl
.DBusConnection
;
10 import org
.freedesktop
.dbus
.connections
.impl
.DBusConnectionBuilder
;
11 import org
.freedesktop
.dbus
.exceptions
.DBusException
;
12 import org
.slf4j
.Logger
;
13 import org
.slf4j
.LoggerFactory
;
15 import java
.util
.ArrayList
;
16 import java
.util
.List
;
18 public class DbusHandler
implements AutoCloseable
{
20 private static final Logger logger
= LoggerFactory
.getLogger(DbusHandler
.class);
22 private final boolean isDbusSystem
;
23 private DBusConnection dBusConnection
;
24 private final String busname
;
26 private final List
<AutoCloseable
> closeables
= new ArrayList
<>();
27 private final DbusRunner dbusRunner
;
28 private final boolean noReceiveOnStart
;
31 final boolean isDbusSystem
, final String busname
, final Manager m
, final boolean noReceiveOnStart
33 this.isDbusSystem
= isDbusSystem
;
34 this.dbusRunner
= (connection
) -> {
36 exportDbusObject(connection
, DbusConfig
.getObjectPath(), m
).join();
37 } catch (InterruptedException ignored
) {
40 this.noReceiveOnStart
= noReceiveOnStart
;
41 this.busname
= busname
;
45 final boolean isDbusSystem
,
47 final MultiAccountManager c
,
48 final boolean noReceiveOnStart
50 this.isDbusSystem
= isDbusSystem
;
51 this.dbusRunner
= (connection
) -> {
52 final var signalControl
= new DbusSignalControlImpl(c
, DbusConfig
.getObjectPath());
53 connection
.exportObject(signalControl
);
55 c
.addOnManagerAddedHandler(m
-> {
56 final var thread
= exportManager(connection
, m
);
59 } catch (InterruptedException ignored
) {
62 c
.addOnManagerRemovedHandler(m
-> {
63 final var path
= DbusConfig
.getObjectPath(m
.getSelfNumber());
65 final var object
= connection
.getExportedObject(null, path
);
66 if (object
instanceof DbusSignalImpl dbusSignal
) {
68 closeables
.remove(dbusSignal
);
70 } catch (DBusException ignored
) {
74 final var initThreads
= c
.getManagers().stream().map(m
-> exportManager(connection
, m
)).toList();
76 for (var t
: initThreads
) {
79 } catch (InterruptedException ignored
) {
83 this.noReceiveOnStart
= noReceiveOnStart
;
84 this.busname
= busname
;
87 public void init() throws CommandException
{
88 if (dBusConnection
!= null) {
89 throw new AssertionError("DbusHandler already initialized");
91 final var busType
= isDbusSystem ? DBusConnection
.DBusBusType
.SYSTEM
: DBusConnection
.DBusBusType
.SESSION
;
92 logger
.debug("Starting DBus server on {} bus: {}", busType
, busname
);
94 dBusConnection
= DBusConnectionBuilder
.forType(busType
).build();
95 dbusRunner
.run(dBusConnection
);
96 } catch (DBusException e
) {
97 throw new UnexpectedErrorException("Dbus command failed: " + e
.getMessage(), e
);
98 } catch (UnsupportedOperationException e
) {
99 throw new UserErrorException("Failed to connect to Dbus: " + e
.getMessage(), e
);
103 dBusConnection
.requestBusName(busname
);
104 } catch (DBusException e
) {
105 throw new UnexpectedErrorException("Dbus command failed, maybe signal-cli dbus daemon is already running: "
106 + e
.getMessage(), e
);
109 logger
.info("Started DBus server on {} bus: {}", busType
, busname
);
113 public void close() throws Exception
{
114 if (dBusConnection
== null) {
117 dBusConnection
.close();
118 for (final var c
: new ArrayList
<>(closeables
)) {
122 dBusConnection
= null;
125 private Thread
exportDbusObject(final DBusConnection conn
, final String objectPath
, final Manager m
) {
126 final var signal
= new DbusSignalImpl(m
, conn
, objectPath
, noReceiveOnStart
);
127 closeables
.add(signal
);
129 return Thread
.ofPlatform().name("dbus-init-" + m
.getSelfNumber()).start(signal
::initObjects
);
132 private Thread
exportManager(final DBusConnection conn
, final Manager m
) {
133 final var objectPath
= DbusConfig
.getObjectPath(m
.getSelfNumber());
134 return exportDbusObject(conn
, objectPath
, m
);
137 private interface DbusRunner
{
139 void run(DBusConnection connection
) throws DBusException
;