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

genkai.RateLimiter.scala Maven / Gradle / Ivy

package genkai

import java.time.Instant

import genkai.monad.MonadError

/**
 * @tparam F - effect type
 */
trait RateLimiter[F[_]] {

  /**
   * @param key - ~ object id
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return - unused permissions
   */
  final def permissions[A: Key](key: A): F[Long] = permissions(key, Instant.now())

  /**
   * For internal usage only (ex. tests)
   * @param key - ~ object id
   * @param instant - request time
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return - unused permissions
   */
  private[genkai] def permissions[A: Key](key: A, instant: Instant): F[Long]

  /**
   * @param key - ~ object id
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return - unit if successfully reset tokens
   */
  def reset[A: Key](key: A): F[Unit]

  /**
   * Try to acquire token. Returns immediately.
   * For internal usage only (ex. tests)
   * @param key - ~ object id
   * @param instant - request time
   * @param cost - request cost
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return - true if token was acquired, false - otherwise
   */
  private[genkai] final def acquire[A: Key](key: A, instant: Instant, cost: Long): F[Boolean] =
    monadError.map(acquireS(key, instant, cost))(_.isAllowed)

  /**
   * Try to acquire token. Returns immediately.
   * For internal usage only (ex. tests)
   * @param key - ~ object id
   * @param instant - request time
   * @param cost - request cost
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return - true if token was acquired, false - otherwise
   */
  private[genkai] def acquireS[A: Key](key: A, instant: Instant, cost: Long): F[RateLimiter.State]

  /**
   * Try to acquire token. Returns immediately.
   * @param key - ~ object id
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return
   */
  final def acquire[A: Key](key: A): F[Boolean] = acquire(key, Instant.now(), cost = 1)

  /**
   * Try to acquire token. Returns immediately.
   * @param key - ~ object id
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return
   */
  final def acquireS[A: Key](key: A): F[RateLimiter.State] = acquireS(key, Instant.now(), cost = 1)

  /**
   * Try to acquire token. Returns immediately.
   * For internal usage only (ex. tests)
   * @param key - ~ object id
   * @param instant - request time
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return
   */
  private[genkai] final def acquire[A: Key](key: A, instant: Instant): F[Boolean] =
    acquire(key, instant, cost = 1)

  /**
   * Try to acquire token. Returns immediately.
   * For internal usage only (ex. tests)
   * @param key - ~ object id
   * @param instant - request time
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return
   */
  private[genkai] def acquireS[A: Key](key: A, instant: Instant): F[RateLimiter.State] =
    acquireS(key, instant, cost = 1)

  /**
   * Try to acquire token. Returns immediately.
   * @param key - ~ object id
   * @param cost - request cost
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return
   */
  final def acquire[A: Key](key: A, cost: Long): F[Boolean] = acquire(key, Instant.now(), cost)

  /**
   * Try to acquire token. Returns immediately.
   * @param key - ~ object id
   * @param cost - request cost
   * @tparam A - key type with implicit [[genkai.Key]] type class instance
   * @return
   */
  final def acquireS[A: Key](key: A, cost: Long): F[RateLimiter.State] =
    acquireS(key, Instant.now(), cost)

  /**
   * Close underlying resources if any
   * @return - unit if successfully closed or error wrapped in effect
   */
  def close(): F[Unit]

  def monadError: MonadError[F]
}

object RateLimiter {

  /**
   * @param limit - max available tokens
   * @param remaining - remaining tokens
   * @param isAllowed - is current request allowed
   * @param reset - epoch seconds at which rate limit resets
   * @param resetAfter - total time (in seconds) of when the current rate limit bucket will reset
   * @param key - bucket
   */
  final case class State(
    limit: Long,
    remaining: Long,
    isAllowed: Boolean,
    reset: Long,
    resetAfter: Long,
    key: String
  )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy