mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
add support for configuring server aliases, and switching servers via the tools menu
This commit is contained in:
parent
bacbdb848b
commit
1f67692727
17 changed files with 649 additions and 140 deletions
|
@ -182,6 +182,9 @@ public class AppController implements Initializable {
|
|||
@FXML
|
||||
private MenuItem showPayNym;
|
||||
|
||||
@FXML
|
||||
private Menu switchServer;
|
||||
|
||||
@FXML
|
||||
private CheckMenuItem preventSleep;
|
||||
private static final BooleanProperty preventSleepProperty = new SimpleBooleanProperty();
|
||||
|
@ -367,6 +370,7 @@ public class AppController implements Initializable {
|
|||
findMixingPartner.setDisable(exportWallet.isDisable() || getSelectedWalletForm() == null || !SorobanServices.canWalletMix(getSelectedWalletForm().getWallet()) || !newValue);
|
||||
});
|
||||
|
||||
configureSwitchServer();
|
||||
setServerType(Config.get().getServerType());
|
||||
serverToggle.setSelected(isConnected());
|
||||
serverToggle.setDisable(Config.get().getServerType() == null);
|
||||
|
@ -408,8 +412,7 @@ public class AppController implements Initializable {
|
|||
WelcomeDialog welcomeDialog = new WelcomeDialog();
|
||||
Optional<Mode> optionalMode = welcomeDialog.showAndWait();
|
||||
if(optionalMode.isPresent() && optionalMode.get().equals(Mode.ONLINE)) {
|
||||
PreferencesDialog preferencesDialog = new PreferencesDialog(PreferenceGroup.SERVER);
|
||||
preferencesDialog.showAndWait();
|
||||
openPreferences(PreferenceGroup.SERVER);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -902,7 +905,7 @@ public class AppController implements Initializable {
|
|||
|
||||
private String getServerToggleTooltipText(Integer currentBlockHeight) {
|
||||
if(AppServices.isConnected()) {
|
||||
return "Connected to " + Config.get().getServerAddress() + (currentBlockHeight != null ? " at height " + currentBlockHeight : "") +
|
||||
return "Connected to " + Config.get().getServerDisplayName() + (currentBlockHeight != null ? " at height " + currentBlockHeight : "") +
|
||||
(Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? "\nWarning! You are connected to a public server and sharing your transaction data with it.\nFor better privacy, consider using your own Bitcoin Core node or private Electrum server." : "");
|
||||
}
|
||||
|
||||
|
@ -1284,13 +1287,17 @@ public class AppController implements Initializable {
|
|||
}
|
||||
|
||||
public void openPreferences(ActionEvent event) {
|
||||
PreferencesDialog preferencesDialog = new PreferencesDialog();
|
||||
preferencesDialog.showAndWait();
|
||||
openPreferences(PreferenceGroup.GENERAL);
|
||||
}
|
||||
|
||||
public void openServerPreferences(ActionEvent event) {
|
||||
PreferencesDialog preferencesDialog = new PreferencesDialog(PreferenceGroup.SERVER);
|
||||
openPreferences(PreferenceGroup.SERVER);
|
||||
}
|
||||
|
||||
private void openPreferences(PreferenceGroup preferenceGroup) {
|
||||
PreferencesDialog preferencesDialog = new PreferencesDialog(preferenceGroup);
|
||||
preferencesDialog.showAndWait();
|
||||
configureSwitchServer();
|
||||
}
|
||||
|
||||
public void signVerifyMessage(ActionEvent event) {
|
||||
|
@ -1996,6 +2003,48 @@ public class AppController implements Initializable {
|
|||
return contextMenu;
|
||||
}
|
||||
|
||||
private void configureSwitchServer() {
|
||||
switchServer.getItems().clear();
|
||||
|
||||
Config config = Config.get();
|
||||
if(config.getServerType() == ServerType.BITCOIN_CORE && config.getRecentCoreServers() != null && config.getRecentCoreServers().size() > 1) {
|
||||
for(Server server : config.getRecentCoreServers()) {
|
||||
switchServer.getItems().add(getSwitchServerMenuItem(ServerType.BITCOIN_CORE, server));
|
||||
}
|
||||
} else if(config.getServerType() == ServerType.ELECTRUM_SERVER && config.getRecentElectrumServers() != null && config.getRecentElectrumServers().size() > 1) {
|
||||
for(Server server : config.getRecentElectrumServers()) {
|
||||
switchServer.getItems().add(getSwitchServerMenuItem(ServerType.ELECTRUM_SERVER, server));
|
||||
}
|
||||
}
|
||||
|
||||
switchServer.setVisible(!switchServer.getItems().isEmpty());
|
||||
}
|
||||
|
||||
private CheckMenuItem getSwitchServerMenuItem(ServerType serverType, Server server) {
|
||||
CheckMenuItem checkMenuItem = new CheckMenuItem(server.getDisplayName());
|
||||
boolean selected = (serverType == ServerType.BITCOIN_CORE ? server.equals(Config.get().getCoreServer()) : server.equals(Config.get().getElectrumServer()));
|
||||
checkMenuItem.setSelected(selected);
|
||||
checkMenuItem.setOnAction(event -> {
|
||||
if(!selected) {
|
||||
boolean online = onlineProperty().get();
|
||||
onlineProperty().set(false);
|
||||
if(serverType == ServerType.BITCOIN_CORE) {
|
||||
Config.get().setCoreServer(server);
|
||||
} else if(serverType == ServerType.ELECTRUM_SERVER) {
|
||||
Config.get().setElectrumServer(server);
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
onlineProperty().set(online);
|
||||
configureSwitchServer();
|
||||
});
|
||||
} else {
|
||||
checkMenuItem.setSelected(true);
|
||||
}
|
||||
});
|
||||
|
||||
return checkMenuItem;
|
||||
}
|
||||
|
||||
public void setServerType(ServerType serverType) {
|
||||
if(serverType == ServerType.PUBLIC_ELECTRUM_SERVER && !serverToggle.getStyleClass().contains("public-server")) {
|
||||
serverToggle.getStyleClass().add("public-server");
|
||||
|
@ -2424,11 +2473,12 @@ public class AppController implements Initializable {
|
|||
|
||||
@Subscribe
|
||||
public void connection(ConnectionEvent event) {
|
||||
String status = "Connected to " + Config.get().getServerAddress() + " at height " + event.getBlockHeight();
|
||||
String status = "Connected to " + Config.get().getServerDisplayName() + " at height " + event.getBlockHeight();
|
||||
statusUpdated(new StatusEvent(status));
|
||||
setServerToggleTooltip(event.getBlockHeight());
|
||||
serverToggleStopAnimation();
|
||||
setTorIcon();
|
||||
configureSwitchServer();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
|
|
@ -203,7 +203,7 @@ public class AppServices {
|
|||
|
||||
private void restartServices() {
|
||||
Config config = Config.get();
|
||||
if(config.hasServerAddress()) {
|
||||
if(config.hasServer()) {
|
||||
restartService(connectionService);
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ public class AppServices {
|
|||
connectionService.setOnRunning(workerStateEvent -> {
|
||||
connectionService.setDelay(Duration.ZERO);
|
||||
if(!ElectrumServer.isConnected()) {
|
||||
EventManager.get().post(new ConnectionStartEvent(Config.get().getServerAddress()));
|
||||
EventManager.get().post(new ConnectionStartEvent(Config.get().getServerDisplayName()));
|
||||
}
|
||||
});
|
||||
connectionService.setOnSucceeded(successEvent -> {
|
||||
|
@ -1157,8 +1157,10 @@ public class AppServices {
|
|||
|
||||
@Subscribe
|
||||
public void requestConnect(RequestConnectEvent event) {
|
||||
if(Config.get().hasServer()) {
|
||||
onlineProperty.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void requestDisconnect(RequestDisconnectEvent event) {
|
||||
|
@ -1209,7 +1211,7 @@ public class AppServices {
|
|||
public void walletHistoryFailed(WalletHistoryFailedEvent event) {
|
||||
if(Config.get().getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER && isConnected()) {
|
||||
onlineProperty.set(false);
|
||||
log.warn("Failed to fetch wallet history from " + Config.get().getServerAddress() + ", reconnecting to another server...");
|
||||
log.warn("Failed to fetch wallet history from " + Config.get().getServerDisplayName() + ", reconnecting to another server...");
|
||||
Config.get().changePublicServer();
|
||||
onlineProperty.set(true);
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ public class MainApp extends Application {
|
|||
} else if(Network.get() == Network.MAINNET) {
|
||||
Config.get().setServerType(ServerType.PUBLIC_ELECTRUM_SERVER);
|
||||
List<PublicElectrumServer> servers = PublicElectrumServer.getServers();
|
||||
Config.get().setPublicElectrumServer(servers.get(new Random().nextInt(servers.size())).getUrl());
|
||||
Config.get().setPublicElectrumServer(servers.get(new Random().nextInt(servers.size())).getServer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ public class FontAwesome5 extends GlyphFont {
|
|||
SNOWFLAKE('\uf2dc'),
|
||||
SORT_NUMERIC_DOWN('\uf162'),
|
||||
SUN('\uf185'),
|
||||
TAG('\uf02b'),
|
||||
THEATER_MASKS('\uf630'),
|
||||
TIMES_CIRCLE('\uf057'),
|
||||
TOGGLE_OFF('\uf204'),
|
||||
|
|
|
@ -53,14 +53,14 @@ public class Config {
|
|||
private Boolean hdCapture;
|
||||
private String webcamDevice;
|
||||
private ServerType serverType;
|
||||
private String publicElectrumServer;
|
||||
private String coreServer;
|
||||
private List<String> recentCoreServers;
|
||||
private Server publicElectrumServer;
|
||||
private Server coreServer;
|
||||
private List<Server> recentCoreServers;
|
||||
private CoreAuthType coreAuthType;
|
||||
private File coreDataDir;
|
||||
private String coreAuth;
|
||||
private String electrumServer;
|
||||
private List<String> recentElectrumServers;
|
||||
private Server electrumServer;
|
||||
private List<Server> recentElectrumServers;
|
||||
private File electrumServerCert;
|
||||
private boolean useProxy;
|
||||
private String proxyServer;
|
||||
|
@ -77,6 +77,8 @@ public class Config {
|
|||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.registerTypeAdapter(File.class, new FileSerializer());
|
||||
gsonBuilder.registerTypeAdapter(File.class, new FileDeserializer());
|
||||
gsonBuilder.registerTypeAdapter(Server.class, new ServerSerializer());
|
||||
gsonBuilder.registerTypeAdapter(Server.class, new ServerDeserializer());
|
||||
return gsonBuilder.setPrettyPrinting().disableHtmlEscaping().create();
|
||||
}
|
||||
|
||||
|
@ -362,14 +364,18 @@ public class Config {
|
|||
flush();
|
||||
}
|
||||
|
||||
public boolean hasServerAddress() {
|
||||
return getServerAddress() != null && !getServerAddress().isEmpty();
|
||||
public boolean hasServer() {
|
||||
return getServer() != null;
|
||||
}
|
||||
|
||||
public String getServerAddress() {
|
||||
public Server getServer() {
|
||||
return getServerType() == ServerType.BITCOIN_CORE ? getCoreServer() : (getServerType() == ServerType.PUBLIC_ELECTRUM_SERVER ? getPublicElectrumServer() : getElectrumServer());
|
||||
}
|
||||
|
||||
public String getServerDisplayName() {
|
||||
return getServer() == null ? "server" : getServer().getDisplayName();
|
||||
}
|
||||
|
||||
public boolean requiresInternalTor() {
|
||||
if(isUseProxy()) {
|
||||
return false;
|
||||
|
@ -379,57 +385,71 @@ public class Config {
|
|||
}
|
||||
|
||||
public boolean requiresTor() {
|
||||
if(!hasServerAddress()) {
|
||||
if(!hasServer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Protocol protocol = Protocol.getProtocol(getServerAddress());
|
||||
if(protocol == null) {
|
||||
return false;
|
||||
return getServer().isOnionAddress();
|
||||
}
|
||||
|
||||
return protocol.isOnionAddress(protocol.getServerHostAndPort(getServerAddress()));
|
||||
}
|
||||
|
||||
public String getPublicElectrumServer() {
|
||||
public Server getPublicElectrumServer() {
|
||||
return publicElectrumServer;
|
||||
}
|
||||
|
||||
public void setPublicElectrumServer(String publicElectrumServer) {
|
||||
public void setPublicElectrumServer(Server publicElectrumServer) {
|
||||
this.publicElectrumServer = publicElectrumServer;
|
||||
flush();
|
||||
}
|
||||
|
||||
public void changePublicServer() {
|
||||
List<String> otherServers = PublicElectrumServer.getServers().stream().map(PublicElectrumServer::getUrl).filter(url -> !url.equals(getPublicElectrumServer())).collect(Collectors.toList());
|
||||
List<Server> otherServers = PublicElectrumServer.getServers().stream().map(PublicElectrumServer::getServer).filter(server -> !server.equals(getPublicElectrumServer())).collect(Collectors.toList());
|
||||
if(!otherServers.isEmpty()) {
|
||||
setPublicElectrumServer(otherServers.get(new Random().nextInt(otherServers.size())));
|
||||
}
|
||||
}
|
||||
|
||||
public String getCoreServer() {
|
||||
public Server getCoreServer() {
|
||||
return coreServer;
|
||||
}
|
||||
|
||||
public void setCoreServer(String coreServer) {
|
||||
public void setCoreServer(Server coreServer) {
|
||||
this.coreServer = coreServer;
|
||||
flush();
|
||||
}
|
||||
|
||||
public List<String> getRecentCoreServers() {
|
||||
return recentCoreServers;
|
||||
public List<Server> getRecentCoreServers() {
|
||||
return recentCoreServers == null ? new ArrayList<>() : recentCoreServers;
|
||||
}
|
||||
|
||||
public void addRecentCoreServer(String coreServer) {
|
||||
public boolean addRecentCoreServer(Server coreServer) {
|
||||
if(recentCoreServers == null) {
|
||||
recentCoreServers = new ArrayList<>();
|
||||
}
|
||||
|
||||
if(!recentCoreServers.contains(coreServer)) {
|
||||
recentCoreServers.stream().filter(url -> Objects.equals(Protocol.getHost(url), Protocol.getHost(coreServer)))
|
||||
.findFirst().ifPresent(existingUrl -> recentCoreServers.remove(existingUrl));
|
||||
int index = getRecentCoreServers().indexOf(coreServer);
|
||||
if(index < 0) {
|
||||
recentCoreServers.removeIf(server -> server.getHost().equals(coreServer.getHost()) && server.getAlias() == null);
|
||||
recentCoreServers.add(coreServer);
|
||||
flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removeRecentCoreServer(Server server) {
|
||||
int index = getRecentCoreServers().indexOf(server);
|
||||
if(index >= 0) {
|
||||
recentCoreServers.remove(index);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void setCoreServerAlias(Server server) {
|
||||
int index = getRecentCoreServers().indexOf(server);
|
||||
if(index >= 0) {
|
||||
recentCoreServers.set(index, server);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,37 +480,59 @@ public class Config {
|
|||
flush();
|
||||
}
|
||||
|
||||
public String getElectrumServer() {
|
||||
public Server getElectrumServer() {
|
||||
return electrumServer;
|
||||
}
|
||||
|
||||
public void setElectrumServer(String electrumServer) {
|
||||
public void setElectrumServer(Server electrumServer) {
|
||||
this.electrumServer = electrumServer;
|
||||
flush();
|
||||
}
|
||||
|
||||
public List<String> getRecentElectrumServers() {
|
||||
return recentElectrumServers;
|
||||
public List<Server> getRecentElectrumServers() {
|
||||
return recentElectrumServers == null ? new ArrayList<>() : recentElectrumServers;
|
||||
}
|
||||
|
||||
public void addRecentServer() {
|
||||
public boolean addRecentServer() {
|
||||
if(serverType == ServerType.BITCOIN_CORE && coreServer != null) {
|
||||
addRecentCoreServer(coreServer);
|
||||
return addRecentCoreServer(coreServer);
|
||||
} else if(serverType == ServerType.ELECTRUM_SERVER && electrumServer != null) {
|
||||
addRecentElectrumServer(electrumServer);
|
||||
}
|
||||
return addRecentElectrumServer(electrumServer);
|
||||
}
|
||||
|
||||
public void addRecentElectrumServer(String electrumServer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean addRecentElectrumServer(Server electrumServer) {
|
||||
if(recentElectrumServers == null) {
|
||||
recentElectrumServers = new ArrayList<>();
|
||||
}
|
||||
|
||||
if(!recentElectrumServers.contains(electrumServer)) {
|
||||
recentElectrumServers.stream().filter(url -> Objects.equals(Protocol.getHost(url), Protocol.getHost(electrumServer)))
|
||||
.findFirst().ifPresent(existingUrl -> recentElectrumServers.remove(existingUrl));
|
||||
int index = getRecentElectrumServers().indexOf(electrumServer);
|
||||
if(index < 0) {
|
||||
recentElectrumServers.removeIf(server -> server.getHost().equals(electrumServer.getHost()) && server.getAlias() == null);
|
||||
recentElectrumServers.add(electrumServer);
|
||||
flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void removeRecentElectrumServer(Server server) {
|
||||
int index = getRecentElectrumServers().indexOf(server);
|
||||
if(index >= 0) {
|
||||
recentElectrumServers.remove(index);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void setElectrumServerAlias(Server server) {
|
||||
int index = getRecentElectrumServers().indexOf(server);
|
||||
if(index >= 0) {
|
||||
recentElectrumServers.set(index, server);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,4 +637,18 @@ public class Config {
|
|||
return new File(json.getAsJsonPrimitive().getAsString());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ServerSerializer implements JsonSerializer<Server> {
|
||||
@Override
|
||||
public JsonElement serialize(Server src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ServerDeserializer implements JsonDeserializer<Server> {
|
||||
@Override
|
||||
public Server deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return Server.fromString(json.getAsJsonPrimitive().getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
99
src/main/java/com/sparrowwallet/sparrow/io/Server.java
Normal file
99
src/main/java/com/sparrowwallet/sparrow/io/Server.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
package com.sparrowwallet.sparrow.io;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.sparrowwallet.sparrow.net.Protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Server {
|
||||
private final String url;
|
||||
private final String alias;
|
||||
|
||||
public Server(String url) {
|
||||
this(url, null);
|
||||
}
|
||||
|
||||
public Server(String url, String alias) {
|
||||
if(url == null) {
|
||||
throw new IllegalArgumentException("Url cannot be null");
|
||||
}
|
||||
|
||||
if(url.isEmpty()) {
|
||||
throw new IllegalArgumentException("Url cannot be empty");
|
||||
}
|
||||
|
||||
if(Protocol.getProtocol(url) == null) {
|
||||
throw new IllegalArgumentException("Unknown protocol for url " + url + ", must be one of " + Arrays.toString(Protocol.values()));
|
||||
}
|
||||
|
||||
if(Protocol.getHost(url) == null) {
|
||||
throw new IllegalArgumentException("Cannot determine host for url " + url);
|
||||
}
|
||||
|
||||
if(alias != null && alias.isEmpty()) {
|
||||
throw new IllegalArgumentException("Server alias cannot be an empty string");
|
||||
}
|
||||
|
||||
this.url = url;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public Protocol getProtocol() {
|
||||
return Protocol.getProtocol(url);
|
||||
}
|
||||
|
||||
public HostAndPort getHostAndPort() {
|
||||
return getProtocol().getServerHostAndPort(url);
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return getHostAndPort().getHost();
|
||||
}
|
||||
|
||||
public boolean isOnionAddress() {
|
||||
return Protocol.isOnionAddress(getHostAndPort());
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return alias == null ? url : alias;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return url + (alias == null ? "" : "|" + alias);
|
||||
}
|
||||
|
||||
public static Server fromString(String server) {
|
||||
String[] parts = server.split("\\|");
|
||||
if(parts.length >= 2) {
|
||||
return new Server(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
return new Server(parts[0], null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) {
|
||||
return true;
|
||||
}
|
||||
if(o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Server server = (Server)o;
|
||||
return url.equals(server.url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return url.hashCode();
|
||||
}
|
||||
}
|
|
@ -143,8 +143,8 @@ public class Bwt {
|
|||
bwtConfig.electrumSkipMerkle = true;
|
||||
|
||||
Config config = Config.get();
|
||||
bwtConfig.bitcoindUrl = config.getCoreServer();
|
||||
if(bwtConfig.bitcoindUrl != null) {
|
||||
if(config.getCoreServer() != null) {
|
||||
bwtConfig.bitcoindUrl = config.getCoreServer().getUrl();
|
||||
try {
|
||||
HostAndPort hostAndPort = Protocol.HTTP.getServerHostAndPort(bwtConfig.bitcoindUrl);
|
||||
if(hostAndPort.getHost().endsWith(".local")) {
|
||||
|
@ -308,7 +308,7 @@ public class Bwt {
|
|||
Bwt.this.shutdown();
|
||||
terminating = false;
|
||||
} else {
|
||||
Platform.runLater(() -> EventManager.get().post(new BwtBootStatusEvent("Connecting to Bitcoin Core node at " + Config.get().getCoreServer() + "...")));
|
||||
Platform.runLater(() -> EventManager.get().post(new BwtBootStatusEvent("Connecting to Bitcoin Core node " + Config.get().getServerDisplayName() + "...")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.github.arteam.simplejsonrpc.client.Transport;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.sparrowwallet.drongo.KeyPurpose;
|
||||
|
@ -15,6 +14,7 @@ import com.sparrowwallet.sparrow.AppServices;
|
|||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
import com.sparrowwallet.sparrow.paynym.PayNym;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
|
@ -51,7 +51,7 @@ public class ElectrumServer {
|
|||
|
||||
private static final Map<String, List<String>> subscribedScriptHashes = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private static String previousServerAddress;
|
||||
private static Server previousServer;
|
||||
|
||||
private static Map<String, String> retrievedScriptHashes = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
|
@ -59,14 +59,14 @@ public class ElectrumServer {
|
|||
|
||||
private static ElectrumServerRpc electrumServerRpc = new SimpleElectrumServerRpc();
|
||||
|
||||
private static String bwtElectrumServer;
|
||||
private static Server bwtElectrumServer;
|
||||
|
||||
private static final Pattern RPC_WALLET_LOADING_PATTERN = Pattern.compile(".*\"(Wallet loading failed:[^\"]*)\".*");
|
||||
|
||||
private static synchronized CloseableTransport getTransport() throws ServerException {
|
||||
if(transport == null) {
|
||||
try {
|
||||
String electrumServer = null;
|
||||
Server electrumServer = null;
|
||||
File electrumServerCert = null;
|
||||
String proxyServer = null;
|
||||
|
||||
|
@ -78,8 +78,8 @@ public class ElectrumServer {
|
|||
throw new ServerConfigException("Could not connect to Bitcoin Core RPC");
|
||||
}
|
||||
electrumServer = bwtElectrumServer;
|
||||
if(previousServerAddress != null && previousServerAddress.contains(Bwt.ELECTRUM_HOST)) {
|
||||
previousServerAddress = bwtElectrumServer;
|
||||
if(previousServer != null && previousServer.getUrl().contains(Bwt.ELECTRUM_HOST)) {
|
||||
previousServer = bwtElectrumServer;
|
||||
}
|
||||
} else if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER) {
|
||||
electrumServer = Config.get().getElectrumServer();
|
||||
|
@ -95,33 +95,30 @@ public class ElectrumServer {
|
|||
throw new ServerConfigException("Electrum server certificate file not found");
|
||||
}
|
||||
|
||||
Protocol protocol = Protocol.getProtocol(electrumServer);
|
||||
if(protocol == null) {
|
||||
throw new ServerConfigException("Electrum server URL must start with " + Protocol.TCP.toUrlString() + " or " + Protocol.SSL.toUrlString());
|
||||
}
|
||||
Protocol protocol = electrumServer.getProtocol();
|
||||
|
||||
//If changing server, don't rely on previous transaction history
|
||||
if(previousServerAddress != null && !electrumServer.equals(previousServerAddress)) {
|
||||
if(previousServer != null && !electrumServer.equals(previousServer)) {
|
||||
retrievedScriptHashes.clear();
|
||||
retrievedTransactions.clear();
|
||||
}
|
||||
previousServerAddress = electrumServer;
|
||||
previousServer = electrumServer;
|
||||
|
||||
HostAndPort server = protocol.getServerHostAndPort(electrumServer);
|
||||
boolean localNetworkAddress = !protocol.isOnionAddress(server) && IpAddressMatcher.isLocalNetworkAddress(server.getHost());
|
||||
HostAndPort hostAndPort = electrumServer.getHostAndPort();
|
||||
boolean localNetworkAddress = !protocol.isOnionAddress(hostAndPort) && IpAddressMatcher.isLocalNetworkAddress(hostAndPort.getHost());
|
||||
|
||||
if(!localNetworkAddress && Config.get().isUseProxy() && proxyServer != null && !proxyServer.isBlank()) {
|
||||
HostAndPort proxy = HostAndPort.fromString(proxyServer);
|
||||
if(electrumServerCert != null) {
|
||||
transport = protocol.getTransport(server, electrumServerCert, proxy);
|
||||
transport = protocol.getTransport(hostAndPort, electrumServerCert, proxy);
|
||||
} else {
|
||||
transport = protocol.getTransport(server, proxy);
|
||||
transport = protocol.getTransport(hostAndPort, proxy);
|
||||
}
|
||||
} else {
|
||||
if(electrumServerCert != null) {
|
||||
transport = protocol.getTransport(server, electrumServerCert);
|
||||
transport = protocol.getTransport(hostAndPort, electrumServerCert);
|
||||
} else {
|
||||
transport = protocol.getTransport(server);
|
||||
transport = protocol.getTransport(hostAndPort);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -1251,7 +1248,7 @@ public class ElectrumServer {
|
|||
@Subscribe
|
||||
public void bwtElectrumReadyStatus(BwtElectrumReadyStatusEvent event) {
|
||||
if(this.isRunning()) {
|
||||
ElectrumServer.bwtElectrumServer = Protocol.TCP.toUrlString(HostAndPort.fromString(event.getElectrumAddr()));
|
||||
ElectrumServer.bwtElectrumServer = new Server(Protocol.TCP.toUrlString(HostAndPort.fromString(event.getElectrumAddr())));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ public final class IpAddressMatcher {
|
|||
return InetAddress.getByName(address);
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
throw new IllegalArgumentException("Failed to parse address" + address, e);
|
||||
throw new IllegalArgumentException("Failed to parse address: " + address, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.github.arteam.simplejsonrpc.client.Transport;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -121,6 +121,14 @@ public enum Protocol {
|
|||
return host != null && host.toLowerCase(Locale.ROOT).endsWith(TorService.TOR_ADDRESS_SUFFIX);
|
||||
}
|
||||
|
||||
public static boolean isOnionAddress(Server server) {
|
||||
if(server != null) {
|
||||
return isOnionAddress(server.getHostAndPort());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isOnionAddress(HostAndPort server) {
|
||||
return isOnionHost(server.getHost());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.sparrowwallet.drongo.Network;
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -15,23 +16,21 @@ public enum PublicElectrumServer {
|
|||
TESTNET_ARANGUREN_ORG("testnet.aranguren.org", "ssl://testnet.aranguren.org:51002", Network.TESTNET);
|
||||
|
||||
PublicElectrumServer(String name, String url, Network network) {
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
this.server = new Server(url, name);
|
||||
this.network = network;
|
||||
}
|
||||
|
||||
public static final List<Network> SUPPORTED_NETWORKS = List.of(Network.MAINNET, Network.TESTNET);
|
||||
|
||||
private final String name;
|
||||
private final String url;
|
||||
private final Server server;
|
||||
private final Network network;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
return server.getUrl();
|
||||
}
|
||||
|
||||
public Network getNetwork() {
|
||||
|
@ -46,10 +45,10 @@ public enum PublicElectrumServer {
|
|||
return SUPPORTED_NETWORKS.contains(Network.get());
|
||||
}
|
||||
|
||||
public static PublicElectrumServer fromUrl(String url) {
|
||||
for(PublicElectrumServer server : values()) {
|
||||
if(server.url.equals(url)) {
|
||||
return server;
|
||||
public static PublicElectrumServer fromServer(Server server) {
|
||||
for(PublicElectrumServer publicServer : values()) {
|
||||
if(publicServer.getServer().equals(server)) {
|
||||
return publicServer;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +57,6 @@ public enum PublicElectrumServer {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
return server.getAlias();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,8 @@ public class TcpOverTlsTransport extends TcpTransport {
|
|||
|
||||
protected boolean shouldSaveCertificate() {
|
||||
//Avoid saving the certificates for blockstream.info public servers - they change too often and encourage approval complacency
|
||||
if(PublicElectrumServer.BLOCKSTREAM_INFO.getName().equals(server.getHost()) || PublicElectrumServer.ELECTRUM_BLOCKSTREAM_INFO.getName().equals(server.getHost())) {
|
||||
if(PublicElectrumServer.BLOCKSTREAM_INFO.getServer().getHost().equals(server.getHost())
|
||||
|| PublicElectrumServer.ELECTRUM_BLOCKSTREAM_INFO.getServer().getHost().equals(server.getHost())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,10 @@ public class TcpTransport implements CloseableTransport, TimeoutCounter {
|
|||
log.trace("Sending to electrum server at " + server + ": " + request);
|
||||
}
|
||||
|
||||
if(socket == null) {
|
||||
throw new IllegalStateException("Socket connection has not been established.");
|
||||
}
|
||||
|
||||
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
|
||||
out.println(request);
|
||||
out.flush();
|
||||
|
@ -207,7 +211,7 @@ public class TcpTransport implements CloseableTransport, TimeoutCounter {
|
|||
String response = readLine(in);
|
||||
|
||||
if(response == null) {
|
||||
throw new IOException("Could not connect to server at " + Config.get().getServerAddress());
|
||||
throw new IOException("Could not connect to server" + (Config.get().hasServer() ? " at " + Config.get().getServer().getUrl() : ""));
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
package com.sparrowwallet.sparrow.preferences;
|
||||
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
import com.sparrowwallet.sparrow.net.ServerType;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.Event;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.util.converter.DefaultStringConverter;
|
||||
import org.controlsfx.glyphfont.Glyph;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ServerAliasDialog extends Dialog<Server> {
|
||||
private final ServerType serverType;
|
||||
private final TableView<ServerEntry> serverTable;
|
||||
|
||||
public ServerAliasDialog(ServerType serverType) {
|
||||
this.serverType = serverType;
|
||||
|
||||
final DialogPane dialogPane = new ServerAliasDialogPane();
|
||||
setDialogPane(dialogPane);
|
||||
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
||||
|
||||
setTitle("Server Aliases");
|
||||
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
|
||||
dialogPane.setHeaderText("Configure aliases for recently connected servers.\nNew servers are added to this list on successful connections.");
|
||||
|
||||
Image image = new Image("/image/sparrow-small.png");
|
||||
dialogPane.setGraphic(new ImageView(image));
|
||||
|
||||
serverTable = new TableView<>();
|
||||
serverTable.setPlaceholder(new Label("No servers added yet"));
|
||||
|
||||
TableColumn<ServerEntry, String> urlColumn = new TableColumn<>("URL");
|
||||
urlColumn.setMinWidth(300);
|
||||
urlColumn.setCellValueFactory((TableColumn.CellDataFeatures<ServerEntry, String> param) -> {
|
||||
return new ReadOnlyObjectWrapper<>(param.getValue().getUrl());
|
||||
});
|
||||
|
||||
TableColumn<ServerEntry, String> aliasColumn = new TableColumn<>("Alias");
|
||||
aliasColumn.setCellValueFactory((TableColumn.CellDataFeatures<ServerEntry, String> param) -> {
|
||||
return param.getValue().labelProperty();
|
||||
});
|
||||
aliasColumn.setCellFactory(value -> new AliasCell());
|
||||
aliasColumn.setGraphic(getTagGlyph());
|
||||
|
||||
serverTable.getColumns().add(urlColumn);
|
||||
serverTable.getColumns().add(aliasColumn);
|
||||
serverTable.setEditable(true);
|
||||
serverTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
|
||||
List<Server> servers = serverType == ServerType.BITCOIN_CORE ? Config.get().getRecentCoreServers() : Config.get().getRecentElectrumServers();
|
||||
List<ServerEntry> serverEntries = servers.stream().map(server -> new ServerEntry(serverType, server)).collect(Collectors.toList());
|
||||
serverTable.setItems(FXCollections.observableArrayList(serverEntries));
|
||||
|
||||
StackPane stackPane = new StackPane();
|
||||
stackPane.getChildren().add(serverTable);
|
||||
dialogPane.setContent(stackPane);
|
||||
|
||||
ButtonType selectButtonType = new ButtonType("Select", ButtonBar.ButtonData.APPLY);
|
||||
ButtonType deleteButtonType = new ButtonType("Delete", ButtonBar.ButtonData.LEFT);
|
||||
dialogPane.getButtonTypes().addAll(deleteButtonType, ButtonType.CLOSE, selectButtonType);
|
||||
|
||||
Button selectButton = (Button)dialogPane.lookupButton(selectButtonType);
|
||||
Button deleteButton = (Button)dialogPane.lookupButton(deleteButtonType);
|
||||
selectButton.setDefaultButton(true);
|
||||
selectButton.setDisable(true);
|
||||
deleteButton.setDisable(true);
|
||||
serverTable.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
selectButton.setDisable(newValue == null);
|
||||
deleteButton.setDisable(newValue == null);
|
||||
});
|
||||
|
||||
setResultConverter(buttonType -> buttonType == selectButtonType ? serverTable.getSelectionModel().getSelectedItem().getServer() : null);
|
||||
|
||||
dialogPane.setPrefWidth(680);
|
||||
dialogPane.setPrefHeight(500);
|
||||
AppServices.setStageIcon(dialogPane.getScene().getWindow());
|
||||
AppServices.moveToActiveWindowScreen(this);
|
||||
}
|
||||
|
||||
private static Glyph getTagGlyph() {
|
||||
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.TAG);
|
||||
glyph.setFontSize(12);
|
||||
return glyph;
|
||||
}
|
||||
|
||||
private class ServerAliasDialogPane extends DialogPane {
|
||||
@Override
|
||||
protected Node createButton(ButtonType buttonType) {
|
||||
Node button;
|
||||
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
|
||||
Button deleteButton = new Button(buttonType.getText());
|
||||
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
|
||||
ButtonBar.setButtonData(deleteButton, buttonData);
|
||||
deleteButton.setOnAction(event -> {
|
||||
ServerEntry serverEntry = serverTable.getSelectionModel().getSelectedItem();
|
||||
if(serverEntry != null) {
|
||||
serverTable.getItems().remove(serverEntry);
|
||||
if(serverType == ServerType.BITCOIN_CORE) {
|
||||
Config.get().removeRecentCoreServer(serverEntry.getServer());
|
||||
} else {
|
||||
Config.get().removeRecentElectrumServer(serverEntry.getServer());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
button = deleteButton;
|
||||
} else {
|
||||
button = super.createButton(buttonType);
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ServerEntry {
|
||||
private final Server server;
|
||||
private final StringProperty labelProperty = new SimpleStringProperty();
|
||||
|
||||
public ServerEntry(ServerType serverType, Server server) {
|
||||
this.server = server;
|
||||
labelProperty.set(server.getAlias());
|
||||
labelProperty.addListener((observable, oldValue, newValue) -> {
|
||||
String alias = newValue;
|
||||
if(alias != null && alias.isEmpty()) {
|
||||
alias = null;
|
||||
}
|
||||
|
||||
Server newServer = new Server(server.getUrl(), alias);
|
||||
if(serverType == ServerType.BITCOIN_CORE) {
|
||||
Config.get().setCoreServerAlias(newServer);
|
||||
} else {
|
||||
Config.get().setElectrumServerAlias(newServer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return server.getHostAndPort().toString();
|
||||
}
|
||||
|
||||
public StringProperty labelProperty() {
|
||||
return labelProperty;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return new Server(server.getUrl(), labelProperty.get());
|
||||
}
|
||||
}
|
||||
|
||||
private static class AliasCell extends TextFieldTableCell<ServerEntry, String> {
|
||||
public AliasCell() {
|
||||
super(new DefaultStringConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitEdit(String label) {
|
||||
if(label != null) {
|
||||
label = label.trim();
|
||||
}
|
||||
|
||||
// This block is necessary to support commit on losing focus, because
|
||||
// the baked-in mechanism sets our editing state to false before we can
|
||||
// intercept the loss of focus. The default commitEdit(...) method
|
||||
// simply bails if we are not editing...
|
||||
if (!isEditing() && !label.equals(getItem())) {
|
||||
TableView<ServerEntry> table = getTableView();
|
||||
if(table != null) {
|
||||
TableColumn<ServerEntry, String> column = getTableColumn();
|
||||
TableColumn.CellEditEvent<ServerEntry, String> event = new TableColumn.CellEditEvent<>(
|
||||
table, new TablePosition<>(table, getIndex(), column),
|
||||
TableColumn.editCommitEvent(), label
|
||||
);
|
||||
Event.fireEvent(column, event);
|
||||
}
|
||||
}
|
||||
|
||||
super.commitEdit(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startEdit() {
|
||||
super.startEdit();
|
||||
|
||||
try {
|
||||
Field f = getClass().getSuperclass().getDeclaredField("textField");
|
||||
f.setAccessible(true);
|
||||
TextField textField = (TextField)f.get(this);
|
||||
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
|
||||
if (!isNowFocused) {
|
||||
commitEdit(getConverter().fromString(textField.getText()));
|
||||
setText(getConverter().fromString(textField.getText()));
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,11 +12,13 @@ import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch;
|
|||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import com.sparrowwallet.sparrow.net.*;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.text.Font;
|
||||
|
@ -51,6 +53,8 @@ import java.util.Random;
|
|||
public class ServerPreferencesController extends PreferencesDetailController {
|
||||
private static final Logger log = LoggerFactory.getLogger(ServerPreferencesController.class);
|
||||
|
||||
private static final Server MANAGE_ALIASES_SERVER = new Server("tcp://localhost", "Manage Aliases...");
|
||||
|
||||
@FXML
|
||||
private ToggleGroup serverTypeToggleGroup;
|
||||
|
||||
|
@ -79,7 +83,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
private Form coreForm;
|
||||
|
||||
@FXML
|
||||
private ComboBox<String> recentCoreServers;
|
||||
private ComboBox<Server> recentCoreServers;
|
||||
|
||||
@FXML
|
||||
private ComboBoxTextField coreHost;
|
||||
|
@ -121,7 +125,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
private Form electrumForm;
|
||||
|
||||
@FXML
|
||||
private ComboBox<String> recentElectrumServers;
|
||||
private ComboBox<Server> recentElectrumServers;
|
||||
|
||||
@FXML
|
||||
private ComboBoxTextField electrumHost;
|
||||
|
@ -267,26 +271,52 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
}
|
||||
});
|
||||
|
||||
recentCoreServers.setConverter(new UrlHostConverter());
|
||||
recentCoreServers.setItems(FXCollections.observableList(Config.get().getRecentCoreServers() == null ? new ArrayList<>() : Config.get().getRecentCoreServers()));
|
||||
recentCoreServers.setCellFactory(value -> new ServerCell());
|
||||
recentCoreServers.setItems(getObservableServerList(Config.get().getRecentCoreServers()));
|
||||
recentCoreServers.prefWidthProperty().bind(coreHost.widthProperty());
|
||||
recentCoreServers.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue != null && Protocol.getProtocol(newValue) != null) {
|
||||
HostAndPort hostAndPort = Protocol.getProtocol(newValue).getServerHostAndPort(newValue);
|
||||
if(newValue != null) {
|
||||
if(newValue == MANAGE_ALIASES_SERVER) {
|
||||
ServerAliasDialog serverAliasDialog = new ServerAliasDialog(ServerType.BITCOIN_CORE);
|
||||
Optional<Server> optServer = serverAliasDialog.showAndWait();
|
||||
recentCoreServers.setItems(getObservableServerList(Config.get().getRecentCoreServers()));
|
||||
Server selectedServer = optServer.orElseGet(() -> Config.get().getCoreServer());
|
||||
Platform.runLater(() -> recentCoreServers.setValue(selectedServer));
|
||||
} else if(newValue.getHostAndPort() != null) {
|
||||
HostAndPort hostAndPort = newValue.getHostAndPort();
|
||||
corePort.setText(hostAndPort.hasPort() ? Integer.toString(hostAndPort.getPort()) : "");
|
||||
if(newValue.getAlias() != null) {
|
||||
coreHost.setText(newValue.getAlias());
|
||||
} else {
|
||||
coreHost.setText(hostAndPort.getHost());
|
||||
corePort.setText(Integer.toString(hostAndPort.getPort()));
|
||||
}
|
||||
coreHost.positionCaret(coreHost.getText().length());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
recentElectrumServers.setConverter(new UrlHostConverter());
|
||||
recentElectrumServers.setItems(FXCollections.observableList(Config.get().getRecentElectrumServers() == null ? new ArrayList<>() : Config.get().getRecentElectrumServers()));
|
||||
recentElectrumServers.setCellFactory(value -> new ServerCell());
|
||||
recentElectrumServers.setItems(getObservableServerList(Config.get().getRecentElectrumServers()));
|
||||
recentElectrumServers.prefWidthProperty().bind(electrumHost.widthProperty());
|
||||
recentElectrumServers.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue != null && Protocol.getProtocol(newValue) != null) {
|
||||
HostAndPort hostAndPort = Protocol.getProtocol(newValue).getServerHostAndPort(newValue);
|
||||
if(newValue != null) {
|
||||
if(newValue == MANAGE_ALIASES_SERVER) {
|
||||
ServerAliasDialog serverAliasDialog = new ServerAliasDialog(ServerType.ELECTRUM_SERVER);
|
||||
Optional<Server> optServer = serverAliasDialog.showAndWait();
|
||||
recentElectrumServers.setItems(getObservableServerList(Config.get().getRecentElectrumServers()));
|
||||
Server selectedServer = optServer.orElseGet(() -> Config.get().getElectrumServer());
|
||||
Platform.runLater(() -> recentElectrumServers.setValue(selectedServer));
|
||||
} else if(newValue.getHostAndPort() != null) {
|
||||
HostAndPort hostAndPort = newValue.getHostAndPort();
|
||||
electrumPort.setText(hostAndPort.hasPort() ? Integer.toString(hostAndPort.getPort()) : "");
|
||||
electrumUseSsl.setSelected(newValue.getProtocol() == Protocol.SSL);
|
||||
if(newValue.getAlias() != null) {
|
||||
electrumHost.setText(newValue.getAlias());
|
||||
} else {
|
||||
electrumHost.setText(hostAndPort.getHost());
|
||||
electrumPort.setText(Integer.toString(hostAndPort.getPort()));
|
||||
electrumUseSsl.setSelected(Protocol.getProtocol(newValue) == Protocol.SSL);
|
||||
}
|
||||
electrumHost.positionCaret(electrumHost.getText().length());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -339,7 +369,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
setTestResultsFont();
|
||||
testConnection.setOnAction(event -> {
|
||||
testConnection.setGraphic(getGlyph(FontAwesome5.Glyph.ELLIPSIS_H, null));
|
||||
testResults.setText("Connecting to " + config.getServerAddress() + "...");
|
||||
testResults.setText("Connecting " + (config.hasServer() ? "to " + config.getServer().getUrl() : "") + "...");
|
||||
|
||||
if(Config.get().requiresInternalTor() && Tor.getDefault() == null) {
|
||||
startTor();
|
||||
|
@ -358,7 +388,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
testConnection.setVisible(true);
|
||||
});
|
||||
|
||||
PublicElectrumServer configPublicElectrumServer = PublicElectrumServer.fromUrl(config.getPublicElectrumServer());
|
||||
PublicElectrumServer configPublicElectrumServer = PublicElectrumServer.fromServer(config.getPublicElectrumServer());
|
||||
if(configPublicElectrumServer == null && PublicElectrumServer.supportedNetwork()) {
|
||||
List<PublicElectrumServer> servers = PublicElectrumServer.getServers();
|
||||
if(!servers.isEmpty()) {
|
||||
|
@ -368,16 +398,16 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
publicElectrumServer.setValue(configPublicElectrumServer);
|
||||
}
|
||||
|
||||
String coreServer = config.getCoreServer();
|
||||
Server coreServer = config.getCoreServer();
|
||||
if(coreServer != null) {
|
||||
Protocol protocol = Protocol.getProtocol(coreServer);
|
||||
|
||||
if(protocol != null) {
|
||||
HostAndPort server = protocol.getServerHostAndPort(coreServer);
|
||||
coreHost.setText(server.getHost());
|
||||
if(server.hasPort()) {
|
||||
corePort.setText(Integer.toString(server.getPort()));
|
||||
HostAndPort hostAndPort = coreServer.getHostAndPort();
|
||||
Server server = config.getRecentCoreServers().stream().filter(coreServer::equals).findFirst().orElse(null);
|
||||
if(server != null) {
|
||||
coreHost.setLeft(getGlyph(FontAwesome5.Glyph.TAG, null));
|
||||
}
|
||||
coreHost.setText(server == null || server.getAlias() == null ? hostAndPort.getHost() : server.getAlias());
|
||||
if(hostAndPort.hasPort()) {
|
||||
corePort.setText(Integer.toString(hostAndPort.getPort()));
|
||||
}
|
||||
} else {
|
||||
coreHost.setText("127.0.0.1");
|
||||
|
@ -396,21 +426,22 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
}
|
||||
}
|
||||
|
||||
String electrumServer = config.getElectrumServer();
|
||||
Server electrumServer = config.getElectrumServer();
|
||||
if(electrumServer != null) {
|
||||
Protocol protocol = Protocol.getProtocol(electrumServer);
|
||||
|
||||
if(protocol != null) {
|
||||
Protocol protocol = electrumServer.getProtocol();
|
||||
boolean ssl = protocol.equals(Protocol.SSL);
|
||||
electrumUseSsl.setSelected(ssl);
|
||||
electrumCertificate.setDisable(!ssl);
|
||||
electrumCertificateSelect.setDisable(!ssl);
|
||||
|
||||
HostAndPort server = protocol.getServerHostAndPort(electrumServer);
|
||||
electrumHost.setText(server.getHost());
|
||||
if(server.hasPort()) {
|
||||
electrumPort.setText(Integer.toString(server.getPort()));
|
||||
HostAndPort hostAndPort = electrumServer.getHostAndPort();
|
||||
Server server = config.getRecentElectrumServers().stream().filter(electrumServer::equals).findFirst().orElse(null);
|
||||
if(server != null) {
|
||||
electrumHost.setLeft(getGlyph(FontAwesome5.Glyph.TAG, null));
|
||||
}
|
||||
electrumHost.setText(server == null || server.getAlias() == null ? hostAndPort.getHost() : server.getAlias());
|
||||
if(hostAndPort.hasPort()) {
|
||||
electrumPort.setText(Integer.toString(hostAndPort.getPort()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,7 +480,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
torService.setOnSucceeded(workerStateEvent -> {
|
||||
Tor.setDefault(torService.getValue());
|
||||
torService.cancel();
|
||||
testResults.appendText("\nTor running, connecting to " + Config.get().getServerAddress() + "...");
|
||||
testResults.appendText("\nTor running, connecting to " + Config.get().getServer().getUrl() + "...");
|
||||
startElectrumConnection();
|
||||
});
|
||||
torService.setOnFailed(workerStateEvent -> {
|
||||
|
@ -495,6 +526,13 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
Config.get().setMode(Mode.ONLINE);
|
||||
connectionService.cancel();
|
||||
useProxyOriginal = null;
|
||||
if(Config.get().addRecentServer()) {
|
||||
if(Config.get().getServerType() == ServerType.BITCOIN_CORE) {
|
||||
recentCoreServers.setItems(getObservableServerList(Config.get().getRecentCoreServers()));
|
||||
} else if(Config.get().getServerType() == ServerType.ELECTRUM_SERVER) {
|
||||
recentElectrumServers.setItems(getObservableServerList(Config.get().getRecentElectrumServers()));
|
||||
}
|
||||
}
|
||||
});
|
||||
connectionService.setOnFailed(workerStateEvent -> {
|
||||
EventManager.get().unregister(connectionService);
|
||||
|
@ -668,24 +706,32 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
@NotNull
|
||||
private ChangeListener<PublicElectrumServer> getPublicElectrumServerListener(Config config) {
|
||||
return (observable, oldValue, newValue) -> {
|
||||
config.setPublicElectrumServer(newValue.getUrl());
|
||||
config.setPublicElectrumServer(newValue.getServer());
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ChangeListener<String> getBitcoinCoreListener(Config config) {
|
||||
return (observable, oldValue, newValue) -> {
|
||||
Server existingServer = config.getRecentCoreServers().stream().filter(server -> coreHost.getText().equals(server.getAlias())).findFirst().orElse(null);
|
||||
coreHost.setLeft(existingServer == null ? null : getGlyph(FontAwesome5.Glyph.TAG, null));
|
||||
setCoreServerInConfig(config);
|
||||
};
|
||||
}
|
||||
|
||||
private void setCoreServerInConfig(Config config) {
|
||||
Server existingServer = config.getRecentCoreServers().stream().filter(server -> coreHost.getText().equals(server.getAlias())).findFirst().orElse(null);
|
||||
if(existingServer != null) {
|
||||
config.setCoreServer(existingServer);
|
||||
return;
|
||||
}
|
||||
|
||||
String hostAsString = getHost(coreHost.getText());
|
||||
Integer portAsInteger = getPort(corePort.getText());
|
||||
if(hostAsString != null && portAsInteger != null && isValidPort(portAsInteger)) {
|
||||
config.setCoreServer(Protocol.HTTP.toUrlString(hostAsString, portAsInteger));
|
||||
config.setCoreServer(new Server(Protocol.HTTP.toUrlString(hostAsString, portAsInteger)));
|
||||
} else if(hostAsString != null) {
|
||||
config.setCoreServer(Protocol.HTTP.toUrlString(hostAsString));
|
||||
config.setCoreServer(new Server(Protocol.HTTP.toUrlString(hostAsString)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -699,17 +745,25 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
@NotNull
|
||||
private ChangeListener<String> getElectrumServerListener(Config config) {
|
||||
return (observable, oldValue, newValue) -> {
|
||||
Server existingServer = config.getRecentElectrumServers().stream().filter(server -> electrumHost.getText().equals(server.getAlias())).findFirst().orElse(null);
|
||||
electrumHost.setLeft(existingServer == null ? null : getGlyph(FontAwesome5.Glyph.TAG, null));
|
||||
setElectrumServerInConfig(config);
|
||||
};
|
||||
}
|
||||
|
||||
private void setElectrumServerInConfig(Config config) {
|
||||
Server existingServer = config.getRecentElectrumServers().stream().filter(server -> electrumHost.getText().equals(server.getAlias())).findFirst().orElse(null);
|
||||
if(existingServer != null) {
|
||||
config.setElectrumServer(existingServer);
|
||||
return;
|
||||
}
|
||||
|
||||
String hostAsString = getHost(electrumHost.getText());
|
||||
Integer portAsInteger = getPort(electrumPort.getText());
|
||||
if(hostAsString != null && portAsInteger != null && isValidPort(portAsInteger)) {
|
||||
config.setElectrumServer(getProtocol().toUrlString(hostAsString, portAsInteger));
|
||||
config.setElectrumServer(new Server(getProtocol().toUrlString(hostAsString, portAsInteger)));
|
||||
} else if(hostAsString != null) {
|
||||
config.setElectrumServer(getProtocol().toUrlString(hostAsString));
|
||||
config.setElectrumServer(new Server(getProtocol().toUrlString(hostAsString)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -777,7 +831,7 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
}
|
||||
}
|
||||
|
||||
private Glyph getGlyph(FontAwesome5.Glyph glyphName, String styleClass) {
|
||||
private static Glyph getGlyph(FontAwesome5.Glyph glyphName, String styleClass) {
|
||||
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, glyphName);
|
||||
glyph.setFontSize(12);
|
||||
if(styleClass != null) {
|
||||
|
@ -813,6 +867,12 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
}
|
||||
}
|
||||
|
||||
private ObservableList<Server> getObservableServerList(List<Server> servers) {
|
||||
ObservableList<Server> serverObservableList = FXCollections.observableList(new ArrayList<>(servers));
|
||||
serverObservableList.add(MANAGE_ALIASES_SERVER);
|
||||
return serverObservableList;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void bwtStatus(BwtStatusEvent event) {
|
||||
if(!(event instanceof BwtSyncStatusEvent)) {
|
||||
|
@ -844,15 +904,28 @@ public class ServerPreferencesController extends PreferencesDetailController {
|
|||
});
|
||||
}
|
||||
|
||||
private static class UrlHostConverter extends StringConverter<String> {
|
||||
private static class ServerCell extends ListCell<Server> {
|
||||
@Override
|
||||
public String toString(String serverUrl) {
|
||||
return serverUrl == null || Protocol.getProtocol(serverUrl) == null ? "" : Protocol.getProtocol(serverUrl).getServerHostAndPort(serverUrl).getHost();
|
||||
}
|
||||
protected void updateItem(Server server, boolean empty) {
|
||||
super.updateItem(server, empty);
|
||||
if(server == null || empty) {
|
||||
setText("");
|
||||
setGraphic(null);
|
||||
} else {
|
||||
String serverAlias = server.getAlias();
|
||||
|
||||
@Override
|
||||
public String fromString(String string) {
|
||||
return null;
|
||||
if(server == MANAGE_ALIASES_SERVER) {
|
||||
setText(serverAlias);
|
||||
setStyle("-fx-font-style: italic");
|
||||
setGraphic(null);
|
||||
} else if(serverAlias != null) {
|
||||
setText(serverAlias);
|
||||
setGraphic(getGlyph(FontAwesome5.Glyph.TAG, null));
|
||||
} else {
|
||||
setText(server.getHost());
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
<MenuItem fx:id="findMixingPartner" mnemonicParsing="false" text="Find Mix Partner" onAction="#findMixingPartner"/>
|
||||
<MenuItem fx:id="showPayNym" mnemonicParsing="false" text="Show PayNym" onAction="#showPayNym"/>
|
||||
<SeparatorMenuItem />
|
||||
<Menu fx:id="switchServer" text="Switch Server"/>
|
||||
<MenuItem styleClass="osxHide,windowsHide" mnemonicParsing="false" text="Install Udev Rules" onAction="#installUdevRules"/>
|
||||
<CheckMenuItem fx:id="preventSleep" mnemonicParsing="false" text="Prevent Computer Sleep" onAction="#preventSleep"/>
|
||||
<MenuItem fx:id="restart" mnemonicParsing="false" text="Restart" onAction="#restart" />
|
||||
|
|
|
@ -52,3 +52,7 @@
|
|||
#electrumUseSsl {
|
||||
-fx-padding: 4 0 2 0;
|
||||
}
|
||||
|
||||
#coreHost .left-pane, #electrumHost .left-pane {
|
||||
-fx-padding: 0 3 0 6;
|
||||
}
|
Loading…
Reference in a new issue