package io.cattle.platform.api.pubsub.subscribe.jetty; import io.cattle.platform.api.pubsub.subscribe.MessageWriter; import io.cattle.platform.archaius.util.ArchaiusUtil; import java.io.EOFException; import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.eclipse.jetty.websocket.api.WebSocketException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.config.DynamicIntProperty; public class WebSocketMessageWriter extends WebSocketAdapter implements MessageWriter { private static final Logger log = LoggerFactory.getLogger(WebSocketMessageWriter.class); private static final DynamicIntProperty MAX_QUEUED_MESSAGES = ArchaiusUtil.getInt("subscribe.max.queued.messages"); private Session session; private boolean connectionClosed = false; private AtomicInteger queuedMessageCount = new AtomicInteger(); @Override public void onWebSocketConnect(Session session) { this.session = session; } @Override public void onWebSocketClose(int closeCode, String message) { connectionClosed = true; log.debug("Websocket connection closed. Code: [{}], message: [{}].", closeCode, message); } @Override public void write(String message, Object writeLock) throws IOException { // The explicit connnectionClosed check is because the session is null until the connection is initially established if (connectionClosed) { throw new EOFException("WebSocket is closed."); } if (queuedMessageCount.get() > MAX_QUEUED_MESSAGES.get()) { throw new IOException("Reached max queued messages [" + MAX_QUEUED_MESSAGES.get() + "]."); } if (session != null && session.isOpen()) { try { session.getRemote().sendString(message, new WebSocketWriteCallback(this)); queuedMessageCount.incrementAndGet(); } catch (WebSocketException e) { // Thrown if getRemote() determines the connection was closed by the client. No need to log. close(); } } } @Override public void close() { if (!connectionClosed) { if (session != null && session.isOpen()) { session.close(); } connectionClosed = true; } } public AtomicInteger getQueuedMessageCount() { return queuedMessageCount; } public void setQueuedMessageCount(AtomicInteger queuedMessageCount) { this.queuedMessageCount = queuedMessageCount; } }