Use pattern matching switch cases

This commit is contained in:
AsamK 2023-10-17 19:52:35 +02:00
parent 80c1a6d2af
commit 8d55dfb66b
27 changed files with 395 additions and 380 deletions

View file

@ -224,52 +224,55 @@ public class GroupHelper {
var group = getGroupForUpdating(groupId); var group = getGroupForUpdating(groupId);
final var avatarBytes = readAvatarBytes(avatarFile); final var avatarBytes = readAvatarBytes(avatarFile);
if (group instanceof GroupInfoV2) { switch (group) {
try { case GroupInfoV2 gv2 -> {
return updateGroupV2((GroupInfoV2) group, try {
name, return updateGroupV2(gv2,
description, name,
members, description,
removeMembers, members,
admins, removeMembers,
removeAdmins, admins,
banMembers, removeAdmins,
unbanMembers, banMembers,
resetGroupLink, unbanMembers,
groupLinkState, resetGroupLink,
addMemberPermission, groupLinkState,
editDetailsPermission, addMemberPermission,
avatarBytes, editDetailsPermission,
expirationTimer, avatarBytes,
isAnnouncementGroup); expirationTimer,
} catch (ConflictException e) { isAnnouncementGroup);
// Detected conflicting update, refreshing group and trying again } catch (ConflictException e) {
group = getGroup(groupId, true); // Detected conflicting update, refreshing group and trying again
return updateGroupV2((GroupInfoV2) group, group = getGroup(groupId, true);
name, return updateGroupV2((GroupInfoV2) group,
description, name,
members, description,
removeMembers, members,
admins, removeMembers,
removeAdmins, admins,
banMembers, removeAdmins,
unbanMembers, banMembers,
resetGroupLink, unbanMembers,
groupLinkState, resetGroupLink,
addMemberPermission, groupLinkState,
editDetailsPermission, addMemberPermission,
avatarBytes, editDetailsPermission,
expirationTimer, avatarBytes,
isAnnouncementGroup); expirationTimer,
isAnnouncementGroup);
}
}
case GroupInfoV1 gv1 -> {
final var result = updateGroupV1(gv1, name, members, avatarBytes);
if (expirationTimer != null) {
setExpirationTimer(gv1, expirationTimer);
}
return result;
} }
} }
final var gv1 = (GroupInfoV1) group;
final var result = updateGroupV1(gv1, name, members, avatarBytes);
if (expirationTimer != null) {
setExpirationTimer(gv1, expirationTimer);
}
return result;
} }
public void updateGroupProfileKey(GroupIdV2 groupId) throws GroupNotFoundException, NotAGroupMemberException, IOException { public void updateGroupProfileKey(GroupIdV2 groupId) throws GroupNotFoundException, NotAGroupMemberException, IOException {

View file

@ -25,19 +25,19 @@ public class PinHelper {
String pin, MasterKey masterKey String pin, MasterKey masterKey
) throws IOException { ) throws IOException {
final var backupResponse = secureValueRecoveryV2.setPin(pin, masterKey).execute(); final var backupResponse = secureValueRecoveryV2.setPin(pin, masterKey).execute();
if (backupResponse instanceof SecureValueRecovery.BackupResponse.Success) { switch (backupResponse) {
} else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ServerRejected) { case SecureValueRecovery.BackupResponse.Success success -> {
logger.warn("Backup svr2 failed: ServerRejected"); }
} else if (backupResponse instanceof SecureValueRecovery.BackupResponse.EnclaveNotFound) { case SecureValueRecovery.BackupResponse.ServerRejected serverRejected ->
logger.warn("Backup svr2 failed: EnclaveNotFound"); logger.warn("Backup svr2 failed: ServerRejected");
} else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ExposeFailure) { case SecureValueRecovery.BackupResponse.EnclaveNotFound enclaveNotFound ->
logger.warn("Backup svr2 failed: ExposeFailure"); logger.warn("Backup svr2 failed: EnclaveNotFound");
} else if (backupResponse instanceof SecureValueRecovery.BackupResponse.ApplicationError error) { case SecureValueRecovery.BackupResponse.ExposeFailure exposeFailure ->
throw new IOException(error.getException()); logger.warn("Backup svr2 failed: ExposeFailure");
} else if (backupResponse instanceof SecureValueRecovery.BackupResponse.NetworkError error) { case SecureValueRecovery.BackupResponse.ApplicationError error ->
throw error.getException(); throw new IOException(error.getException());
} else { case SecureValueRecovery.BackupResponse.NetworkError error -> throw error.getException();
throw new AssertionError("Unexpected response"); case null, default -> throw new AssertionError("Unexpected response");
} }
} }
@ -47,17 +47,17 @@ public class PinHelper {
public void removeRegistrationLockPin() throws IOException { public void removeRegistrationLockPin() throws IOException {
final var deleteResponse = secureValueRecoveryV2.deleteData(); final var deleteResponse = secureValueRecoveryV2.deleteData();
if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.Success) { switch (deleteResponse) {
} else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.ServerRejected) { case SecureValueRecovery.DeleteResponse.Success success -> {
logger.warn("Delete svr2 failed: ServerRejected"); }
} else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.EnclaveNotFound) { case SecureValueRecovery.DeleteResponse.ServerRejected serverRejected ->
logger.warn("Delete svr2 failed: EnclaveNotFound"); logger.warn("Delete svr2 failed: ServerRejected");
} else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.ApplicationError error) { case SecureValueRecovery.DeleteResponse.EnclaveNotFound enclaveNotFound ->
throw new IOException(error.getException()); logger.warn("Delete svr2 failed: EnclaveNotFound");
} else if (deleteResponse instanceof SecureValueRecovery.DeleteResponse.NetworkError error) { case SecureValueRecovery.DeleteResponse.ApplicationError error ->
throw error.getException(); throw new IOException(error.getException());
} else { case SecureValueRecovery.DeleteResponse.NetworkError error -> throw error.getException();
throw new AssertionError("Unexpected response"); case null, default -> throw new AssertionError("Unexpected response");
} }
} }
@ -77,19 +77,21 @@ public class PinHelper {
) throws IOException, IncorrectPinException { ) throws IOException, IncorrectPinException {
final var restoreResponse = secureValueRecovery.restoreDataPreRegistration(authCredentials, pin); final var restoreResponse = secureValueRecovery.restoreDataPreRegistration(authCredentials, pin);
if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.Success s) { switch (restoreResponse) {
return s; case SecureValueRecovery.RestoreResponse.Success s -> {
} else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.PinMismatch pinMismatch) { return s;
throw new IncorrectPinException(pinMismatch.getTriesRemaining()); }
} else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.ApplicationError error) { case SecureValueRecovery.RestoreResponse.PinMismatch pinMismatch ->
throw new IOException(error.getException()); throw new IncorrectPinException(pinMismatch.getTriesRemaining());
} else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.NetworkError error) { case SecureValueRecovery.RestoreResponse.ApplicationError error ->
throw error.getException(); throw new IOException(error.getException());
} else if (restoreResponse instanceof SecureValueRecovery.RestoreResponse.Missing) { case SecureValueRecovery.RestoreResponse.NetworkError error -> throw error.getException();
logger.debug("No SVR data stored for the given credentials."); case SecureValueRecovery.RestoreResponse.Missing missing -> {
return null; logger.debug("No SVR data stored for the given credentials.");
} else { return null;
throw new AssertionError("Unexpected response: " + restoreResponse.getClass().getSimpleName()); }
case null, default ->
throw new AssertionError("Unexpected response: " + restoreResponse.getClass().getSimpleName());
} }
} }
} }

View file

@ -1252,18 +1252,15 @@ public class ManagerImpl implements Manager {
public boolean trustIdentityVerified( public boolean trustIdentityVerified(
RecipientIdentifier.Single recipient, IdentityVerificationCode verificationCode RecipientIdentifier.Single recipient, IdentityVerificationCode verificationCode
) throws UnregisteredRecipientException { ) throws UnregisteredRecipientException {
if (verificationCode instanceof IdentityVerificationCode.Fingerprint fingerprint) { return switch (verificationCode) {
return trustIdentity(recipient, case IdentityVerificationCode.Fingerprint fingerprint -> trustIdentity(recipient,
r -> context.getIdentityHelper().trustIdentityVerified(r, fingerprint.fingerprint())); r -> context.getIdentityHelper().trustIdentityVerified(r, fingerprint.fingerprint()));
} else if (verificationCode instanceof IdentityVerificationCode.SafetyNumber safetyNumber) { case IdentityVerificationCode.SafetyNumber safetyNumber -> trustIdentity(recipient,
return trustIdentity(recipient,
r -> context.getIdentityHelper().trustIdentityVerifiedSafetyNumber(r, safetyNumber.safetyNumber())); r -> context.getIdentityHelper().trustIdentityVerifiedSafetyNumber(r, safetyNumber.safetyNumber()));
} else if (verificationCode instanceof IdentityVerificationCode.ScannableSafetyNumber safetyNumber) { case IdentityVerificationCode.ScannableSafetyNumber safetyNumber -> trustIdentity(recipient,
return trustIdentity(recipient,
r -> context.getIdentityHelper().trustIdentityVerifiedSafetyNumber(r, safetyNumber.safetyNumber())); r -> context.getIdentityHelper().trustIdentityVerifiedSafetyNumber(r, safetyNumber.safetyNumber()));
} else { case null, default -> throw new AssertionError("Invalid verification code type");
throw new AssertionError("Invalid verification code type"); };
}
} }
@Override @Override

View file

@ -109,18 +109,13 @@ public class Main {
} }
private static int getStatusForError(final CommandException e) { private static int getStatusForError(final CommandException e) {
if (e instanceof UserErrorException) { return switch (e) {
return 1; case UserErrorException userErrorException -> 1;
} else if (e instanceof UnexpectedErrorException) { case UnexpectedErrorException unexpectedErrorException -> 2;
return 2; case IOErrorException ioErrorException -> 3;
} else if (e instanceof IOErrorException) { case UntrustedKeyErrorException untrustedKeyErrorException -> 4;
return 3; case RateLimitErrorException rateLimitErrorException -> 5;
} else if (e instanceof UntrustedKeyErrorException) { case null, default -> 2;
return 4; };
} else if (e instanceof RateLimitErrorException) {
return 5;
} else {
return 2;
}
} }
} }

View file

@ -72,8 +72,8 @@ public class Commands {
private static void addCommand(Command command) { private static void addCommand(Command command) {
commands.put(command.getName(), command); commands.put(command.getName(), command);
if (command instanceof CliCommand) { if (command instanceof CliCommand cliCommand) {
commandSubparserAttacher.put(command.getName(), ((CliCommand) command)::attachToSubparser); commandSubparserAttacher.put(command.getName(), cliCommand::attachToSubparser);
} }
} }
} }

View file

@ -249,11 +249,11 @@ public class DaemonCommand implements MultiLocalCommand, LocalCommand {
} }
private void addDefaultReceiveHandler(Manager m, OutputWriter outputWriter, final boolean isWeakListener) { private void addDefaultReceiveHandler(Manager m, OutputWriter outputWriter, final boolean isWeakListener) {
final var handler = outputWriter instanceof JsonWriter o final var handler = switch (outputWriter) {
? new JsonReceiveMessageHandler(m, o) case PlainTextWriter writer -> new ReceiveMessageHandler(m, writer);
: outputWriter instanceof PlainTextWriter o case JsonWriter writer -> new JsonReceiveMessageHandler(m, writer);
? new ReceiveMessageHandler(m, o) case null -> Manager.ReceiveMessageHandler.EMPTY;
: Manager.ReceiveMessageHandler.EMPTY; };
m.addReceiveHandler(handler, isWeakListener); m.addReceiveHandler(handler, isWeakListener);
} }

View file

@ -42,10 +42,9 @@ public class GetAttachmentCommand implements JsonRpcLocalCommand {
try (InputStream attachment = m.retrieveAttachment(id)) { try (InputStream attachment = m.retrieveAttachment(id)) {
final var bytes = attachment.readAllBytes(); final var bytes = attachment.readAllBytes();
final var base64 = Base64.getEncoder().encodeToString(bytes); final var base64 = Base64.getEncoder().encodeToString(bytes);
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
writer.println(base64); case PlainTextWriter writer -> writer.println(base64);
} else if (outputWriter instanceof JsonWriter writer) { case JsonWriter writer -> writer.write(new JsonAttachmentData(base64));
writer.write(new JsonAttachmentData(base64));
} }
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
throw new UserErrorException("Could not find attachment with ID: " + id, ex); throw new UserErrorException("Could not find attachment with ID: " + id, ex);

View file

@ -55,24 +55,26 @@ public class GetUserStatusCommand implements JsonRpcLocalCommand {
} }
// Output // Output
if (outputWriter instanceof JsonWriter jsonWriter) { switch (outputWriter) {
case JsonWriter writer -> {
var jsonUserStatuses = registered.entrySet().stream().map(entry -> { var jsonUserStatuses = registered.entrySet().stream().map(entry -> {
final var number = entry.getValue().number(); final var number = entry.getValue().number();
final var uuid = entry.getValue().uuid(); final var uuid = entry.getValue().uuid();
return new JsonUserStatus(entry.getKey(), number, uuid == null ? null : uuid.toString(), uuid != null); return new JsonUserStatus(entry.getKey(),
}).toList(); number,
uuid == null ? null : uuid.toString(),
jsonWriter.write(jsonUserStatuses); uuid != null);
} else { }).toList();
final var writer = (PlainTextWriter) outputWriter; writer.write(jsonUserStatuses);
}
for (var entry : registered.entrySet()) { case PlainTextWriter writer -> {
final var userStatus = entry.getValue(); for (var entry : registered.entrySet()) {
writer.println("{}: {}{}", final var userStatus = entry.getValue();
entry.getKey(), writer.println("{}: {}{}",
userStatus.uuid() != null, entry.getKey(),
userStatus.unrestrictedUnidentifiedAccess() ? " (unrestricted sealed sender)" : ""); userStatus.uuid() != null,
userStatus.unrestrictedUnidentifiedAccess() ? " (unrestricted sealed sender)" : "");
}
} }
} }
} }

View file

@ -54,35 +54,38 @@ public class JoinGroupCommand implements JsonRpcLocalCommand {
try { try {
final var results = m.joinGroup(linkUrl); final var results = m.joinGroup(linkUrl);
var newGroupId = results.first(); var newGroupId = results.first();
if (outputWriter instanceof JsonWriter writer) { switch (outputWriter) {
var jsonResults = SendMessageResultUtils.getJsonSendMessageResults(results.second().results()); case JsonWriter writer -> {
if (!m.getGroup(newGroupId).isMember()) { var jsonResults = SendMessageResultUtils.getJsonSendMessageResults(results.second().results());
writer.write(Map.of("timestamp", if (!m.getGroup(newGroupId).isMember()) {
results.second().timestamp(), writer.write(Map.of("timestamp",
"results", results.second().timestamp(),
jsonResults, "results",
"groupId", jsonResults,
newGroupId.toBase64(), "groupId",
"onlyRequested", newGroupId.toBase64(),
true)); "onlyRequested",
} else { true));
writer.write(Map.of("timestamp", } else {
results.second().timestamp(), writer.write(Map.of("timestamp",
"results", results.second().timestamp(),
jsonResults, "results",
"groupId", jsonResults,
newGroupId.toBase64())); "groupId",
newGroupId.toBase64()));
}
} }
} else { case PlainTextWriter writer -> {
final var writer = (PlainTextWriter) outputWriter; if (!m.getGroup(newGroupId).isMember()) {
if (!m.getGroup(newGroupId).isMember()) { writer.println("Requested to join group \"{}\"", newGroupId.toBase64());
writer.println("Requested to join group \"{}\"", newGroupId.toBase64()); } else {
} else { writer.println("Joined group \"{}\"", newGroupId.toBase64());
writer.println("Joined group \"{}\"", newGroupId.toBase64()); }
var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results.second()
.results());
SendMessageResultUtils.printSendMessageResultErrors(writer, errors);
writer.println("{}", results.second().timestamp());
} }
var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results.second().results());
SendMessageResultUtils.printSendMessageResultErrors(writer, errors);
writer.println("{}", results.second().timestamp());
} }
} catch (IOException e) { } catch (IOException e) {
throw new IOErrorException("Failed to send message: " throw new IOErrorException("Failed to send message: "

View file

@ -26,12 +26,15 @@ public class ListAccountsCommand implements JsonRpcMultiLocalCommand {
final Namespace ns, final MultiAccountManager c, final OutputWriter outputWriter final Namespace ns, final MultiAccountManager c, final OutputWriter outputWriter
) throws CommandException { ) throws CommandException {
final var accountNumbers = c.getAccountNumbers(); final var accountNumbers = c.getAccountNumbers();
if (outputWriter instanceof JsonWriter jsonWriter) { switch (outputWriter) {
final var jsonAccounts = accountNumbers.stream().map(JsonAccount::new).toList(); case JsonWriter jsonWriter -> {
jsonWriter.write(jsonAccounts); final var jsonAccounts = accountNumbers.stream().map(JsonAccount::new).toList();
} else if (outputWriter instanceof PlainTextWriter plainTextWriter) { jsonWriter.write(jsonAccounts);
for (final var number : accountNumbers) { }
plainTextWriter.println("Number: {}", number); case PlainTextWriter plainTextWriter -> {
for (final var number : accountNumbers) {
plainTextWriter.println("Number: {}", number);
}
} }
} }
} }

View file

@ -51,48 +51,49 @@ public class ListContactsCommand implements JsonRpcLocalCommand {
recipientIdentifiers, recipientIdentifiers,
Optional.ofNullable(name)); Optional.ofNullable(name));
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
for (var r : recipients) { case PlainTextWriter writer -> {
final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact(); for (var r : recipients) {
final var profile = r.getProfile() == null ? Profile.newBuilder().build() : r.getProfile(); final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact();
writer.println( final var profile = r.getProfile() == null ? Profile.newBuilder().build() : r.getProfile();
"Number: {} Name: {} Profile name: {} Username: {} Color: {} Blocked: {} Message expiration: {}", writer.println(
r.getAddress().getLegacyIdentifier(), "Number: {} Name: {} Profile name: {} Username: {} Color: {} Blocked: {} Message expiration: {}",
contact.getName(), r.getAddress().getLegacyIdentifier(),
profile.getDisplayName(), contact.getName(),
r.getAddress().username().orElse(""), profile.getDisplayName(),
contact.getColor(), r.getAddress().username().orElse(""),
contact.isBlocked(), contact.getColor(),
contact.getMessageExpirationTime() == 0 contact.isBlocked(),
? "disabled" contact.getMessageExpirationTime() == 0
: contact.getMessageExpirationTime() + "s"); ? "disabled"
: contact.getMessageExpirationTime() + "s");
}
}
case JsonWriter writer -> {
final var jsonContacts = recipients.stream().map(r -> {
final var address = r.getAddress();
final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact();
return new JsonContact(address.number().orElse(null),
address.uuid().map(UUID::toString).orElse(null),
address.username().orElse(null),
contact.getName(),
contact.getColor(),
contact.isBlocked(),
contact.getMessageExpirationTime(),
r.getProfile() == null
? null
: new JsonContact.JsonProfile(r.getProfile().getLastUpdateTimestamp(),
r.getProfile().getGivenName(),
r.getProfile().getFamilyName(),
r.getProfile().getAbout(),
r.getProfile().getAboutEmoji(),
r.getProfile().getMobileCoinAddress() == null
? null
: Base64.getEncoder()
.encodeToString(r.getProfile().getMobileCoinAddress())));
}).toList();
writer.write(jsonContacts);
} }
} else {
final var writer = (JsonWriter) outputWriter;
final var jsonContacts = recipients.stream().map(r -> {
final var address = r.getAddress();
final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact();
return new JsonContact(address.number().orElse(null),
address.uuid().map(UUID::toString).orElse(null),
address.username().orElse(null),
contact.getName(),
contact.getColor(),
contact.isBlocked(),
contact.getMessageExpirationTime(),
r.getProfile() == null
? null
: new JsonContact.JsonProfile(r.getProfile().getLastUpdateTimestamp(),
r.getProfile().getGivenName(),
r.getProfile().getFamilyName(),
r.getProfile().getAbout(),
r.getProfile().getAboutEmoji(),
r.getProfile().getMobileCoinAddress() == null
? null
: Base64.getEncoder()
.encodeToString(r.getProfile().getMobileCoinAddress())));
}).toList();
writer.write(jsonContacts);
} }
} }

View file

@ -42,21 +42,23 @@ public class ListDevicesCommand implements JsonRpcLocalCommand {
throw new IOErrorException("Failed to get linked devices: " + e.getMessage(), e); throw new IOErrorException("Failed to get linked devices: " + e.getMessage(), e);
} }
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
for (var d : devices) { case PlainTextWriter writer -> {
writer.println("- Device {}{}:", d.id(), (d.isThisDevice() ? " (this device)" : "")); for (var d : devices) {
writer.indent(w -> { writer.println("- Device {}{}:", d.id(), (d.isThisDevice() ? " (this device)" : ""));
w.println("Name: {}", d.name()); writer.indent(w -> {
w.println("Created: {}", DateUtils.formatTimestamp(d.created())); w.println("Name: {}", d.name());
w.println("Last seen: {}", DateUtils.formatTimestamp(d.lastSeen())); w.println("Created: {}", DateUtils.formatTimestamp(d.created()));
}); w.println("Last seen: {}", DateUtils.formatTimestamp(d.lastSeen()));
});
}
}
case JsonWriter writer -> {
final var jsonDevices = devices.stream()
.map(d -> new JsonDevice(d.id(), d.name(), d.created(), d.lastSeen()))
.toList();
writer.write(jsonDevices);
} }
} else {
final var writer = (JsonWriter) outputWriter;
final var jsonDevices = devices.stream()
.map(d -> new JsonDevice(d.id(), d.name(), d.created(), d.lastSeen()))
.toList();
writer.write(jsonDevices);
} }
} }

View file

@ -89,34 +89,34 @@ public class ListGroupsCommand implements JsonRpcLocalCommand {
groups = groups.stream().filter(g -> groupIds.contains(g.groupId())).toList(); groups = groups.stream().filter(g -> groupIds.contains(g.groupId())).toList();
} }
if (outputWriter instanceof JsonWriter jsonWriter) { switch (outputWriter) {
case JsonWriter jsonWriter -> {
var jsonGroups = groups.stream().map(group -> {
final var groupInviteLink = group.groupInviteLinkUrl();
var jsonGroups = groups.stream().map(group -> { return new JsonGroup(group.groupId().toBase64(),
final var groupInviteLink = group.groupInviteLinkUrl(); group.title(),
group.description(),
return new JsonGroup(group.groupId().toBase64(), group.isMember(),
group.title(), group.isBlocked(),
group.description(), group.messageExpirationTimer(),
group.isMember(), resolveJsonMembers(group.members()),
group.isBlocked(), resolveJsonMembers(group.pendingMembers()),
group.messageExpirationTimer(), resolveJsonMembers(group.requestingMembers()),
resolveJsonMembers(group.members()), resolveJsonMembers(group.adminMembers()),
resolveJsonMembers(group.pendingMembers()), resolveJsonMembers(group.bannedMembers()),
resolveJsonMembers(group.requestingMembers()), group.permissionAddMember().name(),
resolveJsonMembers(group.adminMembers()), group.permissionEditDetails().name(),
resolveJsonMembers(group.bannedMembers()), group.permissionSendMessage().name(),
group.permissionAddMember().name(), groupInviteLink == null ? null : groupInviteLink.getUrl());
group.permissionEditDetails().name(), }).toList();
group.permissionSendMessage().name(), jsonWriter.write(jsonGroups);
groupInviteLink == null ? null : groupInviteLink.getUrl()); }
}).toList(); case PlainTextWriter writer -> {
boolean detailed = Boolean.TRUE.equals(ns.getBoolean("detailed"));
jsonWriter.write(jsonGroups); for (var group : groups) {
} else { printGroupPlainText(writer, group, detailed);
final var writer = (PlainTextWriter) outputWriter; }
boolean detailed = Boolean.TRUE.equals(ns.getBoolean("detailed"));
for (var group : groups) {
printGroupPlainText(writer, group, detailed);
} }
} }
} }

View file

@ -57,28 +57,29 @@ public class ListIdentitiesCommand implements JsonRpcLocalCommand {
identities = m.getIdentities(CommandUtil.getSingleRecipientIdentifier(number, m.getSelfNumber())); identities = m.getIdentities(CommandUtil.getSingleRecipientIdentifier(number, m.getSelfNumber()));
} }
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
for (var id : identities) { case PlainTextWriter writer -> {
printIdentityFingerprint(writer, id); for (var id : identities) {
printIdentityFingerprint(writer, id);
}
}
case JsonWriter writer -> {
final var jsonIdentities = identities.stream().map(id -> {
final var address = id.recipient();
var safetyNumber = Util.formatSafetyNumber(id.safetyNumber());
var scannableSafetyNumber = id.scannableSafetyNumber();
return new JsonIdentity(address.number().orElse(null),
address.uuid().map(UUID::toString).orElse(null),
Hex.toString(id.getFingerprint()),
safetyNumber,
scannableSafetyNumber == null
? null
: Base64.getEncoder().encodeToString(scannableSafetyNumber),
id.trustLevel().name(),
id.dateAddedTimestamp());
}).toList();
writer.write(jsonIdentities);
} }
} else {
final var writer = (JsonWriter) outputWriter;
final var jsonIdentities = identities.stream().map(id -> {
final var address = id.recipient();
var safetyNumber = Util.formatSafetyNumber(id.safetyNumber());
var scannableSafetyNumber = id.scannableSafetyNumber();
return new JsonIdentity(address.number().orElse(null),
address.uuid().map(UUID::toString).orElse(null),
Hex.toString(id.getFingerprint()),
safetyNumber,
scannableSafetyNumber == null
? null
: Base64.getEncoder().encodeToString(scannableSafetyNumber),
id.trustLevel().name(),
id.dateAddedTimestamp());
}).toList();
writer.write(jsonIdentities);
} }
} }

View file

@ -30,17 +30,20 @@ public class ListStickerPacksCommand implements JsonRpcLocalCommand {
final Namespace ns, final Manager c, final OutputWriter outputWriter final Namespace ns, final Manager c, final OutputWriter outputWriter
) throws CommandException { ) throws CommandException {
final var stickerPacks = c.getStickerPacks(); final var stickerPacks = c.getStickerPacks();
if (outputWriter instanceof JsonWriter jsonWriter) { switch (outputWriter) {
final var jsonStickerPacks = stickerPacks.stream().map(JsonStickerPack::new).toList(); case JsonWriter jsonWriter -> {
jsonWriter.write(jsonStickerPacks); final var jsonStickerPacks = stickerPacks.stream().map(JsonStickerPack::new).toList();
} else if (outputWriter instanceof PlainTextWriter plainTextWriter) { jsonWriter.write(jsonStickerPacks);
for (final var sticker : stickerPacks) { }
plainTextWriter.println("Pack {}: “{}” by “{}” has {} stickers. {}", case PlainTextWriter plainTextWriter -> {
Hex.toStringCondensed(sticker.packId().serialize()), for (final var sticker : stickerPacks) {
sticker.title(), plainTextWriter.println("Pack {}: “{}” by “{}” has {} stickers. {}",
sticker.author(), Hex.toStringCondensed(sticker.packId().serialize()),
sticker.stickers().size(), sticker.title(),
sticker.url().getUrl()); sticker.author(),
sticker.stickers().size(),
sticker.url().getUrl());
}
} }
} }
} }

View file

@ -74,8 +74,10 @@ public class ReceiveCommand implements LocalCommand, JsonRpcSingleCommand<Receiv
final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts")); final var sendReadReceipts = Boolean.TRUE.equals(ns.getBoolean("send-read-receipts"));
m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts)); m.setReceiveConfig(new ReceiveConfig(ignoreAttachments, ignoreStories, sendReadReceipts));
try { try {
final var handler = outputWriter instanceof JsonWriter ? new JsonReceiveMessageHandler(m, final var handler = switch (outputWriter) {
(JsonWriter) outputWriter) : new ReceiveMessageHandler(m, (PlainTextWriter) outputWriter); case JsonWriter writer -> new JsonReceiveMessageHandler(m, writer);
case PlainTextWriter writer -> new ReceiveMessageHandler(m, writer);
};
final var duration = timeout < 0 ? null : Duration.ofMillis((long) (timeout * 1000)); final var duration = timeout < 0 ? null : Duration.ofMillis((long) (timeout * 1000));
final var maxMessages = maxMessagesRaw < 0 ? null : maxMessagesRaw; final var maxMessages = maxMessagesRaw < 0 ? null : maxMessagesRaw;
m.receiveMessages(Optional.ofNullable(duration), Optional.ofNullable(maxMessages), handler); m.receiveMessages(Optional.ofNullable(duration), Optional.ofNullable(maxMessages), handler);

View file

@ -50,10 +50,9 @@ public class UpdateAccountCommand implements JsonRpcLocalCommand {
if (username != null) { if (username != null) {
try { try {
final var newUsername = m.setUsername(username); final var newUsername = m.setUsername(username);
if (outputWriter instanceof PlainTextWriter w) { switch (outputWriter) {
w.println("Your new username: {}", newUsername); case PlainTextWriter w -> w.println("Your new username: {}", newUsername);
} else if (outputWriter instanceof JsonWriter w) { case JsonWriter w -> w.write(new JsonAccountResponse(newUsername));
w.write(new JsonAccountResponse(newUsername));
} }
} catch (IOException e) { } catch (IOException e) {
throw new IOErrorException("Failed to set username: " + e.getMessage(), e); throw new IOErrorException("Failed to set username: " + e.getMessage(), e);

View file

@ -182,27 +182,29 @@ public class UpdateGroupCommand implements JsonRpcLocalCommand {
private void outputResult( private void outputResult(
final OutputWriter outputWriter, final SendGroupMessageResults results, final GroupId groupId final OutputWriter outputWriter, final SendGroupMessageResults results, final GroupId groupId
) { ) {
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
if (groupId != null) { case PlainTextWriter writer -> {
writer.println("Created new group: \"{}\"", groupId.toBase64()); if (groupId != null) {
writer.println("Created new group: \"{}\"", groupId.toBase64());
}
if (results != null) {
var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results.results());
SendMessageResultUtils.printSendMessageResultErrors(writer, errors);
writer.println("{}", results.timestamp());
}
} }
if (results != null) { case JsonWriter writer -> {
var errors = SendMessageResultUtils.getErrorMessagesFromSendMessageResults(results.results()); final var response = new HashMap<>();
SendMessageResultUtils.printSendMessageResultErrors(writer, errors); if (results != null) {
writer.println("{}", results.timestamp()); response.put("timestamp", results.timestamp());
var jsonResults = SendMessageResultUtils.getJsonSendMessageResults(results.results());
response.put("results", jsonResults);
}
if (groupId != null) {
response.put("groupId", groupId.toBase64());
}
writer.write(response);
} }
} else {
final var writer = (JsonWriter) outputWriter;
final var response = new HashMap<>();
if (results != null) {
response.put("timestamp", results.timestamp());
var jsonResults = SendMessageResultUtils.getJsonSendMessageResults(results.results());
response.put("results", jsonResults);
}
if (groupId != null) {
response.put("groupId", groupId.toBase64());
}
writer.write(response);
} }
} }
} }

View file

@ -42,11 +42,11 @@ public class UploadStickerPackCommand implements JsonRpcLocalCommand {
try { try {
var url = m.uploadStickerPack(path); var url = m.uploadStickerPack(path);
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
writer.println("{}", url.getUrl()); case PlainTextWriter writer -> writer.println("{}", url.getUrl());
} else { case JsonWriter writer -> {
final var writer = (JsonWriter) outputWriter; writer.write(Map.of("url", url.getUrl()));
writer.write(Map.of("url", url.getUrl())); }
} }
} catch (IOException e) { } catch (IOException e) {
throw new IOErrorException("Upload error (maybe image size too large):" + e.getMessage(), e); throw new IOErrorException("Upload error (maybe image size too large):" + e.getMessage(), e);

View file

@ -56,10 +56,9 @@ public class VersionCommand implements JsonRpcLocalCommand, JsonRpcMultiLocalCom
final var projectName = BaseConfig.PROJECT_NAME == null ? "signal-cli" : BaseConfig.PROJECT_NAME; final var projectName = BaseConfig.PROJECT_NAME == null ? "signal-cli" : BaseConfig.PROJECT_NAME;
final var version = BaseConfig.PROJECT_VERSION == null ? "unknown" : BaseConfig.PROJECT_VERSION; final var version = BaseConfig.PROJECT_VERSION == null ? "unknown" : BaseConfig.PROJECT_VERSION;
if (outputWriter instanceof JsonWriter jsonWriter) { switch (outputWriter) {
jsonWriter.write(Map.of("version", version)); case JsonWriter jsonWriter -> jsonWriter.write(Map.of("version", version));
} else if (outputWriter instanceof PlainTextWriter plainTextWriter) { case PlainTextWriter plainTextWriter -> plainTextWriter.println("{} {}", projectName, version);
plainTextWriter.println("{} {}", projectName, version);
} }
} }
} }

View file

@ -65,7 +65,7 @@ public abstract class DbusProperties implements Properties {
.filter(p -> p.getGetter() != null) .filter(p -> p.getGetter() != null)
.collect(Collectors.toMap(DbusProperty::getName, p -> { .collect(Collectors.toMap(DbusProperty::getName, p -> {
final Object o = p.getGetter().get(); final Object o = p.getGetter().get();
return o instanceof Variant ? (Variant<Object>) o : new Variant<>(o); return o instanceof Variant<?> variant ? variant : new Variant<>(o);
})); }));
} }
} }

View file

@ -82,53 +82,55 @@ public class JsonRpcReader {
final RequestHandler requestHandler, final RequestHandler requestHandler,
final Consumer<JsonRpcResponse> responseHandler final Consumer<JsonRpcResponse> responseHandler
) { ) {
if (message instanceof final JsonRpcRequest jsonRpcRequest) { switch (message) {
logger.debug("Received json rpc request, method: " + jsonRpcRequest.getMethod()); case JsonRpcRequest jsonRpcRequest -> {
final var response = handleRequest(requestHandler, jsonRpcRequest); logger.debug("Received json rpc request, method: " + jsonRpcRequest.getMethod());
if (response != null) { final var response = handleRequest(requestHandler, jsonRpcRequest);
jsonRpcSender.sendResponse(response); if (response != null) {
jsonRpcSender.sendResponse(response);
}
} }
} else if (message instanceof JsonRpcResponse jsonRpcResponse) { case JsonRpcResponse jsonRpcResponse -> responseHandler.accept(jsonRpcResponse);
responseHandler.accept(jsonRpcResponse); case JsonRpcBatchMessage jsonRpcBatchMessage -> {
} else { final var messages = jsonRpcBatchMessage.getMessages();
final var messages = ((JsonRpcBatchMessage) message).getMessages(); final var responseList = new ArrayList<JsonRpcResponse>(messages.size());
final var responseList = new ArrayList<JsonRpcResponse>(messages.size()); final var executor = Executors.newFixedThreadPool(10);
final var executor = Executors.newFixedThreadPool(10); try {
try { final var lock = new ReentrantLock();
final var lock = new ReentrantLock(); messages.forEach(jsonNode -> {
messages.forEach(jsonNode -> { final JsonRpcRequest request;
final JsonRpcRequest request;
try {
request = parseJsonRpcRequest(jsonNode);
} catch (JsonRpcException e) {
final var response = JsonRpcResponse.forError(e.getError(), getId(jsonNode));
lock.lock();
try { try {
responseList.add(response); request = parseJsonRpcRequest(jsonNode);
} finally { } catch (JsonRpcException e) {
lock.unlock(); final var response = JsonRpcResponse.forError(e.getError(), getId(jsonNode));
}
return;
}
executor.submit(() -> {
final var response = handleRequest(requestHandler, request);
if (response != null) {
lock.lock(); lock.lock();
try { try {
responseList.add(response); responseList.add(response);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return;
} }
});
});
} finally {
Util.closeExecutorService(executor);
}
if (!responseList.isEmpty()) { executor.submit(() -> {
jsonRpcSender.sendBatchResponses(responseList); final var response = handleRequest(requestHandler, request);
if (response != null) {
lock.lock();
try {
responseList.add(response);
} finally {
lock.unlock();
}
}
});
});
} finally {
Util.closeExecutorService(executor);
}
if (!responseList.isEmpty()) {
jsonRpcSender.sendBatchResponses(responseList);
}
} }
} }
} }
@ -221,7 +223,7 @@ public class JsonRpcReader {
private ValueNode getId(JsonNode jsonNode) { private ValueNode getId(JsonNode jsonNode) {
final var id = jsonNode.get("id"); final var id = jsonNode.get("id");
return id instanceof ValueNode ? (ValueNode) id : null; return id instanceof ValueNode value ? value : null;
} }
private JsonRpcRequest parseJsonRpcRequest(final JsonNode input) throws JsonRpcException { private JsonRpcRequest parseJsonRpcRequest(final JsonNode input) throws JsonRpcException {

View file

@ -223,13 +223,11 @@ public class SignalJsonRpcDispatcherHandler {
} }
private Integer getSubscriptionId(final JsonNode request) { private Integer getSubscriptionId(final JsonNode request) {
if (request instanceof ArrayNode req) { return switch (request) {
return req.get(0).asInt(); case ArrayNode req -> req.get(0).asInt();
} else if (request instanceof ObjectNode req) { case ObjectNode req -> req.get("subscription").asInt();
return req.get("subscription").asInt(); case null, default -> null;
} else { };
return null;
}
} }
} }
} }

View file

@ -1,6 +1,6 @@
package org.asamk.signal.output; package org.asamk.signal.output;
public interface JsonWriter extends OutputWriter { public non-sealed interface JsonWriter extends OutputWriter {
void write(final Object object); void write(final Object object);
} }

View file

@ -1,5 +1,3 @@
package org.asamk.signal.output; package org.asamk.signal.output;
public interface OutputWriter { public sealed interface OutputWriter permits JsonWriter, PlainTextWriter {}
}

View file

@ -2,7 +2,7 @@ package org.asamk.signal.output;
import java.util.function.Consumer; import java.util.function.Consumer;
public interface PlainTextWriter extends OutputWriter { public non-sealed interface PlainTextWriter extends OutputWriter {
void println(String format, Object... args); void println(String format, Object... args);

View file

@ -27,28 +27,32 @@ public class SendMessageResultUtils {
} }
public static void outputResult(final OutputWriter outputWriter, final SendGroupMessageResults sendMessageResults) { public static void outputResult(final OutputWriter outputWriter, final SendGroupMessageResults sendMessageResults) {
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
var errors = getErrorMessagesFromSendMessageResults(sendMessageResults.results()); case PlainTextWriter writer -> {
printSendMessageResultErrors(writer, errors); var errors = getErrorMessagesFromSendMessageResults(sendMessageResults.results());
writer.println("{}", sendMessageResults.timestamp()); printSendMessageResultErrors(writer, errors);
} else { writer.println("{}", sendMessageResults.timestamp());
final var writer = (JsonWriter) outputWriter; }
var results = getJsonSendMessageResults(sendMessageResults.results()); case JsonWriter writer -> {
writer.write(Map.of("timestamp", sendMessageResults.timestamp(), "results", results)); var results = getJsonSendMessageResults(sendMessageResults.results());
writer.write(Map.of("timestamp", sendMessageResults.timestamp(), "results", results));
}
} }
} }
public static void outputResult( public static void outputResult(
final OutputWriter outputWriter, final SendMessageResults sendMessageResults final OutputWriter outputWriter, final SendMessageResults sendMessageResults
) throws CommandException { ) throws CommandException {
if (outputWriter instanceof PlainTextWriter writer) { switch (outputWriter) {
var errors = getErrorMessagesFromSendMessageResults(sendMessageResults.results()); case PlainTextWriter writer -> {
printSendMessageResultErrors(writer, errors); var errors = getErrorMessagesFromSendMessageResults(sendMessageResults.results());
writer.println("{}", sendMessageResults.timestamp()); printSendMessageResultErrors(writer, errors);
} else { writer.println("{}", sendMessageResults.timestamp());
final var writer = (JsonWriter) outputWriter; }
var results = getJsonSendMessageResults(sendMessageResults.results()); case JsonWriter writer -> {
writer.write(Map.of("timestamp", sendMessageResults.timestamp(), "results", results)); var results = getJsonSendMessageResults(sendMessageResults.results());
writer.write(Map.of("timestamp", sendMessageResults.timestamp(), "results", results));
}
} }
if (!sendMessageResults.hasSuccess()) { if (!sendMessageResults.hasSuccess()) {
if (sendMessageResults.hasOnlyUntrustedIdentity()) { if (sendMessageResults.hasOnlyUntrustedIdentity()) {