mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 10:11:27 +00:00
Merge branch 'develop' into feature/#1013-#1061-cleanupAndInformation
This commit is contained in:
@@ -32,7 +32,9 @@ import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
@@ -68,6 +70,7 @@ public class Vault {
|
||||
private final BooleanBinding unknownError;
|
||||
private final StringBinding accessPoint;
|
||||
private final BooleanBinding accessPointPresent;
|
||||
private final BooleanProperty showingStats;
|
||||
|
||||
private volatile Volume volume;
|
||||
|
||||
@@ -90,6 +93,7 @@ public class Vault {
|
||||
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
|
||||
this.accessPoint = Bindings.createStringBinding(this::getAccessPoint, state);
|
||||
this.accessPointPresent = this.accessPoint.isNotEmpty();
|
||||
this.showingStats = new SimpleBooleanProperty(false);
|
||||
}
|
||||
|
||||
// ******************************************************************************
|
||||
@@ -268,6 +272,15 @@ public class Vault {
|
||||
}
|
||||
}
|
||||
|
||||
public BooleanProperty showingStatsProperty() {
|
||||
return showingStats;
|
||||
}
|
||||
|
||||
public boolean isShowingStats() {
|
||||
return accessPointPresent.get();
|
||||
}
|
||||
|
||||
|
||||
// ******************************************************************************
|
||||
// Getter/Setter
|
||||
// *******************************************************************************/
|
||||
|
||||
@@ -8,8 +8,10 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.inject.Inject;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
@@ -28,6 +30,15 @@ public class VaultStats {
|
||||
private final ScheduledService<Optional<CryptoFileSystemStats>> updateService;
|
||||
private final LongProperty bytesPerSecondRead = new SimpleLongProperty();
|
||||
private final LongProperty bytesPerSecondWritten = new SimpleLongProperty();
|
||||
private final LongProperty bytesPerSecondEncrypted = new SimpleLongProperty();
|
||||
private final LongProperty bytesPerSecondDecrypted = new SimpleLongProperty();
|
||||
private final DoubleProperty cacheHitRate = new SimpleDoubleProperty();
|
||||
private final LongProperty toalBytesRead = new SimpleLongProperty();
|
||||
private final LongProperty toalBytesWritten = new SimpleLongProperty();
|
||||
private final LongProperty totalBytesEncrypted = new SimpleLongProperty();
|
||||
private final LongProperty totalBytesDecrypted = new SimpleLongProperty();
|
||||
private final LongProperty filesRead = new SimpleLongProperty();
|
||||
private final LongProperty filesWritten = new SimpleLongProperty();
|
||||
|
||||
@Inject
|
||||
VaultStats(AtomicReference<CryptoFileSystem> fs, ObjectProperty<VaultState> state, ExecutorService executor) {
|
||||
@@ -53,8 +64,28 @@ public class VaultStats {
|
||||
|
||||
private void updateStats(Optional<CryptoFileSystemStats> stats) {
|
||||
assert Platform.isFxApplicationThread();
|
||||
bytesPerSecondRead.set(stats.map(CryptoFileSystemStats::pollBytesRead).orElse(0l));
|
||||
bytesPerSecondWritten.set(stats.map(CryptoFileSystemStats::pollBytesWritten).orElse(0l));
|
||||
bytesPerSecondRead.set(stats.map(CryptoFileSystemStats::pollBytesRead).orElse(0L));
|
||||
bytesPerSecondWritten.set(stats.map(CryptoFileSystemStats::pollBytesWritten).orElse(0L));
|
||||
cacheHitRate.set(stats.map(this::getCacheHitRate).orElse(0.0));
|
||||
bytesPerSecondDecrypted.set(stats.map(CryptoFileSystemStats::pollBytesDecrypted).orElse(0L));
|
||||
bytesPerSecondEncrypted.set(stats.map(CryptoFileSystemStats::pollBytesEncrypted).orElse(0L));
|
||||
toalBytesRead.set(stats.map(CryptoFileSystemStats::pollTotalBytesRead).orElse(0L));
|
||||
toalBytesWritten.set(stats.map(CryptoFileSystemStats::pollTotalBytesWritten).orElse(0L));
|
||||
totalBytesEncrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesEncrypted).orElse(0L));
|
||||
totalBytesDecrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesDecrypted).orElse(0L));
|
||||
filesRead.set(stats.map(CryptoFileSystemStats::pollAmountOfAccessesRead).orElse(0L));
|
||||
filesWritten.set(stats.map(CryptoFileSystemStats::pollAmountOfAccessesWritten).orElse(0L));
|
||||
|
||||
}
|
||||
|
||||
private double getCacheHitRate(CryptoFileSystemStats stats) {
|
||||
long accesses = stats.pollChunkCacheAccesses();
|
||||
long hits = stats.pollChunkCacheHits();
|
||||
if (accesses == 0) {
|
||||
return 0.0;
|
||||
} else {
|
||||
return hits / (double) accesses;
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateStatsService extends ScheduledService<Optional<CryptoFileSystemStats>> {
|
||||
@@ -98,4 +129,50 @@ public class VaultStats {
|
||||
public long getBytesPerSecondWritten() {
|
||||
return bytesPerSecondWritten.get();
|
||||
}
|
||||
|
||||
public LongProperty bytesPerSecondEncryptedProperty() {
|
||||
return bytesPerSecondEncrypted;
|
||||
}
|
||||
|
||||
public long getBytesPerSecondEnrypted() {
|
||||
return bytesPerSecondEncrypted.get();
|
||||
}
|
||||
|
||||
public LongProperty bytesPerSecondDecryptedProperty() {
|
||||
return bytesPerSecondDecrypted;
|
||||
}
|
||||
|
||||
public long getBytesPerSecondDecrypted() {
|
||||
return bytesPerSecondDecrypted.get();
|
||||
}
|
||||
|
||||
public DoubleProperty cacheHitRateProperty() { return cacheHitRate; }
|
||||
|
||||
public double getCacheHitRate() {
|
||||
return cacheHitRate.get();
|
||||
}
|
||||
|
||||
public LongProperty toalBytesReadProperty() {return toalBytesRead;}
|
||||
|
||||
public long getTotalBytesRead() { return toalBytesRead.get();}
|
||||
|
||||
public LongProperty toalBytesWrittenProperty() {return toalBytesWritten;}
|
||||
|
||||
public long getTotalBytesWritten() { return toalBytesWritten.get();}
|
||||
|
||||
public LongProperty totalBytesEncryptedProperty() {return totalBytesEncrypted;}
|
||||
|
||||
public long getTotalBytesEncrypted() { return totalBytesEncrypted.get();}
|
||||
|
||||
public LongProperty totalBytesDecryptedProperty() {return totalBytesDecrypted;}
|
||||
|
||||
public long getTotalBytesDecrypted() { return totalBytesDecrypted.get();}
|
||||
|
||||
public LongProperty filesRead() { return filesRead;}
|
||||
|
||||
public long getFilesRead() { return filesRead.get();}
|
||||
|
||||
public LongProperty filesWritten() {return filesWritten;}
|
||||
|
||||
public long getFilesWritten() {return filesWritten.get();}
|
||||
}
|
||||
|
||||
28
main/pom.xml
28
main/pom.xml
@@ -24,31 +24,29 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>1.9.12</cryptomator.cryptofs.version>
|
||||
<cryptomator.cryptofs.version>1.9.13</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>0.1.6</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>0.1.0-beta1</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>0.1.0-beta3</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>0.1.0-beta1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.integrations.linux.version>0.1.0-beta2</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>1.2.5</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.1.15</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.0.12</cryptomator.webdav.version>
|
||||
<cryptomator.dokany.version>1.2.0</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.0.13</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>14</javafx.version>
|
||||
<javafx.version>15</javafx.version>
|
||||
<commons-lang3.version>3.11</commons-lang3.version>
|
||||
<secret-service.version>1.1.0</secret-service.version>
|
||||
<kdewallet.version>1.1.1</kdewallet.version>
|
||||
<jwt.version>3.10.3</jwt.version>
|
||||
<jwt.version>3.11.0</jwt.version>
|
||||
<easybind.version>2.1.0</easybind.version>
|
||||
<guava.version>30.0-jre</guava.version>
|
||||
<dagger.version>2.22</dagger.version>
|
||||
<dagger.version>2.29.1</dagger.version>
|
||||
<gson.version>2.8.6</gson.version>
|
||||
<slf4j.version>1.7.30</slf4j.version>
|
||||
<logback.version>1.2.3</logback.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.6.2</junit.jupiter.version>
|
||||
<mockito.version>3.3.3</mockito.version>
|
||||
<junit.jupiter.version>5.7.0</junit.jupiter.version>
|
||||
<mockito.version>3.6.0</mockito.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
</properties>
|
||||
|
||||
@@ -79,11 +77,6 @@
|
||||
</dependency>
|
||||
|
||||
<!-- Cryptomator Libs -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>siv-mode</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptofs</artifactId>
|
||||
@@ -242,6 +235,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -382,7 +376,7 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.5</version>
|
||||
<version>0.8.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
|
||||
@@ -4,6 +4,7 @@ import dagger.BindsInstance;
|
||||
import dagger.Subcomponent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@@ -16,6 +17,14 @@ public interface ErrorComponent {
|
||||
Scene scene();
|
||||
|
||||
default void showErrorScene() {
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
show();
|
||||
} else {
|
||||
Platform.runLater(this::show);
|
||||
}
|
||||
}
|
||||
|
||||
private void show() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene());
|
||||
stage.show();
|
||||
|
||||
@@ -28,6 +28,7 @@ public enum FxmlFile {
|
||||
UNLOCK_INVALID_MOUNT_POINT("/fxml/unlock_invalid_mount_point.fxml"), //
|
||||
UNLOCK_SUCCESS("/fxml/unlock_success.fxml"), //
|
||||
VAULT_OPTIONS("/fxml/vault_options.fxml"), //
|
||||
VAULT_STATISTICS("/fxml/stats.fxml"), //
|
||||
WRONGFILEALERT("/fxml/wrongfilealert.fxml");
|
||||
|
||||
private final String ressourcePathString;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package org.cryptomator.ui.common;
|
||||
|
||||
import javafx.beans.binding.DoubleBinding;
|
||||
import javafx.beans.binding.IntegerBinding;
|
||||
import javafx.beans.binding.LongBinding;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.value.ObservableObjectValue;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
|
||||
/**
|
||||
@@ -29,4 +33,61 @@ public final class WeakBindings {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LongBinding that listens to changes from the given observable without being strongly referenced by it.
|
||||
*
|
||||
* @param observable The observable
|
||||
* @return a LongBinding weakly referenced from the given observable
|
||||
*/
|
||||
public static LongBinding bindLong(ObservableValue<Number> observable) {
|
||||
return new LongBinding() {
|
||||
{
|
||||
bind(observable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long computeValue() {
|
||||
return observable.getValue().longValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DoubleBinding that listens to changes from the given observable without being strongly referenced by it.
|
||||
*
|
||||
* @param observable The observable
|
||||
* @return a DoubleBinding weakly referenced from the given observable
|
||||
*/
|
||||
public static DoubleBinding bindDouble(ObservableValue<Number> observable) {
|
||||
return new DoubleBinding() {
|
||||
{
|
||||
bind(observable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double computeValue() {
|
||||
return observable.getValue().doubleValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new IntegerBinding that listens to changes from the given observable without being strongly referenced by it.
|
||||
*
|
||||
* @param observable The observable
|
||||
* @return a IntegerBinding weakly referenced from the given observable
|
||||
*/
|
||||
public static IntegerBinding bindInterger(ObservableValue<Number> observable) {
|
||||
return new IntegerBinding() {
|
||||
{
|
||||
bind(observable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int computeValue() {
|
||||
return observable.getValue().intValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package org.cryptomator.ui.controls;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
public class DataLabel extends Label {
|
||||
|
||||
private static final long KIB_THRESHOLD = 1l << 7; // 0.128 kiB
|
||||
private static final long MIB_THRESHOLD = 1l << 19; // 0.512 MiB
|
||||
private static final long GIB_THRESHOLD = 1l << 29; // 0.512 GiB
|
||||
|
||||
private final StringProperty byteFormat = new SimpleStringProperty("-");
|
||||
private final StringProperty kibFormat = new SimpleStringProperty("%.3f");
|
||||
private final StringProperty mibFormat = new SimpleStringProperty("%.3f");
|
||||
private final StringProperty gibFormat = new SimpleStringProperty("%.3f");
|
||||
private final LongProperty dataInBytes = new SimpleLongProperty();
|
||||
|
||||
public DataLabel() {
|
||||
textProperty().bind(createStringBinding());
|
||||
}
|
||||
|
||||
protected StringBinding createStringBinding() {
|
||||
return Bindings.createStringBinding(this::updateText, kibFormat, mibFormat, gibFormat, dataInBytes);
|
||||
}
|
||||
|
||||
private String updateText() {
|
||||
long data = dataInBytes.get();
|
||||
if (data > GIB_THRESHOLD) {
|
||||
double giB = ((double) data) / 1024.0 / 1024.0 / 1024.0;
|
||||
return String.format(gibFormat.get(), giB);
|
||||
} else if (data > MIB_THRESHOLD) {
|
||||
double miB = ((double) data) / 1024.0 / 1024.0;
|
||||
return String.format(mibFormat.get(), miB);
|
||||
} else if (data > KIB_THRESHOLD) {
|
||||
double kiB = ((double) data) / 1024.0;
|
||||
return String.format(kibFormat.get(), kiB);
|
||||
} else {
|
||||
return String.format(byteFormat.get(), data);
|
||||
}
|
||||
}
|
||||
|
||||
public StringProperty byteFormatProperty() { return byteFormat; }
|
||||
|
||||
public String getByteFormat() { return byteFormat.get(); }
|
||||
|
||||
public void setByteFormat(String byteFormat) {
|
||||
this.byteFormat.set(byteFormat);
|
||||
}
|
||||
|
||||
public StringProperty kibFormatProperty() { return kibFormat; }
|
||||
|
||||
public String getKibFormat() { return kibFormat.get(); }
|
||||
|
||||
public void setKibFormat(String kibFormat) {
|
||||
this.kibFormat.set(kibFormat);
|
||||
}
|
||||
|
||||
public StringProperty mibFormatProperty() { return mibFormat; }
|
||||
|
||||
public String getMibFormat() { return mibFormat.get(); }
|
||||
|
||||
public void setMibFormat(String mibFormat) {
|
||||
this.mibFormat.set(mibFormat);
|
||||
}
|
||||
|
||||
public StringProperty gibFormatProperty() { return gibFormat; }
|
||||
|
||||
public String getGibFormat() { return gibFormat.get(); }
|
||||
|
||||
public void setGibFormat(String gibFormat) {
|
||||
this.gibFormat.set(gibFormat);
|
||||
}
|
||||
|
||||
public LongProperty dataInBytesProperty() { return dataInBytes; }
|
||||
|
||||
public long getDataInBytes() {
|
||||
return dataInBytes.get();
|
||||
}
|
||||
|
||||
public void setDataInBytes(long dataInBytes) { this.dataInBytes.set(dataInBytes); }
|
||||
|
||||
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import javafx.scene.control.Label;
|
||||
|
||||
public class ThrougputLabel extends Label {
|
||||
|
||||
private static final long kibsThreshold = 1l << 7; // 0.128 kiB/s
|
||||
private static final long mibsThreshold = 1l << 19; // 0.512 MiB/s
|
||||
private static final long KIBS_THRESHOLD = 1l << 7; // 0.128 kiB/s
|
||||
private static final long MIBS_THRESHOLD = 1l << 19; // 0.512 MiB/s
|
||||
|
||||
private final StringProperty idleFormat = new SimpleStringProperty("-");
|
||||
private final StringProperty kibsFormat = new SimpleStringProperty("%.3f");
|
||||
@@ -22,18 +22,17 @@ public class ThrougputLabel extends Label {
|
||||
textProperty().bind(createStringBinding());
|
||||
}
|
||||
|
||||
|
||||
protected StringBinding createStringBinding() {
|
||||
return Bindings.createStringBinding(this::updateText, kibsFormat, mibsFormat, bytesPerSecond);
|
||||
}
|
||||
|
||||
private String updateText() {
|
||||
long bps = bytesPerSecond.get();
|
||||
if (bps > mibsThreshold) {
|
||||
double mibs = ((double) bytesPerSecond.get()) / 1024.0 / 1024.0;
|
||||
if (bps > MIBS_THRESHOLD) {
|
||||
double mibs = ((double) bps) / 1024.0 / 1024.0;
|
||||
return String.format(mibsFormat.get(), mibs);
|
||||
} else if (bps > kibsThreshold) {
|
||||
double kibs = ((double) bytesPerSecond.get()) / 1024.0;
|
||||
} else if (bps > KIBS_THRESHOLD) {
|
||||
double kibs = ((double) bps) / 1024.0;
|
||||
return String.format(kibsFormat.get(), kibs);
|
||||
} else {
|
||||
return String.format(idleFormat.get(), bps);
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.migration.MigrationComponent;
|
||||
import org.cryptomator.ui.removevault.RemoveVaultComponent;
|
||||
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
|
||||
import org.cryptomator.ui.stats.VaultStatisticsComponent;
|
||||
import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
|
||||
|
||||
import javax.inject.Provider;
|
||||
@@ -26,7 +27,7 @@ import javafx.stage.StageStyle;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, RemoveVaultComponent.class, VaultOptionsComponent.class, WrongFileAlertComponent.class})
|
||||
@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, RemoveVaultComponent.class, VaultOptionsComponent.class, VaultStatisticsComponent.class, WrongFileAlertComponent.class})
|
||||
abstract class MainWindowModule {
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package org.cryptomator.ui.mainwindow;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.cryptomator.ui.stats.VaultStatisticsComponent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
@@ -14,11 +18,19 @@ public class VaultDetailUnlockedController implements FxController {
|
||||
|
||||
private final ReadOnlyObjectProperty<Vault> vault;
|
||||
private final VaultService vaultService;
|
||||
private final LoadingCache<Vault, VaultStatisticsComponent> vaultStats;
|
||||
private final VaultStatisticsComponent.Builder vaultStatsBuilder;
|
||||
|
||||
@Inject
|
||||
public VaultDetailUnlockedController(ObjectProperty<Vault> vault, VaultService vaultService) {
|
||||
public VaultDetailUnlockedController(ObjectProperty<Vault> vault, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder) {
|
||||
this.vault = vault;
|
||||
this.vaultService = vaultService;
|
||||
this.vaultStats = CacheBuilder.newBuilder().weakValues().build(CacheLoader.from(this::buildVaultStats));
|
||||
this.vaultStatsBuilder = vaultStatsBuilder;
|
||||
}
|
||||
|
||||
private VaultStatisticsComponent buildVaultStats(Vault vault) {
|
||||
return vaultStatsBuilder.vault(vault).build();
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -32,6 +44,11 @@ public class VaultDetailUnlockedController implements FxController {
|
||||
// TODO count lock attempts, and allow forced lock
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showVaultStatistics() {
|
||||
vaultStats.getUnchecked(vault.get()).showVaultStatisticsWindow();
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public ReadOnlyObjectProperty<Vault> vaultProperty() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.cryptomator.common.settings.KeychainBackend;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.UiTheme;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -24,6 +25,7 @@ import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.Toggle;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.StringConverter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
@@ -37,6 +39,7 @@ public class GeneralPreferencesController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GeneralPreferencesController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Settings settings;
|
||||
private final boolean trayMenuSupported;
|
||||
private final Optional<AutoStartStrategy> autoStartStrategy;
|
||||
@@ -47,6 +50,7 @@ public class GeneralPreferencesController implements FxController {
|
||||
private final Application application;
|
||||
private final Environment environment;
|
||||
private final Set<KeychainAccessProvider> keychainAccessProviders;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
public ChoiceBox<UiTheme> themeChoiceBox;
|
||||
public ChoiceBox<KeychainBackend> keychainBackendChoiceBox;
|
||||
public CheckBox startHiddenCheckbox;
|
||||
@@ -57,7 +61,8 @@ public class GeneralPreferencesController implements FxController {
|
||||
public RadioButton nodeOrientationRtl;
|
||||
|
||||
@Inject
|
||||
GeneralPreferencesController(Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartStrategy> autoStartStrategy, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment) {
|
||||
GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartStrategy> autoStartStrategy, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment, ErrorComponent.Builder errorComponent) {
|
||||
this.window = window;
|
||||
this.settings = settings;
|
||||
this.trayMenuSupported = trayMenuSupported;
|
||||
this.autoStartStrategy = autoStartStrategy;
|
||||
@@ -68,6 +73,7 @@ public class GeneralPreferencesController implements FxController {
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.application = application;
|
||||
this.environment = environment;
|
||||
this.errorComponent = errorComponent;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -129,6 +135,7 @@ public class GeneralPreferencesController implements FxController {
|
||||
toggleTask.setOnFailed(event -> {
|
||||
autoStartCheckbox.setSelected(!enableAutoStart); // restore previous state
|
||||
LOG.error("Failed to toggle autostart.", event.getSource().getException());
|
||||
errorComponent.cause(event.getSource().getException()).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
});
|
||||
executor.execute(toggleTask);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.ui.common.Animations;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
@@ -31,16 +32,18 @@ public class RecoveryKeyCreationController implements FxController {
|
||||
private final ExecutorService executor;
|
||||
private final RecoveryKeyFactory recoveryKeyFactory;
|
||||
private final StringProperty recoveryKeyProperty;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
public NiceSecurePasswordField passwordField;
|
||||
|
||||
@Inject
|
||||
public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @FxmlScene(FxmlFile.RECOVERYKEY_SUCCESS) Lazy<Scene> successScene, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey) {
|
||||
public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @FxmlScene(FxmlFile.RECOVERYKEY_SUCCESS) Lazy<Scene> successScene, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey, ErrorComponent.Builder errorComponent) {
|
||||
this.window = window;
|
||||
this.successScene = successScene;
|
||||
this.vault = vault;
|
||||
this.executor = executor;
|
||||
this.recoveryKeyFactory = recoveryKeyFactory;
|
||||
this.recoveryKeyProperty = recoveryKey;
|
||||
this.errorComponent = errorComponent;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -59,6 +62,7 @@ public class RecoveryKeyCreationController implements FxController {
|
||||
Animations.createShakeWindowAnimation(window).play();
|
||||
} else {
|
||||
LOG.error("Creation of recovery key failed.", task.getException());
|
||||
errorComponent.cause(task.getException()).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
}
|
||||
});
|
||||
executor.submit(task);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.cryptomator.ui.stats;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Lazy;
|
||||
import dagger.Subcomponent;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* For each vault there can be up to one statistics component.
|
||||
* <p>
|
||||
* <b>Important:</b> Outside of {@link org.cryptomator.ui.stats}, this component should be weakly referenced,
|
||||
* as it include memory-intensive UI nodes.
|
||||
* <p>
|
||||
* While the stats window is visible, this component is strongly referenced by the window's main controller.
|
||||
* As soon as the window is closed, the full objectgraph becomes eligible for GC.
|
||||
*/
|
||||
@VaultStatisticsScoped
|
||||
@Subcomponent(modules = {VaultStatisticsModule.class})
|
||||
public interface VaultStatisticsComponent {
|
||||
|
||||
@VaultStatisticsWindow
|
||||
Stage window();
|
||||
|
||||
@FxmlScene(FxmlFile.VAULT_STATISTICS)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showVaultStatisticsWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.sizeToScene();
|
||||
stage.show();
|
||||
stage.requestFocus();
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
Builder vault(@VaultStatisticsWindow Vault vault);
|
||||
|
||||
VaultStatisticsComponent build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package org.cryptomator.ui.stats;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultStats;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.WeakBindings;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.animation.Animation;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.beans.binding.DoubleBinding;
|
||||
import javafx.beans.binding.LongBinding;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.chart.AreaChart;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
import javafx.scene.chart.XYChart.Data;
|
||||
import javafx.scene.chart.XYChart.Series;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Duration;
|
||||
import java.util.Arrays;
|
||||
|
||||
@VaultStatisticsScoped
|
||||
public class VaultStatisticsController implements FxController {
|
||||
|
||||
private static final int IO_SAMPLING_STEPS = 30;
|
||||
private static final double IO_SAMPLING_INTERVAL = 1;
|
||||
|
||||
private final VaultStatisticsComponent component; // keep a strong reference to the component (see component's javadoc)
|
||||
private final VaultStats stats;
|
||||
private final Series<Number, Number> readData;
|
||||
private final Series<Number, Number> writeData;
|
||||
private final Timeline ioAnimation;
|
||||
private final LongBinding bpsRead;
|
||||
private final LongBinding bpsWritten;
|
||||
private final DoubleBinding cacheHitRate;
|
||||
private final DoubleBinding cacheHitDegrees;
|
||||
private final DoubleBinding cacheHitPercentage;
|
||||
private final LongBinding totalBytesRead;
|
||||
private final LongBinding totalBytesWritten;
|
||||
private final LongBinding totalBytesEncrypted;
|
||||
private final LongBinding totalBytesDecrypted;
|
||||
private final LongBinding filesRead;
|
||||
private final LongBinding filesWritten;
|
||||
private final LongBinding bpsEncrypted;
|
||||
private final LongBinding bpsDecrypted;
|
||||
|
||||
public AreaChart<Number, Number> readChart;
|
||||
public AreaChart<Number, Number> writeChart;
|
||||
public NumberAxis readChartXAxis;
|
||||
public NumberAxis readChartYAxis;
|
||||
public NumberAxis writeChartXAxis;
|
||||
public NumberAxis writeChartYAxis;
|
||||
|
||||
@Inject
|
||||
public VaultStatisticsController(VaultStatisticsComponent component, @VaultStatisticsWindow Stage window, @VaultStatisticsWindow Vault vault) {
|
||||
this.component = component;
|
||||
this.stats = vault.getStats();
|
||||
this.readData = new Series<>();
|
||||
this.writeData = new Series<>();
|
||||
this.bpsRead = WeakBindings.bindLong(stats.bytesPerSecondReadProperty());
|
||||
this.bpsWritten = WeakBindings.bindLong(stats.bytesPerSecondWrittenProperty());
|
||||
this.cacheHitRate = WeakBindings.bindDouble(stats.cacheHitRateProperty());
|
||||
this.cacheHitDegrees = cacheHitRate.multiply(-270);
|
||||
this.cacheHitPercentage = cacheHitRate.multiply(100);
|
||||
this.totalBytesRead = WeakBindings.bindLong(stats.toalBytesReadProperty());
|
||||
this.totalBytesWritten = WeakBindings.bindLong(stats.toalBytesWrittenProperty());
|
||||
this.totalBytesDecrypted = WeakBindings.bindLong(stats.totalBytesDecryptedProperty());
|
||||
this.totalBytesEncrypted = WeakBindings.bindLong(stats.totalBytesEncryptedProperty());
|
||||
this.filesRead = WeakBindings.bindLong(stats.filesRead());
|
||||
this.filesWritten = WeakBindings.bindLong(stats.filesWritten());
|
||||
this.bpsEncrypted = WeakBindings.bindLong(stats.bytesPerSecondEncryptedProperty());
|
||||
this.bpsDecrypted = WeakBindings.bindLong(stats.bytesPerSecondDecryptedProperty());
|
||||
|
||||
this.ioAnimation = new Timeline(); //TODO Research better timer
|
||||
ioAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(IO_SAMPLING_INTERVAL), new IoSamplingAnimationHandler(readData, writeData)));
|
||||
ioAnimation.setCycleCount(Animation.INDEFINITE);
|
||||
ioAnimation.play();
|
||||
|
||||
// make sure to stop animating while window is closed
|
||||
// otherwise a global timer (GC root) will keep a strong reference to animation
|
||||
window.setOnHiding(evt -> ioAnimation.stop());
|
||||
window.setOnShowing(evt -> ioAnimation.play());
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
readChart.getData().addAll(readData);
|
||||
writeChart.getData().addAll(writeData);
|
||||
}
|
||||
|
||||
private class IoSamplingAnimationHandler implements EventHandler<ActionEvent> {
|
||||
|
||||
private long step = IO_SAMPLING_STEPS;
|
||||
private final Series<Number, Number> decryptedBytesRead;
|
||||
private final Series<Number, Number> encryptedBytesWrite;
|
||||
private final long[] maxBuf = new long[IO_SAMPLING_STEPS];
|
||||
|
||||
public IoSamplingAnimationHandler(Series<Number, Number> readData, Series<Number, Number> writeData) {
|
||||
this.decryptedBytesRead = readData;
|
||||
this.encryptedBytesWrite = writeData;
|
||||
|
||||
// initialize data once and change value of datapoints later:
|
||||
for (int i = 0; i < IO_SAMPLING_STEPS; i++) {
|
||||
decryptedBytesRead.getData().add(new Data<>(i, 0));
|
||||
encryptedBytesWrite.getData().add(new Data<>(i, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
final long currentStep = step++;
|
||||
final long decBytes = stats.bytesPerSecondReadProperty().get();
|
||||
final long encBytes = stats.bytesPerSecondWrittenProperty().get();
|
||||
|
||||
maxBuf[(int) currentStep % IO_SAMPLING_STEPS] = Math.max(decBytes, encBytes);
|
||||
long allTimeMax = Arrays.stream(maxBuf).max().orElse(0l);
|
||||
|
||||
// remove oldest value:
|
||||
decryptedBytesRead.getData().remove(0);
|
||||
encryptedBytesWrite.getData().remove(0);
|
||||
|
||||
// add latest value:
|
||||
decryptedBytesRead.getData().add(new Data<>(currentStep, decBytes));
|
||||
encryptedBytesWrite.getData().add(new Data<>(currentStep, encBytes));
|
||||
|
||||
// adjust ranges:
|
||||
readChartXAxis.setLowerBound(currentStep - IO_SAMPLING_STEPS);
|
||||
readChartXAxis.setUpperBound(currentStep);
|
||||
readChartYAxis.setUpperBound(allTimeMax);
|
||||
writeChartXAxis.setLowerBound(currentStep - IO_SAMPLING_STEPS);
|
||||
writeChartXAxis.setUpperBound(currentStep);
|
||||
writeChartYAxis.setUpperBound(allTimeMax);
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public LongBinding bpsReadProperty() {
|
||||
return bpsRead;
|
||||
}
|
||||
|
||||
public long getBpsRead() {
|
||||
return bpsRead.get();
|
||||
}
|
||||
|
||||
public LongBinding bpsWrittenProperty() {
|
||||
return bpsWritten;
|
||||
}
|
||||
|
||||
public long getBpsWritten() {
|
||||
return bpsWritten.get();
|
||||
}
|
||||
|
||||
public DoubleBinding cacheHitPercentageProperty() {
|
||||
return cacheHitPercentage;
|
||||
}
|
||||
|
||||
public double getCacheHitPercentage() { return cacheHitPercentage.get(); }
|
||||
|
||||
public DoubleBinding cacheHitDegreesProperty() {
|
||||
return cacheHitDegrees;
|
||||
}
|
||||
|
||||
public double getCacheHitDegrees() {
|
||||
return cacheHitDegrees.get();
|
||||
}
|
||||
|
||||
public LongBinding totalBytesReadProperty() { return totalBytesRead;}
|
||||
|
||||
public long getTotalBytesRead() { return totalBytesRead.get();}
|
||||
|
||||
public LongBinding totalBytesWrittenProperty() { return totalBytesWritten;}
|
||||
|
||||
public long getTotalBytesWritten() { return totalBytesWritten.get();}
|
||||
|
||||
public LongBinding totalBytesEncryptedProperty() {return totalBytesEncrypted;}
|
||||
|
||||
public long getTotalBytesEncrypted() { return totalBytesEncrypted.get();}
|
||||
|
||||
public LongBinding totalBytesDecryptedProperty() {return totalBytesDecrypted;}
|
||||
|
||||
public long getTotalBytesDecrypted() { return totalBytesDecrypted.get();}
|
||||
|
||||
public LongBinding bpsEncryptedProperty() {
|
||||
return bpsEncrypted;
|
||||
}
|
||||
|
||||
public long getBpsEncrypted() {
|
||||
return bpsEncrypted.get();
|
||||
}
|
||||
|
||||
public LongBinding bpsDecryptedProperty() {
|
||||
return bpsDecrypted;
|
||||
}
|
||||
|
||||
public long getBpsDecrypted() {
|
||||
return bpsDecrypted.get();
|
||||
}
|
||||
|
||||
public LongBinding filesReadProperty() { return filesRead;}
|
||||
|
||||
public long getFilesRead() { return filesRead.get();}
|
||||
|
||||
public LongBinding filesWrittenProperty() {return filesWritten;}
|
||||
|
||||
public long getFilesWritten() {return filesWritten.get();}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.cryptomator.ui.stats;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module
|
||||
abstract class VaultStatisticsModule {
|
||||
|
||||
@Provides
|
||||
@VaultStatisticsWindow
|
||||
@VaultStatisticsScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@VaultStatisticsWindow
|
||||
@VaultStatisticsScoped
|
||||
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle, @VaultStatisticsWindow Vault vault) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(String.format(resourceBundle.getString("stats.title"), vault.getDisplayName()));
|
||||
stage.setResizable(false);
|
||||
var weakStage = new WeakReference<>(stage);
|
||||
vault.stateProperty().addListener(new ChangeListener<>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends VaultState> observable, VaultState oldValue, VaultState newValue) {
|
||||
if (newValue != VaultState.UNLOCKED) {
|
||||
Stage stage = weakStage.get();
|
||||
if (stage != null) {
|
||||
stage.hide();
|
||||
}
|
||||
observable.removeListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
stage.setOnCloseRequest(windowEvent -> vault.showingStatsProperty().setValue(false));
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.VAULT_STATISTICS)
|
||||
@VaultStatisticsScoped
|
||||
static Scene provideVaultStatisticsScene(@VaultStatisticsWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/stats.fxml");
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(VaultStatisticsController.class)
|
||||
abstract FxController bindVaultStatisticsController(VaultStatisticsController controller);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.cryptomator.ui.stats;
|
||||
|
||||
import javax.inject.Scope;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Scope
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface VaultStatisticsScoped {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.ui.stats;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Qualifier
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
@interface VaultStatisticsWindow {
|
||||
|
||||
}
|
||||
@@ -209,9 +209,7 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
|
||||
private void handleGenericError(Throwable e) {
|
||||
LOG.error("Unlock failed for technical reasons.", e);
|
||||
Platform.runLater(() -> {
|
||||
errorComponent.cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
});
|
||||
errorComponent.cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
}
|
||||
|
||||
private void wipePassword(char[] pw) {
|
||||
|
||||
@@ -162,7 +162,9 @@ public class MountOptionsController implements FxController {
|
||||
|
||||
@Override
|
||||
public String toString(String driveLetter) {
|
||||
if (occupiedDriveLetters.contains(driveLetter)) {
|
||||
if (Strings.isNullOrEmpty(driveLetter)) {
|
||||
return "";
|
||||
} else if (occupiedDriveLetters.contains(driveLetter)) {
|
||||
return driveLetter + ": (" + resourceBundle.getString("vaultOptions.mount.winDriveLetterOccupied") + ")";
|
||||
} else {
|
||||
return driveLetter + ":";
|
||||
|
||||
@@ -884,3 +884,57 @@
|
||||
-fx-background-color: PROGRESS_BAR_BG;
|
||||
-fx-background-radius: 4px;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* I/O Statistics *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
.cache-arc-background {
|
||||
-fx-fill: transparent;
|
||||
-fx-stroke: MUTED_BG;
|
||||
-fx-stroke-type: centered;
|
||||
-fx-stroke-width: 12;
|
||||
-fx-stroke-line-cap: butt;
|
||||
}
|
||||
|
||||
.cache-arc-foreground {
|
||||
-fx-fill: transparent;
|
||||
-fx-stroke: PRIMARY;
|
||||
-fx-stroke-type: centered;
|
||||
-fx-stroke-width: 12;
|
||||
-fx-stroke-line-cap: butt;
|
||||
}
|
||||
|
||||
.chart.io-stats {
|
||||
-fx-padding: 10px;
|
||||
-fx-horizontal-grid-lines-visible: false;
|
||||
-fx-horizontal-zero-line-visible: false;
|
||||
-fx-vertical-grid-lines-visible: false;
|
||||
-fx-vertical-zero-line-visible: false;
|
||||
}
|
||||
|
||||
.axis.io-stats {
|
||||
-fx-tick-mark-visible: false;
|
||||
-fx-minor-tick-visible: false;
|
||||
-fx-tick-labels-visible: false;
|
||||
}
|
||||
|
||||
.chart-plot-background {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.chart-vertical-zero-line,
|
||||
.chart-horizontal-zero-line,
|
||||
.chart-alternative-row-fill {
|
||||
-fx-stroke: transparent;
|
||||
-fx-stroke-width: 0;
|
||||
}
|
||||
|
||||
.default-color0.chart-series-area-line {
|
||||
-fx-stroke: PRIMARY;
|
||||
}
|
||||
.default-color0.chart-series-area-fill {
|
||||
-fx-fill: linear-gradient(to bottom, PRIMARY, transparent);
|
||||
-fx-stroke: transparent;
|
||||
}
|
||||
|
||||
@@ -882,3 +882,68 @@
|
||||
-fx-background-color: PROGRESS_BAR_BG;
|
||||
-fx-background-radius: 4px;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* I/O Statistics *
|
||||
* *
|
||||
******************************************************************************/
|
||||
.chart {
|
||||
-fx-padding: 10px;
|
||||
}
|
||||
|
||||
.chart-plot-background {
|
||||
-fx-background-color: MAIN_BG;
|
||||
-fx-padding: 20px;
|
||||
}
|
||||
|
||||
/* content */
|
||||
|
||||
|
||||
.cache-arc-background {
|
||||
-fx-fill: transparent;
|
||||
-fx-stroke: MUTED_BG;
|
||||
-fx-stroke-type: centered;
|
||||
-fx-stroke-width: 12;
|
||||
-fx-stroke-line-cap: butt;
|
||||
}
|
||||
|
||||
.cache-arc-foreground {
|
||||
-fx-fill: transparent;
|
||||
-fx-stroke: PRIMARY;
|
||||
-fx-stroke-type: centered;
|
||||
-fx-stroke-width: 12;
|
||||
-fx-stroke-line-cap: butt;
|
||||
}
|
||||
|
||||
.chart.io-stats {
|
||||
-fx-padding: 10px;
|
||||
-fx-horizontal-grid-lines-visible: false;
|
||||
-fx-horizontal-zero-line-visible: false;
|
||||
-fx-vertical-grid-lines-visible: false;
|
||||
-fx-vertical-zero-line-visible: false;
|
||||
}
|
||||
|
||||
.axis.io-stats {
|
||||
-fx-tick-mark-visible: false;
|
||||
-fx-minor-tick-visible: false;
|
||||
-fx-tick-labels-visible: false;
|
||||
}
|
||||
|
||||
.chart-plot-background {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.chart-vertical-zero-line,
|
||||
.chart-horizontal-zero-line,
|
||||
.chart-alternative-row-fill {
|
||||
-fx-stroke: transparent;
|
||||
-fx-stroke-width: 0;
|
||||
}
|
||||
|
||||
.default-color0.chart-series-area-line {
|
||||
-fx-stroke: PRIMARY;
|
||||
}
|
||||
.default-color0.chart-series-area-fill {
|
||||
-fx-fill: linear-gradient(to bottom, PRIMARY, transparent);
|
||||
-fx-stroke: transparent;
|
||||
}
|
||||
|
||||
75
main/ui/src/main/resources/fxml/stats.fxml
Normal file
75
main/ui/src/main/resources/fxml/stats.fxml
Normal file
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.DataLabel?>
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<?import org.cryptomator.ui.controls.ThrougputLabel?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.chart.AreaChart?>
|
||||
<?import javafx.scene.chart.NumberAxis?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Cursor?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Arc?>
|
||||
<HBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.stats.VaultStatisticsController"
|
||||
prefWidth="800.0" spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
|
||||
<!-- Caching -->
|
||||
<VBox prefWidth="200" prefHeight="200">
|
||||
<StackPane>
|
||||
<Group>
|
||||
<Arc styleClass="cache-arc-background" centerX="100" centerY="100" radiusX="100" radiusY="100" startAngle="225" length="-270"/>
|
||||
<Arc styleClass="cache-arc-foreground" centerX="100" centerY="100" radiusX="100" radiusY="100" startAngle="225" length="${controller.cacheHitDegrees}"/>
|
||||
</Group>
|
||||
<VBox StackPane.alignment="CENTER" alignment="CENTER">
|
||||
<FormattedLabel styleClass="label-large" format="\%1.0f %%" arg1="${controller.cacheHitPercentage}"/>
|
||||
<Label text="%stats.cacheHitRate"/>
|
||||
</VBox>
|
||||
</StackPane>
|
||||
</VBox>
|
||||
|
||||
<!-- Read -->
|
||||
<VBox prefWidth="300" prefHeight="300" spacing="6" alignment="CENTER">
|
||||
<ThrougputLabel styleClass="label-large" idleFormat="%stats.read.throughput.idle" kibsFormat="%stats.read.throughput.kibs" mibsFormat="%stats.read.throughput.mibs" bytesPerSecond="${controller.bpsRead}"/>
|
||||
<AreaChart fx:id="readChart" styleClass="io-stats" createSymbols="false" animated="false">
|
||||
<xAxis>
|
||||
<NumberAxis fx:id="readChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
|
||||
</xAxis>
|
||||
<yAxis>
|
||||
<NumberAxis fx:id="readChartYAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="true" side="LEFT" tickUnit="Infinity"/>
|
||||
</yAxis>
|
||||
<cursor>
|
||||
<Cursor fx:constant="DEFAULT"/>
|
||||
</cursor>
|
||||
</AreaChart>
|
||||
<DataLabel byteFormat="%stats.read.total.data.none" kibFormat="%stats.read.total.data.kib" mibFormat="%stats.read.total.data.mib" gibFormat="%stats.read.total.data.gib" dataInBytes="${controller.totalBytesRead}"/>
|
||||
<DataLabel byteFormat="%stats.decr.total.data.none" kibFormat="%stats.decr.total.data.kib" mibFormat="%stats.decr.total.data.mib" gibFormat="%stats.decr.total.data.gib" dataInBytes="${controller.totalBytesDecrypted}"/>
|
||||
<FormattedLabel format="%stats.read.accessCount" arg1="${controller.filesRead}"/>
|
||||
</VBox>
|
||||
|
||||
<!-- Write -->
|
||||
<VBox prefWidth="300" prefHeight="300" spacing="6" alignment="CENTER">
|
||||
<ThrougputLabel styleClass="label-large" idleFormat="%stats.write.throughput.idle" kibsFormat="%stats.write.throughput.kibs" mibsFormat="%stats.write.throughput.mibs" bytesPerSecond="${controller.bpsWritten}"/>
|
||||
<AreaChart fx:id="writeChart" styleClass="io-stats" createSymbols="false" animated="false">
|
||||
<xAxis>
|
||||
<NumberAxis fx:id="writeChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
|
||||
</xAxis>
|
||||
<yAxis>
|
||||
<NumberAxis fx:id="writeChartYAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="true" side="LEFT" tickUnit="Infinity"/>
|
||||
</yAxis>
|
||||
<cursor>
|
||||
<Cursor fx:constant="DEFAULT"/>
|
||||
</cursor>
|
||||
</AreaChart>
|
||||
<DataLabel byteFormat="%stats.write.total.data.none" kibFormat="%stats.write.total.data.kib" mibFormat="%stats.write.total.data.mib" gibFormat="%stats.write.total.data.gib" dataInBytes="${controller.totalBytesWritten}"/>
|
||||
<DataLabel byteFormat="%stats.encr.total.data.none" kibFormat="%stats.encr.total.data.kib" mibFormat="%stats.encr.total.data.mib" gibFormat="%stats.encr.total.data.gib" dataInBytes="${controller.totalBytesEncrypted}"/>
|
||||
<FormattedLabel format="%stats.write.accessCount" arg1="${controller.filesWritten}"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
@@ -35,14 +35,20 @@
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<HBox alignment="CENTER_RIGHT" spacing="6">
|
||||
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondRead"/>
|
||||
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
|
||||
mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondRead}"/>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER_RIGHT" spacing="6">
|
||||
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondWritten"/>
|
||||
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
|
||||
mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondWritten}"/>
|
||||
<HBox alignment="BOTTOM_RIGHT">
|
||||
<Button text="%main.vaultDetail.stats" minWidth="120" onAction="#showVaultStatistics" contentDisplay="BOTTOM">
|
||||
<graphic>
|
||||
<VBox spacing="6">
|
||||
<HBox alignment="CENTER_RIGHT" spacing="6">
|
||||
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondRead"/>
|
||||
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps" mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondRead}"/>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER_RIGHT" spacing="6">
|
||||
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondWritten"/>
|
||||
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps" mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondWritten}"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
</VBox>
|
||||
@@ -172,6 +172,36 @@ preferences.donationKey.getDonationKey=Get a donation key
|
||||
## About
|
||||
preferences.about=About
|
||||
|
||||
# Vault Statistics
|
||||
stats.title=Statistics for %s
|
||||
stats.cacheHitRate=Cache Hit Rate
|
||||
## Read
|
||||
stats.read.throughput.idle=Read: idle
|
||||
stats.read.throughput.kibs=Read: %.2f kiB/s
|
||||
stats.read.throughput.mibs=Read: %.2f MiB/s
|
||||
stats.read.total.data.none=Data read: -
|
||||
stats.read.total.data.kib=Data read: %.1f kiB
|
||||
stats.read.total.data.mib=Data read: %.1f MiB
|
||||
stats.read.total.data.gib=Data read: %.1f GiB
|
||||
stats.decr.total.data.none=Data decrypted: -
|
||||
stats.decr.total.data.kib=Data decrypted: %.1f kiB
|
||||
stats.decr.total.data.mib=Data decrypted: %.1f MiB
|
||||
stats.decr.total.data.gib=Data decrypted: %.1f GiB
|
||||
stats.read.accessCount=Total reads: %d
|
||||
## Write
|
||||
stats.write.throughput.idle=Write: idle
|
||||
stats.write.throughput.kibs=Write: %.2f kiB/s
|
||||
stats.write.throughput.mibs=Write: %.2f MiB/s
|
||||
stats.write.total.data.none=Data read: -
|
||||
stats.write.total.data.kib=Data written: %.1f kiB
|
||||
stats.write.total.data.mib=Data written: %.1f MiB
|
||||
stats.write.total.data.gib=Data written: %.1f GiB
|
||||
stats.encr.total.data.none=Data encrypted: -
|
||||
stats.encr.total.data.kib=Data encrypted: %.1f kiB
|
||||
stats.encr.total.data.mib=Data encrypted: %.1f MiB
|
||||
stats.encr.total.data.gib=Data encrypted: %.1f GiB
|
||||
stats.write.accessCount=Total writes: %d
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Close
|
||||
main.minimizeBtn.tooltip=Minimize
|
||||
@@ -199,11 +229,12 @@ main.vaultDetail.unlockedStatus=UNLOCKED
|
||||
main.vaultDetail.accessLocation=Your vault's contents are accessible here:
|
||||
main.vaultDetail.revealBtn=Reveal Drive
|
||||
main.vaultDetail.lockBtn=Lock
|
||||
main.vaultDetail.bytesPerSecondRead=read:
|
||||
main.vaultDetail.bytesPerSecondWritten=written:
|
||||
main.vaultDetail.bytesPerSecondRead=Read:
|
||||
main.vaultDetail.bytesPerSecondWritten=Write:
|
||||
main.vaultDetail.throughput.idle=idle
|
||||
main.vaultDetail.throughput.kbps=%.1f kiB/s
|
||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||
main.vaultDetail.stats=Vault Statistics
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=Cryptomator could not find a vault at this path.
|
||||
main.vaultDetail.missing.recheck=Recheck
|
||||
|
||||
@@ -19,7 +19,7 @@ Cryptomator uses 46 third-party dependencies under the following licenses:
|
||||
- jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
|
||||
- FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
|
||||
- Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
|
||||
- Dagger (com.google.dagger:dagger:2.22 - https://github.com/google/dagger)
|
||||
- Dagger (com.google.dagger:dagger:2.29.1 - https://github.com/google/dagger)
|
||||
- error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.4 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations)
|
||||
- Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
|
||||
- Guava: Google Core Libraries for Java (com.google.guava:guava:30.0-jre - https://github.com/google/guava/guava)
|
||||
@@ -28,19 +28,19 @@ Cryptomator uses 46 third-party dependencies under the following licenses:
|
||||
- Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
|
||||
- Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
|
||||
- javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
|
||||
- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access (net.java.dev.jna:jna:5.5.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.5.0 - https://github.com/java-native-access/jna)
|
||||
- Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - https://commons.apache.org/proper/commons-lang/)
|
||||
- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - http://hc.apache.org/httpcomponents-core-ga)
|
||||
- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.3 - http://jackrabbit.apache.org/jackrabbit-webdav/)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-util)
|
||||
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-webapp)
|
||||
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-xml)
|
||||
BSD:
|
||||
- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
|
||||
- asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
|
||||
@@ -48,30 +48,30 @@ Cryptomator uses 46 third-party dependencies under the following licenses:
|
||||
- asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
|
||||
- asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
|
||||
Eclipse Public License - Version 1.0:
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-util)
|
||||
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-webapp)
|
||||
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.33.v20201020 - https://eclipse.org/jetty/jetty-xml)
|
||||
Eclipse Public License - v 2.0:
|
||||
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
GPLv2:
|
||||
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
GPLv2+CE:
|
||||
- Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
|
||||
- javafx-base (org.openjfx:javafx-base:14 - https://openjdk.java.net/projects/openjfx/javafx-base/)
|
||||
- javafx-controls (org.openjfx:javafx-controls:14 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
|
||||
- javafx-fxml (org.openjfx:javafx-fxml:14 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
|
||||
- javafx-graphics (org.openjfx:javafx-graphics:14 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
|
||||
- javafx-base (org.openjfx:javafx-base:15 - https://openjdk.java.net/projects/openjfx/javafx-base/)
|
||||
- javafx-controls (org.openjfx:javafx-controls:15 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
|
||||
- javafx-fxml (org.openjfx:javafx-fxml:15 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
|
||||
- javafx-graphics (org.openjfx:javafx-graphics:15 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
|
||||
LGPL 2.1:
|
||||
- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access (net.java.dev.jna:jna:5.5.0 - https://github.com/java-native-access/jna)
|
||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.5.0 - https://github.com/java-native-access/jna)
|
||||
MIT License:
|
||||
- java jwt (com.auth0:java-jwt:3.10.3 - https://github.com/auth0/java-jwt)
|
||||
- java jwt (com.auth0:java-jwt:3.11.0 - https://github.com/auth0/java-jwt)
|
||||
- jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
|
||||
- jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)
|
||||
- zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
|
||||
|
||||
Reference in New Issue
Block a user