如何使用Source.asSubscriber来包装被动侦听器?

时间:2018-05-26 16:10:09

标签: akka akka-stream reactive-streams

如何使用Source.asSubscriber包装被动侦听器?我不理解它的好处。

我正在尝试为asynchttpclient WebSocket创建Source[T]。这是我的代码:

def createWsObservable(url: String, onStartAction: Option[WebSocket ⇒ Unit]): Source[WsMessage, KillSwitch] =
  Source.asSubscriber[WsMessage].mapMaterializedValue { subs: Subscriber[WsMessage] ⇒
    val listener: WebSocketListener = new WebSocketListener() {
      override def onOpen(ws: WebSocket): Unit =
        subs.onNext(WsOpen(ws))

      override def onClose(ws: WebSocket, code: Int, reason: String): Unit =
        subs.onComplete()

      override def onBinaryFrame(payload: Array[Byte], finalFragment: Boolean, rsv: Int): Unit =
        // Doing bunch of stuff here
        subs.onNext(...)

      override def onTextFrame(payload: String, finalFragment: Boolean, rsv: Int): Unit =
        // Doing bunch of stuff here
        subs.onNext(...)

      override def onError(t: Throwable): Unit =
        subs.onError(t)

      override def onPongFrame(payload: Array[Byte]): Unit = {
        super.onPingFrame(payload)
      }
    }

    val websocket =
      asyncHttpClient
        .prepareGet(url)
        .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(listener).build).get

    new KillSwitch {
      override def shutdown(): Unit = websocket.sendCloseFrame()
      override def abort(ex: Throwable): Unit = websocket.sendCloseFrame()
    }
  }

在第一个事件中我得到例外:

java.lang.IllegalStateException: spec violation: onNext was signaled from upstream without demand
    at akka.stream.impl.VirtualProcessor.rec$5(StreamLayout.scala:239)
    at akka.stream.impl.VirtualProcessor.onNext(StreamLayout.scala:243)
    at ingestion.NettyClientWrapper$$anon$2.onOpen(NettyClientWrapper.scala:55)

也许Source.asSubscriber对我来说不是一个好选择?我应该怎么做才能将反应流订阅者包装到akka的源中?

2 个答案:

答案 0 :(得分:0)

如果您希望将Publisher公开为Source,则可以使用Source.fromPublisher

在您的情况下,第一个问题是如何从AHC获得Publisher。我不了解AHC,但是根据我所读到的内容,我们不清楚你是否可以同时支持Reactive Streams(这需要你将StreamedAsyncHandler传递给{{1方法)和WebSocket支持(需要execute代替)。我希望可以将它们组合在一起。

答案 1 :(得分:0)

我最终将id2Source.actorRef

一起使用
KillSwitch