codacy.events.InitEventQueue.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of events-rabbitmq_2.13 Show documentation
Show all versions of events-rabbitmq_2.13 Show documentation
A library to send events on rabbit-mq
The newest version!
package codacy.events
import akka.actor.ActorRef
import akka.pattern.{after, ask}
import akka.util.Timeout
import com.newmotion.akka.rabbitmq._
import com.spingo.op_rabbit._
import shapeless.{lazily, Lazy}
import java.util.concurrent.TimeoutException
import scala.collection.JavaConverters._
import scala.concurrent.duration._
import scala.concurrent.Future
final case class RemoveTopics(value: Set[String]) extends AnyVal
final class InitEventQueue(implicit
cn: Lazy[ComponentName.Components[Future]],
tp: Lazy[Topic.Components[Future]],
rm: Lazy[RemoveTopics],
as: Lazy[AsyncRabbitControl]
) {
implicit private lazy val to: Timeout = 10.seconds
private lazy val ctr = lazily[AsyncRabbitControl]
implicit private def ctx = ctr.actorSystem.dispatcher
def initEventQueue = {
for {
rabbitControl <- ctr.rabbitControl
topics <- lazily[Topic.Components[Future]].topics
removeTopics = lazily[RemoveTopics]
componentName <- lazily[ComponentName.Components[Future]].componentName
connectionActor <- rabbitControl.ask(RabbitControl.GetConnectionActor).mapTo[ActorRef]
_ <- waitUntilConnected[ConnectionActor.State](
connectionActor,
connected = ConnectionActor.Connected,
getState = ConnectionActor.GetState
)
channelCreated <- connectionActor
.ask(CreateChannel(ChannelActor.props(), Some("queueInitializer")))
.mapTo[ChannelCreated]
_ <- waitUntilConnected[ChannelActor.State](
channelCreated.channel,
connected = ChannelActor.Connected,
getState = ChannelActor.GetState
)
message = ChannelMessage(
_.queueDeclare(
/*queue=*/ componentName.value, /*durable=*/ true,
/*exclusive=*/ false, /*autoDelete=*/ false,
Map.empty[String, Object].asJava
)
)
_ = channelCreated.channel ! message
_ = topics
.map(_.routingKey)
.foreach(key =>
channelCreated.channel ! ChannelMessage(
_.queueBind(componentName.value, RabbitControl.topicExchangeName, key)
)
)
_ = removeTopics.value.foreach(key =>
channelCreated.channel ! ChannelMessage(
_.queueUnbind(componentName.value, RabbitControl.topicExchangeName, key)
)
)
} yield {
after(5.minutes, ctr.actorSystem.scheduler)(Future(ctr.actorSystem.stop(channelCreated.channel)))
()
}
}
private def waitUntilConnected[State: reflect.ClassTag](
actor: ActorRef,
connected: State,
getState: Any
): Future[Unit] = {
def loop(timeLeft: FiniteDuration): Future[Unit] = {
if (timeLeft > 0.millis) {
actor.ask(getState).mapTo[State].flatMap { state =>
state match {
case `connected` =>
Future.unit
case _ =>
val timeout = 10.millis
after(timeout, ctr.actorSystem.scheduler)(loop(timeLeft - timeout))
}
}
} else {
Future.failed(new TimeoutException(s"$actor didn't connect in $to"))
}
}
loop(to.duration)
}
}
object InitEventQueue {
/* for implicit DI */
implicit def initEventQueueFromRabbitControl(implicit
rc: Lazy[AsyncRabbitControl],
cn: Lazy[ComponentName.Components[Future]],
rm: Lazy[RemoveTopics] = RemoveTopics(Set.empty),
tp: Lazy[Topic.Components[Future]]
) = new InitEventQueue()
/* for compile-time DI */
trait Components {
self: AsyncRabbitControl.Components with ComponentName.Components[Future] with Topic.Components[Future] =>
def removeTopics: RemoveTopics
lazy val initEventQueue = initEventQueueFromRabbitControl(asyncRabbitControl, self, removeTopics, self)
}
}