Skip to content

Commit

Permalink
server: Used in-memory merchantnodes to get count
Browse files Browse the repository at this point in the history
  • Loading branch information
vhurryharry committed Sep 11, 2020
1 parent 3c11e79 commit 401b8d7
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 78 deletions.
8 changes: 5 additions & 3 deletions server/app/com/xsn/explorer/services/StatisticsService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.alexitc.playsonify.core.FutureOr.Implicits.FutureOps
import com.xsn.explorer.data.async.StatisticsFutureDataHandler
import com.xsn.explorer.models.{MarketStatistics, StatisticsDetails, SynchronizationProgress}
import com.xsn.explorer.tasks.CurrencySynchronizerActor
import com.xsn.explorer.services.synchronizer.repository.MerchantnodeRepository
import javax.inject.Inject
import org.scalactic.{Bad, Good}
import akka.util.Timeout
Expand All @@ -17,22 +18,23 @@ import scala.concurrent.ExecutionContext
class StatisticsService @Inject()(
xsnService: XSNService,
actorSystem: ActorSystem,
statisticsFutureDataHandler: StatisticsFutureDataHandler
statisticsFutureDataHandler: StatisticsFutureDataHandler,
merchantnodeRepository: MerchantnodeRepository
)(
implicit ec: ExecutionContext
) {

def getStatistics(): FutureApplicationResult[StatisticsDetails] = {
val dbStats = statisticsFutureDataHandler.getStatistics()
val mnStats = xsnService.getMasternodeCount()
val tposStats = xsnService.getMerchantnodeCount()
val tposStats = merchantnodeRepository.getCount()
val difficultyF = xsnService.getDifficulty()

val result = for {
stats <- dbStats.toFutureOr
mnCount <- discardErrors(mnStats).toFutureOr
tposCount <- discardErrors(tposStats).toFutureOr
difficulty <- discardErrors(difficultyF).toFutureOr
tposCount <- tposStats.map(x => Good(Some(x))).toFutureOr
} yield StatisticsDetails(stats, mnCount, tposCount, difficulty)

result.toFuture
Expand Down
34 changes: 0 additions & 34 deletions server/app/com/xsn/explorer/services/XSNService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ trait XSNService {

def getMasternodeCount(): FutureApplicationResult[Int]

def getMerchantnodeCount(): FutureApplicationResult[Int]

def getDifficulty(): FutureApplicationResult[BigDecimal]

def getMasternodes(): FutureApplicationResult[List[rpc.Masternode]]
Expand Down Expand Up @@ -457,38 +455,6 @@ class XSNServiceRPCImpl @Inject()(
result
}

override def getMerchantnodeCount(): FutureApplicationResult[Int] = {
val body = s"""
|{
| "jsonrpc": "1.0",
| "method": "merchantnode",
| "params": ["count"]
|}
|""".stripMargin

val result = retrying("merchantnode_count") {
server
.post(body)
.map { response =>
val maybe = getResult[Int](response)
maybe.getOrElse {
logger.debug(
s"Unexpected response from XSN Server, status = ${response.status}, response = ${response.body}"
)

Bad(XSNUnexpectedResponseError).accumulating
}
}
}

result.foreach {
case Bad(errors) => logger.info(s"Failed to get merchant node count, errors = $errors")
case _ => ()
}

result
}

override def getDifficulty(): FutureApplicationResult[BigDecimal] = {
val body = s"""
|{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class MerchantnodeSynchronizerActor extends Actor {
sender() ! merchantnodes.find(x => x.ip.split(":").headOption.contains(ipAddress.string))
case MerchantnodeSynchronizerActor.GetMerchantnodes =>
sender() ! merchantnodes
case MerchantnodeSynchronizerActor.GetMerchantnodeCount =>
sender() ! merchantnodes.length
}
}

Expand All @@ -37,4 +39,5 @@ object MerchantnodeSynchronizerActor {
final case class UpdateMerchantnodes(merchantnodes: List[rpc.Merchantnode])
final case class GetMerchantnode(ipAddress: IPAddress)
final case class GetMerchantnodes()
final case class GetMerchantnodeCount()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import scala.concurrent.Future
trait MerchantnodeRepository {
def getAll(): Future[List[Merchantnode]]
def find(ipAddress: IPAddress): Future[Option[Merchantnode]]
def getCount(): Future[Int]
}

object MerchantnodeRepository {
Expand All @@ -27,5 +28,9 @@ object MerchantnodeRepository {
.ask(MerchantnodeSynchronizerActor.GetMerchantnode(ipAddress))
.mapTo[Option[Merchantnode]]
}

override def getCount(): Future[Int] = {
actor.ref.ask(MerchantnodeSynchronizerActor.GetMerchantnodeCount).mapTo[Int]
}
}
}
1 change: 0 additions & 1 deletion server/test/com/xsn/explorer/helpers/DummyXSNService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class DummyXSNService extends XSNService {
override def getLatestBlock(): FutureApplicationResult[rpc.Block.Canonical] = ???
override def getServerStatistics(): FutureApplicationResult[rpc.ServerStatistics] = ???
override def getMasternodeCount(): FutureApplicationResult[Int] = ???
override def getMerchantnodeCount(): FutureApplicationResult[Int] = ???
override def getDifficulty(): FutureApplicationResult[BigDecimal] = ???
override def getMasternodes(): FutureApplicationResult[List[rpc.Masternode]] = ???
override def getMasternode(ipAddress: IPAddress): FutureApplicationResult[Masternode] = ???
Expand Down
15 changes: 0 additions & 15 deletions server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -413,21 +413,6 @@ class XSNServiceRPCImplSpec extends AsyncWordSpec with BeforeAndAfterAll {
}
}

"getMerchantnodeCount" should {
"return the count" in {
val content = "10"

val responseBody = createRPCSuccessfulResponse(Json.parse(content))
val json = Json.parse(responseBody)

mockRequest(request, response)(200, json)

whenReady(service.getMerchantnodeCount()) { result =>
result mustEqual Good(10)
}
}
}

"getDifficulty" should {
"return the difficulty" in {
val content = "129.1827211827212"
Expand Down
33 changes: 8 additions & 25 deletions server/test/controllers/StatisticsControllerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.xsn.explorer.errors.XSNUnexpectedResponseError
import com.xsn.explorer.models.{BlockRewardsSummary, MarketInformation, MarketStatistics, Statistics}
import com.xsn.explorer.services.{Currency, XSNService}
import com.xsn.explorer.tasks.CurrencySynchronizerActor
import com.xsn.explorer.services.synchronizer.repository.MerchantnodeRepository
import controllers.common.MyAPISpec
import org.mockito.MockitoSugar.{when, _}
import org.scalactic.{Bad, Good}
Expand Down Expand Up @@ -47,11 +48,13 @@ class StatisticsControllerSpec extends MyAPISpec with BeforeAndAfterAll {
}

val xsnService = mock[XSNService]
val merchantnodeRepository = mock[MerchantnodeRepository]
val actorSystem = ActorSystem()

override val application = guiceApplicationBuilder
.overrides(bind[StatisticsBlockingDataHandler].to(dataHandler))
.overrides(bind[XSNService].to(xsnService))
.overrides(bind[MerchantnodeRepository].to(merchantnodeRepository))
.overrides(bind[ActorSystem].to(actorSystem))
.build()

Expand All @@ -70,7 +73,7 @@ class StatisticsControllerSpec extends MyAPISpec with BeforeAndAfterAll {
val tposnodes = 100
val difficulty = BigDecimal("129.1827211827212")
when(xsnService.getMasternodeCount()).thenReturn(Future.successful(Good(masternodes)))
when(xsnService.getMerchantnodeCount()).thenReturn(Future.successful(Good(tposnodes)))
when(merchantnodeRepository.getCount()).thenReturn(Future.successful(tposnodes))
when(xsnService.getDifficulty()).thenReturn(Future.successful(Good(difficulty)))

val response = GET("/stats")
Expand All @@ -90,7 +93,7 @@ class StatisticsControllerSpec extends MyAPISpec with BeforeAndAfterAll {
val difficulty = BigDecimal("129.1827211827212")
val tposnodes = 100
when(xsnService.getMasternodeCount()).thenReturn(Future.failed(new Exception))
when(xsnService.getMerchantnodeCount()).thenReturn(Future.successful(Good(tposnodes)))
when(merchantnodeRepository.getCount()).thenReturn(Future.successful(tposnodes))
when(xsnService.getDifficulty()).thenReturn(Future.successful(Good(difficulty)))

missingMasternodesTest(difficulty)
Expand All @@ -100,27 +103,7 @@ class StatisticsControllerSpec extends MyAPISpec with BeforeAndAfterAll {
val difficulty = BigDecimal("129.1827211827212")
val tposnodes = 100
when(xsnService.getMasternodeCount()).thenReturn(Future.successful(Bad(XSNUnexpectedResponseError).accumulating))
when(xsnService.getMerchantnodeCount()).thenReturn(Future.successful(Good(tposnodes)))
when(xsnService.getDifficulty()).thenReturn(Future.successful(Good(difficulty)))

missingMasternodesTest(difficulty)
}

"return the stats even if getting tposnodes throws an exception" in {
val difficulty = BigDecimal("129.1827211827212")
val masternodes = 1000
when(xsnService.getMasternodeCount()).thenReturn(Future.successful(Good(masternodes)))
when(xsnService.getMerchantnodeCount()).thenReturn(Future.failed(new Exception))
when(xsnService.getDifficulty()).thenReturn(Future.successful(Good(difficulty)))

missingMasternodesTest(difficulty)
}

"return the stats even if the tposnodes aren't available" in {
val difficulty = BigDecimal("129.1827211827212")
val masternodes = 1000
when(xsnService.getMasternodeCount()).thenReturn(Future.successful(Good(masternodes)))
when(xsnService.getMerchantnodeCount()).thenReturn(Future.successful(Bad(XSNUnexpectedResponseError).accumulating))
when(merchantnodeRepository.getCount()).thenReturn(Future.successful(tposnodes))
when(xsnService.getDifficulty()).thenReturn(Future.successful(Good(difficulty)))

missingMasternodesTest(difficulty)
Expand All @@ -130,7 +113,7 @@ class StatisticsControllerSpec extends MyAPISpec with BeforeAndAfterAll {
val masternodes = 1000
val tposnodes = 100
when(xsnService.getMasternodeCount()).thenReturn(Future.successful(Good(masternodes)))
when(xsnService.getMerchantnodeCount()).thenReturn(Future.successful(Good(tposnodes)))
when(merchantnodeRepository.getCount()).thenReturn(Future.successful(tposnodes))
when(xsnService.getDifficulty()).thenReturn(Future.failed(new Exception))

missingDifficultyTest(masternodes)
Expand All @@ -140,7 +123,7 @@ class StatisticsControllerSpec extends MyAPISpec with BeforeAndAfterAll {
val masternodes = 1000
val tposnodes = 100
when(xsnService.getMasternodeCount()).thenReturn(Future.successful(Good(masternodes)))
when(xsnService.getMerchantnodeCount()).thenReturn(Future.successful(Good(tposnodes)))
when(merchantnodeRepository.getCount()).thenReturn(Future.successful(tposnodes))
when(xsnService.getDifficulty()).thenReturn(Future.successful(Bad(XSNUnexpectedResponseError).accumulating))

missingDifficultyTest(masternodes)
Expand Down

0 comments on commit 401b8d7

Please sign in to comment.