]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/dbus/DbusHandler.java
Recreate recipient database with aci column
[signal-cli] / src / main / java / org / asamk / signal / dbus / DbusHandler.java
1 package org.asamk.signal.dbus;
2
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;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
18 public class DbusHandler implements AutoCloseable {
19
20 private static final Logger logger = LoggerFactory.getLogger(DbusHandler.class);
21
22 private final boolean isDbusSystem;
23 private DBusConnection dBusConnection;
24
25 private final List<AutoCloseable> closeables = new ArrayList<>();
26 private final DbusRunner dbusRunner;
27 private final boolean noReceiveOnStart;
28
29 public DbusHandler(final boolean isDbusSystem, final Manager m, final boolean noReceiveOnStart) {
30 this.isDbusSystem = isDbusSystem;
31 this.dbusRunner = (connection) -> {
32 try {
33 exportDbusObject(connection, DbusConfig.getObjectPath(), m).join();
34 } catch (InterruptedException ignored) {
35 }
36 };
37 this.noReceiveOnStart = noReceiveOnStart;
38 }
39
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);
45
46 c.addOnManagerAddedHandler(m -> {
47 final var thread = exportManager(connection, m);
48 try {
49 thread.join();
50 } catch (InterruptedException ignored) {
51 }
52 });
53 c.addOnManagerRemovedHandler(m -> {
54 final var path = DbusConfig.getObjectPath(m.getSelfNumber());
55 try {
56 final var object = connection.getExportedObject(null, path);
57 if (object instanceof DbusSignalImpl dbusSignal) {
58 dbusSignal.close();
59 closeables.remove(dbusSignal);
60 }
61 } catch (DBusException ignored) {
62 }
63 });
64
65 final var initThreads = c.getManagers().stream().map(m -> exportManager(connection, m)).toList();
66
67 for (var t : initThreads) {
68 try {
69 t.join();
70 } catch (InterruptedException ignored) {
71 }
72 }
73 };
74 this.noReceiveOnStart = noReceiveOnStart;
75 }
76
77 public void init() throws CommandException {
78 if (dBusConnection != null) {
79 throw new AssertionError("DbusHandler already initialized");
80 }
81 final var busType = isDbusSystem ? DBusConnection.DBusBusType.SYSTEM : DBusConnection.DBusBusType.SESSION;
82 logger.debug("Starting DBus server on {} bus: {}", busType, DbusConfig.getBusname());
83 try {
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);
90 }
91
92 try {
93 dBusConnection.requestBusName(DbusConfig.getBusname());
94 } catch (DBusException e) {
95 throw new UnexpectedErrorException("Dbus command failed, maybe signal-cli dbus daemon is already running: "
96 + e.getMessage(), e);
97 }
98
99 logger.info("Started DBus server on {} bus: {}", busType, DbusConfig.getBusname());
100 }
101
102 @Override
103 public void close() throws Exception {
104 if (dBusConnection == null) {
105 return;
106 }
107 dBusConnection.close();
108 for (final var c : new ArrayList<>(closeables)) {
109 c.close();
110 }
111 closeables.clear();
112 dBusConnection = null;
113 }
114
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);
118
119 return Thread.ofPlatform().name("dbus-init-" + m.getSelfNumber()).start(signal::initObjects);
120 }
121
122 private Thread exportManager(final DBusConnection conn, final Manager m) {
123 final var objectPath = DbusConfig.getObjectPath(m.getSelfNumber());
124 return exportDbusObject(conn, objectPath, m);
125 }
126
127 private interface DbusRunner {
128
129 void run(DBusConnection connection) throws DBusException;
130 }
131 }