WebSocket for spray-can
- Support java.util.zip based per-frame-deflate
- Pass all Autobahn test cases (both ws and wss)
The artifact is published to Sonatype, so in order to use it you just have to add the following dependency:
libraryDependencies += "com.wandoulabs.akka" %% "spray-websocket" % "0.1.2-RC1"
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
libraryDependencies += "com.wandoulabs.akka" %% "spray-websocket" % "0.1.3-SNAPSHOT"
Define your WebSocketWorker by extending WebSocketConnection and overriding method 'businessLogic'. Or, write your own WebSocketConnection.
package spray.can.websocket.examples
import akka.actor.{ ActorSystem, Actor, Props, ActorLogging, ActorRef }
import akka.io.IO
import spray.can.Http
import spray.can.server.UHttp
import spray.can.websocket
import spray.can.websocket.frame.{ BinaryFrame, TextFrame }
import spray.http.HttpRequest
import spray.can.websocket.FrameCommandFailed
import spray.routing.HttpServiceActor
object SimpleServer extends App with MySslConfiguration {
final case class Push(msg: String)
object WebSocketServer {
def props() = Props(classOf[WebSocketServer])
}
class WebSocketServer extends Actor with ActorLogging {
def receive = {
// when a new connection comes in we register a WebSocketConnection actor as the per connection handler
case Http.Connected(remoteAddress, localAddress) =>
val serverConnection = sender()
val conn = context.actorOf(WebSocketWorker.props(serverConnection))
serverConnection ! Http.Register(conn)
}
}
object WebSocketWorker {
def props(serverConnection: ActorRef) = Props(classOf[WebSocketWorker], serverConnection)
}
class WebSocketWorker(val serverConnection: ActorRef) extends HttpServiceActor with websocket.WebSocketServerConnection {
override def receive = handshaking orElse businessLogicNoUpgrade orElse closeLogic
def businessLogic: Receive = {
// just bounce frames back for Autobahn testsuite
case x @ (_: BinaryFrame | _: TextFrame) =>
sender() ! x
case Push(msg) => send(TextFrame(msg))
case x: FrameCommandFailed =>
log.error("frame command failed", x)
case x: HttpRequest => // do something
}
def businessLogicNoUpgrade: Receive = {
implicit val refFactory: ActorRefFactory = context
runRoute {
getFromResourceDirectory("webapp")
}
}
}
def doMain() {
implicit val system = ActorSystem()
import system.dispatcher
val server = system.actorOf(WebSocketServer.props(), "websocket")
IO(UHttp) ! Http.Bind(server, "localhost", 8080)
readLine("Hit ENTER to exit ...\n")
system.shutdown()
system.awaitTermination()
}
// because otherwise we get an ambiguous implicit if doMain is inlined
doMain()
}
- Build and run the project:
sbt 'project spray-websocket-examples-simple' run
- Open your browser: http://localhost:8080/websocket.html
If you see this error:
java.lang.IllegalArgumentException: Cannot support TLS_RSA_WITH_AES_256_CBC_SHA with currently installed providers
at sun.security.ssl.CipherSuiteList.<init>(CipherSuiteList.java:92)
...
Download the JCE, unzip and move the two jars into <java_install_dir>lib/security