Add support for new release download, Fix bug with empty log file

This commit is contained in:
Manfred Karrer 2015-05-21 12:56:07 +02:00
parent 5cc6c5c552
commit 9594ab96cf
23 changed files with 165 additions and 139 deletions

View file

@ -35,6 +35,8 @@ import com.google.inject.Injector;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@ -53,6 +55,7 @@ import org.controlsfx.dialog.Dialogs;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Logger;
import com.vinumeris.updatefx.UpdateFX;
import org.springframework.core.env.Environment;
import static io.bitsquare.app.BitsquareEnvironment.APP_NAME_KEY;
@ -72,6 +75,7 @@ public class BitsquareApp extends Application {
private MainView mainView;
public static Runnable shutDownHandler;
public static Runnable restartDownHandler;
public static void setEnvironment(Environment env) {
BitsquareApp.env = env;
@ -81,7 +85,10 @@ public class BitsquareApp extends Application {
public void start(Stage primaryStage) throws IOException {
this.primaryStage = primaryStage;
Logging.setup(Paths.get(env.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY), "bitsquare").toString());
shutDownHandler = this::stop;
restartDownHandler = this::restart;
// setup UncaughtExceptionHandler
Thread.UncaughtExceptionHandler handler = (thread, throwable) -> {
@ -103,12 +110,6 @@ public class BitsquareApp extends Application {
URI.create("http://188.226.179.109/crashfx/upload"));*/
// Server not setup yet, so we use client side only support
Storage.setDatabaseCorruptionHandler((String fileName) -> {
corruptedDatabaseFiles.add(fileName);
if (mainView != null)
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
});
// Guice
bitsquareAppModule = new BitsquareAppModule(env, primaryStage);
injector = Guice.createInjector(bitsquareAppModule);
@ -119,6 +120,12 @@ public class BitsquareApp extends Application {
mainView = (MainView) viewLoader.load(MainView.class);
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
Storage.setDatabaseCorruptionHandler((String fileName) -> {
corruptedDatabaseFiles.add(fileName);
if (mainView != null)
mainView.setPersistedFilesCorrupted(corruptedDatabaseFiles);
});
scene = new Scene(mainView.getRoot(), 1000, 650);
scene.getStylesheets().setAll(
"/io/bitsquare/gui/bitsquare.css",
@ -218,4 +225,14 @@ public class BitsquareApp extends Application {
bitsquareAppModule.close(injector);
System.exit(0);
}
public void restart() {
try {
bitsquareAppModule.close(injector);
UpdateFX.restartApp();
} catch (Throwable t) {
// in dev mode restart does not work
stop();
}
}
}

View file

@ -1,71 +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.app;
import io.bitsquare.btc.UserAgent;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.KeyStorage;
import io.bitsquare.gui.main.MainView;
import io.bitsquare.p2p.tomp2p.TomP2PModule;
import io.bitsquare.storage.Storage;
import java.nio.file.Paths;
import java.util.Properties;
import joptsimple.OptionSet;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
public class BitsquareAppEnvironment extends BitsquareEnvironment {
public BitsquareAppEnvironment(OptionSet options) {
super(options);
}
BitsquareAppEnvironment(PropertySource commandLineProperties) {
super(commandLineProperties);
}
@Override
protected PropertySource<?> defaultProperties() {
return new PropertiesPropertySource(BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME, new Properties() {
private static final long serialVersionUID = -8478089705207326165L;
{
setProperty(APP_DATA_DIR_KEY, appDataDir);
setProperty(APP_DATA_DIR_CLEAN_KEY, DEFAULT_APP_DATA_DIR_CLEAN);
setProperty(APP_NAME_KEY, appName);
setProperty(UserAgent.NAME_KEY, appName);
setProperty(UserAgent.VERSION_KEY, Version.VERSION);
setProperty(WalletService.DIR_KEY, appDataDir);
setProperty(WalletService.PREFIX_KEY, appName);
setProperty(Storage.DIR_KEY, Paths.get(appDataDir, "db").toString());
setProperty(KeyStorage.DIR_KEY, Paths.get(appDataDir, "keys").toString());
setProperty(MainView.TITLE_KEY, appName);
setProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY, bootstrapNodePort);
}
});
}
}

View file

@ -67,15 +67,12 @@ public class BitsquareAppMain extends BitsquareExecutable {
System.exit(EXIT_FAILURE);
return;
}
BitsquareAppEnvironment bitsquareEnvironment = new BitsquareAppEnvironment(options);
String updatesDirectory = bitsquareEnvironment.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY);
BitsquareEnvironment bitsquareEnvironment = new BitsquareEnvironment(options);
Logging.setup(Paths.get(bitsquareEnvironment.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY), "bitsquare").toString());
// update dir need to be setup before UpdateFX bootstrap
initAppDir(bitsquareEnvironment.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY));
// app dir need to be setup before UpdateFX bootstrap
initAppDir(updatesDirectory);
UpdateFX.bootstrap(BitsquareAppMain.class, new File(updatesDirectory).toPath(), args);
UpdateFX.bootstrap(BitsquareAppMain.class, new File(bitsquareEnvironment.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY)).toPath(), args);
}
// That will be called from UpdateFX after updates are checked
@ -151,7 +148,7 @@ public class BitsquareAppMain extends BitsquareExecutable {
@Override
protected void doExecute(OptionSet options) {
BitsquareApp.setEnvironment(new BitsquareAppEnvironment(options));
BitsquareApp.setEnvironment(new BitsquareEnvironment(options));
javafx.application.Application.launch(BitsquareApp.class);
}
}

View file

@ -21,6 +21,8 @@ import io.bitsquare.util.Utilities;
import com.google.inject.Inject;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -38,7 +40,6 @@ import com.vinumeris.updatefx.UpdateFX;
import com.vinumeris.updatefx.UpdateSummary;
import com.vinumeris.updatefx.Updater;
import org.bouncycastle.math.ec.ECPoint;
import org.springframework.core.env.Environment;
import rx.Observable;
import rx.subjects.BehaviorSubject;
import rx.subjects.Subject;
@ -46,25 +47,26 @@ import rx.subjects.Subject;
public class UpdateProcess {
private static final Logger log = LoggerFactory.getLogger(UpdateProcess.class);
private static final List<ECPoint> UPDATE_SIGNING_KEYS = Crypto.decode("038396415C265C59042AB05A5436356E8D0FA19F13E3DE4915AFF763CB4785345E");
private static final String UPDATES_BASE_URL = "http://bitsquare.io/updateFX/";
private static final List<ECPoint> UPDATE_SIGNING_KEYS = Crypto.decode("029EF2D0D33A2546CB15FB10D969B7D65CAFB811CB3AC902E8D9A46BE847B1DA21");
private static final String UPDATES_BASE_URL = "https://bitsquare.io/updateFX/v03";
private static final int UPDATE_SIGNING_THRESHOLD = 1;
private static final Path ROOT_CLASS_PATH = UpdateFX.findCodePath(BitsquareAppMain.class);
private final Environment environment;
private final BitsquareEnvironment environment;
public enum State {
CHECK_FOR_UPDATES,
UPDATE_AVAILABLE,
UP_TO_DATE,
NEW_RELEASE, // if a new minor release is out we inform the user to download the new binary
FAILURE
}
public final ObjectProperty<State> state = new SimpleObjectProperty<>(State.CHECK_FOR_UPDATES);
protected String errorMessage;
protected final Subject<State, State> process = BehaviorSubject.create();
protected Timer timeoutTimer;
private String releaseUrl;
private final Subject<State, State> process = BehaviorSubject.create();
private Timer timeoutTimer;
@Inject
public UpdateProcess(BitsquareEnvironment environment) {
@ -79,24 +81,35 @@ public class UpdateProcess {
return process.asObservable();
}
public String getErrorMessage() {
return errorMessage;
}
public void init() {
log.info("UpdateFX current version " + Version.PATCH_VERSION);
// process.timeout() will cause an error state back but we don't want to break startup in case of an timeout
timeoutTimer = Utilities.setTimeout(10000, () -> process.onCompleted());
timeoutTimer = Utilities.setTimeout(10000, () -> {
log.error("Timeout reached for UpdateFX");
process.onCompleted();
});
String userAgent = environment.getProperty(BitsquareEnvironment.APP_NAME_KEY) + Version.VERSION;
String agent = environment.getProperty(BitsquareEnvironment.APP_NAME_KEY) + Version.VERSION;
// Check if there is a new minor version release out. The release_url should be empty if no release is available, otherwise the download url.
try {
releaseUrl = Utilities.readTextFileFromServer(UPDATES_BASE_URL + "/release_url", userAgent);
if (releaseUrl != null && releaseUrl.length() > 0) {
log.info("New release available at: " + releaseUrl);
state.set(State.NEW_RELEASE);
timeoutTimer.cancel();
return;
}
else {
// All ok. Empty file if we have no new release.
}
} catch (IOException e) {
// ignore. File might be missing
}
// We use the outer dir not the app data dir including version and btc network
Path dataDirPath = Paths.get(environment.getProperty(BitsquareEnvironment.USER_DATA_DIR_KEY),
environment.getProperty(BitsquareEnvironment.APP_NAME_KEY));
Updater updater = new Updater(UPDATES_BASE_URL, agent, Version.PATCH_VERSION, dataDirPath, ROOT_CLASS_PATH,
UPDATE_SIGNING_KEYS, UPDATE_SIGNING_THRESHOLD) {
Updater updater = new Updater(UPDATES_BASE_URL, userAgent, Version.PATCH_VERSION,
Paths.get(environment.getProperty(BitsquareEnvironment.APP_DATA_DIR_KEY)),
ROOT_CLASS_PATH, UPDATE_SIGNING_KEYS, UPDATE_SIGNING_THRESHOLD) {
@Override
protected void updateProgress(long workDone, long max) {
//log.trace("updateProgress " + workDone + "/" + max);
@ -135,7 +148,6 @@ public class UpdateProcess {
// we treat errors as update not as critical errors to prevent startup,
// so we use state.onCompleted() instead of state.onError()
errorMessage = "Exception at processing UpdateSummary: " + e.getMessage();
state.set(State.FAILURE);
timeoutTimer.cancel();
process.onCompleted();
@ -147,7 +159,6 @@ public class UpdateProcess {
// we treat errors as update not as critical errors to prevent startup,
// so we use state.onCompleted() instead of state.onError()
errorMessage = "Update failed: " + updater.getException();
state.set(State.FAILURE);
timeoutTimer.cancel();
process.onCompleted();
@ -157,4 +168,8 @@ public class UpdateProcess {
thread.setDaemon(true);
thread.start();
}
public String getReleaseUrl() {
return releaseUrl;
}
}

View file

@ -18,6 +18,7 @@
package io.bitsquare.gui;
import io.bitsquare.BitsquareModule;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.gui.common.fxml.FxmlViewLoader;
import io.bitsquare.gui.common.view.CachingViewLoader;
import io.bitsquare.gui.common.view.ViewFactory;
@ -78,6 +79,6 @@ public class GuiModule extends BitsquareModule {
bind(Stage.class).toInstance(primaryStage);
Popups.primaryStage = primaryStage;
bindConstant().annotatedWith(Names.named(MainView.TITLE_KEY)).to(env.getRequiredProperty(MainView.TITLE_KEY));
bindConstant().annotatedWith(Names.named(MainView.TITLE_KEY)).to(env.getRequiredProperty(BitsquareEnvironment.APP_NAME_KEY));
}
}

View file

@ -99,6 +99,7 @@ public class TxIdTextField extends AnchorPane {
try {
// TODO get the url form the app preferences
Utilities.openWebPage("https://www.biteasy.com/testnet/transactions/" + txID);
// https://insight.bitpay.com/ only mainnet?
//Utilities.openURL("https://blockchain.info/tx/" + txID);
} catch (Exception e) {
log.error(e.getMessage());

View file

@ -37,6 +37,7 @@ import io.bitsquare.gui.main.offer.SellOfferView;
import io.bitsquare.gui.main.portfolio.PortfolioView;
import io.bitsquare.gui.main.settings.SettingsView;
import io.bitsquare.gui.util.Transitions;
import io.bitsquare.util.Utilities;
import java.util.List;
@ -75,12 +76,14 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private ChangeListener<Number> bootstrapProgressListener;
private ChangeListener<String> updateIconIdListener;
private Button restartButton;
private Button downloadButton;
private ProgressIndicator bootstrapIndicator;
private Label bootstrapStateLabel;
private ProgressBar blockchainSyncIndicator;
private Label blockchainSyncLabel;
private Label updateInfoLabel;
private List<String> persistedFilesCorrupted;
private Tooltip downloadButtonTooltip;
@Inject
public MainView(MainViewModel model, CachingViewLoader viewLoader, Navigation navigation, Transitions transitions,
@ -296,6 +299,22 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
restartButton.managedProperty().bind(model.showRestartButton);
restartButton.setOnAction(e -> model.restart());
downloadButton = new Button("Download");
downloadButton.setDefaultButton(true);
downloadButton.visibleProperty().bind(model.showDownloadButton);
downloadButton.managedProperty().bind(model.showDownloadButton);
downloadButtonTooltip = new Tooltip();
downloadButtonTooltip.textProperty().bind(model.newReleaseUrl);
downloadButton.setTooltip(downloadButtonTooltip);
downloadButton.setOnAction(e -> {
try {
Utilities.openWebPage(model.newReleaseUrl.get());
} catch (Exception e1) {
e1.printStackTrace();
log.error(e1.getMessage());
}
});
ImageView updateIcon = new ImageView();
updateIcon.setId(model.updateIconId.get());
@ -310,7 +329,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
updateBox.setSpacing(10);
updateBox.setAlignment(Pos.CENTER);
updateBox.setPrefHeight(20);
updateBox.getChildren().addAll(updateInfoLabel, restartButton, updateIcon);
updateBox.getChildren().addAll(updateInfoLabel, restartButton, downloadButton, updateIcon);
vBox.getChildren().addAll(logo, blockchainSyncBox, bootstrapBox, updateBox);
return vBox;
@ -331,6 +350,9 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
updateInfoLabel.textProperty().unbind();
restartButton.visibleProperty().unbind();
restartButton.managedProperty().unbind();
downloadButton.visibleProperty().unbind();
downloadButton.managedProperty().unbind();
downloadButtonTooltip.textProperty().unbind();
}

View file

@ -100,6 +100,8 @@ class MainViewModel implements ViewModel {
String version = "v." + Version.VERSION;
final BooleanProperty showRestartButton = new SimpleBooleanProperty(false);
final BooleanProperty showDownloadButton = new SimpleBooleanProperty(false);
final StringProperty newReleaseUrl = new SimpleStringProperty();
final StringProperty updateIconId = new SimpleStringProperty();
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
@ -295,8 +297,14 @@ class MainViewModel implements ViewModel {
updateInfo.set("Software is up to date. Version: " + Version.VERSION);
updateIconId.set("image-update-up-to-date");
break;
case NEW_RELEASE:
updateInfo.set("A new release is available.");
updateIconId.set("image-update-available");
newReleaseUrl.set(updateProcess.getReleaseUrl());
showDownloadButton.setValue(true);
break;
case FAILURE:
updateInfo.set("Check for updates failed. ");
updateInfo.set("Check for updates failed.");
updateIconId.set("image-update-failed");
break;
}

View file

@ -118,7 +118,7 @@ public class NetworkSettingsView extends InitializableView {
"Do you want to shutdown now?", actions);
if (Popups.isYes(response))
BitsquareApp.shutDownHandler.run();
BitsquareApp.restartDownHandler.run();
}
}

View file

@ -6,18 +6,18 @@
</encoder>
</appender>
<root level="WARN">
<root level="INFO">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
<logger name="io.bitsquare" level="TRACE"/>
<logger name="io.bitsquare" level="DEBUG"/>
<logger name="io.bitsquare.btc.AddressBasedCoinSelector" level="OFF"/>
<logger name="io.bitsquare.gui.util.Profiler" level="ERROR"/>
<logger name="io.bitsquare.locale.BSResources" level="ERROR"/>
<logger name="org.bitcoinj" level="WARN"/>
<logger name="net.tomp2p" level="WARN"/>
<logger name="org.bitcoinj" level="INFO"/>
<logger name="net.tomp2p" level="INFO"/>
<logger name="org.bitcoinj.core.BitcoinSerializer" level="WARN"/>
<logger name="org.bitcoinj.core.Peer" level="WARN"/>

View file

@ -0,0 +1,7 @@
Release notes:
- Bootstrap to all bootstrap nodes
- Separeate btc network by directories in data dir
- Add support for new release download
- Only use mailbox for certain P2P messages
- Bootstrap node update
- Fix bug with empty log file