Browse Source

server: Add getMasternode method to the XSNService

scalafmt-draft
Alexis Hernandez 7 years ago
parent
commit
e76def63cb
  1. 15
      server/app/com/xsn/explorer/errors/masternodeErrors.scala
  2. 17
      server/app/com/xsn/explorer/models/IPAddress.scala
  3. 34
      server/app/com/xsn/explorer/services/XSNService.scala
  4. 2
      server/conf/messages
  5. 2
      server/test/com/xsn/explorer/helpers/DummyXSNService.scala
  6. 53
      server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala

15
server/app/com/xsn/explorer/errors/masternodeErrors.scala

@ -0,0 +1,15 @@
package com.xsn.explorer.errors
import com.alexitc.playsonify.models.{FieldValidationError, NotFoundError, PublicError}
import play.api.i18n.{Lang, MessagesApi}
trait MasternodeError
case object MasternodeNotFoundError extends MasternodeError with NotFoundError {
override def toPublicErrorList(messagesApi: MessagesApi)(implicit lang: Lang): List[PublicError] = {
val message = messagesApi("error.masternode.notFound")
val error = FieldValidationError("ip", message)
List(error)
}
}

17
server/app/com/xsn/explorer/models/IPAddress.scala

@ -0,0 +1,17 @@
package com.xsn.explorer.models
import com.alexitc.playsonify.models.WrappedString
class IPAddress (val string: String) extends WrappedString
object IPAddress {
private val pattern = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$".r.pattern
def from(string: String): Option[IPAddress] = {
if (pattern.matcher(string).matches()) {
Some(new IPAddress(string))
} else {
None
}
}
}

34
server/app/com/xsn/explorer/services/XSNService.scala

@ -33,6 +33,8 @@ trait XSNService {
def getMasternodeCount(): FutureApplicationResult[Int]
def getMasternodes(): FutureApplicationResult[List[rpc.Masternode]]
def getMasternode(ipAddress: IPAddress): FutureApplicationResult[rpc.Masternode]
}
class XSNServiceRPCImpl @Inject() (
@ -232,6 +234,38 @@ class XSNServiceRPCImpl @Inject() (
}
}
override def getMasternode(ipAddress: IPAddress): FutureApplicationResult[rpc.Masternode] = {
val body = s"""
|{
| "jsonrpc": "1.0",
| "method": "masternode",
| "params": ["list", "full", "${ipAddress.string}"]
|}
|""".stripMargin
server
.post(body)
.map { response =>
val maybe = getResult[Map[String, String]](response)
.map {
case Good(map) =>
rpc.Masternode
.fromMap(map)
.headOption
.map(Good(_))
.getOrElse(Bad(MasternodeNotFoundError).accumulating)
case Bad(errors) => Bad(errors)
}
maybe.getOrElse {
logger.warn(s"Unexpected response from XSN Server, status = ${response.status}, response = ${response.body}")
Bad(XSNUnexpectedResponseError).accumulating
}
}
}
private def mapError(json: JsValue, errorCodeMapper: Map[Int, ApplicationError]): Option[ApplicationError] = {
val jsonErrorMaybe = (json \ "error")
.asOpt[JsValue]

2
server/conf/messages

@ -10,6 +10,8 @@ error.address.format=Invalid address format
error.block.format=Invalid blockhash format
error.block.notFound=Block not found
error.masternode.notFound=Masternode not found
error.paginatedQuery.offset.invalid=Invalid offset, it should be a number greater or equal than 0
error.paginatedQuery.limit.invalid=Invalid limit, it should be a number between 1 and and {0}

2
server/test/com/xsn/explorer/helpers/DummyXSNService.scala

@ -2,6 +2,7 @@ package com.xsn.explorer.helpers
import com.alexitc.playsonify.core.FutureApplicationResult
import com.xsn.explorer.models._
import com.xsn.explorer.models.rpc.Masternode
import com.xsn.explorer.services.XSNService
class DummyXSNService extends XSNService {
@ -14,4 +15,5 @@ class DummyXSNService extends XSNService {
override def getServerStatistics(): FutureApplicationResult[rpc.ServerStatistics] = ???
override def getMasternodeCount(): FutureApplicationResult[Int] = ???
override def getMasternodes(): FutureApplicationResult[List[rpc.Masternode]] = ???
override def getMasternode(ipAddress: IPAddress): FutureApplicationResult[Masternode] = ???
}

53
server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala

@ -3,8 +3,8 @@ package com.xsn.explorer.services
import com.xsn.explorer.config.RPCConfig
import com.xsn.explorer.errors._
import com.xsn.explorer.helpers.{BlockLoader, DataHelper, Executors, TransactionLoader}
import com.xsn.explorer.models._
import com.xsn.explorer.models.rpc.Masternode
import com.xsn.explorer.models.{Address, Blockhash, Height, TransactionId}
import org.mockito.ArgumentMatchers._
import org.mockito.Mockito._
import org.scalactic.{Bad, Good}
@ -408,4 +408,55 @@ class XSNServiceRPCImplSpec extends WordSpec with MustMatchers with ScalaFutures
}
}
}
"getMasternode" should {
"return the masternode" in {
val content =
"""
|{
| "b02f99d87194c9400ab147c070bf621770684906dedfbbe9ba5f3a35c26b8d01-1": " ENABLED 70208 XdNDRAiMUC9KiVRzhCTg9w44jQRdCpCRe3 1524349028 777344 1524312645 64183 45.32.148.13:62583"
|}
""".stripMargin
val expected = Masternode(
txid = TransactionId.from("b02f99d87194c9400ab147c070bf621770684906dedfbbe9ba5f3a35c26b8d01").get,
ip = "45.32.148.13:62583",
protocol = "70208",
status = "ENABLED",
activeSeconds = 777344,
lastSeen = 1524349028,
Address.from("XdNDRAiMUC9KiVRzhCTg9w44jQRdCpCRe3").get)
val responseBody = createRPCSuccessfulResponse(Json.parse(content))
val json = Json.parse(responseBody)
when(response.status).thenReturn(200)
when(response.json).thenReturn(json)
when(request.post[String](anyString())(any())).thenReturn(Future.successful(response))
val ip = IPAddress.from("45.32.148.13").get
whenReady(service.getMasternode(ip)) { result =>
result mustEqual Good(expected)
}
}
"fail when the masternode is not found" in {
val content =
"""
|{}
""".stripMargin
val responseBody = createRPCSuccessfulResponse(Json.parse(content))
val json = Json.parse(responseBody)
when(response.status).thenReturn(200)
when(response.json).thenReturn(json)
when(request.post[String](anyString())(any())).thenReturn(Future.successful(response))
val ip = IPAddress.from("45.32.148.13").get
whenReady(service.getMasternode(ip)) { result =>
result mustEqual Bad(MasternodeNotFoundError).accumulating
}
}
}
}

Loading…
Cancel
Save