package actors.auctions import com.google.inject.Provides import com.hivemq.client.mqtt.datatypes.MqttQos import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish import models.Auction import mqttClient.MqttClientFactory import org.apache.pekko.actor.typed.Behavior import org.apache.pekko.actor.typed.scaladsl.Behaviors import play.api.{Configuration, Logging} import play.api.libs.concurrent.ActorModule import play.api.libs.json.Json import java.nio.charset.StandardCharsets import javax.inject.Singleton object AuctionPublisher extends ActorModule with Logging { sealed trait Command private case object Ready extends Command case class Publish(auction: Auction) extends Command private final val topic = "auctions/created" override type Message = Command @Provides @Singleton def apply(configuration: Configuration): Behavior[Message] = Behaviors.setup { context => val client = MqttClientFactory.createClient(configuration, "-auction-publisher") client.connect().whenComplete { (_action, _throwable) => context.self ! Ready } idle(client) } private def idle(client: Mqtt5AsyncClient, waitingPublishes: Seq[Auction] = List()): Behaviors.Receive[Command] = Behaviors.receiveMessage[Command] { case Publish(auction) => idle(client, waitingPublishes :+ auction) case Ready => for { auction <- waitingPublishes } publishAuction(client, auction) ready(client) } private def ready(client: Mqtt5AsyncClient): Behaviors.Receive[Command] = Behaviors.receiveMessage[Command] { case Publish(auction) => publishAuction(client, auction) ready(client) case Ready => logger.warn("Message Ready received after ") ready(client) } private def publishAuction(client: Mqtt5AsyncClient, auction: Auction): Unit = { val payload = Json.toBytes(Json.toJson(auction)) val publish = Mqtt5Publish.builder() .topic(topic) .payload(payload) .qos(MqttQos.EXACTLY_ONCE) .build() logger.info(s"Publishing auction ${auction.id.getOrElse(-1)}") client.publish(publish) } }