From fd21c5789f59ecf5f240a969b83113007430d47b Mon Sep 17 00:00:00 2001 From: kske Date: Sat, 19 Sep 2020 15:28:04 +0200 Subject: [PATCH] Add LocalDB Locking FIxes #32 --- .../main/java/envoy/client/data/LocalDB.java | 26 +++++++++++++++++++ .../main/java/envoy/client/ui/Startup.java | 11 +++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 63e567a..1756c30 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -1,11 +1,14 @@ package envoy.client.data; import java.io.*; +import java.nio.channels.*; +import java.nio.file.StandardOpenOption; import java.time.Instant; import java.util.*; import envoy.data.*; import envoy.event.*; +import envoy.exception.EnvoyException; import envoy.util.SerializationUtils; import dev.kske.eventbus.Event; @@ -35,6 +38,7 @@ public final class LocalDB implements EventListener { private Instant lastSync = Instant.EPOCH; private String authToken; private File dbDir, userFile, idGeneratorFile, lastLoginFile, usersFile; + private FileLock instanceLock; /** * Constructs an empty local database. To serialize any user-specific data to @@ -74,6 +78,28 @@ public final class LocalDB implements EventListener { userFile = new File(dbDir, user.getID() + ".db"); } + FileChannel fc; + + /** + * Ensured that only one Envoy instance is using this local database by creating + * a lock file. + * The lock file is deleted on application exit. + * + * @throws EnvoyException if the lock cannot by acquired + * @since Envoy Client v0.2-beta + */ + public void lock() throws EnvoyException { + File file = new File(dbDir, "instance.lock"); + file.deleteOnExit(); + try { + FileChannel fc = FileChannel.open(file.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE); + instanceLock = fc.tryLock(); + if (instanceLock == null) throw new EnvoyException("Another Envoy instance is using this local database!"); + } catch (IOException e) { + throw new EnvoyException("Could not create lock file!", e); + } + } + /** * Stores all users. If the client user is specified, their chats will be stored * as well. The message id generator will also be saved if present. diff --git a/client/src/main/java/envoy/client/ui/Startup.java b/client/src/main/java/envoy/client/ui/Startup.java index 0b94d8a..90e4499 100644 --- a/client/src/main/java/envoy/client/ui/Startup.java +++ b/client/src/main/java/envoy/client/ui/Startup.java @@ -67,10 +67,13 @@ public final class Startup extends Application { // Initialize the local database try { - localDB = new LocalDB(new File(config.getHomeDirectory(), config.getLocalDB().getPath())); - } catch (final IOException e3) { - logger.log(Level.SEVERE, "Could not initialize local database: ", e3); - new Alert(AlertType.ERROR, "Could not initialize local database!\n" + e3).showAndWait(); + File localDBDir = new File(config.getHomeDirectory(), config.getLocalDB().getPath()); + logger.info("Initializing LocalDB at " + localDBDir); + localDB = new LocalDB(localDBDir); + localDB.lock(); + } catch (IOException | EnvoyException e) { + logger.log(Level.SEVERE, "Could not initialize local database: ", e); + new Alert(AlertType.ERROR, "Could not initialize local database!\n" + e).showAndWait(); System.exit(1); return; }