Playframework 如何使用akka streams重构此代码。

Playframework 如何使用akka streams重构此代码。,playframework,akka,playframework-2.5,Playframework,Akka,Playframework 2.5,这样做的目的是保持频道开放,以便以后使用。在playframework 2.5.x中,文档说明必须使用akka流,但没有说明如何实现此示例。有人能帮我吗 import play.api.mvc._ import play.api.libs.iteratee._ import play.api.libs.concurrent.Execution.Implicits.defaultContext def socket = WebSocket.using[String] { request =&g

这样做的目的是保持频道开放,以便以后使用。在playframework 2.5.x中,文档说明必须使用akka流,但没有说明如何实现此示例。有人能帮我吗

import play.api.mvc._
import play.api.libs.iteratee._
import play.api.libs.concurrent.Execution.Implicits.defaultContext

def socket =  WebSocket.using[String] { request =>

  // Concurrent.broadcast returns (Enumerator, Concurrent.Channel)
  val (out, channel) = Concurrent.broadcast[String]

  // log the message to stdout and send response back to client
  val in = Iteratee.foreach[String] {
    msg => println(msg)
      // the Enumerator returned by Concurrent.broadcast subscribes to the channel and will
      // receive the pushed messages
      channel push("I received your message: " + msg)
  }
  (in,out)
}

我想您正在寻找如何使用Play 2.5和Akka Streams流实现Echo websocket连接

这应该能奏效

  def socket = WebSocket.accept[String, String] { request =>
    Flow[String]
      .map(msg => "I received your message: " + msg)
  }

我终于找到了一个使用演员的解决方案。我发现:

def conect = WebSocket.accept[JsValue, JsValue] {request => 
  ActorFlow.actorRef(out => UserWebSocket.props(out, users))
}
然后我查看了ActorFlow.actorRef的源代码:

并提出了这个解决方案:

import javax.inject._
import play.api.Configuration
import play.api.mvc._
import scala.concurrent._

import akka.stream.{Materializer, OverflowStrategy}
import akka.stream.scaladsl.{Flow, Keep, Sink, Source}
import akka.actor._

class UserActor(out: ActorRef) extends Actor {
  def receive = {
    // receives messages from client browser here
    // out is actor that will send messages back to client(s)
    case msg: String => out ! "Received message "+msg
  }
}
object UserActor {
  def props(out: ActorRef) = Props(new UserActor(out))
}

@Singleton
class NotificationController @Inject()(val config:Configuration)
                          (implicit ec: ExecutionContext, actorSystem:ActorSystem, materializer: Materializer) extends Controller {

  // outActor can be used to send messages to client(s)
  // Sink.asPublisher(true) makes this a broadcast channel (multiple clients can connect to this channel, and messages sent to outActor are broadcast to all of them).  Use Sink.asPublisher(false) to create a unicast channel.
  val (outActor, publisher) = Source.actorRef[String](99, OverflowStrategy.dropNew)
        .toMat(Sink.asPublisher(true))(Keep.both).run()


  def flowsocket = WebSocket.accept[String, String] {request =>
    val aflow:Flow[String, String, _] = {

        val sink = Sink.actorRef( actorSystem.actorOf(UserActor.props(outActor)), akka.actor.Status.Success(()) )

        val source = Source.fromPublisher(publisher)

        Flow.fromSinkAndSource(
            sink, source
        )
    }
    aflow
  }

}
从那以后,我修改了我的解决方案,以更充分地接受演员模型。我现在有了一个“UsersBroadcastActor”,它是一个所有其他“UserActor”都可以连接并通过它进行通信的单例actor:

lazy val broadcastActorRef = actorSystem.actorOf(Props[UsersBroadcastActor])

def flowsocket = WebSocket.accept[JsValue, JsValue] { request =>
    ActorFlow.actorRef(out => UserActor.props(out, broadcastActorRef))
}

当UserActor被实例化时,在其preStart()方法中,它向broadcastActorRef发送一条订阅消息,broadcastActorRef保存对“订阅”它的所有UserActor的引用。我可以向broadcastActorRef发送一条消息,并将其转发给每个用户参与者。如果您还需要此解决方案的完整代码示例,请告诉我。

您必须这样做

val (subscriber, publisher)=Source.asSubscriber[String]
      .toMat(Sink.asPublisher[String](fanout = true))(Keep.both).run()

def websocketAction=WebSocket.accept { requestHeader =>
    Flow.fromSinkAndSource(Sink.fromSubscriber(subscriber),Source.fromPublisher(publisher))
}
第一部分将在给定接收器和流的情况下创建推送消息和接收消息所需的对象(订阅发布者)

最后,您将为收到的每个websocket请求创建一个流,其中包含代码
流。。。关于Akka流(
s、
s和
s)有一点不清楚,那就是它们代表流的形状,而不是流本身。。。当您具体化它们时(使用方法
runWith
run
)。现在。。。Play接收
s(当使用服务器发送的事件时)或
s(当使用WebSocket时)。他们还没有实现。。。因此,您需要具体化它们(第一行),然后再次创建流!(websocketAction行)


很抱歉,如果我不够清楚,但是使用该代码,它会工作。

实际问题是什么?可能是@Anton的重复问题是如何使用akka streams重构代码,我的想法是能够保持频道开放,并在以后回应其他事件时使用它。我理解,但如果你把这个解释放在问题本身中,那将是非常有帮助的。现在,帖子中唯一的句子不是一个真正的问题,而是一个陈述。事实上,我知道如何制作Echo websocket,但这不是我要问的对于在我的示例中,您可以看到您可以使用该频道来推送消息,并且可以存储该频道并在以后使用它。如果你收到一个事件,你必须通过频道通知用户,新的play 2.5 websocket api显然是一个语法开销,但一旦理解,我认为它实际上相当强大