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

Akka 如何使用Source.asSubscriber包装被动侦听器?,akka,akka-stream,reactive-streams,Akka,Akka Stream,Reactive Streams,如何使用Source.asSubscriber包装被动侦听器?我不明白它的好处 我正在尝试为WebSocket创建Source[T]。这是我的密码: def createWsObservable(url: String, onStartAction: Option[WebSocket ⇒ Unit]): Source[WsMessage, KillSwitch] = Source.asSubscriber[WsMessage].mapMaterializedValue { subs: Sub

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

我正在尝试为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
对我来说不是个好选择?如何将reactivestreams订阅服务器包装到akka的源代码中?

如果您有一个
发布者
,希望将其公开为
源代码
,则可以使用
Source.fromPublisher


在您的案例中,第一个问题是如何从AHC获得发布者。我不知道AHC,但从我阅读的内容来看,不清楚您是否可以同时拥有反应流支持(这要求您将
streamdasynchandler
传递给
execute
方法)和WebSocket支持(这需要
WebSocketUpgradeHandler
)。我希望有可能将它们组合在一起。

我最终使用了
Source.actorRef
KillSwitch

def createWsObservable(url: String, onStartAction: WebSocket ⇒ Option[KillSwitch] = _ ⇒ None, bufferSize: Int = 32): Source[WsMessage, KillSwitch] = {
  val actorSource = Source.actorRef[WsMessage](bufferSize, OverflowStrategy.fail)
  actorSource.mapMaterializedValue { actor ⇒
    val listener: WebSocketListener = new WebSocketListener() {

      override def onOpen(ws: WebSocket): Unit =
        actor ! ...

      override def onClose(ws: WebSocket, code: Int, reason: String): Unit =
        actor ! akka.actor.Status.Success(code)

      override def onBinaryFrame(payload: Array[Byte], finalFragment: Boolean, rsv: Int): Unit =
        actor ! ...

      override def onTextFrame(payload: String, finalFragment: Boolean, rsv: Int): Unit =
        actor ! ...

      override def onError(t: Throwable): Unit =
        actor ! akka.actor.Status.Failure(t)
    }

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

    // Use Pong reply as indication that we've connected to the server
    val p = Promise[Void]()
    websocket.sendPingFrame().addListener(p)
    val onStartKillSwitchFut = p.future.map(_ ⇒ onStartAction(websocket))

    new KillSwitch {
      override def shutdown(): Unit = {
        onStartKillSwitchFut.map(_.foreach(_.shutdown()))
        websocket.sendCloseFrame()
      }

      override def abort(ex: Throwable): Unit = {
        onStartKillSwitchFut.map(_.foreach(_.abort(ex)))
        websocket.sendCloseFrame()
      }
    }
  }
}

```override def onPongFrame(payload:Array[Byte]):Unit={super.onPingFrame(payload)}``看起来像是打字错误,也许这就是原因?