Giter Site home page Giter Site logo

spray-websocket's Introduction

spray-websocket

WebSocket for spray-can

spray-websocket build status

Features

Usage

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:

Stable

resolvers += "Spray" at "http://repo.spray.io"

libraryDependencies += "com.wandoulabs.akka" %% "spray-websocket" % "0.1.4"

Snapshot

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"

Example

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()
}

Run the provided example

Troubleshooting

Limited JCE Policy

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

spray-websocket's People

Contributors

briantopping avatar cowboy129 avatar dcaoyuan avatar nefilim avatar petervandenabeele avatar slothspot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spray-websocket's Issues

Sending messages to particular WS sessions

Great library, thank you.

I need the ability to, from an outside source (perhaps HTTP, or some RPC call), given an ID that matches with the session, send a message to the WebSocketServerWorker actor. This is quite similar to this issue: #62

I see two obvious ways of accomplishing this:

  1. Upon connection, when the HttpRequest comes in, we disect the request, perform auth etc, and create the actor with it's name set to whatever session ID we decide. We could then lookup an actor via it's path, and send it messages. This has proved impossible so far. Here is my sample code:
class WebSocketHttpServer extends Actor with ActorLogging {
  def receive = {
    case Http.Connected(remoteAddress, localAddress) => {
      val conn = context.actorOf(Props(classOf[WebSocketSessionWorker], client))
      sender ! Http.Register(conn)
    }
  }

which I modified to become:

class WebSocketHttpServer extends Actor with ActorLogging {
  def receive = {
    case request: HttpRequest =>
      val client = sender
      // disect the request and create a session ID we can associate with
      val conn = context.actorOf(Props(classOf[WebSocketSessionWorker], client), name = "ABC")
      conn ! request

    case Http.Connected(remoteAddress, localAddress) => {
      self ! Http.Register(self)
    }
  }

The issue is that when the request is forwarded to the WebSocketSessionWorker, when it executes the Handshake, it sends the UpgradeServer message BACK to the WebSocketHttpServer, not the WebSocketSessionWorker. Not sure why. Gave up.

Edit: I have solved this issue. i didn't know about the forward method on ActorRefs. Retains the sender reference correctly.

  1. The second approach would be to construct WebSocketSessionWorker's with some sort of ActorCommunication actor, that it then registers with (and inside this ActorCommunication actor). Communication would then go through this actor, as it would maintain state around all WebSocket sessions currently going on.

    Thoughts?

Build changes

Hi there, grateful that you've put this together and maintained it, thanks! A few notes about the build:

It seems like the project is constantly being improved and the version remains at 0.1. Is it possible that the version could be set to 0.1.1-SNAPSHOT to indicate this to build systems? I realize the project isn't published to repositories, but the IDEs do not check for changes to the jar if it appears to be a release.

Is it possible that publishMavenStyle could be set to true? Totally appreciate if it's set to false for a reason, but otherwise other builds have a problem since Maven POMs are kind of the lingua franca of build tools.

Thanks! Brian

Spray Version on Stable branch

Hello,
I noticed that you are not using a stable spray version on your stable branch (here). Are you using new features in Spray? Or I can safely fork and change the versions?

InvalidActorNameException, please help!

Hello,

I get the following error when trying to create a WebSocketServer actor, in the same actor system as my spray route http request handler actor.

I really need to communicate between the two actors, thus why i need them in the same actor system. Is this a bug or simply not doable? If not, maybe there's someway to get the actor ref of an actor in one system, from within another?

akka.actor.InvalidActorNameException: actor name [IO-HTTP] is not unique!

remove logback.xml

Is it possible to remove logback.xml or to move it to another directory (like src/main/config or src/test/resources if it's needed to tests) that's not included in the published artifact?
It interferes with my external production configuration.

TCP kernel buffer sizes: CommandFailed for Tcp.Write

/cc https://groups.google.com/d/msg/akka-user/4djcoUvcRu0/k0CT-Os_PE0J

Hi all,

We are using Spray IO (with the wandoulabs WebSockets layer) on really old RHEL5 boxes in our QA environments.

Bizarrely, our server beta release was working fine on one box, but failing to write messages on another, despite the kernels and software versions being identical.

Clients were able to connect to the server, but as soon as the server started to write to the socket, we got this sort of thing:

19 Mar 15 10:56:55.542 HttpServerConnectionakka://MDES/user/IO-UHTTP/listener-0/0 [ MDES-akka.actor.default-dispatcher-4] WARN - CommandFailed for Tcp.Write text frame: ...
19 Mar 15 10:56:55.543 HttpServerConnectionakka://MDES/user/IO-UHTTP/listener-0/0 [ MDES-akka.actor.default-dispatcher-4] WARN - event pipeline: dropped CommandFailed(Write(ByteString(),NoAck(null)))

The boxes are running "Red Hat Enterprise Linux Server release 5.8 (Tikanga)" with 2.6.18-308.el5 on x86_64 cores. We're using scala 2.11.5, Java 1.6.0_40 and Akka 2.3.8 / Spray-IO 1.3.2.

We spotted that the kernel parameters were different on the boxes, this being the diff:

net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 4194304 16777216
net.ipv4.tcp_sack = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_wmem = 4096 4194304 16777216

and by using those parameters on all boxes the problems went away.

However, we have no control over setting these parameters on PROD boxes so we need a workaround that works without them.

But this is extremely concerning, why was the failure happening because of kernel parameters? Is this a bug in NIO, Spray IO, or Spray-WebSockets? Wandoulabs aren't doing anything unusual as you can see https://github.com/wandoulabs/spray-websocket/blob/master/spray-websocket/src/main/scala/spray/can/server/UpgradableHttpListener.scala

Most importantly, we need a workaround... does anybody have any suggestions?

The current theory is that the default kernel buffer size is too low to accept the outbound WebSocket frames. On the failing boxes (which we can't change), this is

$ cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304

and our messages are a few kb each of JSON.

Best regards,
Sam

Websocket URL

I would like to use a websocket URL with a path and parameters e.g. ws://myserver.com/path?param=1

How can I retrieve the path and the params of the URL from my WebSocketWorker actor?

Thanks!

Server doesn't reply Sec-WebSocket-Protocol header when asked

By reading The WebSocket Protocol specification at section 1.9. Subprotocols Using the WebSocket Protocol, I can understand:

the client CAN (optionally) request that the server use a specific subprotocol by including the Sec-WebSocket-Protocol field in its handshake. If it is specified, the server NEEDS to (mandatory) include the same field and one of the selected subprotocol values in its response for the connection to be established.

Unfortunately neither the most recent tag (actually v0.1.4) nor the master branch are compliant with that piece of specification :-(

As quick test, if you try the following Javascript in your HTML page

new WebSocket(window.location.host, "aSubprotocol");

your browser will almost certainly throw an exception which could look like the following:

WebSocket connection failed: 
Error during WebSocket handshake: 
Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received

Timed out connection not closed?

Running into a strange issue, I'll try to summarize as briefly as possible.

I have two servers, M(onitor) & S(erver). M is receiving data from S, once per second, over a spray-websocket connection.

Browser client connects to M over another web socket connection. As S pushes data to M, it's pushed out to the browser client. If the browser client disappears (I simulate it by quitting my VPN client that browser connects to M over), the data from S fails to be written at M over the web socket connection it had with the browser client.

Brower <---- (websocket/vpn) ---- Monitor <---- (websocket) ---- Server

Spray logs warnings endlessly, it doesn't appear that the connection gets cleaned up:

2014-04-15 18:17:41,701 WARN [ReportingActorSystem-akka.actor.default-dispatcher-10] s.c.s.HttpServerConnection [Slf4jLogger.scala : 71] CommandFailed for Tcp.Write text frame: {"node":"10.0.20.202","up":true,"metrics":{"buildI ...
2014-04-15 18:17:41,704 WARN [ReportingActorSystem-akka.actor.default-dispatcher-10] s.c.s.HttpServerConnection [Slf4jLogger.scala : 71] event pipeline: dropped CommandFailed(Write(ByteString(-127, 126, 0, -69, 123, 34, 110, 111, 100, 101, 34, 58, 34, 49, 48, 46, 48, 46, 50, 48, 46, 50, 48, 50, 34, 44, 34, 117, 112, 34, 58, 116, 114, 117, 101, 44, 34, 109, 101, 116, 114, 105, 99, 115, 34, 58, 123, 34, 98, 117, 105, 108, 100, 73, 110, 102, 111, 34, 58, 123, 34, 99, 111, 109, 112, 111, 110, 101, 110, 116, 78, 97, 109, 101, 34, 58, 34, 119, 111, 114, 107, 101, 114, 34, 44, 34, 99, 111, 109, 112, 111, 110, 101, 110, 116, 86, 101, 114, 115, 105, 111, 110, 34, 58, 34, 48, 46, 49, 46, 50, 45, 83, 78, 65, 80, 83, 72, 79, 84, 34, 44, 34, 98, 117, 105, 108, 100, 84, 105, 109, 101, 34, 58, 34, 84, 104, 117, 32, 65, 112, 114, 32, 49, 48, 32, 49, 57, 58, 50, 49, 58, 52, 56, 32, 80, 68, 84, 32, 50, 48, 49, 52, 34, 44, 34, 117, 112, 116, 105, 109, 101, 77, 105, 108, 108, 105, 115, 34, 58, 50, 54, 55, 57, 55, 57, 48, 53, 57, 125, 125, 125),NoAck(null)))

I don't get any (unhandled) messages at my WebSocketServerConnection (worker) or my web socket server actor (that created the worker), no indication that the connection is unavailable.

Have you witnessed this issue?

WebSocketClientWorker silently overloaded/saturated

UPDATE:

I found out what the problem is, and I'm going to be fixing it in smootoo's fork because this project seems to be dead.

The problem is that Pong is being send without Acking and that mean we can potentially fill up the network buffer and the connection will refuse to write anything until we do the ResumeWriting / WritingResumed dance. The workaround is similar to #78 but also forward all Tcp.Command messages to the connection, and force low level error handling into the worker. Ouch.

Using Acking dramatically reduces the probability of error.

The hierarchy of pipeline actors is too confusing for me to be able to propose an elegant/simple solution, sorry.

This is somewhat concerning because it means that this library effectively doesn't do any real error handling at all, so that certainly gives me pause.

Original description below:

Running this client -- against a basic WebSocket server that simply accepts anything:

import akka.actor._
import akka.io._
import spray.can.websocket._
import spray.can._
import spray.can.server.UHttp
import spray.http._
import concurrent.duration._
import akka.util.Timeout
import spray.can.websocket.frame.TextFrame

object Buggy {
  // for running on a remote
  val host = "myremotemachine"
  val port = 9081
}

// websocket/test:run-main testing.BuggyClient
class BuggyClient(
  host: String,
  port: Int
) extends WebSocketClientWorker {
  object Go

  def upgradeRequest = HttpRequest(
    HttpMethods.GET, "/",
    HttpHeaders.Host(host, port) :: List(
      HttpHeaders.Connection("Upgrade"),
      HttpHeaders.RawHeader("Upgrade", "websocket"),
      HttpHeaders.RawHeader("Sec-WebSocket-Version", "13"),
      HttpHeaders.RawHeader("Sec-WebSocket-Key", "x3JJHMbDL1EzLkh9GBhXDw=="),
      HttpHeaders.RawHeader("Sec-WebSocket-Extensions", "permessage-deflate")
    )
  )

  override def preStart(): Unit = {
    super.preStart()

    import context.system

    IO(UHttp) ! Http.Connect(host, port)

    implicit val d = context.system.dispatcher
    context.system.scheduler.schedule(0 seconds, 1 seconds) {
      println("GO GO GO")
      self ! Go
    }
  }

  def businessLogic: Receive = {
    case UpgradedToWebSocket =>
    case Go =>
      log.info("sending")
      connection ! TextFrame("foobar" * 1024 * 1024)

    case FrameCommandFailed(frame: TextFrame, _) =>
      log.error("FAIL - SHOULD REALLY RETRY")

    case other =>
      log.error("WTF?" + other.getClass)

  }
}
object BuggyClient extends App {
  import BuggyServer._
  val system = ActorSystem()
  system.actorOf(
    Props(new BuggyClient(Buggy.host, Buggy.port))
  )
}

results in the following output

GO GO GO
sending
acked
GO GO GO
sending
acked
(and various permutations thereoff, then)
GO GO GO
sending
GO GO GO
sending
GO GO GO
(and then)
GO GO GO
GO GO GO
GO GO GO
GO GO GO
GO GO GO
GO GO GO
...

I expect

GO GO GO
sending
acked

repeated forever, with the occasional out-of-order message.

I'm logging akka messages and lifecycle changes at DEBUG and not seeing any actors being stopped.

I'm not even seeing any Http.CommandFailed errors although I have on occassion seen the same log messages as reported in #1060

Any ideas what is going on?

stash unexpected messages during handshake

It would be good if the client/server workers stashed unexpected messages during the handshake stage... not stashing means that users of the actor have to wait for the connection to be made and upgraded before they can start sending messages.

Implement broadcast

I need a good way to broadcast frames across a set of websockets. Initially, I would be happy with broadcasting across all sockets, but being able to pass a partial function for the broadcast might be helpful.

broadcast() would be most functional from the client as a peer function to send().

Looked through the code a lot, but couldn't see a clean way of doing this. It's easy enough to record the WebSocketServerConnection in a collection when it is created, but not clear to me where to best remove it when the connection is closed.

Ideas appreciated!

Why does WebSocketClient get Tcp.PeerClosed on connecting?

I don't get a WebSocket connection established to echo.websocket.org. Here is what I'm doing:

  val ssl = true
  val host = "echo.websocket.org"
  val port = 80
  val headers = List(
    HttpHeaders.Host(host, port),
    HttpHeaders.Connection("Upgrade"),
    HttpHeaders.RawHeader("Upgrade", "websocket"),
    HttpHeaders.RawHeader("Sec-WebSocket-Version", "13"),
    HttpHeaders.RawHeader("Sec-WebSocket-Key", "x3JJHMbDL1EzLkh9GBhXDw=="),
    HttpHeaders.RawHeader("Sec-WebSocket-Extensions", "permessage-deflate")
  )
  val connect = Http.Connect(host, port, ssl)
  val pingReq = HttpRequest(HttpMethods.GET, "/ping", headers)

  val ping = system.actorOf(Props(
    new WebSocketClient(connect, pingReq) {
      ...
  }))

what results in

[DEBUG] [...] Connected to echo.websocket.org/174.129.224.73:80 [DEBUG] [...] Received unexpected Tcp.PeerClosed, invalidating SSL session

Any idea why this fails and how to proceed?

Installing Java Cryptography Extension as suggested elsewhere did not help.

Thanks, Peter

I asked the same question on https://groups.google.com/forum/#!topic/spray-user/2xnEYX6ImL0.

what is the maskingKey?

In FrameRendering there is a maskingKey that is passed around. What is it and how is it set?

WebSocketServerConnection actor leak?

it looks like WebSocketServerConnection actors might not be destroyed when a connection is reset which I believe is the intention of:

  def closeLogic: Receive = {
    case ev: Http.ConnectionClosed =>
      context.stop(self)
      log.debug("Connection closed on event: {}", ev)
  }

but from what I can see, Http.ConnectionClosed is never sent to WebSocketServerConnection, I only see ErrorClosed being sent (twice, connection reset by peer & TcpConnection actor died). I am not gracefully closing the client connection, still, one should probably handle this situation.

I believe PeerClosed is sent in case of a graceful connection shutdown.

Support association of connection with connection handler actor

It would be great if there were a means to name the connection handler actor based on some information available in the upgrade request. I'm thinking, for example, of a custom header that provides an ID, and that ID (presumably URL encoded) can be used as the name of the connection handler actor. The problem, of course, is that the connection handler actor already exists, and I don't think there's a way to name the actor after the fact. So presumably the implementation would create a new connection handler with the right name, register it as the handler, and stop the existing connection handler.

The goal is for clients to be able to identify themselves, and for the application to be able to use Akka routers, ActorSelections, etc. to communicate with specific clients (I'm assuming that's what the send() methods are for).

Does this make any sense? Is there a straightforward way to do it?

HttpHeaders for WebSockets

I noticed that the headers are defined explicitly in the examples:

 val headers = ... ::: List(
    HttpHeaders.Connection("Upgrade"),
    HttpHeaders.RawHeader("Upgrade", "websocket"),
    HttpHeaders.RawHeader("Sec-WebSocket-Version", "13"),
    HttpHeaders.RawHeader("Sec-WebSocket-Key", "x3JJHMbDL1EzLkh9GBhXDw=="))

Could you please package the upgrade parts in an object so that all client code doesn't need to write this?

Differentiation of upgraded connections

I am having a problem discovering how to differentiate connections that need upgrade. My intuition is the URI of the upgraded resource should provide the means to multiplex between multiple connections.

Because of the state machine architecture, this should be as simple as changing the businessLogic signature from Actor.Receive to a partial function accepting a path and returning an Actor.Receive. I took a stab at implementing it, but I can't find a good source for the request path. It seems to exist as late as https://github.com/topping/spray-websocket/blob/master/spray-websocket/src/main/scala/spray/can/websocket/WebSocketServerConnection.scala#L33-33, but beyond that, the path needs to be propagated. I could create a PR, but I'd imagine it could be improved on by @dcaoyuan so it may be a waste of time for both of us.

Thoughts?

scala 2.9 release?

I know this is a big ask, but any chance of a backport to scala 2.9?

We'd love to use websockets in ENSIME but we have to maintain a scala-2.9 backend because some people are still using scala-2.9 at their workplace (me, sadly).

Are you using such a modern version of akka that this is effectively impossible?

Sec-WebSocket-Protocol

Do you plan to add support for Sec-WebSocket-Protocol in a way where the caller can pass a list of supported protocols, and allow choosing one at the time the connection is upgraded?

I've tried to do this myself, and it works, but it's not very elegant -- don't want to change too much int he code. I am not sure what the proper way is to pass a list of supported protocols down to the upgrade code to modify the http-response.

pushing messages from the web socket server

How would one go about pushing a message from the WebSocketServer actor or even the WebSocketWorker (WebSocketServerConnection), for instance using the akka scheduler to push a message every X interval?

I'm probably missing something obvious but in the mean time the following change to WebSocketServerConnection made it possible, by making a reference to the "sender" actor available:

  def handshaking: Receive = {

    // when a client request for upgrading to websocket comes in, we send
    // UHttp.Upgrade to upgrade to websocket pipelines with an accepting response.
    case websocket.HandshakeRequest(state) =>
      state match {
        case wsFailure: websocket.HandshakeFailure => sender() ! wsFailure.response
        case wsContext: websocket.HandshakeContext => sender() ! UHttp.UpgradeServer(websocket.pipelineStage(self, wsContext), wsContext.response)
      }

    // upgraded successfully
    case UHttp.Upgraded =>
      context.become(businessLogic(sender) orElse closeLogic)
  }

  def businessLogic(peer: ActorRef): Receive

used like this:

  def businessLogic(peer: ActorRef): Receive = {
    case Push(event) =>
      log.info("pushing message to client {}", peer)
      peer ! event

This works but doesn't feel like a good solution, I have no idea if that original sender reference is stable for the entire lifetime of the connection. (Is it the receiverRef in WebSocketFrontEnd?), especially if it's going to change to an UnregisteredActorRef.

infinite loop in TextFrameStream

in https://github.com/wandoulabs/spray-websocket/blob/master/spray-websocket/src/main/scala/spray/can/websocket/frame/Frame.scala#L185

isn't this an infinite loop? Shouldn't the apply be adding a chunk size and using the new keyword.

object TextFrameStream {
  def apply(payload: InputStream): TextFrameStream = TextFrameStream(payload)
}

final case class TextFrameStream(chunkSize: Int, payload: InputStream) extends FrameStream {
  def opcode = Opcode.Text
}

just do this on the REPL to see

spray.can.websocket.frame.TextFrameStream(new java.io.FileInputStream("some file here"))

Unable to use spray-client

Just wondering if you guys have encountered this, when I try to use spray-client in a process where I've registered the UHTTP extension it fails:

akka.actor.InvalidActorNameException: actor name [IO-HTTP] is not unique!
    at akka.actor.dungeon.ChildrenContainer$NormalChildrenContainer.reserve(ChildrenContainer.scala:130) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.dungeon.Children$class.reserveChild(Children.scala:77) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.ActorCell.reserveChild(ActorCell.scala:369) [com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.dungeon.Children$class.makeChild(Children.scala:202) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.dungeon.Children$class.attachChild(Children.scala:42) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.ActorCell.attachChild(ActorCell.scala:369) [com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.ActorSystemImpl.actorOf(ActorSystem.scala:552) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at spray.can.HttpExt.<init>(Http.scala:152) ~[io.spray.spray-can-1.3.2-20140428.jar:na]
    at sun.reflect.GeneratedConstructorAccessor9.newInstance(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.7.0_51]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526) ~[na:1.7.0_51]
    at akka.actor.ReflectiveDynamicAccess$$anonfun$createInstanceFor$2.apply(DynamicAccess.scala:78) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at scala.util.Try$.apply(Try.scala:161) ~[org.scala-lang.scala-library-2.10.4.jar:na]
    at akka.actor.ReflectiveDynamicAccess.createInstanceFor(DynamicAccess.scala:73) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.ExtensionKey.createExtension(Extension.scala:153) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.ActorSystemImpl.registerExtension(ActorSystem.scala:711) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.ExtensionId$class.apply(Extension.scala:79) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.actor.ExtensionKey.apply(Extension.scala:149) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at akka.io.IO$.apply(IO.scala:30) ~[com.typesafe.akka.akka-actor_2.10-2.3.2.jar:na]
    at spray.client.pipelining$.sendReceive(pipelining.scala:35) ~[io.spray.spray-client-1.3.2-20140428.jar:na]

I'm using spray-client with routing DSL:

val pipeline: HttpRequest => Future[RenewAccessTokenResponse] = (
  logRequest(request => logTheRequest(request))
    ~> sendReceive)

I think sendReceive tries to lookup the HTTP extension and somehow not finding it (I thought it gets registered when UHTTP gets registered) and it tries to create a new one.

Have you encountered this or am I just doing something stupid?

different workers for different endpoints

Perhaps I am misunderstanding, but the WebSocketServerWorker appears to ignore the path when an upgrade request is received. This seems to make it impossible to serve different WebSocket server implementations depending on the path element. One obvious example of this might be the protocol version, which must be encoded in a user-defined handshake following the upgrade, but which would be best achieved in the connection request.

Not able to test this code in CF

I deployed the sample web sokcet server code in cloud foundry.
My web socket client is not able to connect.

following is the url used to connect to web socket server : wss://cfAppInstance:4443/

Basically handshake is not happening.

Scala 2.11

When are you planning to create a release for Scala 2.11?

Sending messages from server to clients

Sorry to duplicate #16, but I could use some help understand the operation:

Inside my WebSocketWorker I have this for debugging

      case UpgradedToWebSocket =>
        log.info(s"Server Upgraded to WebSocket: ${sender()}")
        val staticServerConnection = serverConnection
        val staticSender = sender()
        context.system.scheduler.schedule(10.second, 3.second) {
          staticServerConnection ! TextFrame("ssc")
          staticSender ! TextFrame("sc")
          send(TextFrame("s"))
          serverConnection ! TextFrame("dsc")
          sender() ! TextFrame("ds")

          staticServerConnection ! FrameCommand(TextFrame("fcssc"))
          staticSender ! FrameCommand(TextFrame("fcsc"))
          serverConnection ! FrameCommand(TextFrame("dssc"))
        }

Everything referencing serverConnection (e.g. send, staticServerConnection, serverConnection) and FrameCommand work fine, no other combinations work (they all result in debug logs). Looking at WebSocketServerWorker this makes some sense with the comment that serverConnection holds the pipeline.

However, I don't see who is handling these FrameCommand messages, or the actual type of serverConnection. In the examples it's created as so, but again sender() is just an ActorRef when I see it here - how is the actual type being determined, and what is serverConnection?

    case Http.Connected(remoteAddress, localAddress) =>
      {
        log.info(s"HTTP connected using $remoteAddress and $localAddress")
        val serverConnection = sender()
        val conn = context.actorOf(Props(new WebSocketWorker(serverConnection, httpApi)))
        serverConnection ! Http.Register(conn)
      }

Websocket connection not upgraded behind Heroku proxy

When hosting on Heroku, the handshake request doesn't get recognized. The requests that don't get upgraded (and thus doesn't match handshaking?) and gets picked up like a normal http request looks like

Request : HttpRequest(GET,http://twitchtally.herokuapp.com/,List(
Total-Route-Time: 0,
X-Request-Start: 1408294965243,
Connect-Time: 2,
Via: 1.1 vegur,
X-Forwarded-Port: 80,
X-Forwarded-Proto: http,
X-Forwarded-For: 62.194.104.217,
X-Request-Id: 8eefd65c-383a-4e40-b30e-21fcf2307809,
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36,
Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame,
Sec-Websocket-Version: 13,
Sec-Websocket-Key: r/aycSuwoTrh9GnV6SqgKg==,
Cache-Control: no-cache,
Pragma: no-cache,
Origin: http://twitchtally.herokuapp.com,
Upgrade: websocket,
Connection: Upgrade,
Host: twitchtally.herokuapp.com),Empty,HTTP/1.1)

I fail to run from sbt => no main class or java.lang.ClassNotFoundException: SimpleServer

Hi,

I can run the example SimpleServer perfectly from IntelliJ.

However, trying sbt run =>

> compile
[info] Formatting 1 Scala source {file:/Users/peter_v/Documents/data/.../spray-websocket-wandou-peter_v/}spray-websocket-examples-simple(compile) ...
[info] Compiling 3 Scala sources to /Users/peter_v/Documents/data/.../spray-websocket-wandou-peter_v/examples/spray-websocket-simple/target/scala-2.11/classes...
[success] Total time: 3 s, completed Apr 26, 2015 8:17:44 PM
> run
java.lang.RuntimeException: No main class detected.
    at scala.sys.package$.error(package.scala:27)

or in sbt =>

> runMain SimpleServer
[info] Running SimpleServer 
[error] (run-main-0) java.lang.ClassNotFoundException: SimpleServer
java.lang.ClassNotFoundException: SimpleServer

Should I change something? Once I understand what I need to change, I will try to submit a patch in code or documentation to make this easier for newcomers.

I now tried one more time with a fresh git clone of the newest version, and same result:

➜  spray-websocket git:(master) git log -1 | head -1 # latest sha
commit e10482e26638168965bcb4bbec95e82b0609a431
➜  spray-websocket git:(master) sbt run
[info] Loading project definition from /Users/peter_v/Documents/data/.../new-websocket-wandou/spray-websocket/project
[info] Updating {file:/Users/peter_v/Documents/data/.../new-websocket-wandou/spray-websocket/project/}spray-websocket-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/peter_v/Documents/data/.../new-websocket-wandou/spray-websocket/project/target/scala-2.10/sbt-0.13/classes...
[info] Set current project to spray-websocket-root (in build file:/Users/peter_v/Documents/data/.../new-websocket-wandou/spray-websocket/)
[info] Updating {file:/Users/peter_v/Documents/data/.../new-websocket-wandou/spray-websocket/}spray-websocket-root...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
java.lang.RuntimeException: No main class detected.
    at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last spray-websocket-root/compile:run for the full output.
[error] (spray-websocket-root/compile:run) No main class detected.
[error] Total time: 1 s, completed Apr 27, 2015 8:48:21 AM

Thanks !

Turn off logging

Sorry for simple question, but how can I make this line stop sending log messages?

          context.log.debug("Writing frame {}", frame1.opcode)

I've already got my own logging and want to turn this off

是否支持path param

您好,谢谢您的项目
我想用类似一下的格式 ws://localhost:8090/data/000001.XSHE, 其中,data/000001.XSHE 作为参数。
请问是否支持PATHPARAM,或者在程序中读取到 data/000001.XSHE 这个值。

服务器监听代码为:
IO(UHttp) ! Http.Bind(server, "localhost", 8090)
客户端代码为:

var wsUri = "ws://localhost:8090/data/000001.XSHE";
websocket = new WebSocket(wsUri);

再次感谢!

Sec--WebSocket-Protocol?

How should one handle Sec-WebSocket-Protocol? Is there an elegant solution for me to process the protocol requests and respond with a specific protocol in the response header?

spray-websocket doesn't use the actual ActorSystem configuration but loads "application.conf" regardless of it

Please, consider the following scenario:

  • users could decide to create their ActorSystem passing a Config object different than the application.conf simply because Akka allows it:
implicit val system = ActorSystem("mySystem", ConfigFactory.load("mySystem.conf"))
  • spray-websocket package object is actually loading the default application.conf file regardless the above decision and without considering the ActorySystem could have been configured with a different Config object
package object websocket {

  val config = ConfigFactory.load().getConfig("spray.websocket")
  // ...
}
  • That will certainly lead to a misconfiguration making users notice unexpected behaviour of spray-websocket

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.