From 4557eaa141360078ee45e25400a811ca74f85988 Mon Sep 17 00:00:00 2001 From: Sidd Date: Thu, 3 Mar 2022 23:43:39 -0800 Subject: [PATCH 1/2] feat: track chat socket latency --- .../com/github/twitch4j/chat/ITwitchChat.java | 5 ++++ .../com/github/twitch4j/chat/TwitchChat.java | 26 +++++++++++++++++++ .../chat/TwitchChatConnectionPool.java | 14 ++++++++++ 3 files changed, 45 insertions(+) diff --git a/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java b/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java index 9f957ce1e..3f60a7d71 100644 --- a/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java +++ b/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java @@ -79,6 +79,11 @@ default boolean sendMessage(String channel, String message, @Unofficial String n @Override void close(); + /** + * @return the most recently measured round-trip latency for the socket(s) + */ + long getLatency(); + /** * @return cached mappings of channel ids to names */ diff --git a/chat/src/main/java/com/github/twitch4j/chat/TwitchChat.java b/chat/src/main/java/com/github/twitch4j/chat/TwitchChat.java index 3c1ddc4f5..b4461a03e 100644 --- a/chat/src/main/java/com/github/twitch4j/chat/TwitchChat.java +++ b/chat/src/main/java/com/github/twitch4j/chat/TwitchChat.java @@ -53,6 +53,7 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; @@ -237,6 +238,14 @@ public class TwitchChat implements ITwitchChat { */ private final int wsPingPeriod; + /** + * Tracks the timestamp of the last outbound ping + */ + protected final AtomicLong lastPing = new AtomicLong(); + + @Getter + protected volatile long latency = -1L; + /** * Cache of recent number of join attempts for each channel */ @@ -625,6 +634,23 @@ public void onDisconnected(WebSocket websocket, log.info("Disconnected from Twitch IRC (WebSocket)!"); } } + + @Override + public void onFrameSent(WebSocket websocket, WebSocketFrame frame) { + if (frame != null && frame.isPingFrame()) { + lastPing.compareAndSet(0L, System.currentTimeMillis()); + } + } + + @Override + public void onPongFrame(WebSocket websocket, WebSocketFrame frame) { + final long last = lastPing.getAndSet(0L); + if (last > 0) { + latency = System.currentTimeMillis() - last; + log.trace("TwitchChat: Round-trip socket latency recorded at {} ms.", latency); + } + } + }); } catch (Exception ex) { diff --git a/chat/src/main/java/com/github/twitch4j/chat/TwitchChatConnectionPool.java b/chat/src/main/java/com/github/twitch4j/chat/TwitchChatConnectionPool.java index e7810abff..9564e99f7 100644 --- a/chat/src/main/java/com/github/twitch4j/chat/TwitchChatConnectionPool.java +++ b/chat/src/main/java/com/github/twitch4j/chat/TwitchChatConnectionPool.java @@ -278,6 +278,20 @@ protected void disposeConnection(TwitchChat connection) { connection.close(); } + @Override + public long getLatency() { + long sum = 0; + int count = 0; + for (TwitchChat connection : getConnections()) { + final long latency = connection.getLatency(); + if (latency > 0) { + sum += latency; + count++; + } + } + return count > 0 ? sum / count : -1L; + } + /** * Note: this map does not dynamically update unlike {@link TwitchChat#getChannelIdToChannelName()} *

From a7858075e9b928d92d57713c5cad8cccc1bab10b Mon Sep 17 00:00:00 2001 From: Sidd Date: Thu, 3 Mar 2022 23:56:01 -0800 Subject: [PATCH 2/2] docs: clarify units of ITwitchChat#getLatency --- chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java b/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java index 3f60a7d71..b71ab7f6f 100644 --- a/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java +++ b/chat/src/main/java/com/github/twitch4j/chat/ITwitchChat.java @@ -80,7 +80,7 @@ default boolean sendMessage(String channel, String message, @Unofficial String n void close(); /** - * @return the most recently measured round-trip latency for the socket(s) + * @return the most recently measured round-trip latency for the socket(s) in milliseconds, or -1 if unknown */ long getLatency();