Play 2.4使用Guice创建一个处理websocket的actor

时间:2016-04-22 15:50:19

标签: scala playframework playframework-2.0 akka guice

首先,感谢大家花些时间来回顾我的问题。我是scala生态系统的新手,所以我觉得我在讨论一些概念。

我在Play 2.4项目中介绍了Guice,它在一些REST控制器中工作。我编辑了build.sbt以附加routesGenerator := InjectedRoutesGenerator作为Play官方文档推荐并编辑我的路线,如下例所示:

GET        /socket       @com.letgo.chat.controllers.ChatController.socket

我注入演员的模块如下:

class ChatModule extends AbstractModule with ScalaModule with AkkaGuiceSupport with GuiceAkkaActorRefProvider {
  override def configure() {

    bindActor[TalkerProviderActor](TalkerProviderActor.name)
    ...

所有这一切似乎都在起作用。

但另一个端点使用Play方法WebSocket.acceptWithActor处理websocket。我需要创建一个也需要一些依赖的actor。

控制器创建ConnectionActor

class ConnectionActor(
  @Assisted() websocket: ActorRef,
  monitoring: Monitoring,
  @Named(BouncerActor.name) bouncer: ActorRef,
) extends Actor

...

class ChatController @Inject() extends Controller {
  def socket(): WebSocket[String, JsValue] = WebSocket.acceptWithActor[String, JsValue] { request => out =>
    // I had the following statement in order to build the actor before introducing Guice:
    // ConnectionActor.props()
    // Now, I need some magic here
  }
}

所以你可以看到我需要一个websocket: ActorRef的websocket输出。

我使用bindActorFactory提供的AkkaGuiceSupport方法在应用程序的其他部分创建了一些actor:

bindActorFactory[TalkerActor, TalkerActor.Factory]

但我不知道在这种情况下我应该如何创建一个处理websocket的actor。你能帮助我吗?

谢谢

1 个答案:

答案 0 :(得分:3)

我相信这可以解决问题:

package controllers

import javax.inject._

import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.stream.Materializer
import play.api.libs.streams.ActorFlow
import play.api.libs.ws.WSClient
import play.api.mvc._

import scala.concurrent.ExecutionContext.Implicits.global

@Singleton
class SocketActorProvider @Inject() (ws: WSClient) {
  def get(out: ActorRef) = Props(new SocketActor(out, ws))
}

class SocketActor(out: ActorRef, ws: WSClient) extends Actor {
  override def receive: Receive = {
    case "ping" => ws.url("http://localhost:9000/pong").get().foreach(pong => out ! pong.body)
  }
}

@Singleton
class HomeController @Inject() (implicit system: ActorSystem, ws: WSClient, materializer: Materializer, provider: SocketActorProvider) extends Controller {

  // route '/ws'
  def socket = WebSocket.accept[String, String] { request =>
    ActorFlow.actorRef(out => provider.get(out))
  }

  // route '/pong'
  def pong = Action {
    Ok("PONG!")
  }

  // route '/'
  def index = Action {
    Ok("""
      <script>
        var ws = new WebSocket('ws://localhost:9000/ws');
        ws.onopen = () => console.log('I am open!');
        ws.onmessage = m => console.log(m.data);

        setInterval(() => {console.log('ping'); ws.send('ping')}, 1000)
      </script>
    """).as("text/html")
  }

}

正如你所看到的,有一个由Guice注入的提供者注入了WSClient,在构建一个actor时它传递了依赖