Add rolling backup

This commit is contained in:
Manfred Karrer 2016-04-05 03:31:22 +02:00
parent 530b15147c
commit 4c0cc738e4
11 changed files with 109 additions and 55 deletions

View File

@ -18,6 +18,7 @@
package io.bitsquare.common.crypto;
import com.google.inject.Inject;
import io.bitsquare.storage.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -86,6 +87,7 @@ public class KeyStorage {
}
public KeyPair loadKeyPair(KeyEntry keyEntry) {
FileUtil.rollingBackup(storageDir, keyEntry.getFileName() + ".key");
// long now = System.currentTimeMillis();
try {
KeyFactory keyFactory = KeyFactory.getInstance(keyEntry.getAlgorithm(), "BC");

View File

@ -303,17 +303,6 @@ public class Utilities {
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) {
if (!msg.isEmpty()) {
msg += " / ";
@ -348,29 +337,6 @@ public class Utilities {
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 {
URLConnection connection = URI.create(url).toURL().openConnection();
connection.setDoOutput(true);

View File

@ -17,7 +17,6 @@
package io.bitsquare.storage;
import com.google.common.io.Files;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities;
import org.bitcoinj.core.Utils;
@ -162,13 +161,7 @@ public class FileManager<T> {
}
public synchronized void backupFile(String fileName) throws IOException {
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
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);
FileUtil.rollingBackup(dir, fileName);
}
///////////////////////////////////////////////////////////////////////////////////////////

View 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);
}
}

View File

@ -131,7 +131,6 @@ public class Storage<T extends Serializable> {
}
}
public void remove(String fileName) {
fileManager.removeFile(fileName);
}

View File

@ -1,6 +1,6 @@
package io.bitsquare.common.crypto;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.storage.FileUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Before;
@ -37,7 +37,7 @@ public class EncryptionTest {
@After
public void tearDown() throws IOException {
Utilities.deleteDirectory(dir);
FileUtil.deleteDirectory(dir);
}

View File

@ -1,6 +1,6 @@
package io.bitsquare.common.crypto;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.storage.FileUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Before;
@ -35,7 +35,7 @@ public class SigTest {
@After
public void tearDown() throws IOException {
Utilities.deleteDirectory(dir);
FileUtil.deleteDirectory(dir);
}

View File

@ -30,6 +30,7 @@ import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ExceptionHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.storage.FileUtil;
import io.bitsquare.user.Preferences;
import javafx.beans.property.*;
import org.bitcoinj.core.*;
@ -48,8 +49,10 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
@ -125,6 +128,9 @@ public class WalletService {
exceptionHandler.handleException(new TimeoutException("Wallet did not initialize in " +
STARTUP_TIMEOUT_SEC + " seconds.")), STARTUP_TIMEOUT_SEC);
backupWallet();
// If seed is non-null it means we are restoring from backup.
walletAppKit = new WalletAppKit(params, walletDir, "Bitsquare") {
@Override
@ -275,6 +281,19 @@ public class WalletService {
}, "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
@ -502,7 +521,7 @@ public class WalletService {
public Coin getBalanceForAddressEntryWithTradeId(String tradeId) {
return getBalanceForAddress(getTradeAddressEntry(tradeId).getAddress());
}
private Coin getBalance(List<TransactionOutput> transactionOutputs, Address address) {
Coin balance = Coin.ZERO;
for (TransactionOutput transactionOutput : transactionOutputs) {

View File

@ -118,6 +118,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
.show();
passwordField.setText("");
repeatedPasswordField.setText("");
walletService.backupWallet();
} else {
new Popup()
.warning("You entered the wrong password.\n\n" +
@ -133,6 +134,8 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
.show();
passwordField.setText("");
repeatedPasswordField.setText("");
walletService.clearBackup();
walletService.backupWallet();
}
setText();
});

View File

@ -20,10 +20,10 @@ package io.bitsquare.crypto;
import io.bitsquare.app.Version;
import io.bitsquare.common.crypto.*;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.p2p.NodeAddress;
import io.bitsquare.p2p.messaging.MailboxMessage;
import io.bitsquare.p2p.messaging.PrefixedSealedAndSignedMessage;
import io.bitsquare.storage.FileUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Before;
@ -66,7 +66,7 @@ public class EncryptionServiceTests {
@After
public void tearDown() throws IOException {
Utilities.deleteDirectory(dir);
FileUtil.deleteDirectory(dir);
}
@Test

View File

@ -2,7 +2,6 @@ package io.bitsquare.p2p.storage;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.*;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.crypto.EncryptionService;
import io.bitsquare.p2p.NodeAddress;
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.mocks.MockData;
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
import io.bitsquare.storage.FileUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.*;
import org.slf4j.Logger;
@ -90,10 +90,9 @@ public class ProtectedDataStorageTest {
Path path = Paths.get(TestUtils.test_dummy_dir);
File dir = path.toFile();
Utilities.deleteDirectory(dir);
Utilities.deleteDirectory(dir1);
Utilities.deleteDirectory(dir2);
FileUtil.deleteDirectory(dir);
FileUtil.deleteDirectory(dir1);
FileUtil.deleteDirectory(dir2);
}
//@Test