mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-08-24 14:29:23 -04:00
Add rolling backup
This commit is contained in:
parent
530b15147c
commit
4c0cc738e4
11 changed files with 109 additions and 55 deletions
|
@ -18,6 +18,7 @@
|
||||||
package io.bitsquare.common.crypto;
|
package io.bitsquare.common.crypto;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import io.bitsquare.storage.FileUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -86,6 +87,7 @@ public class KeyStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair loadKeyPair(KeyEntry keyEntry) {
|
public KeyPair loadKeyPair(KeyEntry keyEntry) {
|
||||||
|
FileUtil.rollingBackup(storageDir, keyEntry.getFileName() + ".key");
|
||||||
// long now = System.currentTimeMillis();
|
// long now = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
KeyFactory keyFactory = KeyFactory.getInstance(keyEntry.getAlgorithm(), "BC");
|
KeyFactory keyFactory = KeyFactory.getInstance(keyEntry.getAlgorithm(), "BC");
|
||||||
|
|
|
@ -303,17 +303,6 @@ public class Utilities {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteDirectory(File file) throws IOException {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
File[] files = file.listFiles();
|
|
||||||
if (files != null)
|
|
||||||
for (File c : files)
|
|
||||||
deleteDirectory(c);
|
|
||||||
}
|
|
||||||
if (!file.delete())
|
|
||||||
throw new FileNotFoundException("Failed to delete file: " + file);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void printElapsedTime(String msg) {
|
private static void printElapsedTime(String msg) {
|
||||||
if (!msg.isEmpty()) {
|
if (!msg.isEmpty()) {
|
||||||
msg += " / ";
|
msg += " / ";
|
||||||
|
@ -348,29 +337,6 @@ public class Utilities {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Empty and delete a folder (and subfolders).
|
|
||||||
*
|
|
||||||
* @param folder folder to empty
|
|
||||||
*/
|
|
||||||
private static void removeDirectory(final File folder) {
|
|
||||||
// check if folder file is a real folder
|
|
||||||
if (folder.isDirectory()) {
|
|
||||||
File[] list = folder.listFiles();
|
|
||||||
if (list != null) {
|
|
||||||
for (File tmpF : list) {
|
|
||||||
if (tmpF.isDirectory()) {
|
|
||||||
removeDirectory(tmpF);
|
|
||||||
}
|
|
||||||
if (!tmpF.delete())
|
|
||||||
log.warn("can't delete file : " + tmpF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!folder.delete())
|
|
||||||
log.warn("can't delete folder : " + folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String readTextFileFromServer(String url, String userAgent) throws IOException {
|
public static String readTextFileFromServer(String url, String userAgent) throws IOException {
|
||||||
URLConnection connection = URI.create(url).toURL().openConnection();
|
URLConnection connection = URI.create(url).toURL().openConnection();
|
||||||
connection.setDoOutput(true);
|
connection.setDoOutput(true);
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package io.bitsquare.storage;
|
package io.bitsquare.storage;
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.util.Utilities;
|
import io.bitsquare.common.util.Utilities;
|
||||||
import org.bitcoinj.core.Utils;
|
import org.bitcoinj.core.Utils;
|
||||||
|
@ -162,13 +161,7 @@ public class FileManager<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void backupFile(String fileName) throws IOException {
|
public synchronized void backupFile(String fileName) throws IOException {
|
||||||
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
|
FileUtil.rollingBackup(dir, fileName);
|
||||||
if (!backupDir.exists())
|
|
||||||
if (!backupDir.mkdir())
|
|
||||||
log.warn("make dir failed");
|
|
||||||
|
|
||||||
File backupFile = new File(Paths.get(dir.getAbsolutePath(), "backup", fileName).toString());
|
|
||||||
Files.copy(storageFile, backupFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
73
common/src/main/java/io/bitsquare/storage/FileUtil.java
Normal file
73
common/src/main/java/io/bitsquare/storage/FileUtil.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package io.bitsquare.storage;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FileUtil {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
|
||||||
|
|
||||||
|
public static void rollingBackup(File dir, String fileName) {
|
||||||
|
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
|
||||||
|
if (!backupDir.exists())
|
||||||
|
if (!backupDir.mkdir())
|
||||||
|
log.warn("make dir failed");
|
||||||
|
|
||||||
|
File origFile = new File(Paths.get(dir.getAbsolutePath(), fileName).toString());
|
||||||
|
if (origFile.exists()) {
|
||||||
|
File backupFileDir = new File(Paths.get(backupDir.getAbsolutePath(), fileName.replace(".", "_")).toString());
|
||||||
|
if (!backupFileDir.exists())
|
||||||
|
if (!backupFileDir.mkdir())
|
||||||
|
log.warn("make backupFileDir failed");
|
||||||
|
|
||||||
|
File backupFile = new File(Paths.get(backupFileDir.getAbsolutePath(), new Date().getTime() + "_" + fileName).toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.copy(origFile, backupFile);
|
||||||
|
|
||||||
|
pruneBackup(backupDir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Backup key failed " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void pruneBackup(File backupDir) {
|
||||||
|
if (backupDir.isDirectory()) {
|
||||||
|
File[] files = backupDir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
List<File> filesList = Arrays.asList(files);
|
||||||
|
if (filesList.size() > 10) {
|
||||||
|
filesList.sort((o1, o2) -> o1.getName().compareTo(o2.getName()));
|
||||||
|
File file = filesList.get(0);
|
||||||
|
if (file.isFile()) {
|
||||||
|
if (!file.delete())
|
||||||
|
log.error("Failed to delete file: " + file);
|
||||||
|
} else {
|
||||||
|
pruneBackup(new File(Paths.get(backupDir.getAbsolutePath(), file.getName()).toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteDirectory(File file) throws IOException {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (files != null)
|
||||||
|
for (File c : files)
|
||||||
|
deleteDirectory(c);
|
||||||
|
}
|
||||||
|
if (!file.delete())
|
||||||
|
throw new FileNotFoundException("Failed to delete file: " + file);
|
||||||
|
}
|
||||||
|
}
|
|
@ -131,7 +131,6 @@ public class Storage<T extends Serializable> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void remove(String fileName) {
|
public void remove(String fileName) {
|
||||||
fileManager.removeFile(fileName);
|
fileManager.removeFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.bitsquare.common.crypto;
|
package io.bitsquare.common.crypto;
|
||||||
|
|
||||||
import io.bitsquare.common.util.Utilities;
|
import io.bitsquare.storage.FileUtil;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -37,7 +37,7 @@ public class EncryptionTest {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws IOException {
|
public void tearDown() throws IOException {
|
||||||
Utilities.deleteDirectory(dir);
|
FileUtil.deleteDirectory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.bitsquare.common.crypto;
|
package io.bitsquare.common.crypto;
|
||||||
|
|
||||||
import io.bitsquare.common.util.Utilities;
|
import io.bitsquare.storage.FileUtil;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -35,7 +35,7 @@ public class SigTest {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws IOException {
|
public void tearDown() throws IOException {
|
||||||
Utilities.deleteDirectory(dir);
|
FileUtil.deleteDirectory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||||
import io.bitsquare.common.handlers.ExceptionHandler;
|
import io.bitsquare.common.handlers.ExceptionHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
|
import io.bitsquare.storage.FileUtil;
|
||||||
import io.bitsquare.user.Preferences;
|
import io.bitsquare.user.Preferences;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.*;
|
||||||
|
@ -48,8 +49,10 @@ import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -125,6 +128,9 @@ public class WalletService {
|
||||||
exceptionHandler.handleException(new TimeoutException("Wallet did not initialize in " +
|
exceptionHandler.handleException(new TimeoutException("Wallet did not initialize in " +
|
||||||
STARTUP_TIMEOUT_SEC + " seconds.")), STARTUP_TIMEOUT_SEC);
|
STARTUP_TIMEOUT_SEC + " seconds.")), STARTUP_TIMEOUT_SEC);
|
||||||
|
|
||||||
|
|
||||||
|
backupWallet();
|
||||||
|
|
||||||
// If seed is non-null it means we are restoring from backup.
|
// If seed is non-null it means we are restoring from backup.
|
||||||
walletAppKit = new WalletAppKit(params, walletDir, "Bitsquare") {
|
walletAppKit = new WalletAppKit(params, walletDir, "Bitsquare") {
|
||||||
@Override
|
@Override
|
||||||
|
@ -275,6 +281,19 @@ public class WalletService {
|
||||||
}, "RestoreWallet-%d").start();
|
}, "RestoreWallet-%d").start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void backupWallet() {
|
||||||
|
FileUtil.rollingBackup(walletDir, "Bitsquare.wallet");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearBackup() {
|
||||||
|
try {
|
||||||
|
FileUtil.deleteDirectory(new File(Paths.get(walletDir.getAbsolutePath(), "backup").toString()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Could not delete directory " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Listener
|
// Listener
|
||||||
|
@ -502,7 +521,7 @@ public class WalletService {
|
||||||
public Coin getBalanceForAddressEntryWithTradeId(String tradeId) {
|
public Coin getBalanceForAddressEntryWithTradeId(String tradeId) {
|
||||||
return getBalanceForAddress(getTradeAddressEntry(tradeId).getAddress());
|
return getBalanceForAddress(getTradeAddressEntry(tradeId).getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Coin getBalance(List<TransactionOutput> transactionOutputs, Address address) {
|
private Coin getBalance(List<TransactionOutput> transactionOutputs, Address address) {
|
||||||
Coin balance = Coin.ZERO;
|
Coin balance = Coin.ZERO;
|
||||||
for (TransactionOutput transactionOutput : transactionOutputs) {
|
for (TransactionOutput transactionOutput : transactionOutputs) {
|
||||||
|
|
|
@ -118,6 +118,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||||
.show();
|
.show();
|
||||||
passwordField.setText("");
|
passwordField.setText("");
|
||||||
repeatedPasswordField.setText("");
|
repeatedPasswordField.setText("");
|
||||||
|
walletService.backupWallet();
|
||||||
} else {
|
} else {
|
||||||
new Popup()
|
new Popup()
|
||||||
.warning("You entered the wrong password.\n\n" +
|
.warning("You entered the wrong password.\n\n" +
|
||||||
|
@ -133,6 +134,8 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||||
.show();
|
.show();
|
||||||
passwordField.setText("");
|
passwordField.setText("");
|
||||||
repeatedPasswordField.setText("");
|
repeatedPasswordField.setText("");
|
||||||
|
walletService.clearBackup();
|
||||||
|
walletService.backupWallet();
|
||||||
}
|
}
|
||||||
setText();
|
setText();
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,10 +20,10 @@ package io.bitsquare.crypto;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.common.crypto.*;
|
import io.bitsquare.common.crypto.*;
|
||||||
import io.bitsquare.common.util.Utilities;
|
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
import io.bitsquare.p2p.messaging.PrefixedSealedAndSignedMessage;
|
import io.bitsquare.p2p.messaging.PrefixedSealedAndSignedMessage;
|
||||||
|
import io.bitsquare.storage.FileUtil;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -66,7 +66,7 @@ public class EncryptionServiceTests {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws IOException {
|
public void tearDown() throws IOException {
|
||||||
Utilities.deleteDirectory(dir);
|
FileUtil.deleteDirectory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -2,7 +2,6 @@ package io.bitsquare.p2p.storage;
|
||||||
|
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.crypto.*;
|
import io.bitsquare.common.crypto.*;
|
||||||
import io.bitsquare.common.util.Utilities;
|
|
||||||
import io.bitsquare.crypto.EncryptionService;
|
import io.bitsquare.crypto.EncryptionService;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
|
@ -12,6 +11,7 @@ import io.bitsquare.p2p.peers.PeerManager;
|
||||||
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
||||||
import io.bitsquare.p2p.storage.mocks.MockData;
|
import io.bitsquare.p2p.storage.mocks.MockData;
|
||||||
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
|
import io.bitsquare.storage.FileUtil;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -90,10 +90,9 @@ public class ProtectedDataStorageTest {
|
||||||
|
|
||||||
Path path = Paths.get(TestUtils.test_dummy_dir);
|
Path path = Paths.get(TestUtils.test_dummy_dir);
|
||||||
File dir = path.toFile();
|
File dir = path.toFile();
|
||||||
Utilities.deleteDirectory(dir);
|
FileUtil.deleteDirectory(dir);
|
||||||
|
FileUtil.deleteDirectory(dir1);
|
||||||
Utilities.deleteDirectory(dir1);
|
FileUtil.deleteDirectory(dir2);
|
||||||
Utilities.deleteDirectory(dir2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Test
|
//@Test
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue