diff --git a/pom.xml b/pom.xml
index 01110f9..bda4788 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,12 @@
spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
org.springframework.boot
diff --git a/src/main/java/xyz/mcutils/backend/common/WebRequest.java b/src/main/java/xyz/mcutils/backend/common/WebRequest.java
index 9fc3680..c87b9d5 100644
--- a/src/main/java/xyz/mcutils/backend/common/WebRequest.java
+++ b/src/main/java/xyz/mcutils/backend/common/WebRequest.java
@@ -1,6 +1,5 @@
package xyz.mcutils.backend.common;
-import com.google.gson.JsonObject;
import lombok.experimental.UtilityClass;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
diff --git a/src/main/java/xyz/mcutils/backend/config/WebSocketConfig.java b/src/main/java/xyz/mcutils/backend/config/WebSocketConfig.java
new file mode 100644
index 0000000..ee4c3c1
--- /dev/null
+++ b/src/main/java/xyz/mcutils/backend/config/WebSocketConfig.java
@@ -0,0 +1,22 @@
+package xyz.mcutils.backend.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+import xyz.mcutils.backend.service.MetricService;
+import xyz.mcutils.backend.websocket.MetricsWebSocketHandler;
+
+@Configuration
+@EnableWebSocket
+public class WebSocketConfig implements WebSocketConfigurer {
+
+ @Autowired
+ private MetricService metricService;
+
+ @Override
+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+ registry.addHandler(new MetricsWebSocketHandler(metricService), "/websocket/metrics").setAllowedOrigins("*");
+ }
+}
diff --git a/src/main/java/xyz/mcutils/backend/model/cache/CachedEndpointStatus.java b/src/main/java/xyz/mcutils/backend/model/cache/CachedEndpointStatus.java
index a48270c..d526ec6 100644
--- a/src/main/java/xyz/mcutils/backend/model/cache/CachedEndpointStatus.java
+++ b/src/main/java/xyz/mcutils/backend/model/cache/CachedEndpointStatus.java
@@ -2,14 +2,16 @@ package xyz.mcutils.backend.model.cache;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
-import lombok.*;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
+import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import xyz.mcutils.backend.common.CachedResponse;
import xyz.mcutils.backend.model.mojang.EndpointStatus;
import java.io.Serializable;
-import java.util.Map;
@Setter @Getter @ToString
@RedisHash(value = "mojangEndpointStatus", timeToLive = 60L) // 1 minute (in seconds)
diff --git a/src/main/java/xyz/mcutils/backend/model/metric/WebsocketMetrics.java b/src/main/java/xyz/mcutils/backend/model/metric/WebsocketMetrics.java
new file mode 100644
index 0000000..f1e46ff
--- /dev/null
+++ b/src/main/java/xyz/mcutils/backend/model/metric/WebsocketMetrics.java
@@ -0,0 +1,15 @@
+package xyz.mcutils.backend.model.metric;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Map;
+
+@AllArgsConstructor
+@Getter
+public class WebsocketMetrics {
+ /**
+ * The metrics to send to the client.
+ */
+ private final Map metrics;
+}
diff --git a/src/main/java/xyz/mcutils/backend/model/mojang/EndpointStatus.java b/src/main/java/xyz/mcutils/backend/model/mojang/EndpointStatus.java
index 8edb7fc..bf46307 100644
--- a/src/main/java/xyz/mcutils/backend/model/mojang/EndpointStatus.java
+++ b/src/main/java/xyz/mcutils/backend/model/mojang/EndpointStatus.java
@@ -1,12 +1,7 @@
package xyz.mcutils.backend.model.mojang;
-import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
-import lombok.NonNull;
-import org.springframework.data.annotation.Id;
-import xyz.mcutils.backend.common.CachedResponse;
-import xyz.mcutils.backend.model.cache.CachedEndpointStatus;
import java.util.Map;
diff --git a/src/main/java/xyz/mcutils/backend/websocket/MetricsWebSocketHandler.java b/src/main/java/xyz/mcutils/backend/websocket/MetricsWebSocketHandler.java
new file mode 100644
index 0000000..7c3010c
--- /dev/null
+++ b/src/main/java/xyz/mcutils/backend/websocket/MetricsWebSocketHandler.java
@@ -0,0 +1,54 @@
+package xyz.mcutils.backend.websocket;
+
+import lombok.extern.log4j.Log4j2;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+import xyz.mcutils.backend.Main;
+import xyz.mcutils.backend.common.Timer;
+import xyz.mcutils.backend.model.metric.WebsocketMetrics;
+import xyz.mcutils.backend.service.MetricService;
+import xyz.mcutils.backend.service.metric.metrics.TotalRequestsMetric;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Log4j2(topic = "WebSocket/Metrics")
+public class MetricsWebSocketHandler extends TextWebSocketHandler {
+ private final long interval = TimeUnit.SECONDS.toMillis(5);
+ public final List sessions = new ArrayList<>();
+
+ public MetricsWebSocketHandler(MetricService metricService) {
+ Timer.scheduleRepeating(() -> {
+ try {
+ WebsocketMetrics metrics = new WebsocketMetrics(Map.of(
+ "totalRequests", metricService.getMetric(TotalRequestsMetric.class).getValue())
+ );
+
+ for (WebSocketSession session : sessions) {
+ session.sendMessage(new TextMessage(Main.GSON.toJson(metrics)));
+ }
+ } catch (Exception e) {
+ log.error("An error occurred while sending metrics to the client", e);
+ }
+ }, interval, interval);
+ }
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) {
+ log.info("WebSocket connection established with session id: {}", session.getId());
+
+ sessions.add(session);
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, @NotNull CloseStatus status) {
+ log.info("WebSocket connection closed with session id: {}", session.getId());
+
+ sessions.remove(session);
+ }
+}
\ No newline at end of file