Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
sss.openstar.test.MultiIdentityTestTransactionSender.scala Maven / Gradle / Ivy
package sss.openstar.test
import akka.actor.Status.{Failure => FutureFailure}
import akka.actor.{Actor, ActorContext, ActorLogging, ActorRef, Cancellable, Props}
import akka.pattern.pipe
import sss.openstar.{Currency, UniqueNodeIdentifier}
import sss.openstar.account.{NodeIdTag, NodeIdentity, NodeIdentityManager}
import sss.openstar.block.Synchronized
import sss.openstar.chains.TxWriterActor.{InternalAck, InternalCommit, InternalTempNack, InternalTxResult}
import sss.openstar.network.MessageEventBus
import sss.openstar.test.MultiIdentityTestTransactionSender.{FireTxs, Register}
import sss.openstar.tools.SendTxSupport.SendTx
import sss.openstar.wallet.UnlockedWallet
import sss.openstar.wallet.UtxoTracker.TrackWallet
import sss.openstar.wallet.Wallet.Payment
import us.monoid.web.Resty
import java.util.concurrent.atomic.{AtomicInteger, AtomicLong}
import scala.concurrent.duration._
import scala.util.{Failure, Random, Success, Try}
import sss.ancillary.ByteArrayEncodedStrOps._
import sss.ancillary.FutureOps.AwaitResult
import sss.openstar.common.users.UserDirectory
object MultiIdentityTestTransactionSender {
case object FireTxs
case class Register(missingUsers: Seq[String])
case class TestUsersConfig(numUsers: Int = 10, identityRoot: String = "test_user")
def apply[C <: Currency](nodeIdentityManager: NodeIdentityManager,
users: UserDirectory,
testUsersConfig: Int,
claimHttpUrl: String,
buildUnlockedWallet: NodeIdentity => UnlockedWallet[C],
maxInProgress: Int
)(implicit actorSystem: ActorContext,
sendTx: SendTx,
messageEventBus: MessageEventBus
): ActorRef = {
actorSystem.actorOf(
Props(classOf[MultiIdentityTestTransactionSender[C]],
nodeIdentityManager: NodeIdentityManager,
users: UserDirectory,
testUsersConfig: Int,
claimHttpUrl: String,
buildUnlockedWallet: NodeIdentity => UnlockedWallet[C],
maxInProgress,
sendTx,
messageEventBus)
, "MultiIdentityTestTransactionSender")
}
}
class MultiIdentityTestTransactionSender[C <: Currency](nodeIdentityManager: NodeIdentityManager,
users: UserDirectory,
testUsersConfig: Int,
claimHttpUrl: String,
buildUnlockedWallet: NodeIdentity => UnlockedWallet[C],
maxInProgress: Int
)(implicit
sendTx: SendTx,
messageEventBus: MessageEventBus) extends Actor with ActorLogging {
override def preStart(): Unit = {
super.preStart()
messageEventBus.subscribe(classOf[Synchronized])
}
import context.dispatcher
private def chars = ('a' to 'z').to(LazyList)
def streamOfUserNames: LazyList[String] = for {
a <- chars
b <- chars
c <- chars
d <- chars
e <- chars
f <- chars
} yield (Seq(a,b,c, d, e,f).mkString)
val testUsers = streamOfUserNames.take(testUsersConfig)
def missingUsers: Seq[String] = {
testUsers.filterNot(users.listUsers().contains)
}
private var testUsersWallets: Seq[UnlockedWallet[C]] = {
testUsers.filter(users.listUsers().contains) map { user =>
val ni = nodeIdentityManager(user, NodeIdTag.defaultTag, "password").await()
buildUnlockedWallet(ni)
}
}
private var schedFire: Option[Cancellable] = None
private def scheduleFireTxs(delayInSeconds: Int) = {
schedFire = schedFire match {
case None =>
Option(context.system.scheduler.scheduleOnce(delayInSeconds.seconds, self, FireTxs))
case x => x
}
}
private def randomWallet: UnlockedWallet[C] = {
testUsersWallets(Random.nextInt(testUsersWallets.size))
}
private var inProgress = 0
private val totalTxsProcessed: AtomicInteger = new AtomicInteger(0)
private val totalTimeProcessing = new AtomicLong(0)
private def calculateLatency(): Double = {
val time = totalTimeProcessing.get()
val totalTxs = totalTxsProcessed.get()
if(time > 0 && totalTxs > 0) {
time.toDouble / totalTxs.toDouble
} else {
0
}
}
def sendTransactions: Receive = {
case FutureFailure(e) =>
log.warning("Failed, retry, " + e.toString)
inProgress -= 1
scheduleFireTxs(2)
case com : InternalCommit =>
log.info(s"Got commit: $com, going again")
inProgress -= 1
self ! FireTxs
case ack : InternalAck =>
//log.info(s"Got ack: $ack")
case r: InternalTempNack =>
inProgress -= 1
if(inProgress % 20 == 0) {
log.info(r.toString + s" TxResult $r rescheule")
}
scheduleFireTxs(2)
case r : InternalTxResult =>
inProgress -= 1
self ! FireTxs
case FireTxs if inProgress < maxInProgress =>
schedFire = None
var fired = false
(0 until (maxInProgress - inProgress)) foreach {
_ =>
val wallet = randomWallet
val bal = wallet.w.balance().get.value
log.info(s"User: ${wallet.w.walletOwner} -> balance: ${bal}")
if (bal > 0) {
Try(wallet.payAsync(Payment(wallet.w.walletOwner, 1, 5))) match {
case Success(f) =>
inProgress += 1
val now = System.currentTimeMillis()
f andThen { case Success(_) =>
totalTxsProcessed.incrementAndGet()
totalTimeProcessing.addAndGet(System.currentTimeMillis() - now)
}
f pipeTo self
case Failure(e) =>
log.debug(e.toString)
log.info("Problem, try again")
if (!fired) {
fired = true
scheduleFireTxs(1)
}
}
} else if (!fired) {
fired = true
scheduleFireTxs(1)
}
}
case FireTxs =>
schedFire = None
if(inProgress % 20 == 0) {
log.info(s"$inProgress in progress, wait a few.... (total ${totalTxsProcessed.get()}) average latency = ${calculateLatency()} ms")
}
scheduleFireTxs(1)
}
override def receive: Receive = {
case _ : Synchronized =>
context become registerMissingUSers
self ! Register(missingUsers)
}
private def registerMissingUSers: Receive = {
case Register(Seq()) =>
val total = testUsersWallets.map(_.w.balance().get.value).sum
val number = testUsersWallets.size
log.info(s"$number wallets have $total in total")
//context become sendTransactions
//self ! FireTxs
case Register(user +: rest) => Try {
log.debug(s"Register $user, rest is $rest")
val nodeIdentity = nodeIdentityManager(user, NodeIdTag.defaultTag, "passworD10!").await()
val publicKey = nodeIdentity.publicKey.toBase64Str
Try(new Resty().text(
s"${claimHttpUrl}console/command?1=claim&2=${user}&3=${publicKey}")) match {
case Success(tr) if tr.toString.contains("ok") =>
val wallet = buildUnlockedWallet(nodeIdentity)
messageEventBus publish TrackWallet(wallet.w, wallet.w.amount(0))
/*fund(nodeIdentity.id) match {
case Success(_) =>
testUsersWallets = wallet +: testUsersWallets.filter(_.w.walletOwner != wallet.w.walletOwner)
case Failure(e) =>
log.warning(s"Failed to fund user $user ${e.toString}")
}*/
case Success(s) =>
log.debug(s.toString)
hideUserKeyFile(user)
case Failure(e) =>
log.warning(e.toString)
hideUserKeyFile(user)
}
} recover {
case e => log.warning(s"Failed to register user $user ${e.toString}")
}
self ! Register(rest)
}
private def fund(nodeIdentity: UniqueNodeIdentifier): Try[Unit] = {
val amount = 100
Try(new Resty().text(s"${claimHttpUrl}claim/debit?to=${nodeIdentity}&amount=$amount"))
}
private def hideUserKeyFile(user: String) = users.deleteUser(user).await()
}