X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/320e126eebc4e3ebac5144197e640508704eeb0c..4177deccf1e91483f54c5fcfacffce0ce525ad39:/src/main/java/org/asamk/signal/storage/SignalAccount.java diff --git a/src/main/java/org/asamk/signal/storage/SignalAccount.java b/src/main/java/org/asamk/signal/storage/SignalAccount.java index f03bac3a..d0638e41 100644 --- a/src/main/java/org/asamk/signal/storage/SignalAccount.java +++ b/src/main/java/org/asamk/signal/storage/SignalAccount.java @@ -29,24 +29,27 @@ import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.util.Medium; +import org.whispersystems.libsignal.util.Pair; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.util.Base64; +import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.Channels; +import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.Collection; import java.util.UUID; import java.util.stream.Collectors; -public class SignalAccount { +public class SignalAccount implements Closeable { private final ObjectMapper jsonProcessor = new ObjectMapper(); - private FileChannel fileChannel; - private FileLock lock; + private final FileChannel fileChannel; + private final FileLock lock; private String username; private UUID uuid; private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID; @@ -65,7 +68,9 @@ public class SignalAccount { private JsonContactsStore contactStore; private RecipientStore recipientStore; - private SignalAccount() { + private SignalAccount(final FileChannel fileChannel, final FileLock lock) { + this.fileChannel = fileChannel; + this.lock = lock; jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); // disable autodetect jsonProcessor.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print, you can disable it. jsonProcessor.enable(SerializationFeature.WRITE_NULL_MAP_VALUES); @@ -75,18 +80,28 @@ public class SignalAccount { } public static SignalAccount load(String dataPath, String username) throws IOException { - SignalAccount account = new SignalAccount(); - IOUtils.createPrivateDirectories(dataPath); - account.openFileChannel(getFileName(dataPath, username)); - account.load(); - return account; + final String fileName = getFileName(dataPath, username); + final Pair pair = openFileChannel(fileName); + try { + SignalAccount account = new SignalAccount(pair.first(), pair.second()); + account.load(); + return account; + } catch (Throwable e) { + pair.second().close(); + pair.first().close(); + throw e; + } } public static SignalAccount create(String dataPath, String username, IdentityKeyPair identityKey, int registrationId, ProfileKey profileKey) throws IOException { IOUtils.createPrivateDirectories(dataPath); + String fileName = getFileName(dataPath, username); + if (!new File(fileName).exists()) { + IOUtils.createPrivateFile(fileName); + } - SignalAccount account = new SignalAccount(); - account.openFileChannel(getFileName(dataPath, username)); + final Pair pair = openFileChannel(fileName); + SignalAccount account = new SignalAccount(pair.first(), pair.second()); account.username = username; account.profileKey = profileKey; @@ -101,9 +116,13 @@ public class SignalAccount { public static SignalAccount createLinkedAccount(String dataPath, String username, UUID uuid, String password, int deviceId, IdentityKeyPair identityKey, int registrationId, String signalingKey, ProfileKey profileKey) throws IOException { IOUtils.createPrivateDirectories(dataPath); + String fileName = getFileName(dataPath, username); + if (!new File(fileName).exists()) { + IOUtils.createPrivateFile(fileName); + } - SignalAccount account = new SignalAccount(); - account.openFileChannel(getFileName(dataPath, username)); + final Pair pair = openFileChannel(fileName); + SignalAccount account = new SignalAccount(pair.first(), pair.second()); account.username = username; account.uuid = uuid; @@ -121,15 +140,6 @@ public class SignalAccount { return account; } - public static SignalAccount createTemporaryAccount(IdentityKeyPair identityKey, int registrationId) { - SignalAccount account = new SignalAccount(); - - account.signalProtocolStore = new JsonSignalProtocolStore(identityKey, registrationId); - account.registered = false; - - return account; - } - public static String getFileName(String dataPath, String username) { return dataPath + "/" + username; } @@ -294,21 +304,15 @@ public class SignalAccount { } } - private void openFileChannel(String fileName) throws IOException { - if (fileChannel != null) { - return; - } - - if (!new File(fileName).exists()) { - IOUtils.createPrivateFile(fileName); - } - fileChannel = new RandomAccessFile(new File(fileName), "rw").getChannel(); - lock = fileChannel.tryLock(); + private static Pair openFileChannel(String fileName) throws IOException { + FileChannel fileChannel = new RandomAccessFile(new File(fileName), "rw").getChannel(); + FileLock lock = fileChannel.tryLock(); if (lock == null) { System.err.println("Config file is in use by another instance, waiting…"); lock = fileChannel.lock(); System.err.println("Config file lock acquired."); } + return new Pair<>(fileChannel, lock); } public void setResolver(final SignalServiceAddressResolver resolver) { @@ -422,4 +426,15 @@ public class SignalAccount { public void setMultiDevice(final boolean multiDevice) { isMultiDevice = multiDevice; } + + @Override + public void close() throws IOException { + synchronized (fileChannel) { + try { + lock.close(); + } catch (ClosedChannelException ignored) { + } + fileChannel.close(); + } + } }