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.
package tech.pylons.ipc
import com.beust.klaxon.JsonObject
import com.beust.klaxon.Parser
import tech.pylons.lib.core.ICore
import tech.pylons.lib.types.*
import tech.pylons.lib.types.tx.Coin
import tech.pylons.lib.types.tx.Trade
import tech.pylons.lib.types.tx.item.Item
import tech.pylons.lib.types.tx.msg.*
import tech.pylons.lib.types.tx.recipe.Recipe
import tech.pylons.lib.klaxon
import java.lang.StringBuilder
import kotlin.reflect.full.companionObject
import kotlin.reflect.full.companionObjectInstance
import kotlin.reflect.full.functions
private const val MAX_TX_WAIT_RETRIES = 12
class Response (
val message: Message?,
val accepted : Boolean,
val messageId : Int,
val clientId : Int,
val walletId : Int,
val statusBlock : StatusBlock,
val coinsIn : List,
val coinsOut : List,
val cookbooksIn : List,
val cookbooksOut : List,
val executionsIn : List,
val executionsOut : List,
val itemsIn : List,
val itemsOut : List,
val profilesIn : List,
val profilesOut : List,
val recipesIn : List,
val recipesOut : List,
val tradesIn : List,
val tradesOut : List,
val txs : List,
val unstructured : List // this is used for exportkeys, mainly; we don't want actual named keys fields b/c
// we don't really want end-users using exportkeys or anything else that uses unstructured data
) {
companion object {
protected var core : ICore? = null
fun useCore(core : ICore) {
Companion.core = core
}
@ExperimentalUnsignedTypes
fun emit(message: Message, accepted: Boolean, coinsIn: List = listOf(), coinsOut: List = listOf(),
cookbooksIn: List = listOf(), cookbooksOut: List = listOf(),
executionsIn: List = listOf(), executionsOut: List = listOf(),
itemsIn : List = listOf(), itemsOut : List = listOf(),
profilesIn: List = listOf(), profilesOut: List = listOf(),
recipesIn: List = listOf(), recipesOut: List = listOf(),
tradesIn : List = listOf(), tradesOut: List = listOf(),
unstructured: List = listOf(), txs : List = listOf()) : Response {
val prf = core!!.getProfile(null)
// Before doing anything that changes state: retrieve all the inputs
val mCookbooksIn = mutableListOf()
if (cookbooksIn.isNotEmpty()) {
/**
* We really have to retrieve _every_ cookbook rn. that's manageable in testnet but it's gonna
* be pretty fuckin' untenable in production. We absolutely need to have a way to retrieve single
* cookbooks by ID (or, better yet, sets of cookbooks by a list of ids) before it gets to that.
*/
val cbs = core!!.getCookbooks()
cookbooksIn.forEach {
val id = it
cbs.forEach {
if (it.id == id) mCookbooksIn.add(it)
}
}
}
val mExecutionsIn = mutableListOf()
if (executionsIn.isNotEmpty()) {
// we need better exec handling, getpendingexecutions isn't really enough
val execs = core!!.getPendingExecutions()
executionsIn.forEach {
val id = it
execs.forEach {
if (it.id == id) mExecutionsIn.add(it)
}
}
}
val mItemsIn = mutableListOf()
if (itemsIn.isNotEmpty()) {
val items = prf!!.items
itemsIn.forEach {
val id = it
items.forEach {
if (it.id == id) mItemsIn.add(it)
}
}
}
val mProfilesIn = mutableListOf()
if (profilesIn.isNotEmpty()) {
profilesIn.forEach {
if (it == prf?.address) mProfilesIn.add(prf)
else {
val profile = core!!.getProfile(it)
if (profile != null) mProfilesIn.add(profile)
}
}
}
val mRecipesIn = mutableListOf()
if (recipesIn.isNotEmpty()) {
val recipes = core!!.getRecipes()
recipesIn.forEach {
val id = it
recipes.forEach {
if (it.id == id) mRecipesIn.add(it)
}
}
}
val mTradesIn = mutableListOf()
if (tradesIn.isNotEmpty()) {
val trades = core!!.listTrades()
tradesIn.forEach {
val id = it
trades.forEach {
if (it.id == id) mTradesIn.add(it)
}
}
}
// That's done, so now we can actually deal w/ txs
val mTxs = mutableListOf()
txs.forEach {
if (it.id != null) {
var retries = 0
var tx = core!!.getTransaction(it.id!!)
while (tx.code != Transaction.ResponseCode.OK && retries < MAX_TX_WAIT_RETRIES) {
tx = core!!.getTransaction(it.id!!)
retries++
}
mTxs.add(tx) // TODO: proper error handling (this doesn't have failed txs at all)
}
else
mTxs.add(it) //failed txs from various reason
}
val mCoinsOut = coinsOut.toMutableList()
val mCookbooksOut = cookbooksOut.toMutableList()
val mExecutionsOut = executionsOut.toMutableList()
val mRecipesOut = recipesOut.toMutableList()
val mTradesOut = tradesOut.toMutableList()
val mItemsOut = itemsOut.toMutableList()
// ...but now we have to inspect the emitted transaction and populate the various output fields
// modified by Tierre - this field never working properly.
// transaction.stdTx?.msg type never coming as expected
// msg::javaClass not coming as in this switch cases
mTxs.forEach { transaction ->
println("transaction.stdTx?.msg?.javaClass ${transaction.stdTx?.msg?.javaClass}")
transaction.stdTx?.msg?.forEach { it ->
when (it::javaClass) {
//CancelTrade::javaClass -> {
// there's not any output here b/c the trade is just Not
//}
//CheckExecution::javaClass -> {
// we don't have any structured handling of checkexecution atm b/c it's an edge
// case that doesn't actually enable us to get anything useful out of the msg.
// either backend changes happen or we have to make another network hit to actually do
// anything useful w/ this.
//}
//CreateAccount::javaClass -> {
// same story, but this doesn't really matter b/c we always retrieve our profile regardless
//}
CreateCookbook::javaClass -> {
val msg = it as CreateCookbook
mCookbooksOut.add(Cookbook("", msg.cookbookId, msg.name, msg.description,
msg.version, msg.developer, msg.sender, msg.supportEmail, msg.costPerBlock))
}
CreateRecipe::javaClass -> {
val msg = it as CreateRecipe
mRecipesOut.add(Recipe("", "", msg.sender, false, msg.name,
msg.cookbookId, msg.description, msg.blockInterval, msg.coinInputs, msg.itemInputs,
msg.entries, msg.outputs, msg.extraInfo))
}
CreateTrade::javaClass -> {
val msg = it as CreateTrade
mTradesOut.add(Trade("", "", msg.coinInputs, msg.itemInputs, msg.coinOutputs, msg.itemOutputs,
msg.extraInfo, msg.sender, "", disabled = false, completed = false))
}
DisableRecipe::javaClass -> {
val r = mRecipesIn.first()
mRecipesOut.add(Recipe("", r.id, r.sender, true, r.name, r.cookbookId, r.description,
r.blockInterval, r.coinInputs, r.itemInputs, r.entries, r.outputs, r.extraInfo))
}
EnableRecipe::javaClass -> {
val r = mRecipesIn.first()
mRecipesOut.add(Recipe("", r.id, r.sender, false, r.name, r.cookbookId, r.description,
r.blockInterval, r.coinInputs, r.itemInputs, r.entries, r.outputs, r.extraInfo))
}
//ExecuteRecipe::javaClass -> {
// not enough data in the msg to reconstruct the outputs w/o an extra query, b/c recipes
// have randomness to contend with
//}
FulfillTrade::javaClass -> {
val trade = mTradesIn.first()
mCoinsOut.addAll(trade.coinOutputs)
mItemsOut.addAll(trade.itemOutputs)
}
GetPylons::javaClass -> {
mCoinsOut.addAll((it as GetPylons).amount)
}
SendCoins::javaClass -> {
mCoinsOut.addAll((it as SendCoins).amount)
}
UpdateCookbook::javaClass -> {
val msg = it as UpdateCookbook
// we can't get cookbook name/level from updatecookbook, but it'll be in mCookbooksIn
mCookbooksOut.add(
Cookbook("", msg.id, mCookbooksIn.first().name, msg.description, msg.version,
msg.developer, msg.sender, msg.supportEmail,
mCookbooksIn.first().costPerBlock)
)
}
UpdateItemString::javaClass -> {
// This is the fuckiest thing we actually have enough data to handle
val msg = it as UpdateItemString
var baseItem : Item? = null
mItemsIn.forEach {
if (it.id == msg.itemId)
baseItem = it
}
if (baseItem != null) {
val mItemStrings = baseItem!!.strings.toMutableMap()
mItemStrings[msg.field] = msg.value
// lastupdate will always be wrong here tho, and there's no way to get that correct
// w/o querying the item again...
mItemsOut.add(Item(baseItem!!.nodeVersion, baseItem!!.id, baseItem!!.cookbookId,
baseItem!!.sender, baseItem!!.ownerRecipeID, baseItem!!.ownerTradeID, baseItem!!.tradable,
0, baseItem!!.doubles, baseItem!!.longs, mItemStrings,
baseItem!!.transferFee))
}
}
UpdateRecipe::javaClass -> {
val msg = it as UpdateRecipe
mRecipesOut.add(Recipe("", msg.id, msg.sender, false, msg.name, msg.cookbookId,
msg.description, msg.blockInterval, msg.coinInputs, msg.itemInputs, msg.entries, msg.outputs, msg.extraInfo))
}
//SendItems::javaClass -> {
// like canceltrade - this has inputs but no real output
//}
//GoogleIapGetPylons::javaClass -> {
// this requires us to have the ability to go between product id and actual pylons counts
//}
}
}
}
val mProfilesOut = profilesOut.toMutableList()
if (txs.isNotEmpty()){
val prof = core!!.getProfile(null)!!
mProfilesOut.add(Profile(prof.address, prof.strings, prof.coins, prof.items) )
}
return Response(message, accepted, IPCLayer.implementation!!.messageId, IPCLayer.implementation!!.clientId,
IPCLayer.implementation!!.walletId, core!!.statusBlock, coinsIn, mCoinsOut, mCookbooksIn, mCookbooksOut,
mExecutionsIn, mExecutionsOut, mItemsIn, mItemsOut, mProfilesIn, mProfilesOut, mRecipesIn, mRecipesOut,
mTradesIn, mTradesOut, mTxs, unstructured)
}
/**
* deserialze string to Response Object
* @param1: messageType:String class type of Message
* @param2: msg:String? json string of Response
*/
fun deserialize(messageType:String, msg: String?): Response? {
println("messageType:${messageType} msg: ${msg}")
val jsonObj = Parser.default().parse(StringBuilder(msg)) as JsonObject
//parse message
val msgObj = jsonObj.obj("message")?.toJsonString()
var message:Message? = null
//notice!!! this takes a bit long. should find out the fastest way to deserialize Message
Message::class.sealedSubclasses.forEach { kClass ->
if (kClass.simpleName == messageType) {
println("attempting to parse Message ${kClass.simpleName}")
//here how to convert to Message Obj
val func = kClass.companionObject?.functions?.find { it.name == "deserialize" }
message = func?.call(kClass.companionObjectInstance, msgObj) as Message?
}
}
//Response Initialization
//notice!!! any other way for fastest deserialzing?
return Response(
message = message,
accepted = jsonObj.boolean("accepted")!!,
messageId = jsonObj.int("messageId")!!,
clientId = jsonObj.int("clientId")!!,
walletId = jsonObj.int("walletId")!!,
statusBlock = klaxon.parseFromJsonObject(jsonObj.obj("statusBlock")!!)!!,
coinsIn = klaxon.parseFromJsonArray(jsonObj.array("coinsIn")!!)!!,
coinsOut = klaxon.parseFromJsonArray(jsonObj.array("coinsOut")!!)!!,
cookbooksIn = klaxon.parseFromJsonArray(jsonObj.array("cookbooksIn")!!)!!,
cookbooksOut = klaxon.parseFromJsonArray(jsonObj.array("cookbooksOut")!!)!!,
executionsIn = klaxon.parseFromJsonArray(jsonObj.array("executionsIn")!!)!!,
executionsOut = klaxon.parseFromJsonArray(jsonObj.array("executionsOut")!!)!!,
itemsIn = klaxon.parseFromJsonArray(jsonObj.array("itemsIn")!!)!!,
itemsOut = klaxon.parseFromJsonArray(jsonObj.array("itemsOut")!!)!!,
profilesIn = klaxon.parseFromJsonArray(jsonObj.array("profilesIn")!!)!!,
profilesOut = klaxon.parseFromJsonArray(jsonObj.array("profilesOut")!!)!!,
recipesIn = klaxon.parseFromJsonArray(jsonObj.array("recipesIn")!!)!!,
recipesOut = klaxon.parseFromJsonArray(jsonObj.array("recipesOut")!!)!!,
tradesIn = klaxon.parseFromJsonArray(jsonObj.array("tradesIn")!!)!!,
tradesOut = klaxon.parseFromJsonArray(jsonObj.array("tradesIn")!!)!!,
txs = Transaction.listFromJson(jsonObj.array("txs")!!),
unstructured = klaxon.parseFromJsonArray(jsonObj.array("unstructured")!!)!!
)
}
}
}