Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ dist
.settings
.target
.cache
*.iml
*.ipr
*.iws
83 changes: 83 additions & 0 deletions app/controllers/TopicSubscriberWebSockets.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package controllers

import play.api.mvc.{WebSocket, Controller}
import play.api.libs.iteratee.{Iteratee, Enumerator}
import akka.actor.{Props, ActorSystem, Actor}
import scala.collection.mutable
import play.api.libs.concurrent.Promise
import akka.util.duration._
import java.util
import management.ManagementFactory

/**
*
* Challenge #2: Clients subscribe to different topics (weather news and system load info) through websockets and receive updates every X seconds
*
* @author: Edi Weissmann
*/
object TopicSubscriberWebSockets extends Controller {

/**
* Topics - System load and Weather
*/
trait Topic
object SystemLoad extends Topic {
val statsSystem = ManagementFactory.getOperatingSystemMXBean
override def toString = "System load [%s]".format(statsSystem.getSystemLoadAverage)
}
object WeatherForecast extends Topic {
override def toString = "Weather [sunny all day]"
}
object Topic {
def apply(name:String):Option[Topic] = name match {
case "weather" => Some(WeatherForecast)
case "system" => Some(SystemLoad)
case _ => None
}
}

def topicSubscribers() = WebSocket.using[String] { request =>

/**
* Topics to which current client is subscribed to
*/
val topics = mutable.Set[Topic]()

/**
* Prints topic updates to subscribed clients
*/
val topicOut = Enumerator.fromCallback { () =>
Promise.timeout({
Some(topics.mkString(" "))
}, 3 seconds)
}

/**
* Prints usage options
*/
val usageOut = Enumerator("Commands are: 'subscribe' and 'unsubscribe'.\nTopics are: 'weather' and 'system'\nType your command: subscribe weather")

/**
* Processes incoming commands
*/
val in = Iteratee.foreach[String] { msg => {
val Command = """(\w+) (\w+)""".r
msg match {
case Command(action, topicName) =>
Topic(topicName) match {
case Some(topic) =>
action match {
case "subscribe" => topics.add(topic)
case "unsubscribe" => topics.remove(topic)
case _ => // unknown action
}
case _ => // unknown topic
}
case _ => // unknown, noop
}
}}


(in, topicOut >- usageOut)
}
}
2 changes: 1 addition & 1 deletion app/views/websockets/index.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
</script>
<div id="websocket-controls" class="side-column">
<p>
<label>Websocket Address</label> <input name="address" id="address" />
<label>Websocket Address</label> <input name="address" id="address" value="ws://localhost:9000/websockets/topic-subscribers" />
</p>
<p>
<button id="connect">Connect</button>
Expand Down
1 change: 1 addition & 0 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ GET /websockets/logging controllers.WebSockets.logging()
GET /websockets/echo controllers.WebSockets.echo()
GET /websockets/counter controllers.WebSockets.counter()
GET /websockets/echo-and-counter controllers.WebSockets.echoAndCounter()
GET /websockets/topic-subscribers controllers.TopicSubscriberWebSockets.topicSubscribers

GET /twitter/stream controllers.Twitter.stream(keywords)

Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=0.11.2
sbt.version=0.11.3