From: AsamK Date: Wed, 6 Jul 2016 23:06:08 +0000 (+0200) Subject: Lock config file X-Git-Tag: v0.4.1~5 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/c5ac72a9a592bf9e7a6ce1c5e2bc5c540b48787e?ds=sidebyside Lock config file Fixes #19 --- diff --git a/src/main/java/org/asamk/signal/Manager.java b/src/main/java/org/asamk/signal/Manager.java index 90785824..69800a82 100644 --- a/src/main/java/org/asamk/signal/Manager.java +++ b/src/main/java/org/asamk/signal/Manager.java @@ -18,6 +18,8 @@ package org.asamk.signal; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -56,6 +58,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; @@ -79,6 +84,9 @@ class Manager implements Signal { private final String attachmentsPath; private final String avatarsPath; + private FileChannel fileChannel; + private FileLock lock; + private final ObjectMapper jsonProcessot = new ObjectMapper(); private String username; private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID; @@ -105,6 +113,8 @@ class Manager implements Signal { jsonProcessot.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print, you can disable it. jsonProcessot.enable(SerializationFeature.WRITE_NULL_MAP_VALUES); jsonProcessot.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + jsonProcessot.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE); + jsonProcessot.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET); } public String getUsername() { @@ -141,8 +151,22 @@ class Manager implements Signal { return node; } + private void openFileChannel() throws IOException { + if (fileChannel != null) + return; + + fileChannel = new RandomAccessFile(new File(getFileName()), "rw").getChannel(); + 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."); + } + } + public void load() throws IOException, InvalidKeyException { - JsonNode rootNode = jsonProcessot.readTree(new File(getFileName())); + openFileChannel(); + JsonNode rootNode = jsonProcessot.readTree(Channels.newInputStream(fileChannel)); JsonNode node = rootNode.get("deviceId"); if (node != null) { @@ -227,7 +251,11 @@ class Manager implements Signal { .putPOJO("contactStore", contactStore) ; try { - jsonProcessot.writeValue(new File(getFileName()), rootNode); + openFileChannel(); + fileChannel.position(0); + jsonProcessot.writeValue(Channels.newOutputStream(fileChannel), rootNode); + fileChannel.truncate(fileChannel.position()); + fileChannel.force(false); } catch (Exception e) { System.err.println(String.format("Error saving file: %s", e.getMessage())); }