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

im.actor.server.session.SessionMessagePublisher.scala Maven / Gradle / Ivy

The newest version!
package im.actor.server.session

import scala.annotation.tailrec
import scala.collection.immutable

import akka.actor._
import akka.stream.actor._

import im.actor.api.rpc.ClientData
import im.actor.server.mtproto.protocol._

private[session] object SessionMessagePublisher {
  def props() = Props[SessionMessagePublisher]
}

private[session] class SessionMessagePublisher extends ActorPublisher[SessionStreamMessage] with ActorLogging {

  import ActorPublisherMessage._

  import SessionStreamMessage._

  // TODO: MaxQueueSize
  private[this] var messageQueue = immutable.Queue.empty[SessionStreamMessage]

  def receive = {
    case (mb: MessageBox, clientData: ClientData) ⇒
      log.debug("MessageBox: {} clientData: {}", mb, clientData)

      // TODO: tail-recursive function for container unpacking
      mb.body match {
        case Container(bodies) ⇒
          val ackMessage = HandleOutgoingAck(
            bodies
              .view
              .filter {
                case MessageBox(_, _: MessageAck)      ⇒ false
                case MessageBox(_, _: ProtoRpcRequest) ⇒ false
                case _                                 ⇒ true
              }
              .map(_.messageId) :+ mb.messageId
          )
          val handleMessages = bodies.map(HandleMessageBox(_, clientData)).toList
          publishMessages(ackMessage :: handleMessages)
        case _ ⇒
          val handleMessage = HandleMessageBox(mb, clientData)

          mb.body match {
            case _: MessageAck      ⇒ publishMessage(handleMessage)
            case _: ProtoRpcRequest ⇒ publishMessages(List(handleMessage))
            case _                  ⇒ publishMessages(List(HandleOutgoingAck(Seq(mb.messageId)), handleMessage))
          }
      }
    case command: SubscribeCommand ⇒
      publishMessage(HandleSubscribe(command))
    case Request(_) ⇒
      deliverBuf()
    case Cancel ⇒
      context.stop(self)
    case unmatched ⇒
      log.debug("Unmatched {}", unmatched)
  }

  private def publishMessage(message: SessionStreamMessage): Unit = {
    log.debug("Publish message {}", message)

    if (messageQueue.isEmpty && totalDemand > 0)
      onNext(message)
    else {
      messageQueue = messageQueue.enqueue(message)
      deliverBuf()
    }
  }

  private def publishMessages(messages: immutable.Iterable[SessionStreamMessage]): Unit = {
    messages foreach { message ⇒
      log.debug("Publish message {}", message)
    }
    messageQueue = messageQueue.enqueue(messages)
    deliverBuf()
  }

  @tailrec final def deliverBuf(): Unit =
    if (isActive && totalDemand > 0)
      messageQueue.dequeueOption match {
        case Some((el, queue)) ⇒
          messageQueue = queue
          onNext(el)
          deliverBuf()
        case None ⇒
      }

  override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    log.error(reason, "Exception thrown, message: {}", message)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy