Add command to get an attachment (#1080)

* Add command to get an attachment

* Refactor retrieving of attachments to use StreamDetails

* Refactor AttachmentCommand to GetAttachmentCommand

* Minor improvements to GetAttachmentCommand

* Use JSON serializer to serialize binary data

Serializing the stream is better for memory handling than
loading the whole thing into the file.

* Clean up unneeded class

* Added command to doc

Co-authored-by: cedb <cedb@keylimebox.org>
This commit is contained in:
ced-b 2022-11-01 17:47:43 -04:00 committed by GitHub
parent bf76c04664
commit 2e4d346bc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 138 additions and 0 deletions

View file

@ -11,6 +11,7 @@ public class Commands {
static {
addCommand(new AddDeviceCommand());
addCommand(new GetAttachmentCommand());
addCommand(new BlockCommand());
addCommand(new DaemonCommand());
addCommand(new DeleteLocalAccountDataCommand());

View file

@ -0,0 +1,63 @@
package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.json.JsonAttachmentData;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.output.JsonWriter;
import org.asamk.signal.output.OutputWriter;
import org.asamk.signal.output.PlainTextWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
public class GetAttachmentCommand implements JsonRpcLocalCommand {
@Override
public String getName() {
return "getAttachment";
}
@Override
public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("--id")
.required(true)
.help("The ID of the attachment file.");
var mut = subparser.addMutuallyExclusiveGroup()
.required(true);
mut.addArgument("--recipient")
.help("Sender of the attachment");
mut.addArgument("-g", "--group-id")
.help("Group in which the attachment was received");
}
@Override
public void handleCommand(
final Namespace ns,
final Manager m,
final OutputWriter outputWriter
) throws CommandException {
final var id = ns.getString("id");
try(InputStream attachment = m.retrieveAttachment(id)) {
if (outputWriter instanceof PlainTextWriter writer) {
final var bytes = attachment.readAllBytes();
final var base64 = Base64.getEncoder().encodeToString(bytes);
writer.println(base64);
} else if (outputWriter instanceof JsonWriter writer) {
writer.write(new JsonAttachmentData(attachment));
}
} catch (FileNotFoundException ex) {
throw new UserErrorException("Could not find attachment with ID: " + id, ex);
} catch (IOException ex) {
throw new UnexpectedErrorException("An error occurred reading attachment: " + id, ex);
}
}
}

View file

@ -46,6 +46,7 @@ import org.freedesktop.dbus.types.Variant;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
@ -916,6 +917,11 @@ public class DbusManagerImpl implements Manager {
}).toList();
}
@Override
public InputStream retrieveAttachment(final String id) throws IOException {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked")
private <T> T getValue(
final Map<String, Variant<?>> stringVariantMap, final String field

View file

@ -0,0 +1,9 @@
package org.asamk.signal.json;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.InputStream;
public record JsonAttachmentData(
@JsonSerialize(using=JsonStreamSerializer.class) InputStream data
) {}

View file

@ -0,0 +1,20 @@
package org.asamk.signal.json;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.io.InputStream;
public class JsonStreamSerializer extends JsonSerializer<InputStream> {
@Override
public void serialize(
final InputStream value,
final JsonGenerator jsonGenerator,
final SerializerProvider serializers
) throws IOException {
jsonGenerator.writeBinary(value, -1);
}
}