Skip to content
Permalink
Browse files

Initial commit adding nodesmith

  • Loading branch information...
Samm Desmond
Samm Desmond committed Mar 24, 2019
1 parent f99ceb1 commit a6f291ea23bad35739e6fe2bbff4083cb9727904
@@ -7,7 +7,7 @@ description 'web3j command line tools'

dependencies {
compile project(':codegen'),
project(':infura'),
project(':hosted-providers'),
project(':contracts')
runtime "org.slf4j:slf4j-nop:$slf4jVersion" // prevent logging of the library to the console
testCompile project(path: ':crypto', configuration: 'testArtifacts'),
@@ -15,6 +15,7 @@
import org.web3j.protocol.exceptions.TransactionException;
import org.web3j.protocol.http.HttpService;
import org.web3j.protocol.infura.InfuraHttpService;
import org.web3j.protocol.nodesmith.NodesmithHttpService;
import org.web3j.tx.Transfer;
import org.web3j.utils.Convert;

@@ -137,6 +138,8 @@ private Web3j getEthereumClient() {
web3j = Web3j.build(new HttpService());
} else if (clientAddress.contains("infura.io")) {
web3j = Web3j.build(new InfuraHttpService(clientAddress));
} else if (clientAddress.contains("nodesmith.io")) {
web3j = Web3j.build(new NodesmithHttpService(clientAddress));
} else {
web3j = Web3j.build(new HttpService(clientAddress));
}
@@ -149,6 +149,7 @@ protected InputStream performIO(String request) throws IOException {
.build();

okhttp3.Response response = httpClient.newCall(httpRequest).execute();
processHeaders(response.headers());
ResponseBody responseBody = response.body();
if (response.isSuccessful()) {
if (responseBody != null) {
@@ -164,6 +165,10 @@ protected InputStream performIO(String request) throws IOException {
}
}

protected void processHeaders(Headers headers) {
// Default implementation is empty
}

private InputStream buildInputStream(ResponseBody responseBody) throws IOException {
InputStream inputStream = responseBody.byteStream();

@@ -66,6 +66,15 @@ Or use `Infura <https://infura.io/>`_, which provides **free clients** running i
For further information refer to :doc:`infura`.


Or use `Nodesmith <https://nodesmith.io/>`_, which provides **free API endpoints**:

.. code-block:: java
Web3j web3 = Web3j.build(new HttpService("https://ethereum.api.nodesmith.io/v1/goerli/jsonrpc?apiKey=YOUR_KEY"));
For further information refer to :doc:`nodesmith`.

Instructions on obtaining Ether to transact on the network can be found in the
:ref:`testnet section of the docs <ethereum-testnets>`.

@@ -19,7 +19,7 @@ The below modules only depend on the core module.

* geth - Geth specific JSON-RPC module
* parity - Parity specific JSON-RPC module
* infura - Infura specific HTTP header support
* hosted-providers - Specific support for hosted web3 providers
* contracts - Support for specific EIP's (Ethereum Improvement Proposals)

For most use cases (interacting with the network and smart contracts) the *core* module should be
@@ -0,0 +1,6 @@

description 'web3j customisations for working with hosted web3 providers (Infura.io & Nodesmith.io)'

dependencies {
compile project(':core')
}
@@ -0,0 +1,60 @@
package org.web3j.protocol.nodesmith;

import java.util.Arrays;
import java.util.Optional;
import java.util.Set;

import okhttp3.Headers;
import okhttp3.OkHttpClient;

import org.web3j.protocol.http.HttpService;

/**
* HttpService for working with <a href="https://nodesmith.io/">Nodesmith's</a> hosted infrastructure.
*/
public class NodesmithHttpService extends HttpService {

static final String NS_RATELIMIT_LIMIT = "x-ratelimit-limit";
static final String NS_RATELIMIT_REMAINING = "x-ratelimit-remaining";
static final String NS_RATELIMIT_RESET = "x-ratelimit-reset";

private RateLimitInfo latestRateLimitInfo = null;

public NodesmithHttpService(String url, OkHttpClient httpClient) {
super(url, httpClient);
}

public NodesmithHttpService(String url) {
super(url);
}

public RateLimitInfo getLatestRateLimitInfo() {
return this.latestRateLimitInfo;
}

@Override
protected void processHeaders(Headers headers) {
Optional<RateLimitInfo> info = createRateLimitFromHeaders(headers);
if (info.isPresent()) {
this.latestRateLimitInfo = info.get();
}
}

static Optional<RateLimitInfo> createRateLimitFromHeaders(Headers headers) {
if (headers == null) {
return Optional.empty();
}

Set<String> names = headers.names();
if (!names.containsAll(Arrays.asList(
NS_RATELIMIT_LIMIT, NS_RATELIMIT_REMAINING, NS_RATELIMIT_RESET))) {
return Optional.empty();
}

return RateLimitInfo.createFromHeaders(
headers.get(NS_RATELIMIT_LIMIT),
headers.get(NS_RATELIMIT_REMAINING),
headers.get(NS_RATELIMIT_RESET));

}
}
@@ -0,0 +1,61 @@
package org.web3j.protocol.nodesmith;

import java.time.Instant;
import java.util.Optional;

/**
* Represents the current status of an api key's
* <a href="https://beta.docs.nodesmith.io/#/ethereum/rateLimiting>rate limit</a> for Nodesmith's
* service. This class can be used to inspect when more requests can be sent.
*/
public class RateLimitInfo {
private long limit;
private long remaining;
private Instant resetTime;
RateLimitInfo(long limit, long remaining, Instant resetTime) {
this.limit = limit;
this.remaining = remaining;
this.resetTime = resetTime;
}
/**
* The total rate limit for this API key and endpoint.
* @return total rate limit allowed.
*/
public long getTotalAllowedInWindow() {
return this.limit;
}
/**
* How many more requests can be sent in to current window.
* @return Number of requests remaining.
*/
public long getRemainingInWindow() {
return this.remaining;
}
/**
* When the current window ends and the rate limit will be reset.
* @return Time when the rate limit resets.
*/
public Instant getWindowResetTime() {
return this.resetTime;
}
public static Optional<RateLimitInfo> createFromHeaders(
String limitValue, String remainingValue, String resetTimeValue) {
try {
long limit = Long.parseLong(limitValue);
long remaining = Long.parseLong(remainingValue);
long resetEpochSeconds = Long.parseLong(resetTimeValue);
Instant resetTime = Instant.ofEpochSecond(resetEpochSeconds);
return Optional.of(new RateLimitInfo(limit, remaining, resetTime));
} catch (NumberFormatException ex) {
// TODO - log
return Optional.empty();
}
}
}
@@ -0,0 +1,47 @@
package org.web3j.protocol.nodesmith;

import java.util.Optional;

import okhttp3.Headers;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class NodesmithHttpServiceTest {
NodesmithHttpService service;

@Test
public void testParseHeaders() {
Optional<RateLimitInfo> info = NodesmithHttpService.createRateLimitFromHeaders(Headers.of(
NodesmithHttpService.NS_RATELIMIT_LIMIT, "500",
NodesmithHttpService.NS_RATELIMIT_REMAINING, "442",
NodesmithHttpService.NS_RATELIMIT_RESET, "1553385403"));

assertTrue(info.isPresent());
assertEquals(500, info.get().getTotalAllowedInWindow());
assertEquals(442, info.get().getRemainingInWindow());
assertEquals(1553385403L, info.get().getWindowResetTime().getEpochSecond());
}

@Test
public void testParseHeader_FailureCases() {
// Missing some of the required headers
assertFalse(NodesmithHttpService.createRateLimitFromHeaders(
Headers.of(NodesmithHttpService.NS_RATELIMIT_LIMIT, "42"))
.isPresent());

// Invalid number format
assertFalse(NodesmithHttpService.createRateLimitFromHeaders(
Headers.of(
NodesmithHttpService.NS_RATELIMIT_LIMIT, "42",
NodesmithHttpService.NS_RATELIMIT_REMAINING, "xyz",
NodesmithHttpService.NS_RATELIMIT_RESET, "1553385403"))
.isPresent());

// Null headers
assertFalse(NodesmithHttpService.createRateLimitFromHeaders(null)
.isPresent());
}
}

This file was deleted.

@@ -6,7 +6,7 @@ include 'console'
include 'core'
include 'crypto'
include 'geth'
include 'infura'
include 'hosted-providers'
include 'integration-tests'
include 'parity'
include 'rlp'

0 comments on commit a6f291e

Please sign in to comment.
You can’t perform that action at this time.