Scala,Play,Akka,Websocket:如何通过websocket传递actor消息

时间:2014-02-18 10:49:01

标签: scala playframework websocket playframework-2.0 akka

我有一个使用应用程序启动的actor,在后台运行,观察某些更改以及是否有任何报告。目前它只是控制台的println。我需要做的是每当有新消息时 - 使用Websocket将其发送到前端。

这是我的Play Global对象,其中启动了监视/侦听actor:

object Global extends GlobalSettings {

    override def onStart(app: Application) {

        class Listener extends Actor {
            //This needs to be changed to pass messages to Websocket, how?
            def receive = {
                case Create(path) => println("CREATE " + path)
                case Delete(path) => println("DELETE " + path)
                case Modify(path) => println("MODIFY " + path)
            }
        }

        val listener = Akka.system.actorOf(Props[Listener], "listener")
        val swatch = Akka.system.actorOf(Props[SwatchActor], "swatch")
        swatch ! Watch("/folder/path", Seq(Create, Modify, Delete), true, Some(listener))

    }

}

这是我的Play控制器:

object Application extends Controller {

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

        //This hopefully gets the listener actor reference?
        val listener = Akka.system.actorSelection("/user/listener")

        val (out, channel) = Concurrent.broadcast[String]
        val in = Iteratee.foreach[String] { msg =>
            //Actor messages must be pushed here, how?
            channel push("RESPONSE: " + msg)
        }

        (in, out)

    }   

}

据我所知,为了建立websocket连接,必须有一个初始的“in”。

所以我的问题是:

  1. 如何修改Listener actor以将消息推送到Websocket?
  2. 在建立websocket连接后,我需要做些什么来准备演员推送消息?
  3. 如何将消息从侦听器actor推送到websocket?

2 个答案:

答案 0 :(得分:6)

我找到了解决方案。

必须从单独文件导入的案例类:

case class Start(out: Concurrent.Channel[String])

全球对象:

object Global extends GlobalSettings {

    override def onStart(app: Application) {

        class Listener extends Actor {
            var out = {
                val (enum, chan) = Concurrent.broadcast[String]
                chan
            }
            def receive = {
                //Websocket channel out is set here
                case Start(out) => this.out = out
                //Pushing messages to Websocket
                case Create(path) => this.out.push(path.toString)
                case Delete(path) => this.out.push(path.toString)
                case Modify(path) => this.out.push(path.toString)
            }
        }

        val listener = Akka.system.actorOf(Props[Listener], "listener")
        val swatch = Akka.system.actorOf(Props[SwatchActor], "swatch")
        swatch ! Watch("/folder/path", Seq(Create, Modify, Delete), true, Option(listener))

    }

}

播放控制器:

object Application extends Controller {

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

        val (out, channel) = Concurrent.broadcast[String]

        val listener = Akka.system.actorSelection("akka://application/user/listener")
        //This is where the websocket out channel is being passed to the listener actor
        listener ! Start(channel)

        val in = Iteratee.foreach[String] { msg =>
            channel push("RESPONSE: " + msg)
        }

        (in, out)

    }   

}

答案 1 :(得分:2)

就在前几天我写了这篇文章,它将包含在Play 2.3中。您现在可以将其复制到您自己的应用程序中:

https://github.com/jroper/ReactiveMaps/blob/websocket-actor/app/actors/WebSocketActor.scala

你传递一个Props对象,它会为你创建一个actor。您通过发送到context.parent发送到WebSocket。