diff --git a/.gitignore b/.gitignore index 8acee61..d4f68f4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ dist .settings .target .cache +*.iml +*.ipr +*.iws diff --git a/app/controllers/TopicSubscriberWebSockets.scala b/app/controllers/TopicSubscriberWebSockets.scala new file mode 100644 index 0000000..4245956 --- /dev/null +++ b/app/controllers/TopicSubscriberWebSockets.scala @@ -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) + } +} diff --git a/app/views/websockets/index.scala.html b/app/views/websockets/index.scala.html index 42ae763..411f637 100644 --- a/app/views/websockets/index.scala.html +++ b/app/views/websockets/index.scala.html @@ -45,7 +45,7 @@

- +

diff --git a/conf/routes b/conf/routes index 72deb64..5a4a586 100644 --- a/conf/routes +++ b/conf/routes @@ -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) diff --git a/project/build.properties b/project/build.properties index f4ff7a5..d428711 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.11.2 +sbt.version=0.11.3