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 (cross build with Scala 2.10 and 2.11), so in order to use it you just have to add the following dependency:
resolvers += "Spray" at "http://repo.spray.io"
libraryDependencies += "com.wandoulabs.akka" %% "spray-websocket" % "0.1.4"
resolvers += "Spray" at "http://repo.spray.io"
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
libraryDependencies += "com.wandoulabs.akka" %% "spray-websocket" % "0.1.5-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, ActorRefFactory }
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.WebSocketServerWorker {
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