mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-04-21 08:06:33 -04:00
Use delayed write on background thread for persistence
This commit is contained in:
parent
b807ee17a6
commit
b96b133c31
@ -26,7 +26,6 @@ import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.gui.main.MainView;
|
||||
import io.bitsquare.gui.main.debug.DebugView;
|
||||
import io.bitsquare.gui.util.ImageUtil;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.util.Utilities;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
@ -74,20 +73,13 @@ public class BitsquareApp extends Application {
|
||||
bitsquareAppModule = new BitsquareAppModule(env, primaryStage);
|
||||
injector = Guice.createInjector(bitsquareAppModule);
|
||||
injector.getInstance(InjectorViewFactory.class).setInjector(injector);
|
||||
|
||||
|
||||
// route uncaught exceptions to a user-facing dialog
|
||||
|
||||
Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) ->
|
||||
Popups.handleUncaughtExceptions(Throwables.getRootCause(throwable)));
|
||||
|
||||
// load and apply any stored settings
|
||||
|
||||
|
||||
Persistence persistence = injector.getInstance(Persistence.class);
|
||||
persistence.init();
|
||||
|
||||
// load the main view and create the main scene
|
||||
|
||||
log.trace("viewLoader.load(MainView.class)");
|
||||
CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class);
|
||||
View view = viewLoader.load(MainView.class);
|
||||
|
@ -23,12 +23,11 @@ import io.bitsquare.arbitration.tomp2p.TomP2PArbitratorModule;
|
||||
import io.bitsquare.btc.BitcoinModule;
|
||||
import io.bitsquare.crypto.CryptoModule;
|
||||
import io.bitsquare.gui.GuiModule;
|
||||
import io.bitsquare.p2p.P2PModule;
|
||||
import io.bitsquare.p2p.tomp2p.TomP2PModule;
|
||||
import io.bitsquare.offer.OfferModule;
|
||||
import io.bitsquare.offer.tomp2p.TomP2POfferModule;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.p2p.P2PModule;
|
||||
import io.bitsquare.p2p.tomp2p.TomP2PModule;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.trade.TradeModule;
|
||||
import io.bitsquare.user.AccountSettings;
|
||||
import io.bitsquare.user.Preferences;
|
||||
@ -63,14 +62,9 @@ class BitsquareAppModule extends BitsquareModule {
|
||||
File storageDir = new File(env.getRequiredProperty(Storage.DIR_KEY));
|
||||
bind(File.class).annotatedWith(named(Storage.DIR_KEY)).toInstance(storageDir);
|
||||
|
||||
File persistenceDir = new File(env.getRequiredProperty(Persistence.DIR_KEY));
|
||||
bind(File.class).annotatedWith(named(Persistence.DIR_KEY)).toInstance(persistenceDir);
|
||||
bindConstant().annotatedWith(named(Persistence.PREFIX_KEY)).to(env.getRequiredProperty(Persistence.PREFIX_KEY));
|
||||
bind(Persistence.class).in(Singleton.class);
|
||||
|
||||
bind(Environment.class).toInstance(env);
|
||||
bind(UpdateProcess.class).in(Singleton.class);
|
||||
|
||||
|
||||
install(networkModule());
|
||||
install(bitcoinModule());
|
||||
install(cryptoModule());
|
||||
|
@ -21,8 +21,7 @@ import io.bitsquare.BitsquareException;
|
||||
import io.bitsquare.btc.UserAgent;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.gui.main.MainView;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.util.Utilities;
|
||||
import io.bitsquare.util.spring.JOptCommandLinePropertySource;
|
||||
|
||||
@ -137,9 +136,6 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
||||
|
||||
setProperty(Storage.DIR_KEY, Paths.get(appDataDir, "db").toString());
|
||||
|
||||
setProperty(Persistence.DIR_KEY, appDataDir);
|
||||
setProperty(Persistence.PREFIX_KEY, appName + "_pref");
|
||||
|
||||
setProperty(MainView.TITLE_KEY, appName);
|
||||
}});
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
package io.bitsquare.arbitration;
|
||||
|
||||
import io.bitsquare.locale.LanguageUtil;
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
@ -95,7 +95,7 @@ public class Arbitrator implements Serializable {
|
||||
public Arbitrator(Storage<Arbitrator> storage, User user) {
|
||||
this.storage = storage;
|
||||
|
||||
Arbitrator persisted = storage.getPersisted(this);
|
||||
Arbitrator persisted = storage.initAndGetPersisted(this);
|
||||
if (persisted != null) {
|
||||
//TODO for mock arbitrator
|
||||
id = persisted.getName();
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
package io.bitsquare.btc;
|
||||
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
||||
import org.bitcoinj.core.Wallet;
|
||||
import org.bitcoinj.crypto.DeterministicKey;
|
||||
@ -48,7 +48,7 @@ public class AddressEntryList extends ArrayList<AddressEntry> implements Seriali
|
||||
public void init(Wallet wallet) {
|
||||
this.wallet = wallet;
|
||||
|
||||
AddressEntryList persisted = storage.getPersisted(this);
|
||||
AddressEntryList persisted = storage.initAndGetPersisted(this);
|
||||
if (persisted != null) {
|
||||
for (AddressEntry addressEntry : persisted) {
|
||||
addressEntry.setDeterministicKey((DeterministicKey) wallet.findKeyFromPubHash(addressEntry.getPubKeyHash()));
|
||||
|
@ -21,7 +21,6 @@ import io.bitsquare.btc.listeners.AddressConfidenceListener;
|
||||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.btc.listeners.TxConfidenceListener;
|
||||
import io.bitsquare.crypto.SignatureService;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
|
||||
import org.bitcoinj.core.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.Address;
|
||||
@ -91,11 +90,9 @@ public class WalletService {
|
||||
private final NetworkParameters params;
|
||||
private final FeePolicy feePolicy;
|
||||
private final SignatureService signatureService;
|
||||
private final Persistence persistence;
|
||||
private final File walletDir;
|
||||
private final String walletPrefix;
|
||||
private final UserAgent userAgent;
|
||||
private final BitcoinNetwork bitcoinNetwork;
|
||||
|
||||
private WalletAppKit walletAppKit;
|
||||
private Wallet wallet;
|
||||
@ -111,14 +108,12 @@ public class WalletService {
|
||||
|
||||
@Inject
|
||||
public WalletService(BitcoinNetwork bitcoinNetwork, FeePolicy feePolicy, SignatureService signatureService,
|
||||
Persistence persistence, AddressEntryList addressEntryList, UserAgent userAgent,
|
||||
AddressEntryList addressEntryList, UserAgent userAgent,
|
||||
@Named(DIR_KEY) File walletDir, @Named(PREFIX_KEY) String walletPrefix) {
|
||||
this.bitcoinNetwork = bitcoinNetwork;
|
||||
this.addressEntryList = addressEntryList;
|
||||
this.params = bitcoinNetwork.getParameters();
|
||||
this.feePolicy = feePolicy;
|
||||
this.signatureService = signatureService;
|
||||
this.persistence = persistence;
|
||||
this.walletDir = walletDir;
|
||||
this.walletPrefix = walletPrefix;
|
||||
this.userAgent = userAgent;
|
||||
|
@ -21,7 +21,7 @@ import io.bitsquare.common.viewfx.view.View;
|
||||
import io.bitsquare.common.viewfx.view.ViewPath;
|
||||
import io.bitsquare.gui.main.MainView;
|
||||
import io.bitsquare.gui.main.trade.BuyView;
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
@ -62,7 +62,7 @@ public class Navigation implements Serializable {
|
||||
public Navigation(Storage<Navigation> storage) {
|
||||
this.storage = storage;
|
||||
|
||||
Navigation persisted = storage.getPersisted(this);
|
||||
Navigation persisted = storage.initAndGetPersisted(this);
|
||||
if (persisted != null) {
|
||||
previousPath = persisted.getPreviousPath();
|
||||
}
|
||||
|
@ -68,9 +68,8 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||
private final String title;
|
||||
|
||||
@Inject
|
||||
public MainView(MainViewModel model, CachingViewLoader viewLoader, Navigation navigation, OverlayManager
|
||||
overlayManager,
|
||||
Transitions transitions, @Named(MainView.TITLE_KEY) String title) {
|
||||
public MainView(MainViewModel model, CachingViewLoader viewLoader, Navigation navigation, OverlayManager overlayManager, Transitions transitions,
|
||||
@Named(MainView.TITLE_KEY) String title) {
|
||||
super(model);
|
||||
this.viewLoader = viewLoader;
|
||||
this.navigation = navigation;
|
||||
|
@ -18,7 +18,6 @@
|
||||
package io.bitsquare.gui.main;
|
||||
|
||||
import io.bitsquare.app.UpdateProcess;
|
||||
import io.bitsquare.arbitration.ArbitratorService;
|
||||
import io.bitsquare.btc.BitcoinNetwork;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.common.viewfx.model.ViewModel;
|
||||
@ -29,10 +28,8 @@ import io.bitsquare.locale.CountryUtil;
|
||||
import io.bitsquare.p2p.BaseP2PService;
|
||||
import io.bitsquare.p2p.BootstrapState;
|
||||
import io.bitsquare.p2p.ClientNode;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.user.AccountSettings;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@ -91,27 +88,20 @@ class MainViewModel implements ViewModel {
|
||||
private final User user;
|
||||
private final WalletService walletService;
|
||||
private final ClientNode clientNode;
|
||||
private ArbitratorService arbitratorService;
|
||||
private final TradeManager tradeManager;
|
||||
private UpdateProcess updateProcess;
|
||||
private final BSFormatter formatter;
|
||||
private Persistence persistence;
|
||||
private AccountSettings accountSettings;
|
||||
|
||||
@Inject
|
||||
public MainViewModel(User user, WalletService walletService, ClientNode clientNode,
|
||||
ArbitratorService arbitratorService,
|
||||
TradeManager tradeManager, BitcoinNetwork bitcoinNetwork, UpdateProcess updateProcess,
|
||||
BSFormatter formatter, Persistence persistence, AccountSettings accountSettings) {
|
||||
BSFormatter formatter) {
|
||||
this.user = user;
|
||||
this.walletService = walletService;
|
||||
this.clientNode = clientNode;
|
||||
this.arbitratorService = arbitratorService;
|
||||
this.tradeManager = tradeManager;
|
||||
this.updateProcess = updateProcess;
|
||||
this.formatter = formatter;
|
||||
this.persistence = persistence;
|
||||
this.accountSettings = accountSettings;
|
||||
|
||||
bitcoinNetworkAsString = bitcoinNetwork.toString();
|
||||
|
||||
|
@ -27,7 +27,6 @@ import io.bitsquare.common.viewfx.view.View;
|
||||
import io.bitsquare.common.viewfx.view.ViewLoader;
|
||||
import io.bitsquare.gui.main.account.arbitrator.profile.ArbitratorProfileView;
|
||||
import io.bitsquare.locale.LanguageUtil;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.user.AccountSettings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -54,15 +53,13 @@ public class ArbitratorBrowserView extends ActivatableView<Pane, Void> implement
|
||||
|
||||
private final ViewLoader viewLoader;
|
||||
private final AccountSettings accountSettings;
|
||||
private final Persistence persistence;
|
||||
private final ArbitratorService messageService;
|
||||
|
||||
@Inject
|
||||
public ArbitratorBrowserView(CachingViewLoader viewLoader, AccountSettings accountSettings, Persistence persistence,
|
||||
public ArbitratorBrowserView(CachingViewLoader viewLoader, AccountSettings accountSettings,
|
||||
ArbitratorService messageService) {
|
||||
this.viewLoader = viewLoader;
|
||||
this.accountSettings = accountSettings;
|
||||
this.persistence = persistence;
|
||||
this.messageService = messageService;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ import io.bitsquare.locale.Country;
|
||||
import io.bitsquare.locale.CountryUtil;
|
||||
import io.bitsquare.locale.CurrencyUtil;
|
||||
import io.bitsquare.locale.Region;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.user.AccountSettings;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
@ -46,7 +45,6 @@ class FiatAccountDataModel implements Activatable, DataModel {
|
||||
|
||||
private final User user;
|
||||
private final AccountSettings accountSettings;
|
||||
private final Persistence persistence;
|
||||
|
||||
final StringProperty title = new SimpleStringProperty();
|
||||
final StringProperty holderName = new SimpleStringProperty();
|
||||
@ -68,8 +66,7 @@ class FiatAccountDataModel implements Activatable, DataModel {
|
||||
|
||||
|
||||
@Inject
|
||||
public FiatAccountDataModel(User user, Persistence persistence, AccountSettings accountSettings) {
|
||||
this.persistence = persistence;
|
||||
public FiatAccountDataModel(User user, AccountSettings accountSettings) {
|
||||
this.user = user;
|
||||
this.accountSettings = accountSettings;
|
||||
}
|
||||
|
@ -17,15 +17,12 @@
|
||||
|
||||
package io.bitsquare.gui.main.account.content.irc;
|
||||
|
||||
import io.bitsquare.arbitration.ArbitratorService;
|
||||
import io.bitsquare.common.viewfx.model.Activatable;
|
||||
import io.bitsquare.common.viewfx.model.DataModel;
|
||||
import io.bitsquare.fiat.FiatAccount;
|
||||
import io.bitsquare.fiat.FiatAccountType;
|
||||
import io.bitsquare.locale.CountryUtil;
|
||||
import io.bitsquare.locale.CurrencyUtil;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.user.AccountSettings;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@ -42,9 +39,6 @@ import javafx.collections.ObservableList;
|
||||
class IrcAccountDataModel implements Activatable, DataModel {
|
||||
|
||||
private final User user;
|
||||
private final AccountSettings accountSettings;
|
||||
private final ArbitratorService messageService;
|
||||
private final Persistence persistence;
|
||||
|
||||
final StringProperty nickName = new SimpleStringProperty();
|
||||
final ObjectProperty<FiatAccountType> type = new SimpleObjectProperty<>();
|
||||
@ -57,12 +51,8 @@ class IrcAccountDataModel implements Activatable, DataModel {
|
||||
|
||||
|
||||
@Inject
|
||||
public IrcAccountDataModel(User user, Persistence persistence, AccountSettings accountSettings,
|
||||
ArbitratorService messageService) {
|
||||
this.persistence = persistence;
|
||||
public IrcAccountDataModel(User user) {
|
||||
this.user = user;
|
||||
this.accountSettings = accountSettings;
|
||||
this.messageService = messageService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,7 +22,6 @@ import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.common.viewfx.model.DataModel;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
@ -50,7 +49,6 @@ class RegistrationDataModel implements DataModel {
|
||||
|
||||
private final WalletService walletService;
|
||||
private final User user;
|
||||
private final Persistence persistence;
|
||||
|
||||
private String transactionId;
|
||||
private AddressEntry addressEntry;
|
||||
@ -61,11 +59,10 @@ class RegistrationDataModel implements DataModel {
|
||||
|
||||
|
||||
@Inject
|
||||
public RegistrationDataModel(WalletService walletService, User user, Persistence persistence) {
|
||||
public RegistrationDataModel(WalletService walletService, User user) {
|
||||
|
||||
this.walletService = walletService;
|
||||
this.user = user;
|
||||
this.persistence = persistence;
|
||||
|
||||
if (walletService != null && walletService.getWallet() != null) {
|
||||
addressEntry = walletService.getRegistrationAddressEntry();
|
||||
|
@ -18,16 +18,13 @@
|
||||
package io.bitsquare.gui.main.account.content.restrictions;
|
||||
|
||||
import io.bitsquare.arbitration.Arbitrator;
|
||||
import io.bitsquare.arbitration.ArbitratorService;
|
||||
import io.bitsquare.common.viewfx.model.Activatable;
|
||||
import io.bitsquare.common.viewfx.model.DataModel;
|
||||
import io.bitsquare.locale.Country;
|
||||
import io.bitsquare.locale.CountryUtil;
|
||||
import io.bitsquare.locale.LanguageUtil;
|
||||
import io.bitsquare.locale.Region;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.user.AccountSettings;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
@ -38,10 +35,7 @@ import javafx.collections.ObservableList;
|
||||
|
||||
class RestrictionsDataModel implements Activatable, DataModel {
|
||||
|
||||
private final User user;
|
||||
private final AccountSettings accountSettings;
|
||||
private final Persistence persistence;
|
||||
private final ArbitratorService messageService;
|
||||
|
||||
final ObservableList<Locale> languageList = FXCollections.observableArrayList();
|
||||
final ObservableList<Country> countryList = FXCollections.observableArrayList();
|
||||
@ -52,12 +46,8 @@ class RestrictionsDataModel implements Activatable, DataModel {
|
||||
|
||||
|
||||
@Inject
|
||||
public RestrictionsDataModel(User user, AccountSettings accountSettings, Persistence persistence,
|
||||
ArbitratorService messageService) {
|
||||
this.user = user;
|
||||
public RestrictionsDataModel(AccountSettings accountSettings) {
|
||||
this.accountSettings = accountSettings;
|
||||
this.persistence = persistence;
|
||||
this.messageService = messageService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,7 +28,6 @@ import io.bitsquare.fiat.FiatAccount;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.locale.Country;
|
||||
import io.bitsquare.offer.Direction;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.user.AccountSettings;
|
||||
import io.bitsquare.user.Preferences;
|
||||
@ -72,8 +71,6 @@ class CreateOfferDataModel implements Activatable, DataModel {
|
||||
private final WalletService walletService;
|
||||
private final AccountSettings accountSettings;
|
||||
private Preferences preferences;
|
||||
private final User user;
|
||||
private final Persistence persistence;
|
||||
private final BSFormatter formatter;
|
||||
|
||||
private final String offerId;
|
||||
@ -110,14 +107,12 @@ class CreateOfferDataModel implements Activatable, DataModel {
|
||||
// non private for testing
|
||||
@Inject
|
||||
public CreateOfferDataModel(TradeManager tradeManager, WalletService walletService, AccountSettings accountSettings,
|
||||
Preferences preferences, User user, Persistence persistence,
|
||||
Preferences preferences, User user,
|
||||
BSFormatter formatter) {
|
||||
this.tradeManager = tradeManager;
|
||||
this.walletService = walletService;
|
||||
this.accountSettings = accountSettings;
|
||||
this.preferences = preferences;
|
||||
this.user = user;
|
||||
this.persistence = persistence;
|
||||
this.formatter = formatter;
|
||||
this.offerId = UUID.randomUUID().toString();
|
||||
|
||||
@ -231,7 +226,7 @@ class CreateOfferDataModel implements Activatable, DataModel {
|
||||
}
|
||||
|
||||
void securityDepositInfoDisplayed() {
|
||||
persistence.write("displaySecurityDepositInfo", false);
|
||||
preferences.setDisplaySecurityDepositInfo(false);
|
||||
}
|
||||
|
||||
|
||||
@ -255,15 +250,6 @@ class CreateOfferDataModel implements Activatable, DataModel {
|
||||
return offerId;
|
||||
}
|
||||
|
||||
Boolean displaySecurityDepositInfo() {
|
||||
Object securityDepositInfoDisplayedObject = persistence.read("displaySecurityDepositInfo");
|
||||
if (securityDepositInfoDisplayedObject instanceof Boolean)
|
||||
return (Boolean) securityDepositInfoDisplayedObject;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void updateBalance(@NotNull Coin balance) {
|
||||
isWalletFunded.set(totalToPayAsCoin.get() != null && balance.compareTo(totalToPayAsCoin.get()) >= 0);
|
||||
}
|
||||
@ -281,4 +267,8 @@ class CreateOfferDataModel implements Activatable, DataModel {
|
||||
fiatCode.set(fiatAccount.getCurrency().getCurrencyCode());
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getDisplaySecurityDepositInfo() {
|
||||
return preferences.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||
@FXML
|
||||
void onShowPayFundsScreen() {
|
||||
// TODO deactivate for testing the moment
|
||||
/* if (model.displaySecurityDepositInfo()) {
|
||||
/* if (model.getDisplaySecurityDepositInfo()) {
|
||||
overlayManager.blurContent();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new AbstractAction(BSResources.get("shared.close")) {
|
||||
|
@ -250,8 +250,8 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
||||
return formatter;
|
||||
}
|
||||
|
||||
Boolean displaySecurityDepositInfo() {
|
||||
return dataModel.displaySecurityDepositInfo();
|
||||
Boolean getDisplaySecurityDepositInfo() {
|
||||
return dataModel.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
|
@ -24,7 +24,6 @@ import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.common.viewfx.model.Activatable;
|
||||
import io.bitsquare.common.viewfx.model.DataModel;
|
||||
import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import io.bitsquare.trade.handlers.TradeResultHandler;
|
||||
import io.bitsquare.user.Preferences;
|
||||
@ -58,7 +57,6 @@ class TakeOfferDataModel implements Activatable, DataModel {
|
||||
private final TradeManager tradeManager;
|
||||
private final WalletService walletService;
|
||||
private final Preferences preferences;
|
||||
private final Persistence persistence;
|
||||
|
||||
private Offer offer;
|
||||
private AddressEntry addressEntry;
|
||||
@ -78,12 +76,10 @@ class TakeOfferDataModel implements Activatable, DataModel {
|
||||
@Inject
|
||||
public TakeOfferDataModel(TradeManager tradeManager,
|
||||
WalletService walletService,
|
||||
Preferences preferences,
|
||||
Persistence persistence) {
|
||||
Preferences preferences) {
|
||||
this.tradeManager = tradeManager;
|
||||
this.walletService = walletService;
|
||||
this.preferences = preferences;
|
||||
this.persistence = persistence;
|
||||
|
||||
offerFeeAsCoin.set(FeePolicy.CREATE_OFFER_FEE);
|
||||
networkFeeAsCoin.set(FeePolicy.TX_FEE);
|
||||
@ -174,16 +170,12 @@ class TakeOfferDataModel implements Activatable, DataModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean displaySecurityDepositInfo() {
|
||||
Object securityDepositInfoDisplayedObject = persistence.read("displaySecurityDepositInfo");
|
||||
if (securityDepositInfoDisplayedObject instanceof Boolean)
|
||||
return (Boolean) securityDepositInfoDisplayedObject;
|
||||
else
|
||||
return true;
|
||||
Boolean getDisplaySecurityDepositInfo() {
|
||||
return preferences.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
void securityDepositInfoDisplayed() {
|
||||
persistence.write("displaySecurityDepositInfo", false);
|
||||
preferences.setDisplaySecurityDepositInfo(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -319,7 +319,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||
|
||||
private void setupPaymentScreen() {
|
||||
// TODO deactivate for testing the moment
|
||||
/* if (model.displaySecurityDepositInfo()) {
|
||||
/* if (model.getDisplaySecurityDepositInfo()) {
|
||||
overlayManager.blurContent();
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new AbstractAction(BSResources.get("shared.close")) {
|
||||
|
@ -359,8 +359,8 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
||||
return paymentLabel;
|
||||
}
|
||||
|
||||
Boolean displaySecurityDepositInfo() {
|
||||
return dataModel.displaySecurityDepositInfo();
|
||||
Boolean getDisplaySecurityDepositInfo() {
|
||||
return dataModel.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,299 +0,0 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.persistence;
|
||||
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.bitcoinj.utils.Threading;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple storage solution for serialized data
|
||||
* TODO: Should be improved with a more robust solution or maybe a lightweight database.
|
||||
* TODO: Should run in a dedicated thread.
|
||||
*/
|
||||
public class Persistence {
|
||||
private static final Logger log = LoggerFactory.getLogger(Persistence.class);
|
||||
private static final ReentrantLock lock = Threading.lock("Storage");
|
||||
|
||||
public static final String DIR_KEY = "persistence.dir";
|
||||
public static final String PREFIX_KEY = "persistence.prefix";
|
||||
private static final long MIN_INTERVAL_BETWEEN_WRITE_OPERATIONS = 1000;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private Map<String, Serializable> rootMap = new HashMap<>();
|
||||
private Map<String, Long> timestampMap = new HashMap<>();
|
||||
|
||||
private final File dir;
|
||||
private final String prefix;
|
||||
private final File storageFile;
|
||||
private int resetCounter = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public Persistence(
|
||||
@Named(DIR_KEY) File dir,
|
||||
@Named(PREFIX_KEY) String prefix) {
|
||||
this.dir = dir;
|
||||
this.prefix = prefix;
|
||||
this.storageFile = new File(dir, prefix + ".ser");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void init() {
|
||||
try {
|
||||
lock.lock();
|
||||
final Map<String, Serializable> map = readRootMap();
|
||||
|
||||
if (map == null)
|
||||
saveObjectToFile((Serializable) rootMap);
|
||||
else
|
||||
rootMap = map;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Map
|
||||
public void write(Object classInstance, String propertyKey, List<? extends Serializable> value) {
|
||||
write(classInstance.getClass().getName() + "." + propertyKey, value);
|
||||
}
|
||||
public void write(Object classInstance, String propertyKey, Serializable value) {
|
||||
write(classInstance.getClass().getName() + "." + propertyKey, value);
|
||||
}
|
||||
|
||||
// not used outside
|
||||
public void write(String key, Map<String, ? extends Serializable> value) {
|
||||
write(key, (Serializable) value);
|
||||
}
|
||||
public void write(String key, List<? extends Serializable> value) {
|
||||
write(key, (Serializable) value);
|
||||
}
|
||||
|
||||
|
||||
// Serializable
|
||||
public void remove(Object classInstance, String propertyKey) {
|
||||
try {
|
||||
lock.lock();
|
||||
rootMap.remove(classInstance.getClass().getName() + "." + propertyKey);
|
||||
saveObjectToFile((Serializable) rootMap);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void write(Serializable classInstance) {
|
||||
write(classInstance.getClass().getName(), classInstance);
|
||||
}
|
||||
|
||||
public void write(String key, Serializable value) {
|
||||
//log.trace("Write object with key = " + key + " / value = " + value);
|
||||
// TODO add throttle to limit write operations
|
||||
|
||||
try {
|
||||
lock.lock();
|
||||
rootMap.put(key, value);
|
||||
saveObjectToFile((Serializable) rootMap);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Serializable read(Object classInstance) {
|
||||
return read(classInstance.getClass().getName());
|
||||
}
|
||||
|
||||
public Serializable read(Object classInstance, String propertyKey) {
|
||||
return read(classInstance.getClass().getName() + "." + propertyKey);
|
||||
}
|
||||
|
||||
// read from local rootMap, just if not found read from disc
|
||||
public Serializable read(String key) {
|
||||
try {
|
||||
lock.lock();
|
||||
if (rootMap.containsKey(key)) {
|
||||
// log.trace("Read object with key = " + key + " / value = " + rootMap.get(key));
|
||||
return rootMap.get(key);
|
||||
}
|
||||
else {
|
||||
final Map<String, Serializable> map = readRootMap();
|
||||
if (map != null) {
|
||||
rootMap = map;
|
||||
}
|
||||
if (rootMap.containsKey(key)) {
|
||||
// log.trace("Read object with key = " + key + " / value = " + rootMap.get(key));
|
||||
return rootMap.get(key);
|
||||
}
|
||||
else {
|
||||
log.info("Object with key = " + key + " not found.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private Map<String, Serializable> readRootMap() {
|
||||
try {
|
||||
final Object object = readObjectFromFile(storageFile);
|
||||
if (object == null) {
|
||||
log.error("readRootMap returned null object.");
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
if (object instanceof Map) {
|
||||
return (Map<String, Serializable>) object;
|
||||
}
|
||||
else {
|
||||
log.error("Object is not type of Map<String, Serializable>");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
|
||||
log.trace("File not found is ok for the first execute.");
|
||||
return null;
|
||||
} catch (ClassNotFoundException | IOException e2) {
|
||||
log.warn("Could not read rootMap. " + e2);
|
||||
|
||||
// If there are problems with incompatible versions, we reset the persisted data
|
||||
// TODO We need a clean solution when we use another persistence solution
|
||||
rootMap = new HashMap<>();
|
||||
saveObjectToFile((Serializable) rootMap);
|
||||
resetCounter++;
|
||||
|
||||
// We only try that once, if it fails repeatedly we
|
||||
if (resetCounter == 1) {
|
||||
log.warn("We reset the persisted data and try again to read the root map.");
|
||||
return readRootMap();
|
||||
}
|
||||
else {
|
||||
e2.printStackTrace();
|
||||
log.error("We tried already to reset the persisted data, but we get an error again, so we give up.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveObjectToFile(Serializable serializable) {
|
||||
File tempFile = null;
|
||||
FileOutputStream fileOutputStream = null;
|
||||
ObjectOutputStream objectOutputStream = null;
|
||||
try {
|
||||
tempFile = File.createTempFile("temp_" + prefix, null, dir);
|
||||
|
||||
// Don't use auto closeable resources in try() as we would need too many try/catch clauses (for tempFile)
|
||||
// and we need to close it
|
||||
// manually before replacing file with temp file
|
||||
fileOutputStream = new FileOutputStream(tempFile);
|
||||
objectOutputStream = new ObjectOutputStream(fileOutputStream);
|
||||
|
||||
objectOutputStream.writeObject(serializable);
|
||||
|
||||
// Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide
|
||||
// to not write through to physical media for at least a few seconds, but this is the best we can do.
|
||||
fileOutputStream.flush();
|
||||
fileOutputStream.getFD().sync();
|
||||
|
||||
// Close resources before replacing file with temp file because otherwise it causes problems on windows
|
||||
// when rename temp file
|
||||
fileOutputStream.close();
|
||||
objectOutputStream.close();
|
||||
|
||||
writeTempFileToFile(tempFile, storageFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("save object to file failed." + e);
|
||||
} finally {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
log.warn("Temp file still exists after failed save.");
|
||||
if (!tempFile.delete()) log.error("Cannot delete temp file.");
|
||||
}
|
||||
|
||||
try {
|
||||
if (objectOutputStream != null) objectOutputStream.close();
|
||||
if (fileOutputStream != null) fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error("Cannot close resources.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object readObjectFromFile(File file) throws IOException, ClassNotFoundException {
|
||||
lock.lock();
|
||||
try (final FileInputStream fileInputStream = new FileInputStream(file);
|
||||
final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
|
||||
return objectInputStream.readObject();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTempFileToFile(File tempFile, File file) throws IOException {
|
||||
if (Utils.isWindows()) {
|
||||
// Work around an issue on Windows whereby you can't rename over existing files.
|
||||
final File canonical = file.getCanonicalFile();
|
||||
if (canonical.exists() && !canonical.delete()) {
|
||||
throw new IOException("Failed to delete canonical file for replacement with save");
|
||||
}
|
||||
if (!tempFile.renameTo(canonical)) {
|
||||
throw new IOException("Failed to rename " + tempFile + " to " + canonical);
|
||||
}
|
||||
}
|
||||
else if (!tempFile.renameTo(file)) {
|
||||
throw new IOException("Failed to rename " + tempFile + " to " + file);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.persistence;
|
||||
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.util.FileUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Storage<T extends Serializable> {
|
||||
private static final Logger log = LoggerFactory.getLogger(Storage.class);
|
||||
|
||||
public static final String DIR_KEY = "storage.dir";
|
||||
private final File dir;
|
||||
private File storageFile;
|
||||
private T serializable;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public Storage(@Named(DIR_KEY) File dir) {
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if (storageFile == null)
|
||||
throw new RuntimeException("storageFile = null. Call setupFileStorage before using read/write.");
|
||||
|
||||
try {
|
||||
FileUtil.write(serializable, dir, storageFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
Popups.openErrorPopup("An exception occurred at writing data to disc.", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public T getPersisted(T serializable) {
|
||||
this.serializable = serializable;
|
||||
storageFile = new File(dir, serializable.getClass().getSimpleName() + ".ser");
|
||||
|
||||
if (storageFile == null)
|
||||
throw new RuntimeException("storageFile = null. Call init before using read/write.");
|
||||
|
||||
try {
|
||||
T persistedObject = (T) FileUtil.read(storageFile);
|
||||
|
||||
// If we did not get any exception we can be sure the data are consistent so we make a backup
|
||||
FileUtil.backupFile(storageFile, new File(Paths.get(dir.getAbsolutePath(), "backups").toString()),
|
||||
serializable.getClass().getSimpleName() + ".ser");
|
||||
return persistedObject;
|
||||
} catch (InvalidClassException e) {
|
||||
log.error("Version of persisted class has changed. We cannot read the persisted data anymore. We make a backup and remove the inconsistent file.");
|
||||
try {
|
||||
// In case the persisted data have been critical (keys) we keep a backup which might be used for recovery
|
||||
FileUtil.removeAndBackupFile(storageFile, new File(Paths.get(dir.getAbsolutePath(), "inconsistent").toString()),
|
||||
serializable.getClass().getSimpleName() + ".ser");
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
log.error(e1.getMessage());
|
||||
// We swallow Exception if backup fails
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
log.info("File not available. That is OK for the first run.");
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
Popups.openErrorPopup("An exception occurred at reading data from disc.", e.getMessage());
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
302
core/src/main/java/io/bitsquare/storage/FileManager.java
Normal file
302
core/src/main/java/io/bitsquare/storage/FileManager.java
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright 2014 Andreas Schildbach
|
||||
* <p/>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p/>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.bitsquare.storage;
|
||||
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.bitcoinj.utils.Threading;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javafx.application.Platform;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Borrowed from BitcoinJ WalletFiles
|
||||
* A class that handles atomic and optionally delayed writing of a file to disk.
|
||||
* It can be useful to delay writing of a file to disk on slow devices.
|
||||
* By coalescing writes and doing serialization
|
||||
* and disk IO on a background thread performance can be improved.
|
||||
*/
|
||||
public class FileManager<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(FileManager.class);
|
||||
private static final ReentrantLock lock = Threading.lock("FileUtil");
|
||||
|
||||
private final File dir;
|
||||
private final File storageFile;
|
||||
private final ScheduledThreadPoolExecutor executor;
|
||||
private final AtomicBoolean savePending;
|
||||
private final long delay;
|
||||
private final TimeUnit delayTimeUnit;
|
||||
private final Callable<Void> saver;
|
||||
private T serializable;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public FileManager(File dir, File storageFile, long delay, TimeUnit delayTimeUnit) {
|
||||
this.dir = dir;
|
||||
this.storageFile = storageFile;
|
||||
|
||||
final ThreadFactoryBuilder builder = new ThreadFactoryBuilder()
|
||||
.setDaemon(true)
|
||||
.setNameFormat("FileManager thread")
|
||||
.setPriority(Thread.MIN_PRIORITY); // Avoid competing with the GUI thread.
|
||||
|
||||
builder.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable throwable) {
|
||||
Platform.runLater(() -> Popups.handleUncaughtExceptions(Throwables.getRootCause(throwable)));
|
||||
}
|
||||
});
|
||||
|
||||
// An executor that starts up threads when needed and shuts them down later.
|
||||
this.executor = new ScheduledThreadPoolExecutor(1, builder.build());
|
||||
this.executor.setKeepAliveTime(5, TimeUnit.SECONDS);
|
||||
this.executor.allowCoreThreadTimeOut(true);
|
||||
this.executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
|
||||
// File must only be accessed from the auto-save executor from now on, to avoid simultaneous access.
|
||||
this.savePending = new AtomicBoolean();
|
||||
this.delay = delay;
|
||||
this.delayTimeUnit = checkNotNull(delayTimeUnit);
|
||||
|
||||
this.saver = new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
// Runs in an auto save thread.
|
||||
if (!savePending.getAndSet(false)) {
|
||||
// Some other scheduled request already beat us to it.
|
||||
return null;
|
||||
}
|
||||
saveNowInternal(serializable);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
FileManager.this.shutdown();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Actually write the wallet file to disk, using an atomic rename when possible. Runs on the current thread.
|
||||
*/
|
||||
public void saveNow(T serializable) throws IOException {
|
||||
saveNowInternal(serializable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues up a save in the background. Useful for not very important wallet changes.
|
||||
*/
|
||||
public void saveLater(T serializable) {
|
||||
this.serializable = serializable;
|
||||
|
||||
if (savePending.getAndSet(true))
|
||||
return; // Already pending.
|
||||
executor.schedule(saver, delay, delayTimeUnit);
|
||||
}
|
||||
|
||||
public Object read(File file) throws IOException, ClassNotFoundException {
|
||||
lock.lock();
|
||||
try (final FileInputStream fileInputStream = new FileInputStream(file);
|
||||
final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
|
||||
return objectInputStream.readObject();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFile(T serializable) {
|
||||
storageFile.delete();
|
||||
|
||||
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
|
||||
if (backupDir.exists()) {
|
||||
File backupFile = new File(backupDir, serializable.getClass().getSimpleName());
|
||||
if (backupFile.exists())
|
||||
backupFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shut down auto-saving.
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (serializable != null)
|
||||
log.debug("shutDown " + serializable.getClass().getSimpleName());
|
||||
else
|
||||
log.debug("shutDown");
|
||||
|
||||
executor.shutdown();
|
||||
try {
|
||||
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); // forever
|
||||
} catch (InterruptedException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAndBackupFile(File storageFile, File dir, String name) throws IOException {
|
||||
File corruptedBackupDir = new File(Paths.get(dir.getAbsolutePath(), "corrupted").toString());
|
||||
if (!corruptedBackupDir.exists())
|
||||
corruptedBackupDir.mkdir();
|
||||
|
||||
renameTempFileToFile(storageFile, new File(corruptedBackupDir, serializable.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
public void backupFile(T serializable) throws IOException {
|
||||
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
|
||||
if (!backupDir.exists())
|
||||
backupDir.mkdir();
|
||||
|
||||
Files.copy(storageFile, new File(backupDir, serializable.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void saveNowInternal(T serializable) throws IOException {
|
||||
long now = System.currentTimeMillis();
|
||||
saveToFile(serializable, dir, storageFile);
|
||||
log.info("Save completed in {}msec", System.currentTimeMillis() - now);
|
||||
}
|
||||
|
||||
private void saveToFile(T serializable, File dir, File storageFile) throws IOException {
|
||||
lock.lock();
|
||||
File tempFile = null;
|
||||
FileOutputStream fileOutputStream = null;
|
||||
ObjectOutputStream objectOutputStream = null;
|
||||
try {
|
||||
if (!dir.exists())
|
||||
dir.mkdir();
|
||||
|
||||
tempFile = File.createTempFile("temp", null, dir);
|
||||
|
||||
// Don't use auto closeable resources in try() as we would need too many try/catch clauses (for tempFile)
|
||||
// and we need to close it
|
||||
// manually before replacing file with temp file
|
||||
fileOutputStream = new FileOutputStream(tempFile);
|
||||
objectOutputStream = new ObjectOutputStream(fileOutputStream);
|
||||
|
||||
objectOutputStream.writeObject(serializable);
|
||||
|
||||
// Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide
|
||||
// to not write through to physical media for at least a few seconds, but this is the best we can do.
|
||||
fileOutputStream.flush();
|
||||
fileOutputStream.getFD().sync();
|
||||
|
||||
// Close resources before replacing file with temp file because otherwise it causes problems on windows
|
||||
// when rename temp file
|
||||
fileOutputStream.close();
|
||||
objectOutputStream.close();
|
||||
|
||||
renameTempFileToFile(tempFile, storageFile);
|
||||
} finally {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
log.warn("Temp file still exists after failed save.");
|
||||
if (!tempFile.delete()) log.error("Cannot delete temp file.");
|
||||
}
|
||||
|
||||
try {
|
||||
if (objectOutputStream != null)
|
||||
objectOutputStream.close();
|
||||
if (fileOutputStream != null)
|
||||
fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
// We swallow that
|
||||
e.printStackTrace();
|
||||
log.error("Cannot close resources.");
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void renameTempFileToFile(File tempFile, File file) throws IOException {
|
||||
lock.lock();
|
||||
try {
|
||||
if (Utils.isWindows()) {
|
||||
// Work around an issue on Windows whereby you can't rename over existing files.
|
||||
final File canonical = file.getCanonicalFile();
|
||||
if (canonical.exists() && !canonical.delete()) {
|
||||
throw new IOException("Failed to delete canonical file for replacement with save");
|
||||
}
|
||||
if (!tempFile.renameTo(canonical)) {
|
||||
throw new IOException("Failed to rename " + tempFile + " to " + canonical);
|
||||
}
|
||||
}
|
||||
else if (!tempFile.renameTo(file)) {
|
||||
throw new IOException("Failed to rename " + tempFile + " to " + file);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
141
core/src/main/java/io/bitsquare/storage/Storage.java
Normal file
141
core/src/main/java/io/bitsquare/storage/Storage.java
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.storage;
|
||||
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* That class handles the storage of a particular object to disk using Java serialisation.
|
||||
* To support evolving versions of the serialised data we need to take care that we don't break the object structure.
|
||||
* Java serialisation is tolerant with added fields, but removing or changing existing fields will break the backwards compatibility.
|
||||
* Alternative frameworks for serialisation like Kyro or mapDB have shown problems with version migration, so we stuck with plain Java
|
||||
* serialisation.
|
||||
* <p/>
|
||||
* For every data object we write a separate file to minimize the risk of corrupted files in case of inconsistency from newer versions.
|
||||
* In case of a corrupted file we backup the old file to a separate directory, so if it holds critical data it might be helpful for recovery.
|
||||
* <p/>
|
||||
* We also backup at first read the file, so we have a valid file form the latest version in case a write operation corrupted the file.
|
||||
* <p/>
|
||||
* The read operation is triggered just at object creation (startup) and is at the moment not executed on a background thread to avoid asynchronous behaviour.
|
||||
* As the data are small and it is just one read access the performance penalty is small and might be even worse to create and setup a thread for it.
|
||||
* <p/>
|
||||
* The write operation used a background thread and supports a delayed write to avoid too many repeated write operations.
|
||||
*/
|
||||
public class Storage<T extends Serializable> {
|
||||
private static final Logger log = LoggerFactory.getLogger(Storage.class);
|
||||
public static final String DIR_KEY = "storage.dir";
|
||||
|
||||
private final File dir;
|
||||
private FileManager<T> fileManager;
|
||||
private File storageFile;
|
||||
private T serializable;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public Storage(@Named(DIR_KEY) File dir) {
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
public T initAndGetPersisted(T serializable) {
|
||||
return initAndGetPersisted(serializable, serializable.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
public T initAndGetPersisted(T serializable, String fileName) {
|
||||
this.serializable = serializable;
|
||||
storageFile = new File(dir, fileName);
|
||||
fileManager = new FileManager<>(dir, storageFile, 500, TimeUnit.MILLISECONDS);
|
||||
|
||||
return getPersisted(serializable);
|
||||
}
|
||||
|
||||
// Save delayed and on a background thread
|
||||
public void save() {
|
||||
if (storageFile == null)
|
||||
throw new RuntimeException("storageFile = null. Call setupFileStorage before using read/write.");
|
||||
|
||||
fileManager.saveLater(serializable);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
fileManager.removeFile(serializable);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We do the file read on the UI thread to avoid problems from multi threading.
|
||||
// Data are small and read is done only at startup, so it is no performance issue.
|
||||
private T getPersisted(T serializable) {
|
||||
if (storageFile == null)
|
||||
throw new RuntimeException("storageFile = null. Call init before using read/write.");
|
||||
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
T persistedObject = (T) fileManager.read(storageFile);
|
||||
log.info("Read {} completed in {}msec", serializable.getClass().getSimpleName(), System.currentTimeMillis() - now);
|
||||
|
||||
// If we did not get any exception we can be sure the data are consistent so we make a backup
|
||||
now = System.currentTimeMillis();
|
||||
fileManager.backupFile(serializable);
|
||||
log.info("Backup {} completed in {}msec", serializable.getClass().getSimpleName(), System.currentTimeMillis() - now);
|
||||
|
||||
return persistedObject;
|
||||
} catch (InvalidClassException e) {
|
||||
log.error("Version of persisted class has changed. We cannot read the persisted data anymore. We make a backup and remove the inconsistent file.");
|
||||
try {
|
||||
// In case the persisted data have been critical (keys) we keep a backup which might be used for recovery
|
||||
fileManager.removeAndBackupFile(storageFile, new File(Paths.get(dir.getAbsolutePath(), "inconsistent").toString()),
|
||||
serializable.getClass().getSimpleName());
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
log.error(e1.getMessage());
|
||||
// We swallow Exception if backup fails
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
log.info("File not available. That is OK for the first run.");
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
log.error(e.getMessage());
|
||||
Popups.openErrorPopup("An exception occurred at reading data from disc.", e.getMessage());
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -33,7 +33,6 @@ import io.bitsquare.p2p.MailboxMessage;
|
||||
import io.bitsquare.p2p.MailboxService;
|
||||
import io.bitsquare.p2p.MessageService;
|
||||
import io.bitsquare.p2p.Peer;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.trade.handlers.TradeResultHandler;
|
||||
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
|
||||
@ -51,17 +50,16 @@ import io.bitsquare.user.User;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.File;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -72,7 +70,6 @@ public class TradeManager {
|
||||
|
||||
private final User user;
|
||||
private final AccountSettings accountSettings;
|
||||
private final Persistence persistence;
|
||||
private final MessageService messageService;
|
||||
private MailboxService mailboxService;
|
||||
private final AddressService addressService;
|
||||
@ -81,14 +78,15 @@ public class TradeManager {
|
||||
private final SignatureService signatureService;
|
||||
private EncryptionService<MailboxMessage> encryptionService;
|
||||
private final OfferBookService offerBookService;
|
||||
private File storageDir;
|
||||
|
||||
private final Map<String, TakerAsSellerProtocol> takerAsSellerProtocolMap = new HashMap<>();
|
||||
private final Map<String, OffererAsBuyerProtocol> offererAsBuyerProtocolMap = new HashMap<>();
|
||||
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
|
||||
|
||||
private final ObservableList<Trade> openOfferTrades = FXCollections.observableArrayList();
|
||||
private final ObservableList<Trade> pendingTrades = FXCollections.observableArrayList();
|
||||
private final ObservableList<Trade> closedTrades = FXCollections.observableArrayList();
|
||||
private final TradesList openOfferTrades;
|
||||
private final TradesList pendingTrades;
|
||||
private final TradesList closedTrades;
|
||||
private final Map<String, MailboxMessage> mailboxMessages = new HashMap<>();
|
||||
|
||||
|
||||
@ -97,13 +95,15 @@ public class TradeManager {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public TradeManager(User user, AccountSettings accountSettings, Persistence persistence,
|
||||
public TradeManager(User user, AccountSettings accountSettings, TradesList openOfferTrades, TradesList pendingTrades, TradesList closedTrades,
|
||||
MessageService messageService, MailboxService mailboxService, AddressService addressService, BlockChainService blockChainService,
|
||||
WalletService walletService, SignatureService signatureService, EncryptionService<MailboxMessage> encryptionService,
|
||||
OfferBookService offerBookService) {
|
||||
OfferBookService offerBookService, @Named("storage.dir") File storageDir) {
|
||||
this.user = user;
|
||||
this.accountSettings = accountSettings;
|
||||
this.persistence = persistence;
|
||||
this.openOfferTrades = openOfferTrades;
|
||||
this.pendingTrades = pendingTrades;
|
||||
this.closedTrades = closedTrades;
|
||||
this.messageService = messageService;
|
||||
this.mailboxService = mailboxService;
|
||||
this.addressService = addressService;
|
||||
@ -112,19 +112,7 @@ public class TradeManager {
|
||||
this.signatureService = signatureService;
|
||||
this.encryptionService = encryptionService;
|
||||
this.offerBookService = offerBookService;
|
||||
|
||||
Serializable openOffersObject = persistence.read(this, "openOffers");
|
||||
if (openOffersObject instanceof List<?>) {
|
||||
openOfferTrades.addAll((List<Trade>) openOffersObject);
|
||||
}
|
||||
Serializable pendingTradesObject = persistence.read(this, "pendingTrades");
|
||||
if (pendingTradesObject instanceof List<?>) {
|
||||
pendingTrades.addAll((List<Trade>) pendingTradesObject);
|
||||
}
|
||||
Serializable closedTradesObject = persistence.read(this, "closedTrades");
|
||||
if (closedTradesObject instanceof List<?>) {
|
||||
closedTrades.addAll((List<Trade>) closedTradesObject);
|
||||
}
|
||||
this.storageDir = storageDir;
|
||||
}
|
||||
|
||||
|
||||
@ -198,7 +186,6 @@ public class TradeManager {
|
||||
Trade trade = new Trade(offer);
|
||||
trade.setLifeCycleState(Trade.LifeCycleState.OPEN_OFFER);
|
||||
openOfferTrades.add(trade);
|
||||
persistOpenOfferTrades();
|
||||
|
||||
createOffererAsBuyerProtocol(trade);
|
||||
resultHandler.handleResult(transaction);
|
||||
@ -265,7 +252,7 @@ public class TradeManager {
|
||||
// TODO remove if check when persistence is impl.
|
||||
if (offererAsBuyerProtocolMap.containsKey(tradeId)) {
|
||||
offererAsBuyerProtocolMap.get(tradeId).onFiatPaymentStarted();
|
||||
persistPendingTrades();
|
||||
// persistPendingTrades();
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,9 +263,7 @@ public class TradeManager {
|
||||
public void onWithdrawAtTradeCompleted(Trade trade) {
|
||||
trade.setLifeCycleState(Trade.LifeCycleState.COMPLETED);
|
||||
pendingTrades.remove(trade);
|
||||
persistPendingTrades();
|
||||
closedTrades.add(trade);
|
||||
persistClosedTrades();
|
||||
removeFromProtocolMap(trade);
|
||||
}
|
||||
|
||||
@ -297,15 +282,15 @@ public class TradeManager {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ObservableList<Trade> getOpenOfferTrades() {
|
||||
return openOfferTrades;
|
||||
return openOfferTrades.getObservableList();
|
||||
}
|
||||
|
||||
public ObservableList<Trade> getPendingTrades() {
|
||||
return pendingTrades;
|
||||
return pendingTrades.getObservableList();
|
||||
}
|
||||
|
||||
public ObservableList<Trade> getClosedTrades() {
|
||||
return closedTrades;
|
||||
return closedTrades.getObservableList();
|
||||
}
|
||||
|
||||
|
||||
@ -329,12 +314,10 @@ public class TradeManager {
|
||||
if (result.isPresent()) {
|
||||
Trade trade = result.get();
|
||||
openOfferTrades.remove(trade);
|
||||
persistOpenOfferTrades();
|
||||
|
||||
if (isCancelRequest) {
|
||||
trade.setLifeCycleState(Trade.LifeCycleState.CANCELED);
|
||||
closedTrades.add(trade);
|
||||
persistClosedTrades();
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,7 +358,6 @@ public class TradeManager {
|
||||
trade.setTradingPeer(peer);
|
||||
trade.setLifeCycleState(Trade.LifeCycleState.PENDING);
|
||||
pendingTrades.add(trade);
|
||||
persistPendingTrades();
|
||||
|
||||
TakerAsSellerProtocol sellerTakesOfferProtocol = createTakerAsSellerProtocol(trade);
|
||||
//trade.setProtocol(sellerTakesOfferProtocol);
|
||||
@ -397,7 +379,7 @@ public class TradeManager {
|
||||
case FIAT_PAYMENT_STARTED:
|
||||
case FIAT_PAYMENT_RECEIVED:
|
||||
case PAYOUT_PUBLISHED:
|
||||
persistPendingTrades();
|
||||
// persistPendingTrades();
|
||||
break;
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
case FAULT:
|
||||
@ -418,7 +400,7 @@ public class TradeManager {
|
||||
blockChainService,
|
||||
signatureService,
|
||||
user,
|
||||
persistence);
|
||||
storageDir);
|
||||
|
||||
TakerAsSellerProtocol protocol = new TakerAsSellerProtocol(model);
|
||||
takerAsSellerProtocolMap.put(trade.getId(), protocol);
|
||||
@ -440,7 +422,7 @@ public class TradeManager {
|
||||
blockChainService,
|
||||
signatureService,
|
||||
user,
|
||||
persistence);
|
||||
storageDir);
|
||||
|
||||
|
||||
// TODO check, remove listener
|
||||
@ -450,7 +432,7 @@ public class TradeManager {
|
||||
case INIT:
|
||||
break;
|
||||
case TAKE_OFFER_FEE_TX_CREATED:
|
||||
persistPendingTrades();
|
||||
// persistPendingTrades();
|
||||
break;
|
||||
case DEPOSIT_PUBLISHED:
|
||||
removeOpenOffer(trade.getOffer(),
|
||||
@ -459,13 +441,12 @@ public class TradeManager {
|
||||
false);
|
||||
model.trade.setLifeCycleState(Trade.LifeCycleState.PENDING);
|
||||
pendingTrades.add(trade);
|
||||
persistPendingTrades();
|
||||
break;
|
||||
case DEPOSIT_CONFIRMED:
|
||||
case FIAT_PAYMENT_STARTED:
|
||||
case FIAT_PAYMENT_RECEIVED:
|
||||
case PAYOUT_PUBLISHED:
|
||||
persistPendingTrades();
|
||||
// persistPendingTrades();
|
||||
break;
|
||||
case TAKE_OFFER_FEE_PUBLISH_FAILED:
|
||||
case MESSAGE_SENDING_FAILED:
|
||||
@ -541,16 +522,4 @@ public class TradeManager {
|
||||
});
|
||||
}
|
||||
|
||||
private void persistOpenOfferTrades() {
|
||||
persistence.write(this, "openOfferTrades", (List<Trade>) new ArrayList<>(openOfferTrades));
|
||||
}
|
||||
|
||||
private void persistPendingTrades() {
|
||||
persistence.write(this, "pendingTrades", (List<Trade>) new ArrayList<>(pendingTrades));
|
||||
}
|
||||
|
||||
private void persistClosedTrades() {
|
||||
persistence.write(this, "closedTrades", (List<Trade>) new ArrayList<>(closedTrades));
|
||||
}
|
||||
|
||||
}
|
72
core/src/main/java/io/bitsquare/trade/TradesList.java
Normal file
72
core/src/main/java/io/bitsquare/trade/TradesList.java
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.trade;
|
||||
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TradesList extends ArrayList<Trade> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger log = LoggerFactory.getLogger(TradesList.class);
|
||||
|
||||
transient final private Storage<TradesList> storage;
|
||||
transient private ObservableList<Trade> observableList;
|
||||
|
||||
@Inject
|
||||
public TradesList(Storage<TradesList> storage) {
|
||||
this.storage = storage;
|
||||
|
||||
TradesList persisted = storage.initAndGetPersisted(this);
|
||||
if (persisted != null) {
|
||||
addAll(persisted);
|
||||
observableList = FXCollections.observableArrayList(this);
|
||||
}
|
||||
else {
|
||||
observableList = FXCollections.observableArrayList(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Trade trade) {
|
||||
boolean result = super.add(trade);
|
||||
storage.save();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object trade) {
|
||||
boolean result = super.remove(trade);
|
||||
storage.save();
|
||||
return result;
|
||||
}
|
||||
|
||||
public ObservableList<Trade> getObservableList() {
|
||||
return observableList;
|
||||
}
|
||||
}
|
@ -26,7 +26,6 @@ import io.bitsquare.offer.Offer;
|
||||
import io.bitsquare.p2p.MailboxMessage;
|
||||
import io.bitsquare.p2p.MailboxService;
|
||||
import io.bitsquare.p2p.MessageService;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -45,7 +44,6 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
|
||||
transient public final WalletService walletService;
|
||||
transient public final BlockChainService blockChainService;
|
||||
transient public final SignatureService signatureService;
|
||||
transient protected final Persistence persistence;
|
||||
|
||||
transient public MailboxMessage mailboxMessage;
|
||||
|
||||
@ -62,15 +60,13 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
|
||||
MailboxService mailboxService,
|
||||
WalletService walletService,
|
||||
BlockChainService blockChainService,
|
||||
SignatureService signatureService,
|
||||
Persistence persistence) {
|
||||
SignatureService signatureService) {
|
||||
this.offer = offer;
|
||||
this.messageService = messageService;
|
||||
this.mailboxService = mailboxService;
|
||||
this.walletService = walletService;
|
||||
this.blockChainService = blockChainService;
|
||||
this.signatureService = signatureService;
|
||||
this.persistence = persistence;
|
||||
|
||||
id = offer.getId();
|
||||
tradeWalletService = walletService.getTradeWalletService();
|
||||
|
@ -22,11 +22,12 @@ import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.crypto.SignatureService;
|
||||
import io.bitsquare.p2p.MailboxService;
|
||||
import io.bitsquare.p2p.MessageService;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.SharedTradeModel;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -34,9 +35,11 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
public class OffererAsBuyerModel extends SharedTradeModel implements Serializable {
|
||||
private static final long serialVersionUID = 5000457153390911569L;
|
||||
private static final Logger log = LoggerFactory.getLogger(OffererAsBuyerModel.class);
|
||||
transient private static final Logger log = LoggerFactory.getLogger(OffererAsBuyerModel.class);
|
||||
|
||||
transient private Storage<OffererAsBuyerModel> storage;
|
||||
transient public final Trade trade;
|
||||
|
||||
public final Taker taker;
|
||||
public final Offerer offerer;
|
||||
|
||||
@ -50,26 +53,25 @@ public class OffererAsBuyerModel extends SharedTradeModel implements Serializabl
|
||||
BlockChainService blockChainService,
|
||||
SignatureService signatureService,
|
||||
User user,
|
||||
Persistence persistence) {
|
||||
File storageDir) {
|
||||
super(trade.getOffer(),
|
||||
messageService,
|
||||
mailboxService,
|
||||
walletService,
|
||||
blockChainService,
|
||||
signatureService,
|
||||
persistence);
|
||||
signatureService);
|
||||
|
||||
this.trade = trade;
|
||||
|
||||
Serializable serializable = persistence.read(this, "BuyerAsOffererModel_" + id);
|
||||
if (serializable instanceof OffererAsBuyerModel) {
|
||||
OffererAsBuyerModel persistedModel = (OffererAsBuyerModel) serializable;
|
||||
this.storage = new Storage<>(storageDir);
|
||||
|
||||
OffererAsBuyerModel persisted = storage.initAndGetPersisted(this, getClass().getSimpleName() + id);
|
||||
if (persisted != null) {
|
||||
log.debug("Model reconstructed form persisted model.");
|
||||
|
||||
setTakeOfferFeeTxId(persistedModel.takeOfferFeeTxId);
|
||||
setTakeOfferFeeTxId(persisted.takeOfferFeeTxId);
|
||||
|
||||
taker = persistedModel.taker;
|
||||
offerer = persistedModel.offerer;
|
||||
taker = persisted.taker;
|
||||
offerer = persisted.offerer;
|
||||
}
|
||||
else {
|
||||
taker = new Taker();
|
||||
@ -90,13 +92,13 @@ public class OffererAsBuyerModel extends SharedTradeModel implements Serializabl
|
||||
// Get called form taskRunner after each completed task
|
||||
@Override
|
||||
public void persist() {
|
||||
persistence.write(this, "BuyerAsOffererModel_" + id, this);
|
||||
storage.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
// Just in case of successful completion we delete our persisted object
|
||||
persistence.remove(this, "BuyerAsOffererModel_" + id);
|
||||
storage.remove();
|
||||
}
|
||||
|
||||
public String getTakeOfferFeeTxId() {
|
||||
|
@ -22,13 +22,14 @@ import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.crypto.SignatureService;
|
||||
import io.bitsquare.p2p.MailboxService;
|
||||
import io.bitsquare.p2p.MessageService;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.protocol.trade.SharedTradeModel;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import org.bitcoinj.core.Transaction;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -36,9 +37,11 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TakerAsSellerModel extends SharedTradeModel implements Serializable {
|
||||
private static final long serialVersionUID = -963501132927618376L;
|
||||
private static final Logger log = LoggerFactory.getLogger(TakerAsSellerModel.class);
|
||||
transient private static final Logger log = LoggerFactory.getLogger(TakerAsSellerModel.class);
|
||||
|
||||
transient private Storage<TakerAsSellerModel> storage;
|
||||
transient public final Trade trade;
|
||||
|
||||
public final Trade trade;
|
||||
public final Taker taker;
|
||||
public final Offerer offerer;
|
||||
|
||||
@ -52,28 +55,27 @@ public class TakerAsSellerModel extends SharedTradeModel implements Serializable
|
||||
WalletService walletService,
|
||||
BlockChainService blockChainService,
|
||||
SignatureService signatureService,
|
||||
User user,
|
||||
Persistence persistence) {
|
||||
User user,
|
||||
File storageDir) {
|
||||
super(trade.getOffer(),
|
||||
messageService,
|
||||
mailboxService,
|
||||
walletService,
|
||||
blockChainService,
|
||||
signatureService,
|
||||
persistence);
|
||||
signatureService);
|
||||
|
||||
this.trade = trade;
|
||||
this.storage = new Storage<>(storageDir);
|
||||
|
||||
Serializable serializable = persistence.read(this, "SellerAsTakerModel_" + id);
|
||||
if (serializable instanceof TakerAsSellerModel) {
|
||||
TakerAsSellerModel persistedModel = (TakerAsSellerModel) serializable;
|
||||
log.debug("Model reconstructed form persisted model.");
|
||||
TakerAsSellerModel persisted = storage.initAndGetPersisted(this, getClass().getSimpleName() + id);
|
||||
if (persisted != null) {
|
||||
log.debug("Model reconstructed from persisted model.");
|
||||
|
||||
setTakeOfferFeeTx(persistedModel.getTakeOfferFeeTx());
|
||||
setPayoutTx(persistedModel.payoutTx);
|
||||
setTakeOfferFeeTx(persisted.getTakeOfferFeeTx());
|
||||
setPayoutTx(persisted.payoutTx);
|
||||
|
||||
taker = persistedModel.taker;
|
||||
offerer = persistedModel.offerer;
|
||||
taker = persisted.taker;
|
||||
offerer = persisted.offerer;
|
||||
}
|
||||
else {
|
||||
taker = new Taker();
|
||||
@ -93,13 +95,13 @@ public class TakerAsSellerModel extends SharedTradeModel implements Serializable
|
||||
// Get called form taskRunner after each completed task
|
||||
@Override
|
||||
public void persist() {
|
||||
persistence.write(this, "SellerAsTakerModel_" + id, this);
|
||||
storage.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
// Just in case of successful completion we delete our persisted object
|
||||
persistence.remove(this, "SellerAsTakerModel_" + id);
|
||||
storage.remove();
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ import io.bitsquare.arbitration.Arbitrator;
|
||||
import io.bitsquare.locale.Country;
|
||||
import io.bitsquare.locale.CountryUtil;
|
||||
import io.bitsquare.locale.LanguageUtil;
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
||||
@ -44,6 +44,7 @@ public class AccountSettings implements Serializable {
|
||||
private List<Locale> acceptedLanguageLocales = new ArrayList<>();
|
||||
private List<Country> acceptedCountryLocales = new ArrayList<>();
|
||||
private List<Arbitrator> acceptedArbitrators = new ArrayList<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
@ -53,7 +54,7 @@ public class AccountSettings implements Serializable {
|
||||
public AccountSettings(Storage<AccountSettings> storage, Arbitrator defaultArbitrator) {
|
||||
this.storage = storage;
|
||||
|
||||
AccountSettings persisted = storage.getPersisted(this);
|
||||
AccountSettings persisted = storage.initAndGetPersisted(this);
|
||||
if (persisted != null) {
|
||||
acceptedLanguageLocales = persisted.getAcceptedLanguageLocales();
|
||||
acceptedCountryLocales = persisted.getAcceptedCountries();
|
||||
@ -106,7 +107,7 @@ public class AccountSettings implements Serializable {
|
||||
storage.save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
package io.bitsquare.user;
|
||||
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
|
||||
@ -53,13 +53,13 @@ public class Preferences implements Serializable {
|
||||
private String _btcDenomination = MonetaryFormat.CODE_BTC;
|
||||
private Boolean _useAnimations = true;
|
||||
private Boolean _useEffects = true;
|
||||
private Boolean displaySecurityDepositInfo = true;
|
||||
|
||||
// Observable wrappers
|
||||
transient private final StringProperty btcDenomination = new SimpleStringProperty(_btcDenomination);
|
||||
transient private final BooleanProperty useAnimations = new SimpleBooleanProperty(_useAnimations);
|
||||
transient private final BooleanProperty useEffects = new SimpleBooleanProperty(_useEffects);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -68,11 +68,12 @@ public class Preferences implements Serializable {
|
||||
public Preferences(Storage<Preferences> storage) {
|
||||
this.storage = storage;
|
||||
|
||||
Preferences persisted = storage.getPersisted(this);
|
||||
Preferences persisted = storage.initAndGetPersisted(this);
|
||||
if (persisted != null) {
|
||||
setBtcDenomination(persisted._btcDenomination);
|
||||
setUseAnimations(persisted._useAnimations);
|
||||
setUseEffects(persisted._useEffects);
|
||||
displaySecurityDepositInfo = persisted.getDisplaySecurityDepositInfo();
|
||||
}
|
||||
|
||||
// Use that to guarantee update of the serializable field and to make a storage update in case of a change
|
||||
@ -107,6 +108,11 @@ public class Preferences implements Serializable {
|
||||
this.useEffects.set(useEffects);
|
||||
}
|
||||
|
||||
public void setDisplaySecurityDepositInfo(Boolean displaySecurityDepositInfo) {
|
||||
this.displaySecurityDepositInfo = displaySecurityDepositInfo;
|
||||
storage.save();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getter
|
||||
@ -124,6 +130,10 @@ public class Preferences implements Serializable {
|
||||
return useAnimations.get();
|
||||
}
|
||||
|
||||
public Boolean getDisplaySecurityDepositInfo() {
|
||||
return displaySecurityDepositInfo;
|
||||
}
|
||||
|
||||
public StringProperty btcDenominationProperty() {
|
||||
return btcDenomination;
|
||||
}
|
||||
@ -135,4 +145,6 @@ public class Preferences implements Serializable {
|
||||
public BooleanProperty useEffectsProperty() {
|
||||
return useEffects;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ package io.bitsquare.user;
|
||||
import io.bitsquare.crypto.EncryptionService;
|
||||
import io.bitsquare.fiat.FiatAccount;
|
||||
import io.bitsquare.gui.components.Popups;
|
||||
import io.bitsquare.persistence.Storage;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@ -72,7 +72,7 @@ public class User implements Serializable {
|
||||
this.storage = storage;
|
||||
this.encryptionService = encryptionService;
|
||||
|
||||
User persisted = storage.getPersisted(this);
|
||||
User persisted = storage.initAndGetPersisted(this);
|
||||
if (persisted != null) {
|
||||
p2pSigKeyPair = persisted.getP2pSigKeyPair();
|
||||
p2pEncryptKeyPair = persisted.getP2pEncryptKeyPair();
|
||||
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* This file is part of Bitsquare.
|
||||
*
|
||||
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.util;
|
||||
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.bitcoinj.utils.Threading;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FileUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
|
||||
private static final ReentrantLock lock = Threading.lock("FileUtil");
|
||||
|
||||
public static void write(Serializable serializable, File dir, File storageFile) throws IOException {
|
||||
lock.lock();
|
||||
File tempFile = null;
|
||||
FileOutputStream fileOutputStream = null;
|
||||
ObjectOutputStream objectOutputStream = null;
|
||||
try {
|
||||
if (!dir.exists())
|
||||
dir.mkdir();
|
||||
|
||||
tempFile = File.createTempFile("temp", null, dir);
|
||||
|
||||
// Don't use auto closeable resources in try() as we would need too many try/catch clauses (for tempFile)
|
||||
// and we need to close it
|
||||
// manually before replacing file with temp file
|
||||
fileOutputStream = new FileOutputStream(tempFile);
|
||||
objectOutputStream = new ObjectOutputStream(fileOutputStream);
|
||||
|
||||
objectOutputStream.writeObject(serializable);
|
||||
|
||||
// Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide
|
||||
// to not write through to physical media for at least a few seconds, but this is the best we can do.
|
||||
fileOutputStream.flush();
|
||||
fileOutputStream.getFD().sync();
|
||||
|
||||
// Close resources before replacing file with temp file because otherwise it causes problems on windows
|
||||
// when rename temp file
|
||||
fileOutputStream.close();
|
||||
objectOutputStream.close();
|
||||
|
||||
writeTempFileToFile(tempFile, storageFile);
|
||||
} finally {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
log.warn("Temp file still exists after failed save.");
|
||||
if (!tempFile.delete()) log.error("Cannot delete temp file.");
|
||||
}
|
||||
|
||||
try {
|
||||
if (objectOutputStream != null)
|
||||
objectOutputStream.close();
|
||||
if (fileOutputStream != null)
|
||||
fileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
// We swallow that
|
||||
e.printStackTrace();
|
||||
log.error("Cannot close resources.");
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object read(File file) throws IOException, ClassNotFoundException {
|
||||
lock.lock();
|
||||
try (final FileInputStream fileInputStream = new FileInputStream(file);
|
||||
final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
|
||||
return objectInputStream.readObject();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeTempFileToFile(File tempFile, File file) throws IOException {
|
||||
lock.lock();
|
||||
try {
|
||||
if (Utils.isWindows()) {
|
||||
// Work around an issue on Windows whereby you can't rename over existing files.
|
||||
final File canonical = file.getCanonicalFile();
|
||||
if (canonical.exists() && !canonical.delete()) {
|
||||
throw new IOException("Failed to delete canonical file for replacement with save");
|
||||
}
|
||||
if (!tempFile.renameTo(canonical)) {
|
||||
throw new IOException("Failed to rename " + tempFile + " to " + canonical);
|
||||
}
|
||||
}
|
||||
else if (!tempFile.renameTo(file)) {
|
||||
throw new IOException("Failed to rename " + tempFile + " to " + file);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeAndBackupFile(File storageFile, File dir, String name) throws IOException {
|
||||
if (!dir.exists())
|
||||
dir.mkdir();
|
||||
|
||||
writeTempFileToFile(storageFile, new File(dir, name));
|
||||
}
|
||||
|
||||
public static void backupFile(File storageFile, File dir, String name) throws IOException {
|
||||
if (!dir.exists())
|
||||
dir.mkdir();
|
||||
|
||||
Files.copy(storageFile, new File(dir, name));
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ public class CreateOfferViewModelTest {
|
||||
BSFormatter formatter = new BSFormatter(new User());
|
||||
formatter.setLocale(Locale.US);
|
||||
formatter.setFiatCurrencyCode("USD");
|
||||
model = new CreateOfferDataModel(null, null, null, null, null, null, formatter);
|
||||
model = new CreateOfferDataModel(null, null, null, null, null, formatter);
|
||||
|
||||
presenter = new CreateOfferViewModel(model, new FiatValidator(null), new BtcValidator(), formatter);
|
||||
}
|
||||
|
@ -17,38 +17,21 @@
|
||||
|
||||
package io.bitsquare.trade.protocol.placeoffer;
|
||||
|
||||
import io.bitsquare.btc.BitcoinNetwork;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.UserAgent;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.offer.OfferBookService;
|
||||
import io.bitsquare.offer.tomp2p.TomP2POfferBookService;
|
||||
import io.bitsquare.p2p.BootstrapState;
|
||||
import io.bitsquare.p2p.MessageService;
|
||||
import io.bitsquare.p2p.Node;
|
||||
import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
|
||||
import io.bitsquare.p2p.tomp2p.TomP2PMessageService;
|
||||
import io.bitsquare.p2p.tomp2p.TomP2PNode;
|
||||
import io.bitsquare.persistence.Persistence;
|
||||
import io.bitsquare.user.User;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.utils.Threading;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* That test is ignored for automated testing as it needs custom setup.
|
||||
* <p/>
|
||||
@ -72,22 +55,19 @@ public class PlaceOfferProtocolTest {
|
||||
private TomP2PNode tomP2PNode;
|
||||
private BootstrappedPeerBuilder bootstrappedPeerBuilder;
|
||||
|
||||
@Before
|
||||
/* @Before
|
||||
public void setup() throws InterruptedException {
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
dir.mkdirs();
|
||||
|
||||
Persistence persistence = new Persistence(dir, "prefs");
|
||||
persistence.init();
|
||||
|
||||
// messageService
|
||||
Node bootstrapNode = Node.at("localhost", "127.0.0.1");
|
||||
User user = new User();
|
||||
/* try {
|
||||
*//* try {
|
||||
user.initPersistedObject();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
}*//*
|
||||
bootstrappedPeerBuilder = new BootstrappedPeerBuilder(Node.DEFAULT_PORT, false, bootstrapNode, "<unspecified>");
|
||||
tomP2PNode = new TomP2PNode(bootstrappedPeerBuilder);
|
||||
messageService = new TomP2PMessageService(tomP2PNode, null, null, null);
|
||||
@ -153,7 +133,7 @@ public class PlaceOfferProtocolTest {
|
||||
public void shutDown() throws IOException, InterruptedException {
|
||||
walletService.shutDown();
|
||||
bootstrappedPeerBuilder.shutDown();
|
||||
}
|
||||
}*/
|
||||
|
||||
/* @Test
|
||||
public void validateOfferTest() throws InterruptedException {
|
||||
|
Loading…
x
Reference in New Issue
Block a user