Source.actorRef没有使用akka-stream流式传输到websocket

时间:2016-06-26 19:57:02

标签: akka akka-stream

我正在尝试将akka-stream Source与websocket连接。

object TestWebServer {

  val source1 = Source.actorRef[WsMessage](10, OverflowStrategy.dropHead)
    .map { case msg@WsMessage(a,b,c,d,e,f) => println("Received from stream" + msg);TextMessage(c) }

  import scala.concurrent.duration._
  val source2 = Source.tick(initialDelay = 0 second, interval = 1 second, tick = TextMessage("tick"))



  def main(args: Array[String]) {

    implicit val system = ActorSystem("my-system")
    implicit val materializer = ActorMaterializer()
    // needed for the future flatMap/onComplete in the end
    implicit val executionContext = system.dispatcher


    val requestHandler: HttpRequest => HttpResponse = {
      case req@HttpRequest(HttpMethods.GET, Uri.Path("/ws"), _, _, _) =>
        req.header[UpgradeToWebSocket] match {
          case Some(upgrade) => upgrade.handleMessagesWithSinkSource(Sink.ignore, source1)
          case None => HttpResponse(400, entity = "Not a valid websocket request!")
        }
      case _: HttpRequest => HttpResponse(404, entity = "Unknown resource!")
    }


    val bindingFuture = Http().bindAndHandleSync(requestHandler, "localhost", 8080)

    println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
    StdIn.readLine() // let it run until user presses return
    bindingFuture
      .flatMap(_.unbind()) // trigger unbinding from the port
      .onComplete(_ => system.terminate()) // and shutdown when done
  }
}

使用Simple Web Socket Client(SWSC)等客户端,我可以看到

  • 如果我将websocket与source1连接, upgrade.handleMessagesWithSinkSource(Sink.ignore, source1) 我没有看到任何回复SWSC
  • 如果我将websocket与source2连接, upgrade.handleMessagesWithSinkSource(Sink.ignore, source2)我可以看到每隔1秒(预期)在SVSC控制台中显示消息tick

当我向source1发送消息时,我可以看到消息Received from stream。所以我相信source1设置正确。

有谁知道如何让source1表现得像source2?将source1连接到?

的特殊内容

谢谢

已更新

  • 我已更新代码。我实际上在main之外声明了2个源,以便我可以从另一个Actor系统中使用它来发送消息。 这是分享引用以向source1发送邮件的正确方法,还是应该使用actorSelection或变种?
  • 弗拉基米尔·马特维耶夫提到,我试过: source1.mapMaterializedValue { ref => ref ! WsMessage(..., "x", ...); ref ! WsMessage(..., "y", ...) }但我仍然看不到SWSC中的更新

以下是我的测试客户端的代码:

object Test {

  def main(args: Array[String]): Unit = {

    implicit val system = ActorSystem("my-system2")
    implicit val materializer = ActorMaterializer()
    // needed for the future flatMap/onComplete in the end
    implicit val executionContext = system.dispatcher

    val source1Client = TestWebServer.source1
    source1Client.mapMaterializedValue { ref => ref ! WsMessage(DateTime.now(), "x", "xx", 0, 0, 0); ref ! WsMessage(DateTime.now(), "y", "yy", 0, 0, 0) }

    val source11Client = TestWebServer.source1
    val actorRefClient = source11.to(Sink.ignore).run()
    actorRef2 ! WsMessage(DateTime.now(), "x", "xx", 0, 0, 0)

  }
}
    来自source1
  • Test未到达Source.actorRefsource1中的TestWebServer
  • actorRefClientsource1打印输出TestWebServer
  • 时到达Received from streamWsMessage(...)

1 个答案:

答案 0 :(得分:1)

对不起,但是你的更新没有多大帮助。这是一个运行良好的示例程序,当我使用akka-http websockets客户端时以及使用wsta之类的外部工具时:

@foreach ($images as $image )

    @if($count==0  OR is_int($count/3))
        <?php echo '<div class="row">';?>
     @endif

    <div class="col-md-3">
      <div class="well" style="background:white;">
        <img src="{{ url('images/'.$image->filepath) }}" alt="" class="" height="100" width="100" ></br>

       {{ $image->title }}<br>
        {{$image->filepath }}
      </div>
    </div>

    @if($count==0 OR is_int($count/3))
        <?php echo '</div>' ;?>

    @endif

    <?php $count++;?>
@endforeach

我认为此程序与您的程序没有任何重要区别。该程序还包括服务器和客户端,因此您可以启动服务器,然后多次启动客户端。例如,以下是两个客户端运行后的服务器输出:

import java.time.Instant
import scala.io.StdIn

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.ws.{TextMessage, UpgradeToWebSocket, WebSocketRequest}
import akka.stream.{ActorMaterializer, OverflowStrategy}
import akka.stream.scaladsl.{Flow, Sink, Source}

case class WsMessage(a: Instant, b: String, c: String, d: Int, e: Int, f: Int)

object MainServer extends App {
  implicit val actorSystem = ActorSystem()
  implicit val materializer = ActorMaterializer()
  implicit val executionContext = actorSystem.dispatcher

  val source = Source.actorRef[WsMessage](10, OverflowStrategy.dropHead)
    .map {
      case msg@WsMessage(_, _, c, _, _, _) =>
        println(s"Received from stream: $msg")
        TextMessage(c)
    }
    .mapMaterializedValue { ref =>
      ref ! WsMessage(Instant.now(), "a", "x", 0, 0, 0)
      ref ! WsMessage(Instant.now(), "b", "y", 0, 0, 0)
    }

  val requestHandler: HttpRequest => HttpResponse = {
    case req@HttpRequest(HttpMethods.GET, Uri.Path("/ws"), _, _, _) =>
      req.header[UpgradeToWebSocket] match {
        case Some(upgrade) => upgrade.handleMessagesWithSinkSource(Sink.ignore, source)
        case None => HttpResponse(StatusCodes.BadRequest, entity = "Not a valid websocket request!")
      }
    case _ =>
      HttpResponse(StatusCodes.NotFound, entity = "Unknown resource!")
  }

  val bindingFuture = Http().bindAndHandleSync(requestHandler, "localhost", 8080)

  println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
  StdIn.readLine()
  bindingFuture
    .flatMap(_.unbind())
    .onComplete(_ => actorSystem.terminate())
}

object MainClient extends App {
  implicit val actorSystem = ActorSystem()
  implicit val materializer = ActorMaterializer()
  implicit val executionContext = actorSystem.dispatcher

  Http()
    .singleWebSocketRequest(WebSocketRequest(Uri("ws://localhost:8080/ws")), Flow.fromSinkAndSource(Sink.foreach(println), Source.empty))
  Thread.sleep(5000)
  actorSystem.terminate()
}

这是客户输出之一:

Server online at http://localhost:8080/
Press RETURN to stop...
Received from stream: WsMessage(2016-06-28T08:58:21.478Z,a,x,0,0,0)
Received from stream: WsMessage(2016-06-28T08:58:21.478Z,b,y,0,0,0)
Received from stream: WsMessage(2016-06-28T08:58:29.925Z,a,x,0,0,0)
Received from stream: WsMessage(2016-06-28T08:58:29.925Z,b,y,0,0,0)

当我运行TextMessage.Strict(x) TextMessage.Strict(y) 时,我看到类似的事情。

此外,您在wsta ws://localhost:8080/wsSourceSink s声明的位置无关紧要:它们是不可变的蓝图,只有在{{1}时才能“行动” }}