]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/commands/DaemonCommand.java
334d9adbf415e2b042deabab6acc9538e5c42220
[signal-cli] / src / main / java / org / asamk / signal / commands / DaemonCommand.java
1 package org.asamk.signal.commands;
2
3 import net.sourceforge.argparse4j.impl.Arguments;
4 import net.sourceforge.argparse4j.inf.Namespace;
5 import net.sourceforge.argparse4j.inf.Subparser;
6
7 import org.asamk.signal.DbusConfig;
8 import org.asamk.signal.DbusReceiveMessageHandler;
9 import org.asamk.signal.JsonDbusReceiveMessageHandler;
10 import org.asamk.signal.OutputType;
11 import org.asamk.signal.commands.exceptions.CommandException;
12 import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
13 import org.asamk.signal.dbus.DbusSignalImpl;
14 import org.asamk.signal.manager.Manager;
15 import org.freedesktop.dbus.connections.impl.DBusConnection;
16 import org.freedesktop.dbus.exceptions.DBusException;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Set;
24 import java.util.concurrent.TimeUnit;
25
26 public class DaemonCommand implements MultiLocalCommand {
27
28 private final static Logger logger = LoggerFactory.getLogger(DaemonCommand.class);
29
30 @Override
31 public void attachToSubparser(final Subparser subparser) {
32 subparser.help("Run in daemon mode and provide an experimental dbus interface.");
33 subparser.addArgument("--system")
34 .action(Arguments.storeTrue())
35 .help("Use DBus system bus instead of user bus.");
36 subparser.addArgument("--ignore-attachments")
37 .help("Don’t download attachments of received messages.")
38 .action(Arguments.storeTrue());
39 subparser.addArgument("--json")
40 .help("WARNING: This parameter is now deprecated! Please use the global \"--output=json\" option instead.\n\nOutput received messages in json format, one json object per line.")
41 .action(Arguments.storeTrue());
42 }
43
44 @Override
45 public Set<OutputType> getSupportedOutputTypes() {
46 return Set.of(OutputType.PLAIN_TEXT, OutputType.JSON);
47 }
48
49 @Override
50 public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
51 var inJson = ns.get("output") == OutputType.JSON || ns.getBoolean("json");
52
53 // TODO delete later when "json" variable is removed
54 if (ns.getBoolean("json")) {
55 logger.warn("\"--json\" option has been deprecated, please use the global \"--output=json\" instead.");
56 }
57
58 boolean ignoreAttachments = ns.getBoolean("ignore-attachments");
59
60 DBusConnection.DBusBusType busType;
61 if (ns.getBoolean("system")) {
62 busType = DBusConnection.DBusBusType.SYSTEM;
63 } else {
64 busType = DBusConnection.DBusBusType.SESSION;
65 }
66
67 try (var conn = DBusConnection.getConnection(busType)) {
68 var objectPath = DbusConfig.getObjectPath();
69 var t = run(conn, objectPath, m, ignoreAttachments, inJson);
70
71 conn.requestBusName(DbusConfig.getBusname());
72
73 try {
74 t.join();
75 } catch (InterruptedException ignored) {
76 }
77 } catch (DBusException | IOException e) {
78 logger.error("Dbus command failed", e);
79 throw new UnexpectedErrorException("Dbus command failed");
80 }
81 }
82
83 @Override
84 public void handleCommand(final Namespace ns, final List<Manager> managers) throws CommandException {
85 var inJson = ns.get("output") == OutputType.JSON || ns.getBoolean("json");
86
87 // TODO delete later when "json" variable is removed
88 if (ns.getBoolean("json")) {
89 logger.warn("\"--json\" option has been deprecated, please use the global \"--output=json\" instead.");
90 }
91
92 boolean ignoreAttachments = ns.getBoolean("ignore-attachments");
93
94 DBusConnection.DBusBusType busType;
95 if (ns.getBoolean("system")) {
96 busType = DBusConnection.DBusBusType.SYSTEM;
97 } else {
98 busType = DBusConnection.DBusBusType.SESSION;
99 }
100
101 try (var conn = DBusConnection.getConnection(busType)) {
102 var receiveThreads = new ArrayList<Thread>();
103 for (var m : managers) {
104 var objectPath = DbusConfig.getObjectPath(m.getUsername());
105 var thread = run(conn, objectPath, m, ignoreAttachments, inJson);
106 receiveThreads.add(thread);
107 }
108
109 conn.requestBusName(DbusConfig.getBusname());
110
111 for (var t : receiveThreads) {
112 try {
113 t.join();
114 } catch (InterruptedException ignored) {
115 }
116 }
117 } catch (DBusException | IOException e) {
118 logger.error("Dbus command failed", e);
119 throw new UnexpectedErrorException("Dbus command failed");
120 }
121 }
122
123 private Thread run(
124 DBusConnection conn, String objectPath, Manager m, boolean ignoreAttachments, boolean inJson
125 ) throws DBusException {
126 conn.exportObject(objectPath, new DbusSignalImpl(m));
127
128 final var thread = new Thread(() -> {
129 while (true) {
130 try {
131 m.receiveMessages(1,
132 TimeUnit.HOURS,
133 false,
134 ignoreAttachments,
135 inJson
136 ? new JsonDbusReceiveMessageHandler(m, conn, objectPath)
137 : new DbusReceiveMessageHandler(m, conn, objectPath));
138 } catch (IOException e) {
139 logger.warn("Receiving messages failed, retrying", e);
140 }
141 }
142 });
143
144 logger.info("Exported dbus object: " + objectPath);
145
146 thread.start();
147
148 return thread;
149 }
150 }