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
,
34 final boolean noReceiveOnStart
36 this.isDbusSystem
= isDbusSystem
;
37 this.dbusRunner
= (connection
) -> {
39 exportDbusObject(connection
, DbusConfig
.getObjectPath(), m
).join();
40 } catch (InterruptedException ignored
) {
43 this.noReceiveOnStart
= noReceiveOnStart
;
44 this.busname
= busname
;
48 final boolean isDbusSystem
,
50 final MultiAccountManager c
,
51 final boolean noReceiveOnStart
53 this.isDbusSystem
= isDbusSystem
;
54 this.dbusRunner
= (connection
) -> {
55 final var signalControl
= new DbusSignalControlImpl(c
, DbusConfig
.getObjectPath());
56 connection
.exportObject(signalControl
);
58 c
.addOnManagerAddedHandler(m
-> {
59 final var thread
= exportManager(connection
, m
);
62 } catch (InterruptedException ignored
) {
65 c
.addOnManagerRemovedHandler(m
-> {
66 final var path
= DbusConfig
.getObjectPath(m
.getSelfNumber());
68 final var object
= connection
.getExportedObject(null, path
);
69 if (object
instanceof DbusSignalImpl dbusSignal
) {
71 closeables
.remove(dbusSignal
);
73 } catch (DBusException ignored
) {
77 final var initThreads
= c
.getManagers().stream().map(m
-> exportManager(connection
, m
)).toList();
79 for (var t
: initThreads
) {
82 } catch (InterruptedException ignored
) {
86 this.noReceiveOnStart
= noReceiveOnStart
;
87 this.busname
= busname
;
90 public void init() throws CommandException
{
91 if (dBusConnection
!= null) {
92 throw new AssertionError("DbusHandler already initialized");
94 final var busType
= isDbusSystem ? DBusConnection
.DBusBusType
.SYSTEM
: DBusConnection
.DBusBusType
.SESSION
;
95 logger
.debug("Starting DBus server on {} bus: {}", busType
, busname
);
97 dBusConnection
= DBusConnectionBuilder
.forType(busType
).build();
98 dbusRunner
.run(dBusConnection
);
99 } catch (DBusException e
) {
100 throw new UnexpectedErrorException("Dbus command failed: " + e
.getMessage(), e
);
101 } catch (UnsupportedOperationException e
) {
102 throw new UserErrorException("Failed to connect to Dbus: " + e
.getMessage(), e
);
106 dBusConnection
.requestBusName(busname
);
107 } catch (DBusException e
) {
108 throw new UnexpectedErrorException("Dbus command failed, maybe signal-cli dbus daemon is already running: "
109 + e
.getMessage(), e
);
112 logger
.info("Started DBus server on {} bus: {}", busType
, busname
);
116 public void close() throws Exception
{
117 if (dBusConnection
== null) {
120 dBusConnection
.close();
121 for (final var c
: new ArrayList
<>(closeables
)) {
125 dBusConnection
= null;
128 private Thread
exportDbusObject(final DBusConnection conn
, final String objectPath
, final Manager m
) {
129 final var signal
= new DbusSignalImpl(m
, conn
, objectPath
, noReceiveOnStart
);
130 closeables
.add(signal
);
132 return Thread
.ofPlatform().name("dbus-init-" + m
.getSelfNumber()).start(signal
::initObjects
);
135 private Thread
exportManager(final DBusConnection conn
, final Manager m
) {
136 final var objectPath
= DbusConfig
.getObjectPath(m
.getSelfNumber());
137 return exportDbusObject(conn
, objectPath
, m
);
140 private interface DbusRunner
{
142 void run(DBusConnection connection
) throws DBusException
;