From e777c67314e30fb7185d4e13a7286091c8eb2f6d Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Thu, 5 Nov 2015 23:07:54 -0800 Subject: [PATCH 1/9] Bump to macAppBundle 2.1.3 --- beelinj-browser-fx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beelinj-browser-fx/build.gradle b/beelinj-browser-fx/build.gradle index d7891c4..bcdf418 100644 --- a/beelinj-browser-fx/build.gradle +++ b/beelinj-browser-fx/build.gradle @@ -1,6 +1,6 @@ plugins { id 'com.github.johnrengelman.shadow' version '1.2.1' - id "edu.sc.seis.macAppBundle" version "2.1.1" + id "edu.sc.seis.macAppBundle" version '2.1.3' } apply plugin: 'org.javafxports.jfxmobile' From c2bdafa771038f322b161aa7463918e353ad14ef Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Tue, 24 Nov 2015 11:31:14 -0800 Subject: [PATCH 2/9] Add Namecoin RPC lookup support. Configuration in the FX Browser between Namecoin RPC and DNSChain is currently at compile time and configured for DNSChain. --- .../main/java/bit/beelin/browser/Main.java | 4 +- beelinj-lib/build.gradle | 3 +- .../main/java/bit/beelin/DNSChainClient.java | 31 ++------- .../java/bit/beelin/DNSChainNameService.java | 43 +------------ .../beelin/DNSChainNameServiceDescriptor.java | 2 +- .../java/bit/beelin/NamecoinNameService.java | 62 ++++++++++++++++++ .../bit/beelin/NamecoinRpcNameService.java | 62 ++++++++++++++++++ .../NamecoinRpcNameServiceDescriptor.java | 26 ++++++++ .../main/java/bit/beelin/NamecoinValue.java | 63 +++++++++++++++++++ ....net.spi.nameservice.NameServiceDescriptor | 2 + .../DNSChainNameServiceDescriptorSpec.groovy | 2 +- .../beelin/NamecoinRpcNameServiceSpec.groovy | 41 ++++++++++++ build.gradle | 1 + 13 files changed, 271 insertions(+), 71 deletions(-) create mode 100644 beelinj-lib/src/main/java/bit/beelin/NamecoinNameService.java create mode 100644 beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java create mode 100644 beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameServiceDescriptor.java create mode 100644 beelinj-lib/src/main/java/bit/beelin/NamecoinValue.java create mode 100644 beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java index 0491ede..b8e72fa 100644 --- a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java @@ -21,7 +21,9 @@ public class Main extends Application { @Override public void init() { // Configure Java to first search our Namecoin NameService provider, then fall back to the default - System.setProperty("sun.net.spi.nameservice.provider.1", "namecoin,beelin"); + // TODO: Add a preference setting to switch between DNSChain and Namecoin RPC for lookup + System.setProperty("sun.net.spi.nameservice.provider.1", "namecoin-dnschain,beelin"); +// System.setProperty("sun.net.spi.nameservice.provider.1", "namecoin-rpc,beelin"); System.setProperty("sun.net.spi.nameservice.provider.2", "default"); } diff --git a/beelinj-lib/build.gradle b/beelinj-lib/build.gradle index 7b6eed4..8958083 100644 --- a/beelinj-lib/build.gradle +++ b/beelinj-lib/build.gradle @@ -4,6 +4,7 @@ dependencies { compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.google.guava:guava:18.0' compile 'commons-codec:commons-codec:1.10' + compile 'com.msgilligan:bitcoinj-rpcclient:0.0.11' } sourceCompatibility = 1.7 @@ -12,4 +13,4 @@ idea { module { jdkName = '1.7' } -} \ No newline at end of file +} diff --git a/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java b/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java index 76a9321..f6b0fad 100644 --- a/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java +++ b/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java @@ -12,8 +12,6 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -67,33 +65,14 @@ public Map lookupNamecoin(String domain) throws UnknownHostExce } public InetAddress[] resolveNamecoin(String hostname) throws UnknownHostException { - List addresses = new ArrayList<>(1); Map result = lookupNamecoin(hostname); Map data = (Map) result.get("data"); - Map value = (Map) data.get("value"); - Object alias = value.get("alias"); - if ((alias instanceof String) && ((String) alias).endsWith(".")) { - // If there's an alias to an absolute domain, use it to get InetAddress[] - return InetAddress.getAllByName((String) alias); + Map valueMap = (Map) data.get("value"); + if (valueMap == null) { + System.out.println("shouldn't happen"); } - Object ip = value.get("ip"); - try { - if (ip instanceof String) { - addresses.add(InetAddress.getByName((String) ip)); - } else if (ip instanceof List) { - for (String addr : (List) ip) { - addresses.add(InetAddress.getByName(addr)); - } - } else if (ip == null) { - throw new RuntimeException("'data.value.ip' is null in JSON result"); - } else { - throw new RuntimeException("'data.value.ip' is unknown type in JSON result"); - } - } catch (UnknownHostException e) { - // Should never happen since we're only using already resolved IP address literal - throw new RuntimeException(e); - } - return addresses.toArray(new InetAddress[addresses.size()]); + NamecoinValue value = new NamecoinValue(valueMap); + return value.getAddresses(); } private OkHttpClient initClient() { diff --git a/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java b/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java index f48c444..f7c97e5 100644 --- a/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java +++ b/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java @@ -24,50 +24,11 @@ * http://rkuzmik.blogspot.ca/2006/08/local-managed-dns-java_11.html * */ -public class DNSChainNameService implements NameService { +public class DNSChainNameService extends NamecoinNameService { private DNSChainClient dnsChainClient = new DNSChainClient(); - /** - * @see sun.net.spi.nameservice.NameService#getHostByAddr(byte[]) - */ @Override - public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException { - List addresses = new ArrayList<>(1); - InternetDomainName idn = InternetDomainName.from(host); - String tld = getTld(idn); - if (!tld.equals("bit")) { - // Not a .bit domain, fall back to standard resolver - throw new UnknownHostException(); - } - List parts = idn.parts(); - - if (parts.size() < 2) { - throw new UnknownHostException(); - } - - // For now assume only 2 parts. - String domain = parts.get(parts.size() - 2); + protected InetAddress[] resolveNamecoin(String domain) throws UnknownHostException { return dnsChainClient.resolveNamecoin(domain); } - - /** - * Reverse lookup (get hostname from address) - * - * @see sun.net.spi.nameservice.NameService#lookupAllHostAddr(java.lang.String) - */ - @Override - public String getHostByAddr(byte[] bytes) throws UnknownHostException { - // Can we use DNSChain for reverse lookups, should we? - // For now, throw UnknownHostException which should cause a fallback to doing - // reverse lookup with the next resolver in the chain. - throw new UnknownHostException(); - } - - private String getTld(InternetDomainName hostname) { - InternetDomainName n = hostname; - while (n.hasParent()) { - n = n.parent(); - } - return n.toString(); - } } diff --git a/beelinj-lib/src/main/java/bit/beelin/DNSChainNameServiceDescriptor.java b/beelinj-lib/src/main/java/bit/beelin/DNSChainNameServiceDescriptor.java index 4015847..f7fa98e 100644 --- a/beelinj-lib/src/main/java/bit/beelin/DNSChainNameServiceDescriptor.java +++ b/beelinj-lib/src/main/java/bit/beelin/DNSChainNameServiceDescriptor.java @@ -21,6 +21,6 @@ public String getProviderName() { @Override public String getType() { - return "namecoin"; + return "namecoin-dnschain"; } } diff --git a/beelinj-lib/src/main/java/bit/beelin/NamecoinNameService.java b/beelinj-lib/src/main/java/bit/beelin/NamecoinNameService.java new file mode 100644 index 0000000..4d95d3c --- /dev/null +++ b/beelinj-lib/src/main/java/bit/beelin/NamecoinNameService.java @@ -0,0 +1,62 @@ +package bit.beelin; + +import com.google.common.net.InternetDomainName; +import sun.net.spi.nameservice.NameService; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public abstract class NamecoinNameService implements NameService { + private DNSChainClient dnsChainClient = new DNSChainClient(); + + /** + * @see NameService#getHostByAddr(byte[]) + */ + @Override + public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException { + List addresses = new ArrayList<>(1); + InternetDomainName idn = InternetDomainName.from(host); + String tld = getTld(idn); + if (!tld.equals("bit")) { + // Not a .bit domain, fall back to standard resolver + throw new UnknownHostException(); + } + List parts = idn.parts(); + + if (parts.size() < 2) { + throw new UnknownHostException(); + } + + // For now assume only 2 parts. + String domain = parts.get(parts.size() - 2); + return resolveNamecoin(domain); + } + + protected abstract InetAddress[] resolveNamecoin(String domain) throws UnknownHostException; + + /** + * Reverse lookup (get hostname from address) + * + * @see NameService#lookupAllHostAddr(String) + */ + @Override + public String getHostByAddr(byte[] bytes) throws UnknownHostException { + // Can we use DNSChain for reverse lookups, should we? + // For now, throw UnknownHostException which should cause a fallback to doing + // reverse lookup with the next resolver in the chain. + throw new UnknownHostException(); + } + + private String getTld(InternetDomainName hostname) { + InternetDomainName n = hostname; + while (n.hasParent()) { + n = n.parent(); + } + return n.toString(); + } +} diff --git a/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java new file mode 100644 index 0000000..353ea01 --- /dev/null +++ b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java @@ -0,0 +1,62 @@ +package bit.beelin; + +import com.msgilligan.bitcoinj.rpc.JsonRPCStatusException; +import com.msgilligan.namecoinj.core.NMCMainNetParams; +import com.msgilligan.namecoinj.json.pojo.NameData; +import com.msgilligan.namecoinj.rpc.NamecoinClient; +import org.bitcoinj.core.NetworkParameters; +import org.bitcoinj.params.MainNetParams; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.Map; + +/** + * This class implements a Name Service Provider, which Java can use + * (starting with version 1.4), to perform DNS resolutions instead of using + * the standard calls. Starting with Java 1.7 (which this implementation requires) + * the resolvers are chained, so that if the first resolver in the chain + * throws UnknownHostException, the next resolver will be called. + *

+ * This Name Service Provider uses Namecoin JSON-RPC to resolve .bit domains. + *

+ * To use this provider, you must set the following system property: + * sun.net.spi.nameservice.provider.1=namecoin-rpc,beelin + * + * See http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html and + * http://rkuzmik.blogspot.ca/2006/08/local-managed-dns-java_11.html + * + */ +public class NamecoinRpcNameService extends NamecoinNameService { + public static String rpcName = "msgnmc"; + public static String rpcPassword = "msgnmc2015"; + private NamecoinClient namecoinClient; + + public NamecoinRpcNameService() { + URI server = null; + try { + server = new URI("http://localhost:8336"); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + NetworkParameters netParams = NMCMainNetParams.get(); + namecoinClient = new NamecoinClient(netParams, server, rpcName, rpcPassword); + } + + @Override + protected InetAddress[] resolveNamecoin(String domain) throws UnknownHostException { + NameData result = null; + try { + result = namecoinClient.nameShow("d/" + domain); + } catch (IOException e) { + e.printStackTrace(); + } catch (JsonRPCStatusException e) { + e.printStackTrace(); + } + NamecoinValue data = new NamecoinValue(result.getValue()); + return data.getAddresses(); + } +} diff --git a/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameServiceDescriptor.java b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameServiceDescriptor.java new file mode 100644 index 0000000..3e6c9e8 --- /dev/null +++ b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameServiceDescriptor.java @@ -0,0 +1,26 @@ +package bit.beelin; + +import sun.net.spi.nameservice.NameService; +import sun.net.spi.nameservice.NameServiceDescriptor; + +/** + * The descriptor class for NamecoinRPCNameService + */ +public class NamecoinRpcNameServiceDescriptor implements NameServiceDescriptor { + private static NameService nameService = new NamecoinRpcNameService(); + + @Override + public NameService createNameService() throws Exception { + return nameService; + } + + @Override + public String getProviderName() { + return "beelin"; + } + + @Override + public String getType() { + return "namecoin-rpc"; + } +} diff --git a/beelinj-lib/src/main/java/bit/beelin/NamecoinValue.java b/beelinj-lib/src/main/java/bit/beelin/NamecoinValue.java new file mode 100644 index 0000000..1345b5f --- /dev/null +++ b/beelinj-lib/src/main/java/bit/beelin/NamecoinValue.java @@ -0,0 +1,63 @@ +package bit.beelin; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class NamecoinValue { + private Map value; + + public NamecoinValue(Map value) { + this.value = value; + } + + public String getAlias() { + Object alias = value.get("alias"); + if ((alias instanceof String) && ((String) alias).endsWith(".")) { + // If there's an alias to an absolute domain, return it as String + return (String) alias; + } + return null; + } + + public List getIps() { + List ips = new ArrayList(); + Object ip = value.get("ip"); + if (ip instanceof String) { + ips.add((String) ip); + } else if (ip instanceof List) { + for (String addr : (List) ip) { + ips.add(addr); + } + } else if (ip == null) { + throw new RuntimeException("'data.value.ip' is null in JSON result"); + } else { + throw new RuntimeException("'data.value.ip' is unknown type in JSON result"); + } + return ips; + } + + public InetAddress[] getAddresses() throws UnknownHostException { + List addresses = new ArrayList<>(1); + String alias = getAlias(); + if (alias != null) { + // If there's an alias to an absolute domain, use it to get InetAddress[] + return InetAddress.getAllByName(alias); + } + List ips = getIps(); + try { + for (String address : ips) { + addresses.add(InetAddress.getByName(address)); + } + } catch (UnknownHostException e) { + // Should never happen since we're only using already resolved IP address literal + throw new RuntimeException(e); + } + return addresses.toArray(new InetAddress[addresses.size()]); + } +} diff --git a/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor b/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor index 653aafe..0fce841 100644 --- a/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor +++ b/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor @@ -1 +1,3 @@ bit.beelin.DNSChainNameServiceDescriptor +bit.beelin.NamecoinRpcNameServiceDescriptor + diff --git a/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceDescriptorSpec.groovy b/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceDescriptorSpec.groovy index 006fd9f..43329f3 100644 --- a/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceDescriptorSpec.groovy +++ b/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceDescriptorSpec.groovy @@ -21,7 +21,7 @@ class DNSChainNameServiceDescriptorSpec extends Specification { def "name and provider are correct"() { expect: - descriptor.getType() == "namecoin" + descriptor.getType() == "namecoin-dnschain" descriptor.getProviderName() == "beelin" } diff --git a/beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy b/beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy new file mode 100644 index 0000000..375ba79 --- /dev/null +++ b/beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy @@ -0,0 +1,41 @@ +package bit.beelin + +import spock.lang.Shared +import spock.lang.Specification + +/** + * + */ +class NamecoinRpcNameServiceSpec extends Specification { + @Shared NamecoinRpcNameService service + + def "can lookup .bit hostnames"() { + when: + InetAddress[] ip = service.lookupAllHostAddr("okturtles.bit") + + then: + ip.length == 1 + ip[0] == InetAddress.getByName("192.184.93.146") + } + + def "throws exception when not a .bit domain, passing responsibility to next in chain"() { + when: + InetAddress[] ip = service.lookupAllHostAddr("okturtles.com") + + then: + UnknownHostException e = thrown() + + } + + def "throws exception on reverse lookup, passing responsibility to next in chain"() { + when: + String hostname = service.getHostByAddr(InetAddress.getByName("192.184.93.146").address) + + then: + UnknownHostException e = thrown() + } + + def setup() { + service = new NamecoinRpcNameService() + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 8bf4b28..3a4a0d6 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ allprojects { repositories { jcenter() + maven { url 'https://dl.bintray.com/msgilligan/maven' } // bitcoinj-addons (Namecoin RPC client) } } From 5a0b01173fdf8e7154a21be8f9a053ea11386958 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Thu, 3 Dec 2015 21:09:14 -0800 Subject: [PATCH 3/9] Add some logging. --- .../src/main/java/bit/beelin/browser/Main.java | 7 +++++++ .../src/main/java/bit/beelin/DNSChainNameService.java | 7 ++++++- .../src/main/java/bit/beelin/NamecoinRpcNameService.java | 5 +++++ build.gradle | 4 ++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java index b8e72fa..064ba4f 100644 --- a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java @@ -13,13 +13,18 @@ import javafx.scene.web.WebView; import javafx.stage.Screen; import javafx.stage.Stage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Main extends Application { + private static final Logger log = LoggerFactory.getLogger(Main.class); private final String startPage = "http://okturtles.bit"; @Override public void init() { + log.info("init()"); + // Configure Java to first search our Namecoin NameService provider, then fall back to the default // TODO: Add a preference setting to switch between DNSChain and Namecoin RPC for lookup System.setProperty("sun.net.spi.nameservice.provider.1", "namecoin-dnschain,beelin"); @@ -29,6 +34,7 @@ public void init() { @Override public void start(Stage stage) { + log.info("start()"); BorderPane bp = new BorderPane(); // Load text field with default text (the start page URL) TextField location = new TextField(startPage); @@ -74,6 +80,7 @@ public void start(Stage stage) { * @return A URL string that WebEngine (standard Java libs) can resolve. */ String resolveLocation(String input) { + log.info("resolveLocation() -> " + input); return input; // No-op since we now have a Java NameService implementation } diff --git a/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java b/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java index f7c97e5..97ac48c 100644 --- a/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java +++ b/beelinj-lib/src/main/java/bit/beelin/DNSChainNameService.java @@ -1,6 +1,8 @@ package bit.beelin; import com.google.common.net.InternetDomainName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sun.net.spi.nameservice.NameService; import java.net.InetAddress; @@ -25,10 +27,13 @@ * */ public class DNSChainNameService extends NamecoinNameService { + private static final Logger log = LoggerFactory.getLogger(DNSChainNameService.class); private DNSChainClient dnsChainClient = new DNSChainClient(); @Override protected InetAddress[] resolveNamecoin(String domain) throws UnknownHostException { - return dnsChainClient.resolveNamecoin(domain); + InetAddress[] addresses = dnsChainClient.resolveNamecoin(domain); + log.info("resolveNamecoin({}) -> {}", domain, addresses); + return addresses; } } diff --git a/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java index 353ea01..106ea4f 100644 --- a/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java +++ b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java @@ -6,6 +6,8 @@ import com.msgilligan.namecoinj.rpc.NamecoinClient; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.params.MainNetParams; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.InetAddress; @@ -31,6 +33,7 @@ * */ public class NamecoinRpcNameService extends NamecoinNameService { + private static final Logger log = LoggerFactory.getLogger(DNSChainNameService.class); public static String rpcName = "msgnmc"; public static String rpcPassword = "msgnmc2015"; private NamecoinClient namecoinClient; @@ -57,6 +60,8 @@ protected InetAddress[] resolveNamecoin(String domain) throws UnknownHostExcepti e.printStackTrace(); } NamecoinValue data = new NamecoinValue(result.getValue()); + InetAddress[] addresses = data.getAddresses(); + log.info("resolveNamecoin({}) -> {}", domain, addresses); return data.getAddresses(); } } diff --git a/build.gradle b/build.gradle index 3a4a0d6..70f706e 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,10 @@ subprojects { apply plugin: 'groovy' dependencies { + compile 'org.slf4j:slf4j-api:1.7.7' + + runtime 'org.slf4j:slf4j-jdk14:1.7.7' // Runtime implementation of slf4j + testCompile 'org.codehaus.groovy:groovy:2.4.4' testCompile("org.spockframework:spock-core:1.0-groovy-2.4") { exclude module: "groovy-all" From 1eb2e84685cbb5278b4f01a289710cf55a488309 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Thu, 3 Dec 2015 21:24:39 -0800 Subject: [PATCH 4/9] More logging --- .../src/main/java/bit/beelin/browser/Main.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java index 064ba4f..38e4918 100644 --- a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java @@ -48,6 +48,9 @@ public void start(Stage stage) { WebView webView = new WebView(); bp.setCenter(webView); WebEngine engine = webView.getEngine(); + engine.setOnError(e -> { + log.info("Error: {}", e.getMessage()); + }); engine.load(startPage); Worker loadWorker = engine.getLoadWorker(); loadWorker.stateProperty().addListener(e -> { @@ -57,7 +60,7 @@ public void start(Stage stage) { } else { launch.setDisable(false); } -// System.out.println("new state for worker = " + loadWorker.getState()); + log.info("new state for worker = {}", loadWorker.getState()); }); launch.setOnAction(e -> { String resolved = resolveLocation(location.getText()); From 8a75044983f4dad130f6636f7c560ccefac3792b Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 13 Dec 2015 20:58:26 -0800 Subject: [PATCH 5/9] Add MacMenuBar using NSMenuFX 2.0.0 --- beelinj-browser-fx/build.gradle | 2 + .../main/java/bit/beelin/browser/Main.java | 13 +++- .../bit/beelin/browser/ui/MacMenuBar.java | 67 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java diff --git a/beelinj-browser-fx/build.gradle b/beelinj-browser-fx/build.gradle index bcdf418..17bd6d3 100644 --- a/beelinj-browser-fx/build.gradle +++ b/beelinj-browser-fx/build.gradle @@ -14,6 +14,8 @@ shadowJar { dependencies { compile project(':beelinj-lib') + + compile 'de.codecentric.centerdevice:centerdevice-nsmenufx:2.0.0' } test { diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java index 38e4918..e586223 100644 --- a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java @@ -1,5 +1,6 @@ package bit.beelin.browser; +import bit.beelin.browser.ui.MacMenuBar; import javafx.application.Application; import javafx.concurrent.Worker; import javafx.geometry.Pos; @@ -19,7 +20,14 @@ public class Main extends Application { private static final Logger log = LoggerFactory.getLogger(Main.class); - private final String startPage = "http://okturtles.bit"; + private static final String appName = "beeLīn"; + private static final String startPage = "http://okturtles.bit"; + + private MacMenuBar macMenuBar; + + public static void main(String[] args) { + launch(args); + } @Override public void init() { @@ -72,7 +80,10 @@ public void start(Stage stage) { Scene scene = new Scene(bp, visualBounds.getWidth(), visualBounds.getHeight()); stage.setScene(scene); + stage.setTitle(appName); stage.show(); + + macMenuBar = new MacMenuBar(appName); } /** diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java new file mode 100644 index 0000000..417ab97 --- /dev/null +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java @@ -0,0 +1,67 @@ +package bit.beelin.browser.ui; + +import javafx.scene.control.Menu; +import javafx.scene.control.MenuBar; +import javafx.scene.control.MenuItem; +import javafx.scene.control.SeparatorMenuItem; + +import de.codecentric.centerdevice.MenuToolkit; + +/** + * + */ +public class MacMenuBar { + + String appName; + + public MacMenuBar(String appName) { + this.appName = appName; + + MenuToolkit tk = MenuToolkit.toolkit(); + + MenuBar bar = new MenuBar(); + + // Application Menu + // TBD: services menu + Menu appMenu = new Menu(appName); // Name for appMenu can't be set at + // Runtime + MenuItem aboutItem = new MenuItem("About"); + MenuItem prefsItem = new MenuItem("Preferences..."); + appMenu.getItems().addAll(aboutItem, new SeparatorMenuItem(), prefsItem, new SeparatorMenuItem(), + tk.createHideMenuItem(appName), tk.createHideOthersMenuItem(), tk.createUnhideAllMenuItem(), + new SeparatorMenuItem(), tk.createQuitMenuItem(appName)); + + // File Menu (items TBD) + Menu fileMenu = new Menu("File"); + MenuItem newItem = new MenuItem("New..."); + fileMenu.getItems().addAll(newItem, new SeparatorMenuItem(), tk.createCloseWindowMenuItem(), + new SeparatorMenuItem(), new MenuItem("TBD")); + + // Edit (items TBD) + Menu editMenu = new Menu("Edit"); + editMenu.getItems().addAll(new MenuItem("TBD")); + + // Format (items TBD) + Menu formatMenu = new Menu("Format"); + formatMenu.getItems().addAll(new MenuItem("TBD")); + + // View Menu (items TBD) + Menu viewMenu = new Menu("View"); + viewMenu.getItems().addAll(new MenuItem("TBD")); + + // Window Menu + // TBD standard window menu items + Menu windowMenu = new Menu("Window"); + windowMenu.getItems().addAll(tk.createMinimizeMenuItem(), tk.createZoomMenuItem(), tk.createCycleWindowsItem(), + new SeparatorMenuItem(), tk.createBringAllToFrontItem()); + + // Help Menu (items TBD) + Menu helpMenu = new Menu("Help"); + helpMenu.getItems().addAll(new MenuItem("TBD")); + + bar.getMenus().addAll(appMenu, fileMenu, editMenu, formatMenu, viewMenu, windowMenu, helpMenu); + + tk.autoAddWindowMenuItems(windowMenu); + tk.setGlobalMenuBar(bar); + } +} From f67872204c9706868af8f11c7eb4e1e6fe6b455f Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 13 Dec 2015 21:07:26 -0800 Subject: [PATCH 6/9] =?UTF-8?q?Add=20hardcoded=20=E2=80=9CAbout=E2=80=9D?= =?UTF-8?q?=20box?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bit/beelin/browser/ui/MacMenuBar.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java index 417ab97..8f5bf15 100644 --- a/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java @@ -1,11 +1,19 @@ package bit.beelin.browser.ui; +import javafx.event.ActionEvent; +import javafx.scene.Scene; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; import de.codecentric.centerdevice.MenuToolkit; +import javafx.scene.layout.BorderPane; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.Text; +import javafx.stage.Stage; +import javafx.stage.StageStyle; /** * @@ -25,7 +33,8 @@ public MacMenuBar(String appName) { // TBD: services menu Menu appMenu = new Menu(appName); // Name for appMenu can't be set at // Runtime - MenuItem aboutItem = new MenuItem("About"); + MenuItem aboutItem = new MenuItem("About " + appName); + aboutItem.setOnAction(this::aboutHandler); MenuItem prefsItem = new MenuItem("Preferences..."); appMenu.getItems().addAll(aboutItem, new SeparatorMenuItem(), prefsItem, new SeparatorMenuItem(), tk.createHideMenuItem(appName), tk.createHideOthersMenuItem(), tk.createUnhideAllMenuItem(), @@ -64,4 +73,23 @@ public MacMenuBar(String appName) { tk.autoAddWindowMenuItems(windowMenu); tk.setGlobalMenuBar(bar); } + + public void aboutHandler(ActionEvent event) { + Stage stage = new Stage(StageStyle.UNDECORATED); + stage.setWidth(300); + stage.setHeight(300); + stage.setResizable(false); + + Text text = new Text(10, 40, "About beeLīn"); + text.setFont(new Font(40)); + Scene scene = new Scene(new BorderPane(text)); + scene.setFill(Color.AQUA); + scene.setOnMousePressed(mouseEvent -> { + stage.close(); + }); + + stage.setScene(scene); + stage.show(); + } + } From 19df0abb3f499a1cf8f6d80fb39dede8910900d1 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 13 Dec 2015 22:10:11 -0800 Subject: [PATCH 7/9] =?UTF-8?q?Add=20About=20Box=20from=20Gen=E2=80=99s=20?= =?UTF-8?q?email?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bit/beelin/browser/ui/MacMenuBar.java | 22 ++++++++--- .../bit/beelin/browser/ui/about.fxml | 37 ++++++++++++++++++ .../beelin/browser/ui/beeLin_logo_442x250.png | Bin 0 -> 6308 bytes 3 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 beelinj-browser-fx/src/main/resources/bit/beelin/browser/ui/about.fxml create mode 100644 beelinj-browser-fx/src/main/resources/bit/beelin/browser/ui/beeLin_logo_442x250.png diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java index 8f5bf15..04c1ab0 100644 --- a/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/ui/MacMenuBar.java @@ -1,6 +1,8 @@ package bit.beelin.browser.ui; import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; @@ -15,6 +17,8 @@ import javafx.stage.Stage; import javafx.stage.StageStyle; +import java.io.IOException; + /** * */ @@ -75,15 +79,21 @@ public MacMenuBar(String appName) { } public void aboutHandler(ActionEvent event) { + Parent root; + try { + FXMLLoader loader = new FXMLLoader(getClass().getResource("about.fxml")); + root = loader.load(); + } catch (IOException e) { + e.printStackTrace(); + return; + } + Stage stage = new Stage(StageStyle.UNDECORATED); - stage.setWidth(300); - stage.setHeight(300); + stage.setWidth(600); + stage.setHeight(400); stage.setResizable(false); - Text text = new Text(10, 40, "About beeLīn"); - text.setFont(new Font(40)); - Scene scene = new Scene(new BorderPane(text)); - scene.setFill(Color.AQUA); + Scene scene = new Scene(root, 600, 400); scene.setOnMousePressed(mouseEvent -> { stage.close(); }); diff --git a/beelinj-browser-fx/src/main/resources/bit/beelin/browser/ui/about.fxml b/beelinj-browser-fx/src/main/resources/bit/beelin/browser/ui/about.fxml new file mode 100644 index 0000000..80fae7f --- /dev/null +++ b/beelinj-browser-fx/src/main/resources/bit/beelin/browser/ui/about.fxml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/beelinj-browser-fx/src/main/resources/bit/beelin/browser/ui/beeLin_logo_442x250.png b/beelinj-browser-fx/src/main/resources/bit/beelin/browser/ui/beeLin_logo_442x250.png new file mode 100644 index 0000000000000000000000000000000000000000..2f12bafddc7bb3f8b42b18996f82952d1bebc105 GIT binary patch literal 6308 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 TbTjba-*H1d6J4y%lc@gzf_e*} literal 0 HcmV?d00001 From 597e42e705dbd05c8c3a2472812993e2becf62fa Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 26 Jun 2016 20:37:01 -0700 Subject: [PATCH 8/9] Default to Namecoin JSON-RPC (autoconfigure via namecoin.conf) * Upgrade to bitcoinj-rpcclient v0.1.1 (can find and parse namecoin.conf) * Add placeholder BeelinSwitchableNameService and use it by Default * Improved error handling and logging * Add JDK logging config class, properties (in resource), build settings * Use msgilligan.bit for tests and default home page (okturtles not working) --- beelinj-browser-fx/build.gradle | 6 +++-- .../main/java/bit/beelin/browser/Main.java | 12 ++++++--- .../util/logging/DefaultLoggingConfig.java | 23 ++++++++++++++++ .../src/main/resources/logging.properties | 17 ++++++++++++ beelinj-lib/build.gradle | 2 +- .../beelin/BeelinSwitchableNameService.java | 24 +++++++++++++++++ ...BeelinSwitchableNameServiceDescriptor.java | 26 +++++++++++++++++++ .../bit/beelin/NamecoinRpcNameService.java | 12 ++++++--- ....net.spi.nameservice.NameServiceDescriptor | 1 + .../beelin/NamecoinRpcNameServiceSpec.groovy | 4 +-- build.gradle | 1 + 11 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 beelinj-browser-fx/src/main/java/bit/beelin/browser/util/logging/DefaultLoggingConfig.java create mode 100644 beelinj-browser-fx/src/main/resources/logging.properties create mode 100644 beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameService.java create mode 100644 beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameServiceDescriptor.java diff --git a/beelinj-browser-fx/build.gradle b/beelinj-browser-fx/build.gradle index 17bd6d3..d26ecf3 100644 --- a/beelinj-browser-fx/build.gradle +++ b/beelinj-browser-fx/build.gradle @@ -21,7 +21,7 @@ dependencies { test { // NOTE: You'll need to manually set these properties in your IDEA Run/Debug configuration VM options // if you want to run the tests directly from the IDE - systemProperties ([ 'sun.net.spi.nameservice.provider.1': 'namecoin,beelin', + systemProperties ([ 'sun.net.spi.nameservice.provider.1': 'beelin-switchable,beelin', 'sun.net.spi.nameservice.provider.2': 'default', ]) } @@ -32,7 +32,9 @@ macAppBundle { icon = "src/macos/icons/app-icon.icns" // For now, only bundle the JRE if building under Mac OS X bundleJRE = System.getProperty("os.name").toLowerCase().contains("mac os") -// javaProperties.put("apple.laf.useScreenMenuBar", "true") +// javaProperties.put("sun.net.spi.nameservice.provider.1", "\"namecoin-dnschain,beelin\""); + javaProperties.put("sun.net.spi.nameservice.provider.1", "\"beelin-switchable,beelin\""); + javaProperties.put("sun.net.spi.nameservice.provider.2", "\"default\""); // backgroundImage = "doc/macbackground.png" } diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java index e586223..e54e0af 100644 --- a/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/Main.java @@ -21,7 +21,7 @@ public class Main extends Application { private static final Logger log = LoggerFactory.getLogger(Main.class); private static final String appName = "beeLīn"; - private static final String startPage = "http://okturtles.bit"; + private static final String startPage = "http://msgilligan.bit"; private MacMenuBar macMenuBar; @@ -34,10 +34,14 @@ public void init() { log.info("init()"); // Configure Java to first search our Namecoin NameService provider, then fall back to the default - // TODO: Add a preference setting to switch between DNSChain and Namecoin RPC for lookup - System.setProperty("sun.net.spi.nameservice.provider.1", "namecoin-dnschain,beelin"); + System.setProperty("sun.net.spi.nameservice.provider.1", "beelin-switchable,beelin"); +// System.setProperty("sun.net.spi.nameservice.provider.1", "namecoin-dnschain,beelin"); // System.setProperty("sun.net.spi.nameservice.provider.1", "namecoin-rpc,beelin"); System.setProperty("sun.net.spi.nameservice.provider.2", "default"); + + // TODO: Add a preference setting and connect to BeelinSwitchableNameService class + // to switch between DNSChain and Namecoin RPC or others for lookup + } @Override @@ -57,7 +61,7 @@ public void start(Stage stage) { bp.setCenter(webView); WebEngine engine = webView.getEngine(); engine.setOnError(e -> { - log.info("Error: {}", e.getMessage()); + log.error("Error: {}", e.getMessage()); }); engine.load(startPage); Worker loadWorker = engine.getLoadWorker(); diff --git a/beelinj-browser-fx/src/main/java/bit/beelin/browser/util/logging/DefaultLoggingConfig.java b/beelinj-browser-fx/src/main/java/bit/beelin/browser/util/logging/DefaultLoggingConfig.java new file mode 100644 index 0000000..1a31093 --- /dev/null +++ b/beelinj-browser-fx/src/main/java/bit/beelin/browser/util/logging/DefaultLoggingConfig.java @@ -0,0 +1,23 @@ +package bit.beelin.browser.util.logging; + +import java.io.InputStream; +import java.util.logging.LogManager; + +/** + * Default runtime configuration for JDK logging + * Use -Djava.util.logging.config.class=bit.beelin.browser.util.logging.DefaultLoggingConfig + * on the command line to select this configuration + */ +public class DefaultLoggingConfig { + public DefaultLoggingConfig() { + try { + final LogManager logManager = LogManager.getLogManager(); + try (final InputStream is = getClass().getResourceAsStream("/logging.properties")) { + logManager.readConfiguration(is); + } + } catch (Exception e) { + // The runtime won't show stack traces if the exception is thrown + e.printStackTrace(); + } + } +} diff --git a/beelinj-browser-fx/src/main/resources/logging.properties b/beelinj-browser-fx/src/main/resources/logging.properties new file mode 100644 index 0000000..36aeb7a --- /dev/null +++ b/beelinj-browser-fx/src/main/resources/logging.properties @@ -0,0 +1,17 @@ +handlers=java.util.logging.ConsoleHandler +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] (%2$s) %5$s %6$s%n + +java.util.logging.ConsoleHandler.level=FINEST +app.level=FINEST + +bit.beelin.level=FINE +bit.beelin.browser.level=FINE + +# Use for logging RPC requests and responses +com.msgilligan.bitcoinj.rpc=FINE + + # Set bitcoinj log level to WARNING to avoid "Creating bitcoinj 0.14.3 context" INFO message + org.bitcoinj.core.level=WARNING + + diff --git a/beelinj-lib/build.gradle b/beelinj-lib/build.gradle index 8958083..dbdf5bc 100644 --- a/beelinj-lib/build.gradle +++ b/beelinj-lib/build.gradle @@ -4,7 +4,7 @@ dependencies { compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.google.guava:guava:18.0' compile 'commons-codec:commons-codec:1.10' - compile 'com.msgilligan:bitcoinj-rpcclient:0.0.11' + compile 'com.msgilligan:bitcoinj-rpcclient:0.1.1' } sourceCompatibility = 1.7 diff --git a/beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameService.java b/beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameService.java new file mode 100644 index 0000000..803dde2 --- /dev/null +++ b/beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameService.java @@ -0,0 +1,24 @@ +package bit.beelin; + +import sun.net.spi.nameservice.NameService; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Delegate to another name service (currently RPC client) + * Future versions will be switchable via a preferences object. + */ +public class BeelinSwitchableNameService implements NameService { + private NameService activeNameService = new NamecoinRpcNameService(); + + @Override + public InetAddress[] lookupAllHostAddr(String s) throws UnknownHostException { + return activeNameService.lookupAllHostAddr(s); + } + + @Override + public String getHostByAddr(byte[] bytes) throws UnknownHostException { + return activeNameService.getHostByAddr(bytes); + } +} diff --git a/beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameServiceDescriptor.java b/beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameServiceDescriptor.java new file mode 100644 index 0000000..95c507b --- /dev/null +++ b/beelinj-lib/src/main/java/bit/beelin/BeelinSwitchableNameServiceDescriptor.java @@ -0,0 +1,26 @@ +package bit.beelin; + +import sun.net.spi.nameservice.NameService; +import sun.net.spi.nameservice.NameServiceDescriptor; + +/** + * + */ +public class BeelinSwitchableNameServiceDescriptor implements NameServiceDescriptor { + private static NameService nameService = new BeelinSwitchableNameService(); + + @Override + public NameService createNameService() throws Exception { + return nameService; + } + + @Override + public String getProviderName() { + return "beelin"; + } + + @Override + public String getType() { + return "beelin-switchable"; + } +} diff --git a/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java index 106ea4f..e973f9d 100644 --- a/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java +++ b/beelinj-lib/src/main/java/bit/beelin/NamecoinRpcNameService.java @@ -34,11 +34,13 @@ */ public class NamecoinRpcNameService extends NamecoinNameService { private static final Logger log = LoggerFactory.getLogger(DNSChainNameService.class); - public static String rpcName = "msgnmc"; - public static String rpcPassword = "msgnmc2015"; private NamecoinClient namecoinClient; public NamecoinRpcNameService() { + namecoinClient = new NamecoinClient(NamecoinClient.readConfig()); + } + + public NamecoinRpcNameService(String rpcName, String rpcPassword) { URI server = null; try { server = new URI("http://localhost:8336"); @@ -55,9 +57,11 @@ protected InetAddress[] resolveNamecoin(String domain) throws UnknownHostExcepti try { result = namecoinClient.nameShow("d/" + domain); } catch (IOException e) { - e.printStackTrace(); + log.error("IOException: {}", e); + throw new RuntimeException(e); } catch (JsonRPCStatusException e) { - e.printStackTrace(); + log.error("JsonRPCStatusException: {}", e); + throw new RuntimeException(e); } NamecoinValue data = new NamecoinValue(result.getValue()); InetAddress[] addresses = data.getAddresses(); diff --git a/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor b/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor index 0fce841..0fe6002 100644 --- a/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor +++ b/beelinj-lib/src/main/resources/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor @@ -1,3 +1,4 @@ +bit.beelin.BeelinSwitchableNameServiceDescriptor bit.beelin.DNSChainNameServiceDescriptor bit.beelin.NamecoinRpcNameServiceDescriptor diff --git a/beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy b/beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy index 375ba79..5213d86 100644 --- a/beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy +++ b/beelinj-lib/src/test/groovy/bit/beelin/NamecoinRpcNameServiceSpec.groovy @@ -11,11 +11,11 @@ class NamecoinRpcNameServiceSpec extends Specification { def "can lookup .bit hostnames"() { when: - InetAddress[] ip = service.lookupAllHostAddr("okturtles.bit") + InetAddress[] ip = service.lookupAllHostAddr("msgilligan.bit") then: ip.length == 1 - ip[0] == InetAddress.getByName("192.184.93.146") + ip[0] == InetAddress.getByName("207.111.216.146") } def "throws exception when not a .bit domain, passing responsibility to next in chain"() { diff --git a/build.gradle b/build.gradle index 70f706e..587b357 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ allprojects { repositories { jcenter() + // mavenLocal() // uncomment to use local snapshots maven { url 'https://dl.bintray.com/msgilligan/maven' } // bitcoinj-addons (Namecoin RPC client) } } From e7d4c250374a8e598102130c8de98dda0fe140a9 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Wed, 22 Mar 2017 15:07:39 -0700 Subject: [PATCH 9/9] Update dependencies and functional tests * NSMenuFX to 2.1.1 * Retrofit to 2.0.1 (and related dependencies) * Update expected results on functional tests for current state of Namecoin chain --- beelinj-browser-fx/build.gradle | 2 +- beelinj-lib/build.gradle | 7 +-- .../main/java/bit/beelin/DNSChainClient.java | 49 ++++++++++++------- .../bit/beelin/DNSChainClientSpec.groovy | 22 +++++---- .../bit/beelin/DNSChainNameServiceSpec.groovy | 16 ++++-- 5 files changed, 61 insertions(+), 35 deletions(-) diff --git a/beelinj-browser-fx/build.gradle b/beelinj-browser-fx/build.gradle index d26ecf3..9918f11 100644 --- a/beelinj-browser-fx/build.gradle +++ b/beelinj-browser-fx/build.gradle @@ -15,7 +15,7 @@ shadowJar { dependencies { compile project(':beelinj-lib') - compile 'de.codecentric.centerdevice:centerdevice-nsmenufx:2.0.0' + compile 'de.codecentric.centerdevice:centerdevice-nsmenufx:2.1.1' } test { diff --git a/beelinj-lib/build.gradle b/beelinj-lib/build.gradle index dbdf5bc..9e872cc 100644 --- a/beelinj-lib/build.gradle +++ b/beelinj-lib/build.gradle @@ -1,7 +1,8 @@ dependencies { - compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' - compile 'com.squareup.retrofit:converter-jackson:2.0.0-beta2' - compile 'com.squareup.okhttp:okhttp:2.5.0' + compile 'com.squareup.retrofit2:retrofit:2.0.1' + compile 'com.squareup.retrofit2:converter-jackson:2.0.1' + compile 'com.squareup.okhttp3:logging-interceptor:3.0.1' + //compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.google.guava:guava:18.0' compile 'commons-codec:commons-codec:1.10' compile 'com.msgilligan:bitcoinj-rpcclient:0.1.1' diff --git a/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java b/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java index f6b0fad..cddb7c9 100644 --- a/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java +++ b/beelinj-lib/src/main/java/bit/beelin/DNSChainClient.java @@ -1,13 +1,14 @@ package bit.beelin; -import com.squareup.okhttp.CertificatePinner; -import com.squareup.okhttp.OkHttpClient; -import retrofit.Call; -import retrofit.Response; -import retrofit.Retrofit; -import retrofit.http.GET; -import retrofit.http.Path; -import retrofit.JacksonConverterFactory; +import okhttp3.OkHttpClient; +import okhttp3.CertificatePinner; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.converter.jackson.JacksonConverterFactory; import java.io.IOException; import java.net.InetAddress; @@ -76,15 +77,27 @@ public InetAddress[] resolveNamecoin(String hostname) throws UnknownHostExceptio } private OkHttpClient initClient() { - OkHttpClient client = new OkHttpClient(); - client.setConnectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - client.setReadTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - client.setCertificatePinner( - new CertificatePinner.Builder() - // Pinning for DNSChain API Server -- is this right? - .add("api.dnschain.net", "sha1/OmfEeJ94QcdL+YrCl2bMp6Zh9LI=") - .add("api.dnschain.net", "sha1/KqqJgAYLy9ogXOWETcR36ioKf20=") - .build()); - return client; + boolean debug = false; + + OkHttpClient.Builder builder = new OkHttpClient.Builder() + .connectTimeout(CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) + .readTimeout(READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + + if (debug) { + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + builder.addInterceptor(interceptor); + } + + // TODO: Enable cert pinning? +// CertificatePinner pinner = new CertificatePinner.Builder() +// // Pinning for DNSChain API Server -- is this right? +// .add("api.dnschain.net", "sha1/OmfEeJ94QcdL+YrCl2bMp6Zh9LI=") +// .add("api.dnschain.net", "sha1/KqqJgAYLy9ogXOWETcR36ioKf20=") +// .build(); + + return builder + //.certificatePinner(pinner) + .build(); } } diff --git a/beelinj-lib/src/test/groovy/bit/beelin/DNSChainClientSpec.groovy b/beelinj-lib/src/test/groovy/bit/beelin/DNSChainClientSpec.groovy index 0ab376e..2ca4ca5 100644 --- a/beelinj-lib/src/test/groovy/bit/beelin/DNSChainClientSpec.groovy +++ b/beelinj-lib/src/test/groovy/bit/beelin/DNSChainClientSpec.groovy @@ -20,9 +20,10 @@ class DNSChainClientSpec extends Specification { json.version == "0.0.1" json.header.datastore == "namecoin" json.data.name == "d/okturtles" - json.data.value.email == "hi@okturtles.com" - json.data.value.ip[0] == "192.184.93.146" - json.data.value.tls.sha1[0] == "5F:8B:74:78:4F:55:27:19:DC:53:6B:9B:C8:99:CD:91:8A:57:DD:07" + json.data.value == "BM-NBS2L3Ry5TvmG9nK2RnGjqTw2Di1bx7N" + //json.data.value.email == "hi@okturtles.com" + //json.data.value.ip[0] == "192.184.93.146" + //json.data.value.tls.sha1[0] == "5F:8B:74:78:4F:55:27:19:DC:53:6B:9B:C8:99:CD:91:8A:57:DD:07" } def "test lookup of msgilligan"() { @@ -46,7 +47,7 @@ class DNSChainClientSpec extends Specification { json.version == "0.0.1" json.header.datastore == "namecoin" json.data.name == "d/namecoin" - json.data.value.ip == null + //json.data.value.ip == null } def "test lookup of genevieveprimavera"() { @@ -70,13 +71,14 @@ class DNSChainClientSpec extends Specification { UnknownHostException e = thrown() } - def "test resolve of okturtles"() { + def "test resolve of okturtles fails"() { when: def ip = client.resolveNamecoin("okturtles") then: - ip.length == 1 - ip[0] == InetAddress.getByName("192.184.93.146") + Exception e = thrown() +// ip.length == 1 +// ip[0] == InetAddress.getByName("192.184.93.146") } def "test resolve of msgilligan"() { @@ -88,13 +90,13 @@ class DNSChainClientSpec extends Specification { ip[0] == InetAddress.getByName("207.111.216.146") } - def "test resolve of namecoin"() { + def "test resolve of namecoin fails"() { when: def ip = client.resolveNamecoin("namecoin") then: - RuntimeException e = thrown() - e.message == "'data.value.ip' is null in JSON result" + Exception e = thrown() +// e.message == "'data.value.ip' is null in JSON result" } def setup() { diff --git a/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceSpec.groovy b/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceSpec.groovy index 85d2b3b..ee6480b 100644 --- a/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceSpec.groovy +++ b/beelinj-lib/src/test/groovy/bit/beelin/DNSChainNameServiceSpec.groovy @@ -11,13 +11,23 @@ import java.net.UnknownHostException; class DNSChainNameServiceSpec extends Specification { @Shared DNSChainNameService service - def "can lookup .bit hostnames"() { + def "can lookup .bit hostname"() { when: - InetAddress[] ip = service.lookupAllHostAddr("okturtles.bit") + InetAddress[] ip = service.lookupAllHostAddr("msgilligan.bit") then: ip.length == 1 - ip[0] == InetAddress.getByName("192.184.93.146") + ip[0] == InetAddress.getByName("207.111.216.146") + } + + def "okturtles.bit throws Exception"() { + when: + InetAddress[] ip = service.lookupAllHostAddr("okturtles.bit") + + then: + Exception e = thrown() + //ip.length == 1 + //ip[0] == InetAddress.getByName("192.184.93.146") } def "throws exception when not a .bit domain, passing responsibility to next in chain"() {