0

I'm new to Spray and trying to implement a client that receives a stream of data from a server. My current code looks like the following. The client send a request to the HTTP server which then responds back with a stream of data (as chunked responses).I checked that it connects to the server and can get responses back.

However, it's not clear to me how I should be handling disconnects and reconnects. For example, (A) if I loose network connectivity or (B) my client timeouts because the server may not have any data to send at that moment. Any pointers/examples would be appreciated.

UPDATE

First, I want to detect events (A) and (B) above. When the client experiences either (A) or (B) above it should reestablish connection and re-authenticate so that it can continue (get back to connected state to get the data stream.

import spray.http._
import spray.client.pipelining._
import akka.actor._
import spray.can.Http
import akka.io.IO
import spray.http.HttpRequest
import spray.http.ChunkedResponseStart
import spray.http.HttpRequest
import spray.http.ChunkedResponseStart

trait Authorization {
  def authorize: HttpRequest => HttpRequest
}

trait OAuthAuthorization extends Authorization {

  import OAuth._

  val consumer = ???
  val token = ???
  val authorize: (HttpRequest) => HttpRequest = OAuthorizer(token, token)
}


class StreamerActor(uri: Uri) extends Actor with ActorLogging {
  this: Authorization =>
  val io = IO(Http)(context.system)

  //Initial state of the Actor
  def receive = ready

  def ready: Receive = {
    case query: String =>
      val body = HttpEntity(ContentType(MediaTypes.`application/x-www-form-urlencoded`), s"$query")
      val req = HttpRequest(HttpMethods.POST, uri = uri, entity = body) ~> authorize
      sendTo(io).withResponsesReceivedBy(self)(req)
      //As soon as you get the data you should change state to "connected" by using a "become"
      context become connected
  }

  def connected: Receive = {
    case ChunkedResponseStart(_) => log.info("Chunked Response started.")
    case MessageChunk(entity, _) => log.info(entity.asString)
    case ChunkedMessageEnd(_, _) => log.info("Chunked Message Ended")
    case Http.Closed => log.info("HTTP closed")
    case _ =>
  }
}

object SprayStreamer extends App {

  val system = ActorSystem("simple-spray-http")
  val Uri = Uri("https://.....")
  val streamClient = system.actorOf(Props(new StreamerActor(Uri) with OAuthAuthorization), name = "spray-client")
  streamClient ! "keyword"

}

These are the contents of my resources/application.conf

spray {
  can.server {
    idle-timeout = 90 s
    request-timeout = 80 s
    connection-timeout = 90 s
    reqiest-chunk-aggregation-limit = 0
  }

  can.client {
    idle-timeout = 90 s
    request-timeout = 80 s
    connection-timeout = 90 s
    response-chunk-aggregation-limit = 0
  }

  io.confirm-sends = on

}
Soumya Simanta
  • 11,523
  • 24
  • 106
  • 161
  • 1
    It's not an answer to your question but you might wanna take a look at activator and template called `activator-spray-twitter`. – goral May 29 '14 at 05:52
  • Maybe you could add some information about *what* the desired behavior should be in cases of disconnect/reconnect. Afterwards, we can try to find solutions for the *how* to do it. – jrudolph May 29 '14 at 08:57
  • @goral - I've looked at the activator template but it doesn't take care of the issue(s) I've mentioned in the question. – Soumya Simanta May 29 '14 at 11:40
  • @jrudolph - I've updated the question with the desired behavior. – Soumya Simanta May 29 '14 at 11:45
  • Regarding (B): all connection closing should be reported via a message of type `Http.ConnectionClosed` (which is the supertype of `Http.Closed`). Regarding (A): this is difficult to do. In many cases losing a connection isn't distinguishable from just getting no response currently so it may also run into the timeouts. To distinguish timeouts from other closing scenarios you can also switch off the spray-can timeouts completely and manage timeouts yourself. – jrudolph May 30 '14 at 11:44
  • @jrudolph - thanks. Let me try this out. I was looking something like this https://github.com/etaty/rediscala/blob/master/src/main/scala/redis/actors/RedisWorkerIO.scala – Soumya Simanta May 30 '14 at 12:39

0 Answers0