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

eventstore.EsConnection.scala Maven / Gradle / Ivy

The newest version!
package eventstore

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.Future
import scala.concurrent.duration.FiniteDuration
import tcp.ConnectionActor
import java.io.Closeable
import util.ActorCloseable

class EsConnection(
    connection: ActorRef,
    factory: ActorRefFactory,
    operationTimeout: FiniteDuration = Settings.Default.operationTimeout) {
  import scala.concurrent.ExecutionContext.Implicits.global
  implicit val timeout = Timeout(operationTimeout)

  def future[OUT <: Out, IN <: In](out: OUT, credentials: Option[UserCredentials] = None)(
    implicit outIn: ClassTags[OUT, IN]): Future[IN] = {
    val future = connection ? credentials.fold[OutLike](out)(WithCredentials(out, _))
    future.mapTo[IN](outIn.in)
  }

  def startTransaction(data: TransactionStart, credentials: Option[UserCredentials] = None): Future[EsTransaction] = {
    val props = TransactionActor.props(connection, TransactionActor.Start(data), credentials = credentials)
    val actor = factory.actorOf(props)
    EsTransaction.start(actor)
  }

  def continueTransaction(transactionId: Long, credentials: Option[UserCredentials] = None): EsTransaction = {
    val props = TransactionActor.props(connection, TransactionActor.Continue(transactionId), credentials = credentials)
    val actor = factory.actorOf(props)
    EsTransaction.continue(transactionId, actor)
  }

  def subscribeToStream(
    streamId: EventStream.Id,
    observer: SubscriptionObserver[Event],
    resolveLinkTos: Boolean = Settings.Default.resolveLinkTos,
    credentials: Option[UserCredentials] = None): Closeable =
    subscribeToStream(streamId, observer, Some(EventNumber.Last), resolveLinkTos, credentials)

  def subscribeToStreamFrom(
    streamId: EventStream.Id,
    observer: SubscriptionObserver[Event],
    fromNumberExclusive: Option[EventNumber.Exact] = None,
    resolveLinkTos: Boolean = Settings.Default.resolveLinkTos,
    credentials: Option[UserCredentials] = None): Closeable =
    subscribeToStream(streamId, observer, fromNumberExclusive, resolveLinkTos, credentials)

  private def subscribeToStream(
    streamId: EventStream.Id,
    observer: SubscriptionObserver[Event],
    fromNumberExclusive: Option[EventNumber],
    resolveLinkTos: Boolean,
    credentials: Option[UserCredentials]): Closeable = {
    val client = factory.actorOf(SubscriptionObserverActor.props(observer))
    val props = StreamSubscriptionActor.props(connection, client, streamId, fromNumberExclusive, resolveLinkTos, credentials)
    factory.actorOf(props)
    ActorCloseable(client)
  }

  def subscribeToAll(
    observer: SubscriptionObserver[IndexedEvent],
    resolveLinkTos: Boolean = Settings.Default.resolveLinkTos,
    credentials: Option[UserCredentials] = None): Closeable =
    subscribeToAll(observer, Some(Position.Last), resolveLinkTos, credentials)

  def subscribeToAllFrom(
    observer: SubscriptionObserver[IndexedEvent],
    fromPositionExclusive: Option[Position.Exact] = None,
    resolveLinkTos: Boolean = Settings.Default.resolveLinkTos,
    credentials: Option[UserCredentials] = None): Closeable =
    subscribeToAll(observer, fromPositionExclusive, resolveLinkTos, credentials)

  private def subscribeToAll(
    observer: SubscriptionObserver[IndexedEvent],
    fromPositionExclusive: Option[Position],
    resolveLinkTos: Boolean,
    credentials: Option[UserCredentials]) = {
    val client = factory.actorOf(SubscriptionObserverActor.props(observer))
    val props = SubscriptionActor.props(connection, client, fromPositionExclusive, resolveLinkTos)
    factory.actorOf(props)
    ActorCloseable(client)
  }

  def setStreamMetadata(
    streamId: EventStream.Id,
    metadata: Content,
    expectedMetastreamVersion: ExpectedVersion = ExpectedVersion.Any,
    credentials: Option[UserCredentials] = None): Future[Option[WriteResult]] = {
    val writeEvents = WriteEvents.StreamMetadata(streamId.metadata, metadata, expectedMetastreamVersion)
    future(writeEvents, credentials).map(WriteResult.opt)
  }

  // TODO think about replacing content with something similar to what is in the .Net client
  def getStreamMetadata(streamId: EventStream.Id, credentials: Option[UserCredentials] = None): Future[Content] = {
    future(ReadEvent.StreamMetadata(streamId.metadata), credentials).map {
      case ReadEventCompleted(Event.StreamMetadata(data)) => data
      case ReadEventCompleted(event)                      => throw NonMetadataEventException(event)
    }.recover {
      case _: StreamNotFoundException => Content.Empty
      case _: StreamDeletedException  => Content.Empty
    }
  }
}

object EsConnection {
  def apply(system: ActorSystem, settings: Settings = Settings.Default): EsConnection = new EsConnection(
    connection = system.actorOf(ConnectionActor.props(settings)),
    factory = system,
    operationTimeout = settings.operationTimeout)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy