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

spray.io.ConnectionHandler.scala Maven / Gradle / Ivy

/*
 * Copyright © 2011-2015 the spray project 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package spray.io

import java.net.InetSocketAddress
import akka.actor.{ ActorLogging, ActorRef, Terminated, Actor }
import akka.io.Tcp

trait ConnectionHandler extends Actor with ActorLogging {

  //# final-stages
  def baseCommandPipeline(tcpConnection: ActorRef): Pipeline[Command] = {
    case x @ (_: Tcp.WriteCommand | _: Tcp.CloseCommand) ⇒ tcpConnection ! x
    case Pipeline.Tell(receiver, msg, sender) ⇒ receiver.tell(msg, sender)
    case x @ (Tcp.SuspendReading | Tcp.ResumeReading | Tcp.ResumeWriting) ⇒ tcpConnection ! x
    case _: Droppable ⇒ // don't warn
    case cmd ⇒ log.warning("command pipeline: dropped {}", cmd)
  }

  def baseEventPipeline(tcpConnection: ActorRef): Pipeline[Event] = {
    case x: Tcp.ConnectionClosed ⇒
      log.debug("Connection was {}, awaiting TcpConnection termination...", x)
      context.become {
        case Terminated(`tcpConnection`) ⇒
          log.debug("TcpConnection terminated, stopping")
          context.stop(self)
      }

    case _: Droppable ⇒ // don't warn
    case ev           ⇒ log.warning("event pipeline: dropped {}", ev)
  }
  //#

  def running(tcpConnection: ActorRef, stage: PipelineStage, remoteAddress: InetSocketAddress,
              localAddress: InetSocketAddress): Receive = {
    val pipelineContext = PipelineContext(context, remoteAddress, localAddress, log)
    running(tcpConnection, stage, pipelineContext)
  }

  def running[C <: PipelineContext](tcpConnection: ActorRef, pipelineStage: RawPipelineStage[C],
                                    pipelineContext: C): Receive = {
    val stage = pipelineStage(pipelineContext, baseCommandPipeline(tcpConnection), baseEventPipeline(tcpConnection))
    running(tcpConnection, stage)
  }

  def running(tcpConnection: ActorRef, pipelines: Pipelines): Receive = {
    case x: Command ⇒ pipelines.commandPipeline(x)
    case x: Event   ⇒ pipelines.eventPipeline(x)
    case x @ Terminated(`tcpConnection`) ⇒
      pipelines.eventPipeline(Tcp.ErrorClosed("TcpConnection actor died"))
      log.debug("TcpConnection actor died, stopping")
      context.stop(self)
    case Terminated(actor) ⇒ pipelines.eventPipeline(Pipeline.ActorDeath(actor))
  }
}

class SimpleConnectionHandler(tcpConnection: ActorRef,
                              pipelineStage: PipelineStage,
                              remoteAddress: InetSocketAddress,
                              localAddress: InetSocketAddress) extends ConnectionHandler {
  def receive = running(tcpConnection, pipelineStage, remoteAddress, localAddress)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy