public Mono<String> queryPublicIp() {
        IpProperties ipProperties = propertiesManager.getLocalProperties()
                .getIp();
        int cachedPublicIpExpireAfterMillis = ipProperties.getCachedPublicIpExpireAfterMillis();
        String localCachedPublicIp = cachedPublicIp;
        if (cachedPublicIpExpireAfterMillis > 0
                && localCachedPublicIp != null
                && System.nanoTime() - publicIpLastUpdatedTimeNanos < DateTimeUtil
                        .millisToNanos(cachedPublicIpExpireAfterMillis)) {
            return Mono.just(localCachedPublicIp);
        }
        List<String> ipDetectorAddresses = ipProperties.getPublicIpDetectorAddresses();
        if (ipDetectorAddresses.isEmpty()) {
            return Mono.error(new IllegalArgumentException(
                    "Failed to detect the public IP of the local node because no IP detector address is specified"));
        }
        List<Mono<String>> monos = new ArrayList<>(ipDetectorAddresses.size());
        HttpClient httpClient = HttpClient.newConnection();
        for (String ipDetectorAddress : ipDetectorAddresses) {
            Mono<String> ipMono = httpClient.get()
                    .uri(ipDetectorAddress)
                    .responseSingle((response, body) -> response.status()
                            .codeClass()
                            .equals(HttpStatusClass.SUCCESS)
                                    ? body.asString()
                                            .flatMap(ip -> {
                                                ip = ip.trim();
                                                return InetAddressUtil.isIp(ip)
                                                        ? Mono.just(ip)
                                                        : Mono.empty();
                                            })
                                    : Mono.empty());
            monos.add(ipMono);
        }
        return Mono.firstWithValue(monos)
                .doOnNext(ip -> {
                    publicIpLastUpdatedTimeNanos = System.nanoTime();
                    cachedPublicIp = ip;
                })
                .switchIfEmpty(EXCEPTION_NO_AVAILABLE_ADDRESS_FOUND)
                .onErrorResume(t -> {
                    if (t instanceof NoSuchElementException) {
                        return EXCEPTION_NO_AVAILABLE_ADDRESS_FOUND;
                    }
                    return Mono.error(new RuntimeException(
                            "Failed to detect the public IP of the local node",
                            t));
                });
    }
@author James Chen
@implNote Don't cache the IP forever because they may change over time.
turms-server-common/src/main/java/im/turms/server/common/infra/address/IpDetector.java