繁体   English   中英

使用 ReactorNettyWebSocketClient 的入站 stream 的正确方法是什么

[英]What is proper way to consume inbound stream of ReactorNettyWebSocketClient

我尝试使用 Spring Reactor Webflux 学习反应式编程。 特别是在以下示例中,我尝试弄清楚如何正确组合处理管道,以使用 ReactorNettyWebSocketClient 使用 Websocket 连接的入站 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ。

以下代码段工作正常:

WebSocketClient client = new ReactorNettyWebSocketClient();
    client.execute(
            URI.create("wss://stream.binance.com:9443/ws/btcusdt@trade"),
            session -> {
                Flux<String> tradesFlux = session.receive()
                        .map(WebSocketMessage::getPayloadAsText)
                        .doOnNext(event -> log.info(event));

                return tradesFlux.then();
            }
).subscribe();

在上面的片段中,我在入站 stream Flux 上使用doOnNext() - tradesFlux来消耗每个传入的事件。它适用于上面的片段,但据我所知, doOnNext()是一个sideEffect-op,所以我试图做以下事情:

WebSocketClient client = new ReactorNettyWebSocketClient();
    client.execute(
            URI.create("wss://stream.binance.com:9443/ws/btcusdt@trade"),
            session -> {
                Flux<String> tradesFlux = session.receive()
                        .map(WebSocketMessage::getPayloadAsText);

                tradesFlux.subscribe(new Subscriber<String>() {
                    @Override
                    public void onSubscribe(Subscription s) {
                    }

                    @Override
                    public void onNext(String s) {
                        log.info("replicate binance trade {}", s);
                    }

                    @Override
                    public void onError(Throwable t) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });

                return tradesFlux.then();
            }
).subscribe();

在第二个片段中,我尝试通过在入站 stream - tradesFlux上调用subscribe来使用Subscriber者的入站 stream 。 但是有了这个片段,我得到了以下异常:

reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalStateException: Only one connection receive subscriber allowed.
Caused by: java.lang.IllegalStateException: Only one connection receive subscriber allowed.

不知何故,一个人不能通过他自己的Subscriber消耗入站 stream Flux,所以我想问的问题是:第一个片段是否已经是通过使用ReactorNettyWebSocketClient -op doOnNext()或这里有什么?

非常感谢!

我发现这个 Websocket 连接不能订阅两次,就像例外说的那样。 对我来说,解决方案是使用map操作 - 实际上是在入站 stream Flux 上的链,以一对一的方式处理事件。 之后上面的问题听起来很愚蠢,但我发现所有关于使用ReactorNettyWebSocketClient的示例总是使用doOnNext()来处理来自入站 stream 的事件,这让我感到非常困惑。

运行代码如下所示:

@Bean
public WebSocketClient binanceTradesWS(Function<String, BinanceTrade> binanceTradeMapper,
                                       Function<BinanceTrade, Trade> binanceTradeReplicator) {
    WebSocketClient client = new ReactorNettyWebSocketClient();
    client.execute(
            URI.create("wss://stream.binance.com:9443/ws/btcusdt@trade"),
            session -> {
                return session.receive()
                        .map(WebSocketMessage::getPayloadAsText)
                        .map(binanceTradeMapper)
                        .map(binanceTradeReplicator)
                        .then();
            }
    ).subscribe();

    return client;
}

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper().registerModule(new KotlinModule());
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    return mapper;
}

@Bean
public Function<String, BinanceTrade> binanceTradeMapper(ObjectMapper objectMapper) {
    return (String tradeJSON) -> {
        log.info("map binance trade {}", tradeJSON);
        try {
            return objectMapper.readValue(tradeJSON, BinanceTrade.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    };
}

@Bean
public Function<BinanceTrade, Trade> binanceTradeReplicator() {
    return (BinanceTrade binanceTrade) -> {
        Trade trade =new Trade(
                binanceTrade.getT(),
                binanceTrade.getS(),
                new BigDecimal(binanceTrade.getQ()),
                new BigDecimal(binanceTrade.getP()),
                LocalDateTime.ofInstant(Instant.ofEpochMilli(binanceTrade.getTime()), TimeZone.getTimeZone("GMT").toZoneId())
        );
        log.info("replicated binance trade {}", trade);
        return trade;
    };
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM