io.scalecube.services.gateway.client.websocket.WebsocketGatewayClientSession Maven / Gradle / Ivy
The newest version!
package io.scalecube.services.gateway.client.websocket;
import static reactor.core.publisher.Sinks.EmitFailureHandler.busyLooping;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.scalecube.services.api.ErrorData;
import io.scalecube.services.api.ServiceMessage;
import io.scalecube.services.gateway.ReferenceCountUtil;
import io.scalecube.services.gateway.client.GatewayClientCodec;
import java.nio.channels.ClosedChannelException;
import java.time.Duration;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks;
import reactor.core.publisher.Sinks.Many;
import reactor.core.publisher.Sinks.One;
import reactor.netty.Connection;
import reactor.netty.http.websocket.WebsocketInbound;
import reactor.netty.http.websocket.WebsocketOutbound;
public final class WebsocketGatewayClientSession {
private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketGatewayClientSession.class);
private static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION =
new ClosedChannelException();
private static final String STREAM_ID = "sid";
private static final String SIGNAL = "sig";
private final String id; // keep id for tracing
private final GatewayClientCodec clientCodec;
private final Connection connection;
// processor by sid mapping
private final Map inboundProcessors = new ConcurrentHashMap<>(1024);
WebsocketGatewayClientSession(GatewayClientCodec clientCodec, Connection connection) {
this.id = Integer.toHexString(System.identityHashCode(this));
this.clientCodec = clientCodec;
this.connection = connection;
WebsocketInbound inbound = (WebsocketInbound) connection.inbound();
inbound
.receive()
.retain()
.subscribe(
byteBuf -> {
if (!byteBuf.isReadable()) {
ReferenceCountUtil.safestRelease(byteBuf);
return;
}
// decode message
ServiceMessage message;
try {
message = clientCodec.decode(byteBuf);
} catch (Exception ex) {
LOGGER.error("Response decoder failed", ex);
return;
}
// ignore messages w/o sid
if (!message.headers().containsKey(STREAM_ID)) {
LOGGER.error("Ignore response: {} with null sid, session={}", message, id);
if (message.data() != null) {
ReferenceCountUtil.safestRelease(message.data());
}
return;
}
// processor?
long sid = Long.parseLong(message.header(STREAM_ID));
Object processor = inboundProcessors.get(sid);
if (processor == null) {
if (message.data() != null) {
ReferenceCountUtil.safestRelease(message.data());
}
return;
}
// handle response message
handleResponse(message, processor);
});
connection.onDispose(
() -> inboundProcessors.forEach((k, o) -> emitError(o, CLOSED_CHANNEL_EXCEPTION)));
}
@SuppressWarnings({"rawtypes", "unchecked"})
One newMonoProcessor(long sid) {
return (One) inboundProcessors.computeIfAbsent(sid, this::newMonoProcessor0);
}
@SuppressWarnings({"rawtypes", "unchecked"})
Many newUnicastProcessor(long sid) {
return (Many) inboundProcessors.computeIfAbsent(sid, this::newUnicastProcessor0);
}
private One © 2015 - 2025 Weber Informatics LLC | Privacy Policy