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

sss.openstar.telemetry.ReportActor.scala Maven / Gradle / Ivy

package sss.openstar.telemetry

import akka.actor.{Actor, ActorContext, ActorLogging, ActorRef, Cancellable, Props}
import sss.ancillary.Serialize._
import sss.openstar.UniqueNodeIdentifier
import sss.openstar.actor.SystemPanic
import sss.openstar.block.BlockChainLedger.NewBlockId
import sss.openstar.block.{BlockClosedEvent, NotSynchronized, Synchronized}
import sss.openstar.chains.LeaderElectionActor.{LeaderFound, LeaderLost}
import sss.openstar.chains.QuorumMonitor.QuorumLost
import sss.openstar.common.block.BlockId
import sss.openstar.common.chains.Quorum
import sss.openstar.common.telemetry._
import sss.openstar.network._
import sss.openstar.telemetry.Client.ClientResponse
import sss.openstar.telemetry.ReportActor.AskForConnections

import scala.concurrent.duration._
import scala.util.Try

object ReportActor {

  case object AskForConnections

  def props(client: Client, nodeName: String, initialSleepSeconds: Int = 10)
           (implicit events: MessageEventBus): Props = Props(classOf[ReportActor], client, nodeName, initialSleepSeconds, events)

  def apply(props: Props)(implicit actorSystem: ActorContext): ActorRef = actorSystem.actorOf(props, "ReportActor")

}
class ReportActor(client: Client, nodeName: String, initialSleepSeconds: Int)
                 (implicit events: MessageEventBus) extends Actor with ActorLogging with SystemPanic {

  override def preStart(): Unit = {
    super.preStart()
    events subscribe classOf[ClientResponse]
    events subscribe classOf[NewBlockId]
    events subscribe classOf[Connection]
    events subscribe classOf[ConnectionLost]
    events subscribe classOf[LeaderFound]
    events subscribe classOf[LeaderLost]
    events subscribe classOf[Quorum]
    events subscribe classOf[QuorumLost]
    events subscribe classOf[Connections]
    events subscribe classOf[Synchronized]
    events subscribe classOf[NotSynchronized]

  }

  private var interval = initialSleepSeconds

  import context.dispatcher

  /*context.system.scheduler.schedule(
    1.seconds, interval.seconds, self, AskForConnections
  )*/

  private case object ReportTrigger

  private var latestBlockId: Option[BlockId] = None


  private var currentSync: Option[UniqueNodeIdentifier] = None
  private var currentLeader: Option[UniqueNodeIdentifier] = None
  private var currentQuorum: Option[Quorum] = None
  private var currentConnections: Set[String] = Set.empty



  private def resetTrigger(c:Option[Cancellable]): Option[Cancellable] = {
    c foreach(_.cancel())
    Option(
      context.system.scheduler.scheduleOnce(
        interval.seconds, self, ReportTrigger
      )
    )
  }

  private var cancellable = resetTrigger(None)

  override def receive: Receive = {

    case AskForConnections =>
      events.publish(PublishConnections())

    case Connections(conns) =>
      val notInCurrent =  conns.filterNot(currentConnections.contains)
      log.warning(s"Adding $notInCurrent to $conns")
      currentConnections ++= conns.toSet

    case ClientResponse(rawBs) => Try {
      val newReportSleepInterval = rawBs.toArray.extract(IntDeSerialize)
      interval = newReportSleepInterval
      cancellable = resetTrigger(cancellable)
    } recover {
      case e => log.warning("Could not decode client telemetry response {}", e)
    }

    case ReportTrigger =>

      val leaderOrSync = if(currentLeader.isDefined) currentLeader else currentSync

      val r = Report(nodeName,
        interval,
        latestBlockId,
        leaderOrSync,
        currentQuorum,
        currentConnections.size,
        currentConnections.toSeq
      )
      client.report(r.toByteString)
      cancellable = resetTrigger(cancellable)

    case BlockClosedEvent(cId, blockId) =>
      latestBlockId = Some(blockId)

    case NotSynchronized(_) =>
      currentSync = None

    case Synchronized(chainId, h, i, upStream) =>
      latestBlockId = Some(BlockId(h,i))
      currentSync = Some(s"U:$upStream")

    case NewBlockId(chId, blockId) =>
      latestBlockId = Option(blockId)

    case Connection(node) =>
      currentConnections += node

    case ConnectionLost(node) =>
      currentConnections -= node

    case newLeader: LeaderFound =>
      currentLeader = Option(newLeader.leader)

    case leaderLost: LeaderLost =>
      currentLeader = None

    case ql: QuorumLost =>
      currentQuorum = None

    case q: Quorum =>
      currentQuorum = Some(q)
  }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy