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

internal.MessageDispatcher.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 Hossein Naderi
 *
 * 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 lepus.client
package internal

import cats.effect.Concurrent
import cats.effect.kernel.Resource
import cats.effect.std.*
import cats.effect.syntax.all.*
import cats.syntax.all.*
import lepus.protocol.domains.*

private[client] trait MessageDispatcher[F[_]] {
  def deliver(msg: DeliveredMessageRaw): F[Unit]
  def `return`(msg: ReturnedMessageRaw): F[Unit]
  def confirm(msg: ConfirmationResponse): F[Unit]
  def cancel(ctag: ConsumerTag): F[Unit]

  def deliveryQ(
      ctag: Option[ConsumerTag]
  ): Resource[F, (ConsumerTag, QueueSource[F, Option[DeliveredMessageRaw]])]
  final def deliveryQ: Resource[
    F,
    (ConsumerTag, QueueSource[F, Option[DeliveredMessageRaw]])
  ] =
    deliveryQ(None)

  def returnQ: QueueSource[F, ReturnedMessageRaw]
  def confirmationQ: QueueSource[F, ConfirmationResponse]
}

private[client] object MessageDispatcher {
  def apply[F[_]](
      returnedBufSize: Int = 10,
      confirmBufSize: Int = 10,
      deliveryBufSize: Int = 10
  )(using F: Concurrent[F]): F[MessageDispatcher[F]] = for {
    dqs <- F.ref(Map.empty[ConsumerTag, Queue[F, Option[DeliveredMessageRaw]]])
    rq <- Queue.bounded[F, ReturnedMessageRaw](returnedBufSize)
    cq <- Queue.bounded[F, ConfirmationResponse](confirmBufSize)
    counter <- F.ref(0)
  } yield new {

    override def cancel(ctag: ConsumerTag): F[Unit] =
      dqs.get.map(_.get(ctag)).flatMap {
        case Some(q) => q.offer(None)
        case None    => F.unit
      }

    private def newCtag = counter
      .getAndUpdate(_ + 1)
      .map(i => ConsumerTag.from(s"consumer-$i").getOrElse(???))
      .toResource

    override def deliver(msg: DeliveredMessageRaw): F[Unit] =
      dqs.get.map(_.get(msg.consumerTag)).flatMap {
        case Some(q) => q.offer(Some(msg))
        case None    => F.unit
      }

    override def `return`(msg: ReturnedMessageRaw): F[Unit] = rq.offer(msg)

    override def deliveryQ(ctag: Option[ConsumerTag]): Resource[
      F,
      (ConsumerTag, QueueSource[F, Option[DeliveredMessageRaw]])
    ] =
      for {
        ctag <- ctag.fold(newCtag)(Resource.pure)
        q <- addQ(ctag)
      } yield (ctag, q)

    private def addQ(
        ctag: ConsumerTag
    ): Resource[F, QueueSource[F, Option[DeliveredMessageRaw]]] = Resource.make(
      Queue
        .bounded[F, Option[DeliveredMessageRaw]](deliveryBufSize)
        .flatTap(q => dqs.update(_.updated(ctag, q)))
    )(_ => removeQ(ctag))

    private def removeQ(ctag: ConsumerTag) = dqs.update(_ - ctag)

    override def returnQ: QueueSource[F, ReturnedMessageRaw] = rq

    override def confirm(msg: ConfirmationResponse): F[Unit] = cq.offer(msg)

    override def confirmationQ: QueueSource[F, ConfirmationResponse] = cq
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy