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
;
25 private final List
<AutoCloseable
> closeables
= new ArrayList
<>();
26 private final DbusRunner dbusRunner
;
27 private final boolean noReceiveOnStart
;
29 public DbusHandler(final boolean isDbusSystem
, final Manager m
, final boolean noReceiveOnStart
) {
30 this.isDbusSystem
= isDbusSystem
;
31 this.dbusRunner
= (connection
) -> {
33 exportDbusObject(connection
, DbusConfig
.getObjectPath(), m
).join();
34 } catch (InterruptedException ignored
) {
37 this.noReceiveOnStart
= noReceiveOnStart
;
40 public DbusHandler(final boolean isDbusSystem
, final MultiAccountManager c
, final boolean noReceiveOnStart
) {
41 this.isDbusSystem
= isDbusSystem
;
42 this.dbusRunner
= (connection
) -> {
43 final var signalControl
= new DbusSignalControlImpl(c
, DbusConfig
.getObjectPath());
44 connection
.exportObject(signalControl
);
46 c
.addOnManagerAddedHandler(m
-> {
47 final var thread
= exportManager(connection
, m
);
50 } catch (InterruptedException ignored
) {
53 c
.addOnManagerRemovedHandler(m
-> {
54 final var path
= DbusConfig
.getObjectPath(m
.getSelfNumber());
56 final var object
= connection
.getExportedObject(null, path
);
57 if (object
instanceof DbusSignalImpl dbusSignal
) {
59 closeables
.remove(dbusSignal
);
61 } catch (DBusException ignored
) {
65 final var initThreads
= c
.getManagers().stream().map(m
-> exportManager(connection
, m
)).toList();
67 for (var t
: initThreads
) {
70 } catch (InterruptedException ignored
) {
74 this.noReceiveOnStart
= noReceiveOnStart
;
77 public void init() throws CommandException
{
78 if (dBusConnection
!= null) {
79 throw new AssertionError("DbusHandler already initialized");
81 final var busType
= isDbusSystem ? DBusConnection
.DBusBusType
.SYSTEM
: DBusConnection
.DBusBusType
.SESSION
;
82 logger
.debug("Starting DBus server on {} bus: {}", busType
, DbusConfig
.getBusname());
84 dBusConnection
= DBusConnectionBuilder
.forType(busType
).build();
85 dbusRunner
.run(dBusConnection
);
86 } catch (DBusException e
) {
87 throw new UnexpectedErrorException("Dbus command failed: " + e
.getMessage(), e
);
88 } catch (UnsupportedOperationException e
) {
89 throw new UserErrorException("Failed to connect to Dbus: " + e
.getMessage(), e
);
93 dBusConnection
.requestBusName(DbusConfig
.getBusname());
94 } catch (DBusException e
) {
95 throw new UnexpectedErrorException("Dbus command failed, maybe signal-cli dbus daemon is already running: "
99 logger
.info("Started DBus server on {} bus: {}", busType
, DbusConfig
.getBusname());
103 public void close() throws Exception
{
104 if (dBusConnection
== null) {
107 dBusConnection
.close();
108 for (final var c
: new ArrayList
<>(closeables
)) {
112 dBusConnection
= null;
115 private Thread
exportDbusObject(final DBusConnection conn
, final String objectPath
, final Manager m
) {
116 final var signal
= new DbusSignalImpl(m
, conn
, objectPath
, noReceiveOnStart
);
117 closeables
.add(signal
);
119 return Thread
.ofPlatform().name("dbus-init-" + m
.getSelfNumber()).start(signal
::initObjects
);
122 private Thread
exportManager(final DBusConnection conn
, final Manager m
) {
123 final var objectPath
= DbusConfig
.getObjectPath(m
.getSelfNumber());
124 return exportDbusObject(conn
, objectPath
, m
);
127 private interface DbusRunner
{
129 void run(DBusConnection connection
) throws DBusException
;