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

epus-protocol_3.0.5.3.source-code.Domains.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.protocol.domains

import java.time.Instant
import java.util.UUID

trait TaggedOpaqueComp[U, T <: U](using ev: U =:= T) {
  def apply(u: U): T = ev(u)
  def lift[F[_]](f: F[U]): F[T] = ev.liftCo(f)
}

opaque type ChannelNumber <: Short = Short
object ChannelNumber extends TaggedOpaqueComp[Short, ChannelNumber]

opaque type ShortString <: String = String
object ShortString extends Literally[String, ShortString] {

  inline def apply(t: String): ShortString = ${ build('t) }

  def from(uuid: UUID): ShortString = uuid.toString()
  def from(long: Long): ShortString = long.toString()

  private[lepus] inline def unsafe(str: String): ShortString = str

  def empty: ShortString = ""
  def from(str: String): Either[String, ShortString] =
    Either.cond(
      str.length <= 255,
      str,
      s"Maximum size for short strings is 255 characters! cannot create short string with length of ${str.length}"
    )
}

opaque type LongString <: String = String
private inline val LongStringSize = 4294967296L // 2 ^ 32
object LongString extends Literally[String, LongString] {

  inline def apply(t: String): LongString = ${ build('t) }

  def empty: LongString = ""
  def from(str: String): Either[String, LongString] =
    Either.cond(
      str.length <= LongStringSize,
      str,
      s"Maximum size for long strings is $LongStringSize characters! cannot create short string with length of ${str.length}"
    )
}

opaque type Timestamp <: Long = Long
object Timestamp {
  def apply(t: Long): Timestamp = t
  extension (t: Timestamp) {
    def toInstant: Instant = Instant.ofEpochMilli(t)
  }
  def from(instant: Instant): Timestamp = instant.toEpochMilli()
}

final case class Decimal(scale: Byte, value: Int)

type FieldData =
  ShortString | LongString | Boolean | Byte | Short | Int | Long | Float |
    Double | Decimal | Timestamp | FieldTable

final case class FieldTable(values: Map[ShortString, FieldData])
    extends AnyVal {
  def get(key: ShortString): Option[FieldData] = values.get(key)
  def updated(key: ShortString, value: FieldData): FieldTable = FieldTable(
    values.updated(key, value)
  )
  def updated(key: ShortString, value: Option[FieldData]): FieldTable =
    value.fold(this)(this.updated(key, _))
}
object FieldTable {
  def apply(entries: (ShortString, FieldData)*): FieldTable = new FieldTable(
    entries.toMap
  )
  val empty: FieldTable = FieldTable(Map.empty)
}

opaque type ClassId <: Short = Short
object ClassId extends TaggedOpaqueComp[Short, ClassId]

/** Identifier for the consumer, valid within the current c hannel.
  */
opaque type ConsumerTag <: ShortString = ShortString
object ConsumerTag extends TaggedOpaqueComp[ShortString, ConsumerTag] {
  inline def of(inline t: String): ConsumerTag = ShortString(t)
  def empty: ConsumerTag = ShortString.empty
  def from(t: String): Either[String, ConsumerTag] = ShortString.from(t)
}

/** The server-assigned and channel-specific delivery tag
  */
opaque type DeliveryTag <: Long = Long
object DeliveryTag extends TaggedOpaqueComp[Long, DeliveryTag]

private val namePattern = "^[a-zA-Z0-9-_.:]*$".r
private def validateName(name: String): Either[String, String] =
  Either.cond(namePattern.matches(name), name, "Invalid name!")
private def validateNameSize(name: String): Either[String, String] =
  Either.cond(
    name.length <= 127,
    name,
    "Maximum name length is 127 characters!"
  )

/** The exchange name is a client-selected string that identifies the exchange
  * for publish methods.
  */
opaque type ExchangeName <: ShortString = String
object ExchangeName extends Literally[String, ExchangeName] {
  val default: ExchangeName = ""

  inline def apply(t: String): ExchangeName = ${ build('t) }

  def from(name: String): Either[String, ExchangeName] =
    validateName(name).flatMap(validateNameSize)
}

opaque type MethodId <: Short = Short
object MethodId extends TaggedOpaqueComp[Short, MethodId]

/** If this field is set the server does not expect acknowledgements for
  * messages. That is, when a message is delivered to the client the server
  * assumes the delivery will succeed and immediately dequeues it. This
  * functionality may increase performance but at the cost of reliability.
  * Messages can get lost if a client dies before they are delivered to the
  * application.
  */
type NoAck = Boolean

/** If the no-local field is set the server will not send messages to the
  * connection that published them.
  */
type NoLocal = Boolean

/** If set, the server will not respond to the method. The client should not
  * wait for a reply method. If the server could not complete the method it will
  * raise a channel or connection exception.
  */
type NoWait = Boolean

/** Unconstrained.
  */
opaque type Path <: ShortString = String
object Path extends Literally[String, Path] {

  inline def apply(t: String): Path = ${ build('t) }

  def from(str: String): Either[String, Path] =
    Either.cond(str.length <= 127, str, "Maximum length is 127 characters!")
}

/** This table provides a set of peer properties, used for identification,
  * debugging, and general information.
  */
type PeerProperties = FieldTable

/** The queue name identifies the queue within the vhost. In methods where the
  * queue name may be blank, and that has no specific significance, this refers
  * to the 'current' queue for the channel, meaning the last queue that the
  * client declared on the channel. If the client did not declare a queue, and
  * the method needs a queue name, this will result in a 502 (syntax error)
  * channel exception.
  */
opaque type QueueName <: ShortString = String
object QueueName extends Literally[String, QueueName] {
  val autoGen: QueueName = ""

  inline def apply(t: String): QueueName = ${ build('t) }

  def from(name: String): Either[String, QueueName] =
    validateName(name).flatMap(validateNameSize)
}

/** This indicates that the message has been previously delivered to this or
  * another client.
  */
type Redelivered = Boolean

/** The number of messages in the queue, which will be zero for newly-declared
  * queues. This is the number of messages present in the queue, and committed
  * if the channel on which they were published is transacted, that are not
  * waiting acknowledgement.
  */
opaque type MessageCount <: Long = Long
object MessageCount extends Literally[Long, MessageCount] {

  inline def apply(t: Long): MessageCount = ${ build('t) }

  def from(count: Long): Either[String, MessageCount] =
    Either.cond(count >= 0, count, "Count cannot be negative!")
}

/** The localised reply text. This text can be logged as an aid to resolving
  * issues.
  */
type ReplyText = ShortString

enum DeliveryMode(val value: Byte) {
  case NonPersistent extends DeliveryMode(1)
  case Persistent extends DeliveryMode(2)
}

type Priority = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
object Priority extends Literally[Int, Priority] {

  inline def apply(t: Int): Priority = ${ build('t) }

  def from(b: Int): Either[String, Priority] = b match {
    case p: Priority => Right(p)
    case _           => Left("Valid priorities are 0-9")
  }
}

opaque type ExchangeType <: ShortString = ShortString
object ExchangeType extends Literally[String, ExchangeType] {
  inline def apply(t: String): ExchangeType = ${ build('t) }

  override def from(str: String): Either[String, ExchangeType] =
    ShortString.from(str)

  val Direct: ExchangeType = "direct"
  val Topic: ExchangeType = "topic"
  val Fanout: ExchangeType = "fanout"
  val Headers: ExchangeType = "headers"
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy