Skip to content
This repository has been archived by the owner on Feb 2, 2021. It is now read-only.

Commit

Permalink
Big refactor / rewrite / convert to Kotlin of backend code, part one:
Browse files Browse the repository at this point in the history
• Remove the DiskManager and with it disk watching in all but the server.
• Fixes some bugs and deletes a lot of last minute pre-beta hacks.
• Converts the directory watcher code to Kotlin and adds duplicate suppression so the server doesn't try and load half-copied files anymore.

Fixes #190
Makes progress on #191
  • Loading branch information
mikehearn committed Jul 22, 2015
1 parent be3cf22 commit e3c1ae4
Show file tree
Hide file tree
Showing 25 changed files with 654 additions and 1,015 deletions.
2 changes: 1 addition & 1 deletion client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,6 @@
</dependency>
</dependencies>
<properties>
<kotlin.version>0.12.200</kotlin.version>
<kotlin.version>0.12.613</kotlin.version>
</properties>
</project>
29 changes: 17 additions & 12 deletions client/src/main/java/lighthouse/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import lighthouse.files.AppDirectory;
import lighthouse.protocol.*;
import lighthouse.subwindows.*;
import lighthouse.threading.*;
import lighthouse.utils.*;
import lighthouse.utils.ipc.*;
import lighthouse.wallet.*;
Expand Down Expand Up @@ -164,7 +165,7 @@ public void start(Stage stage) throws Exception {
firstRun = !prefs.getPrefsFileFound();
initGUI(stage);

if (firstRun) {
if (firstRun && params != RegTestParams.get()) {
// We haven't been used on this computer/user account before. Do an initial online update to ensure the
// user is always on the freshest version and avoid us needing to rebuild the downloadable binaries for
// every single update.
Expand Down Expand Up @@ -215,15 +216,13 @@ private void performInitialAutoUpdate(List<Path> filesToOpen) {
bar.progressProperty().bind(checks.getProgress());
label.setText(UpdateCheckStrings.DOWNLOADING_SOFTWARE_UPDATE);
break;
case FAILED:
// Error already shown to the user, so just restart with the current version.
case AWAITING_APP_RESTART:
// Create the prefs file as a signal when we restart that it's not the first run anymore.
prefs.storeStageSettings(mainStage);
Main.restart();
break;
case FAILED:
// Error was already shown to user in modal dialog box and logged.
Platform.exit();
break;
}
return Unit.INSTANCE$;
}).start();
Expand Down Expand Up @@ -448,7 +447,7 @@ public void initBitcoin(@Nullable DeterministicSeed restoreFromSeed) throws IOEx
@Override
protected void onSetupCompleted() {
wallet = (PledgingWallet) bitcoin.wallet();
backend = new LighthouseBackend(CLIENT, vPeerGroup, xtPeers, vChain, wallet);
backend = new LighthouseBackend(CLIENT, vPeerGroup, xtPeers, vChain, wallet, new AffinityExecutor.ServiceAffinityExecutor("backend"));

reached("onSetupCompleted");
walletLoadedLatch.countDown();
Expand Down Expand Up @@ -529,12 +528,18 @@ private void refreshStylesheets(Scene scene) {

public boolean waitForInit() {
log.info("Waiting for bitcoin load ...");
Uninterruptibles.awaitUninterruptibly(walletLoadedLatch);
if (Main.backend != null) {
log.info("Waiting for backend init ...");
Main.backend.waitForInit();
return true;
} else {

try {
Uninterruptibles.awaitUninterruptibly(walletLoadedLatch);
if (Main.backend != null) {
log.info("Waiting for backend init ...");
Main.backend.waitForInit();
return true;
} else {
return false;
}
} catch (Exception e) {
CrashWindow.open(e);
return false;
}
}
Expand Down
28 changes: 13 additions & 15 deletions client/src/main/java/lighthouse/activities/OverviewActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import lighthouse.Main
import lighthouse.MainWindow
import lighthouse.controls.ProjectOverviewWidget
import lighthouse.files.AppDirectory
import lighthouse.files.DiskManager
import lighthouse.nav.Activity
import lighthouse.protocol.Project
import lighthouse.subwindows.EditProjectWindow
Expand All @@ -39,6 +38,7 @@ import lighthouse.utils.I18nUtil
import lighthouse.utils.I18nUtil.tr
import lighthouse.utils.easing.EasingMode
import lighthouse.utils.easing.ElasticInterpolator
import lighthouse.utils.hash
import org.bitcoinj.core.Sha256Hash
import org.slf4j.LoggerFactory
import java.io.File
Expand All @@ -54,7 +54,7 @@ public class OverviewActivity : VBox(), Activity {
FXML var addProjectIcon: Label? = null

private val projects: ObservableList<Project> = Main.backend.mirrorProjects(AffinityExecutor.UI_THREAD)
private val projectStates: ObservableMap<String, LighthouseBackend.ProjectStateInfo> = Main.backend.mirrorProjectStates(AffinityExecutor.UI_THREAD)
private val projectStates: ObservableMap<Sha256Hash, LighthouseBackend.ProjectStateInfo> = Main.backend.mirrorProjectStates(AffinityExecutor.UI_THREAD)
// A map indicating the status of checking each project against the network (downloading, found an error, done, etc)
// This is mirrored into the UI thread from the backend.
private val checkStates: ObservableMap<Project, LighthouseBackend.CheckStatus> = Main.backend.mirrorCheckStatuses(AffinityExecutor.UI_THREAD)
Expand Down Expand Up @@ -93,7 +93,7 @@ public class OverviewActivity : VBox(), Activity {
fun importClicked(event: ActionEvent) {
val chooser = FileChooser()
chooser.setTitle(tr("Select a bitcoin project file to import"))
chooser.getExtensionFilters().add(FileChooser.ExtensionFilter(tr("Project/contract files"), "*" + DiskManager.PROJECT_FILE_EXTENSION))
chooser.getExtensionFilters().add(FileChooser.ExtensionFilter(tr("Project/contract files"), "*" + LighthouseBackend.PROJECT_FILE_EXTENSION))
platformFiddleChooser(chooser)
val file = chooser.showOpenDialog(Main.instance.mainStage) ?: return
log.info("Import clicked: $file")
Expand All @@ -106,7 +106,8 @@ public class OverviewActivity : VBox(), Activity {
if (event.getGestureSource() != null)
return // Coming from us.
for (file in event.getDragboard().getFiles()) {
if (file.toString().endsWith(DiskManager.PROJECT_FILE_EXTENSION) || file.toString().endsWith(DiskManager.PLEDGE_FILE_EXTENSION)) {
val s = file.toString()
if (s.endsWith(LighthouseBackend.PROJECT_FILE_EXTENSION) || s.endsWith(LighthouseBackend.PLEDGE_FILE_EXTENSION)) {
accept = true
break
}
Expand All @@ -130,8 +131,8 @@ public class OverviewActivity : VBox(), Activity {
GuiUtils.checkGuiThread()
log.info("Opening {}", file)
when {
file.toString().endsWith(DiskManager.PROJECT_FILE_EXTENSION) -> importProject(file)
file.toString().endsWith(DiskManager.PLEDGE_FILE_EXTENSION) -> importPledge(file)
file.toString().endsWith(LighthouseBackend.PROJECT_FILE_EXTENSION) -> importProject(file)
file.toString().endsWith(LighthouseBackend.PLEDGE_FILE_EXTENSION) -> importPledge(file)

else -> log.error("Unknown file type open requested: should not happen: " + file)
}
Expand All @@ -140,7 +141,7 @@ public class OverviewActivity : VBox(), Activity {
public fun importPledge(file: File) {
try {
val hash = Sha256Hash.of(file)
Files.copy(file.toPath(), AppDirectory.dir().resolve(hash.toString() + DiskManager.PLEDGE_FILE_EXTENSION))
Files.copy(file.toPath(), AppDirectory.dir().resolve(hash.toString() + LighthouseBackend.PLEDGE_FILE_EXTENSION))
} catch (e: IOException) {
GuiUtils.informationalAlert(tr("Import failed"), // TRANS: %1$s = app name, %2$s = error message
tr("Could not copy the dropped pledge into the %1\$s application directory: %2\$s"), Main.APP_NAME, e)
Expand All @@ -154,21 +155,18 @@ public class OverviewActivity : VBox(), Activity {
public fun importProject(file: Path) {
try {
Main.backend.importProjectFrom(file)
} catch (e: IOException) {
} catch (e: Exception) {
GuiUtils.informationalAlert(tr("Failed to import project"), // TRANS: %s = error message
tr("Could not read project file: %s"), e.getMessage())
}

}

// Triggered by the project disk model being adjusted.
// Triggered by the projects list being touched by the backend.
private fun updateExistingProject(index: Int, newProject: Project) {
log.info("Update at index $index")
val uiIndex = getChildren().size() - 1 // from size to index
- numInitialBoxes // the vbox for buttons at the bottom
- index
if (uiIndex < 0)
return // This can happen if the project which is updated is not even on screen yet; Windows fucks up sometimes and tells us this so just ignore it.
val uiIndex = getChildren().size() - 1 - numInitialBoxes - index
check(uiIndex >= 0)
getChildren().set(uiIndex, buildProjectWidget(newProject))
}

Expand Down Expand Up @@ -246,7 +244,7 @@ public class OverviewActivity : VBox(), Activity {
return animation
}

private fun getProjectState(p: Project) = projectStates.get(p.getID())?.state ?: LighthouseBackend.ProjectState.OPEN
private fun getProjectState(p: Project) = projectStates[p.hash]?.state ?: LighthouseBackend.ProjectState.OPEN

override fun onStart() {}

Expand Down
14 changes: 9 additions & 5 deletions client/src/main/java/lighthouse/activities/ProjectActivity.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package lighthouse.activities;

import com.google.common.base.Charsets;
import com.google.common.base.*;
import com.google.common.collect.*;
import javafx.animation.*;
Expand All @@ -19,6 +20,7 @@
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import kotlin.*;
import lighthouse.*;
import lighthouse.controls.*;
import lighthouse.nav.*;
Expand Down Expand Up @@ -74,7 +76,7 @@ public class ProjectActivity extends HBox implements Activity {
private UIBindings bindings;
private LongProperty pledgedValue;
private ObjectBinding<LighthouseBackend.CheckStatus> checkStatus;
private ObservableMap<String, LighthouseBackend.ProjectStateInfo> projectStates; // project id -> status
private ObservableMap<Sha256Hash, LighthouseBackend.ProjectStateInfo> projectStates; // project id -> status
private ObservableMap<Project, LighthouseBackend.CheckStatus> statusMap;
@Nullable private NotificationBarPane.Item notifyBarItem;
@Nullable private Sha256Hash myPledgeHash;
Expand Down Expand Up @@ -247,9 +249,11 @@ private void updateForProject() {
// If a cloned wallet double spends our pledge, the backend can notice this before the wallet does.
// Because the decision on what the button action should be depends on whether the wallet thinks it's pledged,
// we have to watch out for this and update the mode here.
Main.wallet.addOnRevokeHandler(pledge -> setModeFor(p, pledgedValue.get()), Platform::runLater);
Main.wallet.addOnRevokeHandler(Platform::runLater, pledge -> {
setModeFor(p, pledgedValue.get()); return Unit.INSTANCE$;
});

if (p.getPaymentURL() != null) {
if (p.isServerAssisted()) {
Platform.runLater(() -> {
Main.instance.scene.getAccelerators().put(KeyCombination.keyCombination("Shortcut+R"), () -> Main.backend.refreshProjectStatusFromServer(p));
});
Expand Down Expand Up @@ -328,7 +332,7 @@ private void updateGUIForState() {
private void setModeFor(Project project, long value) {
priorMode = mode.get();
Mode newMode = Mode.OPEN_FOR_PLEDGES;
if (projectStates.get(project.getID()).getState() == LighthouseBackend.ProjectState.CLAIMED) {
if (projectStates.get(project.getIDHash()).getState() == LighthouseBackend.ProjectState.CLAIMED) {
newMode = Mode.CLAIMED;
} else {
if (Main.wallet.getPledgedAmountFor(project) > 0)
Expand Down Expand Up @@ -407,7 +411,7 @@ private void actionClicked(ActionEvent event) {
}

private void viewClaim(Project p) {
LighthouseBackend.ProjectStateInfo info = projectStates.get(p.getID());
LighthouseBackend.ProjectStateInfo info = projectStates.get(p.getIDHash());
checkState(info.getState() == LighthouseBackend.ProjectState.CLAIMED);
String url = String.format(Main.params == TestNet3Params.get() ? BLOCK_EXPLORER_SITE_TESTNET : BLOCK_EXPLORER_SITE, info.getClaimedBy());
log.info("Opening {}", url);
Expand Down
13 changes: 13 additions & 0 deletions client/src/main/java/lighthouse/model/ProjectModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.bitcoinj.core.*;
import org.bitcoinj.script.*;

import javax.annotation.*;

import static lighthouse.protocol.LHUtils.*;
import static lighthouse.utils.I18nUtil.*;

Expand All @@ -28,6 +30,8 @@ public class ProjectModel {

private LHProtos.ProjectDetails.Builder proto;

// Pointer to the original Project object that this model is based on, if editing.
@Nullable public final Project originalProject;

public static final int ESTIMATED_INPUT_SIZE = Script.SIG_SIZE + 35 /* bytes for a compressed pubkey */ + 32 /* hash */ + 4;
public static final int MAX_NUM_INPUTS = (Transaction.MAX_STANDARD_TX_SIZE - 64) /* for output */ / ESTIMATED_INPUT_SIZE;
Expand All @@ -37,8 +41,17 @@ public ProjectModel(PledgingWallet wallet) {
wallet.getKeychainLookaheadSize()));
}

public ProjectModel(Project editing) {
this(editing.getProtoDetails().toBuilder(), editing);
}

public ProjectModel(LHProtos.ProjectDetails.Builder liveProto) {
this(liveProto, null);
}

public ProjectModel(LHProtos.ProjectDetails.Builder liveProto, @Nullable Project editing) {
this.proto = liveProto;
this.originalProject = editing;
final LHProtos.Project.Builder wrapper = LHProtos.Project.newBuilder().setSerializedPaymentDetails(liveProto.build().toByteString());
Project project = unchecked(() -> new Project(wrapper.build()));
title.set(project.getTitle());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

import com.google.common.base.*;
import com.google.common.net.*;
import com.vinumeris.crashfx.*;
import javafx.application.Platform;
import javafx.collections.*;
import javafx.event.*;
import javafx.fxml.*;
import javafx.scene.control.*;
import javafx.scene.text.*;
import javafx.stage.*;
import lighthouse.*;
import lighthouse.model.*;
import lighthouse.protocol.*;
import lighthouse.utils.*;
import org.slf4j.*;

import java.io.*;
import java.nio.file.*;

import static com.google.common.base.Preconditions.*;
import static lighthouse.utils.GuiUtils.*;
import static lighthouse.utils.I18nUtil.*;

Expand Down Expand Up @@ -110,30 +108,8 @@ public void saveClicked(ActionEvent event) {
final LHProtos.ProjectDetails detailsProto = model.getDetailsProto().build();
log.info("Saving: {}", detailsProto.getExtraDetails().getTitle());
try {
Project project;
if (detailsProto.hasPaymentUrl()) {
// User has to explicitly export it somewhere (not watched) so they can get it to the server.
project = Main.backend.saveProject(model.getProject());
ExportWindow.openForProject(project);
} else {
GuiUtils.informationalAlert(tr("Folder watching"),
tr("The folder to which you save your project file will be watched for pledge files. When you receive them from backers, just put them in the same directory and they will appear."));
// Request directory first then save, so the animations are right.
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle(tr("Select a directory to store the project and pledges"));
platformFiddleChooser(chooser);
File dir = chooser.showDialog(Main.instance.mainStage);
if (dir == null)
return;
final Path dirPath = dir.toPath();
project = model.getProject();
// Make sure we don't try and run too many animations simultaneously.
final Project fp = project;
overlayUI.runAfterFade(ev -> {
saveAndWatchDirectory(fp, dirPath);
});
overlayUI.done();
}
Project project = editing ? Main.backend.editProject(model.getProject(), checkNotNull(model.originalProject)) : Main.backend.saveProject(model.getProject());
ExportWindow.openForProject(project);
} catch (IOException e) {
log.error("Could not save project", e);
informationalAlert(tr("Could not save project"),
Expand All @@ -144,18 +120,6 @@ public void saveClicked(ActionEvent event) {
});
}

private void saveAndWatchDirectory(Project project, Path dirPath) {
try {
Path file = dirPath.resolve(project.getSuggestedFileName());
try (OutputStream stream = new BufferedOutputStream(Files.newOutputStream(file))) {
project.getProto().writeTo(stream);
}
Main.backend.importProjectFrom(file);
} catch (IOException e) {
CrashFX.propagate(e);
}
}

@FXML
public void cancelClicked(ActionEvent event) {
// Work around ConcurrentModificationException error in framework.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public static void openForCreate(ProjectModel project) {
}

public static void openForEdit(Project project) {
open(new ProjectModel(project.getProtoDetails().toBuilder()), tr("Edit project"), true);
open(new ProjectModel(project), tr("Edit project"), true);
}

public static void openForEdit(ProjectModel project) {
Expand Down
9 changes: 1 addition & 8 deletions client/src/main/java/lighthouse/subwindows/ExportWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import javafx.scene.paint.*;
import javafx.stage.*;
import lighthouse.*;
import lighthouse.files.*;
import lighthouse.protocol.*;
import lighthouse.utils.*;
import lighthouse.wallet.*;
Expand All @@ -29,7 +28,6 @@
public class ExportWindow {
private static final Logger log = LoggerFactory.getLogger(ExportWindow.class);

@FXML HBox folderWatchExplainer;
@FXML StackPane dragArea;
@FXML Label moneyIcon;
@FXML Button saveButton;
Expand All @@ -50,17 +48,12 @@ public static void openForPledge(Project project, PledgingWallet.PledgeSupplier
ExportWindow window = Main.instance.<ExportWindow>overlayUI("subwindows/export.fxml", tr("Export pledge")).controller;
window.project = project;
window.pledge = pledge;
((BorderPane)window.folderWatchExplainer.getParent()).setBottom(null);
}

public static void openForProject(Project project) {
log.info("Open ExportWindow for saving project '{}'", project.getTitle());
ExportWindow window = Main.instance.<ExportWindow>overlayUI("subwindows/export.fxml", tr("Export project")).controller;
window.project = project;
// Don't show "will watch directory" explainer for server assisted projects.
if (project.getPaymentURL() != null) {
((BorderPane)window.folderWatchExplainer.getParent()).setBottom(null);
}
}

public static DataFormat PLEDGE_MIME_TYPE = new DataFormat(LHUtils.PLEDGE_MIME_TYPE);
Expand Down Expand Up @@ -122,7 +115,7 @@ private String getFileName() {
if (pledge != null) {
// TRANS: %1$s = pledger's name, %2$s = project name, %3$s = file extension
final String FILE_NAME = tr("Pledge by %1$s for %2$s%3$s");
return String.format(FILE_NAME, Main.demoName == null ? System.getProperty("user.name") : Main.demoName, project.getTitle(), DiskManager.PLEDGE_FILE_EXTENSION);
return String.format(FILE_NAME, Main.demoName == null ? System.getProperty("user.name") : Main.demoName, project.getTitle(), LighthouseBackend.PLEDGE_FILE_EXTENSION);
} else {
return project.getSuggestedFileName();
}
Expand Down
Loading

0 comments on commit e3c1ae4

Please sign in to comment.