diff --git a/src/main/java/io/mapsmessaging/MessageDaemon.java b/src/main/java/io/mapsmessaging/MessageDaemon.java index 1a9cb0670..2ff437e6b 100644 --- a/src/main/java/io/mapsmessaging/MessageDaemon.java +++ b/src/main/java/io/mapsmessaging/MessageDaemon.java @@ -41,6 +41,7 @@ import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; import io.mapsmessaging.logging.ServerLogMessages; +import io.mapsmessaging.rest.RestApiServerManager; import io.mapsmessaging.security.uuid.UuidGenerator; import io.mapsmessaging.stats.StatsReporter; import io.mapsmessaging.utilities.SystemProperties; @@ -272,13 +273,16 @@ public Integer start() throws IOException { subSystemManager.start(); logger.log(ServerLogMessages.MESSAGE_DAEMON_STARTUP, BuildInfo.getBuildVersion(), BuildInfo.getBuildDate()); if (ConsulManagerFactory.getInstance().isStarted()) { - ConsulManagerFactory.getInstance().getManager().register(buildMetaData()); + Map meta = buildMetaData(); + if (meta.containsKey("rest")) { + ConsulManagerFactory.getInstance().getManager().register(meta); + } } statsReporter = new StatsReporter(); return null; } - private Map buildMetaData(){ + private Map buildMetaData() throws IOException { NetworkManagerConfig networkManagerConfig = NetworkManagerConfig.getInstance(); Map meta =new LinkedHashMap<>(); for(EndPointServerConfigDTO serverConfig: networkManagerConfig.getEndPointServerConfigList()){ @@ -292,9 +296,40 @@ private Map buildMetaData(){ } meta.put(protocols, url); } + RestApiServerManager restApiServerManager = subSystemManager.getRestApiServerManager(); + if (restApiServerManager != null && restApiServerManager.isEnabled()) { + InetAddress consulRouteAddress = ConsulManagerFactory.getInstance().getManager().getLocalAddress(); + meta.put("rest", buildRestEndpoint(restApiServerManager.getHost(), restApiServerManager.getPort(), consulRouteAddress)); + } return meta; } + static String buildRestEndpoint(String configuredHosts, int port, InetAddress localAddress) throws UnknownHostException { + if (port < 1 || port > 65535) { + throw new IllegalArgumentException("Invalid REST API port: " + port); + } + + InetAddress serviceAddress = null; + if (configuredHosts != null) { + for (String configuredHost : configuredHosts.split(",")) { + String host = configuredHost.trim(); + if (!host.isEmpty()) { + InetAddress candidate = InetAddress.getByName(host); + if (!candidate.isAnyLocalAddress()) { + serviceAddress = candidate; + break; + } + } + } + } + if (serviceAddress == null) { + serviceAddress = localAddress; + } + + String host = serviceAddress.getHostAddress(); + return host.contains(":") ? "[" + host + "]:" + port : host + ":" + port; + } + /** * Stops the MessageDaemon by setting the 'isStarted' flag to false and stopping all agents in the 'agentMap'. */ diff --git a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java index b7b63f08b..579ac3b36 100644 --- a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java +++ b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java @@ -121,6 +121,10 @@ public int getPort() { return config.getPort(); } + public boolean isEnabled() { + return config.isEnabled(); + } + public String getHost() { return config.getHostnames(); } diff --git a/src/test/java/io/mapsmessaging/MessageDaemonConsulMetadataTest.java b/src/test/java/io/mapsmessaging/MessageDaemonConsulMetadataTest.java new file mode 100644 index 000000000..a8ca87e62 --- /dev/null +++ b/src/test/java/io/mapsmessaging/MessageDaemonConsulMetadataTest.java @@ -0,0 +1,66 @@ +/* + * + * Copyright [ 2020 - 2024 ] Matthew Buckton + * Copyright [ 2024 - 2026 ] MapsMessaging B.V. + * + * Licensed under the Apache License, Version 2.0 with the Commons Clause + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * https://commonsclause.com/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.mapsmessaging; + +import org.junit.jupiter.api.Test; + +import java.net.InetAddress; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class MessageDaemonConsulMetadataTest { + + @Test + void buildRestEndpoint_usesConfiguredAddress() throws Exception { + String endpoint = MessageDaemon.buildRestEndpoint("192.0.2.20", 8081, InetAddress.getByName("192.0.2.10")); + + assertEquals("192.0.2.20:8081", endpoint); + } + + @Test + void buildRestEndpoint_replacesIpv4WildcardWithLocalAddress() throws Exception { + String endpoint = MessageDaemon.buildRestEndpoint("0.0.0.0", 8080, InetAddress.getByName("192.0.2.10")); + + assertEquals("192.0.2.10:8080", endpoint); + } + + @Test + void buildRestEndpoint_replacesWildcardListWithLocalAddress() throws Exception { + String endpoint = MessageDaemon.buildRestEndpoint("0.0.0.0, ::", 8080, InetAddress.getByName("192.0.2.10")); + + assertEquals("192.0.2.10:8080", endpoint); + } + + @Test + void buildRestEndpoint_formatsIpv6Address() throws Exception { + String endpoint = MessageDaemon.buildRestEndpoint("::", 8443, InetAddress.getByName("2001:db8::10")); + + assertEquals("[2001:db8:0:0:0:0:0:10]:8443", endpoint); + } + + @Test + void buildRestEndpoint_rejectsInvalidPort() throws Exception { + InetAddress address = InetAddress.getByName("192.0.2.10"); + + assertThrows(IllegalArgumentException.class, () -> MessageDaemon.buildRestEndpoint("0.0.0.0", 0, address)); + assertThrows(IllegalArgumentException.class, () -> MessageDaemon.buildRestEndpoint("0.0.0.0", 65536, address)); + } +}