package wow.doge.mygame.utils import scala.concurrent.duration.FiniteDuration import scala.util.Random import akka.actor.typed.ActorRef import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.TimerScheduler import wow.doge.mygame.implicits._ object GenericTimerActor { sealed trait Command final case object Start extends Command final case object Stop extends Command private case object Tick extends Command case class TimerKey(seed: Long) case class Props[T]( target: ActorRef[T], messageToSend: T, timeInterval: FiniteDuration ) { def behavior = Behaviors.withTimers[Command] { timers => Behaviors.setup { ctx => new GenericTimerActor( ctx, timers, TimerKey(Random.nextLong()), this ).idle } } } } class GenericTimerActor[T]( ctx: ActorContext[GenericTimerActor.Command], timers: TimerScheduler[GenericTimerActor.Command], timerKey: GenericTimerActor.TimerKey, props: GenericTimerActor.Props[T] ) { import GenericTimerActor._ val idle: Behavior[Command] = Behaviors.receiveMessage { case Start => timers.startTimerWithFixedDelay(timerKey, Tick, props.timeInterval) active case _ => Behaviors.unhandled } val active: Behavior[Command] = Behaviors.receiveMessage { case Start => ctx.log.warnP(s"Timer-${timerKey.seed}: Timer already started") Behaviors.same case Tick => props.target ! props.messageToSend Behaviors.same case Stop => timers.cancel(timerKey) idle } }