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

io.youi.communication.HookupQueue.scala Maven / Gradle / Ivy

The newest version!
package io.youi.communication

import reactify.{Val, Var}

import scala.concurrent.{Future, Promise}

class HookupQueue {
  private var disposed = false
  private val queue = new SafeQueue[HookupRequest]
  private val running = new SafeMap[Long, HookupRequest]

  private val _hasNext: Var[Boolean] = Var(false)
  private val _hasRunning: Var[Boolean] = Var(false)

  val hasNext: Val[Boolean] = _hasNext
  val hasRunning: Val[Boolean] = _hasRunning

  def enqueue(message: Message): Future[Message] = if (disposed) {
    throw new RuntimeException("Queue is disposed")
  } else {
    val promise = Promise[Message]()
    queue.add(HookupRequest(message, promise))
    _hasNext @= true
    promise.future
  }
  def next(): Option[HookupRequest] = {
    val o = queue.poll()
    o.foreach { r =>
      if (r.isRunning) {
        running.put(r.request.id, r)
        _hasRunning @= true
      }
    }
    _hasNext @= !queue.isEmpty
    o
  }

  def success(message: Message): Boolean = running(message.id) match {
    case Some(request) => {
      request.success(message)
      true
    }
    case None => false
  }

  def failure(id: Long, throwable: Throwable): Boolean = running(id) match {
    case Some(request) => {
      request.failure(throwable)
      true
    }
    case None => false
  }

  private def running(id: Long): Option[HookupRequest] = running.get(id) match {
    case s: Some[HookupRequest] => {
      running.remove(id)
      _hasRunning @= !running.isEmpty
      s
    }
    case None => None
  }

  def clear(): Unit = {
    val t = new RuntimeException("Queue disposed")
    def recurse(): Unit = next() match {
      case None => // Done
      case Some(request) => {
        request.failure(t)
        recurse()
      }
    }
    recurse()
    running.values.foreach(_.failure(t))
    running.clear()
    _hasNext @= false
    _hasRunning @= false
  }

  def dispose(): Unit = {
    disposed = true
    clear()
  }

  class SafeQueue[T] {
    private var queue = List.empty[T]

    def add(t: T): Unit = synchronized {
      queue = queue ::: List(t)
    }

    def isEmpty: Boolean = queue.isEmpty

    def poll(): Option[T] = synchronized {
      val head = queue.headOption
      if (head.nonEmpty) {
        queue = queue.tail
      }
      head
    }
  }

  class SafeMap[K, V] {
    private var map = Map.empty[K, V]

    def values: Iterable[V] = map.values

    def isEmpty: Boolean = map.isEmpty

    def get(key: K): Option[V] = map.get(key)

    def put(key: K, value: V): Unit = synchronized(map += key -> value)

    def remove(key: K): Unit = synchronized(map -= key)

    def clear(): Unit = synchronized {
      map = Map.empty[K, V]
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy