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