All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalatra.atmosphere.AtmosphereClient.scala Maven / Gradle / Ivy

The newest version!
package org.scalatra
package atmosphere

import org.atmosphere.cpr._
import org.json4s._
import org.scalatra.util.RicherString._
import grizzled.slf4j.Logger
import scala.collection.JavaConverters._

object AtmosphereClient {
  def lookupAll(): Seq[ScalatraBroadcaster] = {
    BroadcasterFactory.getDefault.lookupAll().asScala.toSeq collect {
      case b: ScalatraBroadcaster => b
    }
  }

  def lookup(path: String): Option[ScalatraBroadcaster] = {
    val pth = path.blankOption getOrElse "/*"
    val norm = if (!pth.endsWith("/*")) {
      if (!pth.endsWith("/")) pth + "/*" else "*"
    } else pth
    val res = BroadcasterFactory.getDefault.lookup(norm)
    if (res.isInstanceOf[ScalatraBroadcaster]) Option(res).map(_.asInstanceOf[ScalatraBroadcaster])
    else None
  }

  def broadcast(path: String, message: OutboundMessage, filter: ClientFilter = _ => true) = {
    lookup(path) foreach { _.broadcast(message, filter) }
  }

  def broadcastAll(message: OutboundMessage, filter: ClientFilter = _ => true) = {
    lookupAll() foreach {
      _ broadcast (message, filter)
    }
  }
}

/**
 * Provides a handle for a single Atmosphere connection. 
 * 
 * Each browser or other device which connects to an `atmosphere` route is
 * assigned its own AtmosphereClient, with a uuid. This is a good bet for
 * subclassing if you need to implement your own message distribution logic.
 * Subclasses may define their own ClientFilter logic in addition to the
 * stock ClientFilters already defined, in order to segment message delivery.
 */
trait AtmosphereClient {

  @volatile private[atmosphere] var resource: AtmosphereResource = _
  private[this] val internalLogger = Logger[AtmosphereClient]
  private[this] def broadcaster = resource.getBroadcaster.asInstanceOf[ScalatraBroadcaster]

  /**
   * Deliver the message to everyone except the current user.
   */
  final protected def SkipSelf: ClientFilter = _.uuid != uuid
  
  /**
   * Deliver the message only to the current user.
   */
  final protected def OnlySelf: ClientFilter = _.uuid == uuid
  
  /**
   * Deliver the message to all connected users.
   */
  final protected val Everyone: ClientFilter = _ => true

  protected def requestUri = {
    val u = resource.getRequest.getRequestURI.blankOption getOrElse "/"
    if (u.endsWith("/")) u + "*" else u + "/*"
  }

  /**
   * A unique identifier for a given connection. Can be used for filtering
   * purposes.
   */
  final def uuid: String = resource.uuid()

  /**
   * Receive an inbound message. 
   */
  def receive: AtmoReceive

  /**
   * A convenience method which sends a message only to the current client,
   * using a broadcast filter.
   */
  final def send(msg: OutboundMessage) = broadcast(msg, OnlySelf)

  /**
   * A convenience method which sends a message only to the current client,
   * using a broadcast filter.
   */
  final def !(msg: OutboundMessage) = send(msg)

  /**
   * Broadcast a message to all clients, skipping the current client by default
   * (i.e. normal chat server behaviour). Optionally filter the clients to
   * deliver the message to by applying a filter.
   */
  final def broadcast(msg: OutboundMessage, filter: ClientFilter = SkipSelf) = {
    if (resource == null)
      internalLogger.warn("The resource is null, can't publish")

    if (resource.getBroadcaster == null)
      internalLogger.warn("The broadcaster is null, can't publish")

    broadcaster.broadcast(msg, filter)
  }

  /**
   * Broadcast a message to all clients, skipping the current client by default
   * (i.e. normal chat server behaviour). Optionally filter the clients to
   * deliver the message to by applying a filter.
   */
  final def ><(msg: OutboundMessage, filter: ClientFilter = SkipSelf) = broadcast(msg, filter)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy