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

harness.archive.client.QueuedSender.scala Maven / Gradle / Ivy

package harness.archive.client

import cats.syntax.option.*
import harness.core.*
import harness.zio.*
import zio.*

final class QueuedSender[R, A] private (
    name: String,
    send: Chunk[A] => URIO[R, Unit],
    chunkSize: Int,
    forked: Boolean,
    ref: Ref[List[A]],
    open: Ref[Boolean],
) {

  private inline def forkIf(effect: URIO[R, Unit]): URIO[R, Unit] =
    if (forked) effect.fork.unit
    else effect

  def push(value: A): URIO[R, Unit] =
    forkIf {
      checkOpen *>
        ref
          .modify { list =>
            val newList = value :: list
            if (newList.size >= chunkSize) (newList.reverse.some, Nil)
            else (None, newList)
          }
          .flatMap {
            ZIO.foreachDiscard(_) { list => send(Chunk.fromIterable(list)) }
          }
    }

  def pushAll(values: List[A]): URIO[R, Unit] =
    forkIf {
      checkOpen *>
        ref
          .modify { list =>
            val newList = values.reverse ::: list
            if (newList.size >= chunkSize) (newList.reverse.some, Nil)
            else (None, newList)
          }
          .flatMap {
            ZIO.foreachDiscard(_) { list => send(Chunk.fromIterable(list)) }
          }
    }

  def dump: URIO[R, Unit] =
    checkOpen *>
      ref
        .modify { list => (list.reverse, Nil) }
        .flatMap { list =>
          ZIO.foreachDiscard(Option.when(list.nonEmpty)(list)) { list => send(Chunk.fromIterable(list)) }
        }

  private def checkOpen: UIO[Unit] =
    ZIO.dieMessage(s"QueuedSender '$name' is closed").unlessZIO(open.get).unit

  private def close: URIO[R, Unit] =
    dump *> open.set(false)

}
object QueuedSender {

  /**
    * Make sure this is not called outside the `Scope` from which it is returned.
    * (Or it will die)
    */
  def make[R, A](
      name: String,
      chunkSize: Int,
      dumpEvery: Option[Duration],
      forked: Boolean,
  )(send: Chunk[A] => URIO[R, Unit]): URIO[R & Scope, QueuedSender[R, A]] =
    for {
      ref <- Ref.make(List.empty[A])
      open <- Ref.make(true)
      sender <- ZIO
        .succeed(new QueuedSender[R, A](name, send, chunkSize, forked, ref, open))
        .withFinalizer { _.close }
      _ <- ZIO.foreachDiscard(dumpEvery) { dumpEvery =>
        (
          Clock.sleep(dumpEvery) *>
            sender.dump.repeat(Schedule.spaced(dumpEvery)),
        ).interruptible.fork.withFinalizer { _.interrupt }
      }
    } yield sender

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy