Skip to content

Instantly share code, notes, and snippets.

@rucko24
Created December 2, 2023 22:26
Show Gist options
  • Save rucko24/4f14eb8cbc2852ad110b71dad1968aa8 to your computer and use it in GitHub Desktop.
Save rucko24/4f14eb8cbc2852ad110b71dad1968aa8 to your computer and use it in GitHub Desktop.
Get public ip address using project reactor and jbang
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.projectreactor:reactor-core:3.6.0
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration;
import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author rubn
*/
public class GetIpAddressFromHostWithReactor {
private static final String IFCONFIG_CO = "http://ifconfig.cao";
private static final String CHECKIP_AMAZON_COM = "http://checkip.amazonaws.com";
public GetIpAddressFromHostWithReactor() {
System.out.println("Initial host: " + IFCONFIG_CO);
final CountDownLatch countDownLatch = new CountDownLatch(1);
Mono.fromCallable(GetIpAddressFromHostWithReactor::makeRequest)
.subscribeOn(Schedulers.boundedElastic())
.flatMap(Function.identity())
.map(HttpResponse::body)
.flatMap(GetIpAddressFromHostWithReactor::extractIp)
.onErrorResume(fallback)
.doOnNext(ip -> System.out.println("ip " + ip))
.doOnTerminate(countDownLatch::countDown)
.subscribe();
try {
countDownLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static HttpClient client() {
return HttpClient.newBuilder()
.version(Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(5))
.build();
}
private static Mono<HttpResponse<String>> makeRequest() {
return Mono.just(client())
.flatMap(httpClient -> send(httpClient, IFCONFIG_CO))
.doOnError(throwable -> System.out.println("Request error on: " + IFCONFIG_CO + " " + throwable.getMessage()));
}
private static Mono<HttpResponse<String>> send(HttpClient client, final String url) {
try {
return Mono.just(client.send(request(url), BodyHandlers.ofString()));
} catch (IOException | InterruptedException e) {
return Mono.error(new RequestWTFHostException(e));
}
}
private static HttpRequest request(final String url) {
return HttpRequest.newBuilder(URI.create(url))
.GET()
.build();
}
private static Mono<String> extractIp(String body) {
return Mono.just(Stream.of(body.split("<ip>"))
.map(internalData -> internalData.split("class=\"ip\">")[1])
.map(ip -> ip.split("</code")[0])
.collect(Collectors.joining()));
}
static Function<Throwable, Mono<String>> fallback = (throwable) -> {
System.out.println("Fallback host " + CHECKIP_AMAZON_COM);
return Mono.just(client())
.flatMap(httpClient -> send(httpClient, CHECKIP_AMAZON_COM))
.doOnError(onError -> System.out.println("Request error on: " + CHECKIP_AMAZON_COM + " " + throwable.getMessage()))
.map(HttpResponse::body);
};
public static class RequestWTFHostException extends Exception {
public RequestWTFHostException(Throwable error) {
super(error);
}
}
public static void main(String... bull$hXt) {
new GetIpAddressFromHostWithReactor();
}
}
@rucko24
Copy link
Author

rucko24 commented Dec 2, 2023

rubn ⲁƛ ▸ jbang GetIpAddressFromHostWithReactor.java
[jbang] Building jar for GetIpAddressFromHostWithReactor.java...
Initial host: http://ifconfig.co <1>
ip 139.XX.XX.XXX
  • (1) good
rubn ⲁƛ ▸ jbang GetIpAddressFromHostWithReactor.java
Initial host: http://ifconfig.cao <1>
Request error on: http://ifconfig.cao java.net.ConnectException
Fallback host http://checkip.amazonaws.com <2>
ip 139.XX.XX.XXX
  • (1) bad url
  • (2) good host

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment