]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/commands/DaemonCommand.java
Implement jsonRpc command
[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.DbusSignalControlImpl;
17 import org.asamk.signal.dbus.DbusSignalImpl;
18 import org.asamk.signal.manager.Manager;
19 import org.freedesktop.dbus.connections.impl.DBusConnection;
20 import org.freedesktop.dbus.exceptions.DBusException;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import java.io.IOException;
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(
82 final Namespace ns, final List<Manager> managers, SignalCreator c
83 ) throws CommandException {
84 boolean ignoreAttachments = ns.getBoolean("ignore-attachments");
85
86 DBusConnection.DBusBusType busType;
87 if (ns.getBoolean("system")) {
88 busType = DBusConnection.DBusBusType.SYSTEM;
89 } else {
90 busType = DBusConnection.DBusBusType.SESSION;
91 }
92
93 try (var conn = DBusConnection.getConnection(busType)) {
94 final var signalControl = new DbusSignalControlImpl(c, m -> {
95 try {
96 final var objectPath = DbusConfig.getObjectPath(m.getUsername());
97 return run(conn, objectPath, m, ignoreAttachments);
98 } catch (DBusException e) {
99 logger.error("Failed to export object", e);
100 return null;
101 }
102 }, DbusConfig.getObjectPath());
103 conn.exportObject(signalControl);
104
105 for (var m : managers) {
106 signalControl.addManager(m);
107 }
108
109 conn.requestBusName(DbusConfig.getBusname());
110
111 signalControl.run();
112 } catch (DBusException | IOException e) {
113 logger.error("Dbus command failed", e);
114 throw new UnexpectedErrorException("Dbus command failed");
115 }
116 }
117
118 private Thread run(
119 DBusConnection conn, String objectPath, Manager m, boolean ignoreAttachments
120 ) throws DBusException {
121 conn.exportObject(new DbusSignalImpl(m, objectPath));
122
123 logger.info("Exported dbus object: " + objectPath);
124
125 final var thread = new Thread(() -> {
126 while (!Thread.interrupted()) {
127 try {
128 final var receiveMessageHandler = outputWriter instanceof JsonWriter
129 ? new JsonDbusReceiveMessageHandler(m, (JsonWriter) outputWriter, conn, objectPath)
130 : new DbusReceiveMessageHandler(m, (PlainTextWriter) outputWriter, conn, objectPath);
131 m.receiveMessages(1, TimeUnit.HOURS, false, ignoreAttachments, receiveMessageHandler);
132 break;
133 } catch (IOException e) {
134 logger.warn("Receiving messages failed, retrying", e);
135 } catch (InterruptedException ignored) {
136 break;
137 }
138 }
139 });
140
141 thread.start();
142
143 return thread;
144 }
145 }