Ещё сырые наброски

This commit is contained in:
justuser-31 2025-11-23 20:15:33 +03:00
parent 8a53f321af
commit 0dcf402e8e
3 changed files with 414 additions and 40 deletions

View File

@ -0,0 +1,57 @@
package main.vp_server_integration
import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.plugin.java.JavaPlugin
import java.io.File
class DataManager(private val dataFolder: File) {
companion object {
private lateinit var dataFile: File
private var playerData: MutableMap<String, String> = mutableMapOf()
fun initialize(dataFolder: File) {
dataFile = File(dataFolder, "player_data.yml")
if (!dataFile.exists()) {
dataFile.parentFile?.mkdirs()
dataFile.createNewFile()
}
loadData()
}
fun getPlayerVPCUsername(playerName: String): String? {
return playerData[playerName]
}
fun setPlayerVPCUsername(playerName: String, vpcUsername: String) {
playerData[playerName] = vpcUsername
saveData()
}
fun removePlayerVPCUsername(playerName: String) {
playerData.remove(playerName)
saveData()
}
fun saveData() {
val config = YamlConfiguration.loadConfiguration(dataFile)
playerData.forEach { (playerName, vpcUsername) ->
config.set(playerName, vpcUsername)
}
try {
config.save(dataFile)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun loadData() {
val config = YamlConfiguration.loadConfiguration(dataFile)
playerData.clear()
config.getKeys(false).forEach { key: String ->
config.getString(key)?.let { value: String ->
playerData[key] = value
}
}
}
}
}

View File

@ -16,15 +16,17 @@ import net.md_5.bungee.api.chat.HoverEvent
import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.TextComponent
import org.bukkit.ChatColor
import org.bukkit.plugin.java.JavaPluginLoader
import org.bukkit.scheduler.BukkitRunnable
import java.io.File
import java.io.FileInputStream
import java.util.Properties
import kotlin.collections.mutableMapOf
import kotlin.math.abs
class Vp_server_integration() : JavaPlugin(), CommandExecutor {
companion object {
lateinit var LOGGER: Logger
lateinit var SERVER: org.bukkit.Server
// A lot of needed configurations
lateinit var USERNAME: String
lateinit var USER_TOKEN: String
lateinit var USER_API_URL: String
@ -33,10 +35,10 @@ class Vp_server_integration() : JavaPlugin(), CommandExecutor {
lateinit var COMMAND_REMOVE_COINS: String
lateinit var COMMAND_REMOVE_ERROR: String
lateinit var COURSE_MODE: String
var COURSE_STATIC_VALUE: Float = DEFAULT_COURSE_STATIC_VALUE
var COURSE_STATIC_VALUE: Double = DEFAULT_COURSE_STATIC_VALUE
lateinit var COURSE_DYNAMIC_COMMAND: String
var COURSE_COMMISSION: Float = DEFAULT_COURSE_COMMISSION
// A lot of needed configurations
const val DEFAULT_USERNAME: String = "test"
const val DEFAULT_USER_TOKEN: String = "test"
const val DEFAULT_USER_API_URL: String = "http://127.0.0.1:8010/api/"
@ -45,9 +47,26 @@ class Vp_server_integration() : JavaPlugin(), CommandExecutor {
const val DEFAULT_COMMAND_REMOVE_COINS: String = "eco take %player% %amount%"
const val DEFAULT_COMMAND_REMOVE_ERROR: String = "Error:"
const val DEFAULT_COURSE_MODE: String = "dynamic"
const val DEFAULT_COURSE_STATIC_VALUE: Float = 1000.0f
const val DEFAULT_COURSE_STATIC_VALUE: Double = 1000.0
const val DEFAULT_COURSE_DYNAMIC_COMMAND: String = "baltop force"
const val DEFAULT_COURSE_COMMISSION: Float = 5.0f
const val PREFIX = "&9[&bVPC&7-&6I&9] &3"
// Helpful variables
lateinit var LOGGER: Logger
lateinit var SERVER: org.bukkit.Server
// For background checks
@JvmStatic
var TO_AUTH_PLAYERS: MutableMap<String, String> = mutableMapOf() // Pair: {player: vpc_username}
@JvmStatic
var TO_AUTH_PLAYERS_INVOICES: MutableMap<String, String> = mutableMapOf() // Pair: {player: invoice_id}
@JvmStatic
var TO_PAY_INVOICES: MutableMap<String, String> = mutableMapOf() // Pair: {player: invoice_id}
@JvmStatic
var INVOICES_AMOUNT: MutableMap<String, Double> = mutableMapOf() // To re-send message when user rejoin/etc.
@JvmStatic
var INVOICES_REWARDS: MutableMap<String, String> = mutableMapOf() // How many should we pay to player after invoice?
}
private fun loadConfiguration() {
@ -116,19 +135,19 @@ course_commission=$DEFAULT_COURSE_COMMISSION
val properties = Properties()
FileInputStream(configFile).use { properties.load(it) }
USERNAME = properties.getProperty("username", DEFAULT_USERNAME)
USER_TOKEN = properties.getProperty("user_token", DEFAULT_USER_TOKEN)
USER_API_URL = properties.getProperty("user_api_url", DEFAULT_USER_API_URL)
COMMAND_ADD_COINS = properties.getProperty("command_add_coins", DEFAULT_COMMAND_ADD_COINS)
COMMAND_REMOVE_MODE = properties.getProperty("command_remove_mode", DEFAULT_COMMAND_REMOVE_MODE)
COMMAND_REMOVE_COINS = properties.getProperty("command_remove_coins", DEFAULT_COMMAND_REMOVE_COINS)
COMMAND_REMOVE_ERROR = properties.getProperty("command_remove_error", DEFAULT_COMMAND_REMOVE_ERROR)
COURSE_MODE = properties.getProperty("course_mode", DEFAULT_COURSE_MODE)
COURSE_STATIC_VALUE = properties.getProperty("course_static_value", DEFAULT_COURSE_STATIC_VALUE.toString()).toFloat()
COURSE_DYNAMIC_COMMAND = properties.getProperty("course_dynamic_command", DEFAULT_COURSE_DYNAMIC_COMMAND)
COURSE_COMMISSION = properties.getProperty("course_commission", DEFAULT_COURSE_COMMISSION.toString()).toFloat()
USERNAME = properties.getProperty("username", DEFAULT_USERNAME).replace("'", "")
USER_TOKEN = properties.getProperty("user_token", DEFAULT_USER_TOKEN).replace("'", "")
USER_API_URL = properties.getProperty("user_api_url", DEFAULT_USER_API_URL).replace("'", "")
COMMAND_ADD_COINS = properties.getProperty("command_add_coins", DEFAULT_COMMAND_ADD_COINS).replace("'", "")
COMMAND_REMOVE_MODE = properties.getProperty("command_remove_mode", DEFAULT_COMMAND_REMOVE_MODE).replace("'", "")
COMMAND_REMOVE_COINS = properties.getProperty("command_remove_coins", DEFAULT_COMMAND_REMOVE_COINS).replace("'", "")
COMMAND_REMOVE_ERROR = properties.getProperty("command_remove_error", DEFAULT_COMMAND_REMOVE_ERROR).replace("'", "")
COURSE_MODE = properties.getProperty("course_mode", DEFAULT_COURSE_MODE).replace("'", "")
COURSE_STATIC_VALUE = properties.getProperty("course_static_value", DEFAULT_COURSE_STATIC_VALUE.toString()).replace("'", "").toDouble()
COURSE_DYNAMIC_COMMAND = properties.getProperty("course_dynamic_command", DEFAULT_COURSE_DYNAMIC_COMMAND).replace("'", "")
COURSE_COMMISSION = properties.getProperty("course_commission", DEFAULT_COURSE_COMMISSION.toString()).replace("'", "").toFloat()
logger.info("Loaded configuration, username: $USERNAME, user_api_url: $USER_API_URL")
logger.info("Loaded configuration: username: $USERNAME, user_api_url: $USER_API_URL")
} catch (e: Exception) {
// In Spigot, we use severe() for error logging
logger.severe("Failed to load configuration, using defaults: ${e.message}")
@ -149,6 +168,11 @@ course_commission=$DEFAULT_COURSE_COMMISSION
getCommand("vpi")?.setExecutor(this)
// Background checks such a auth, invoice check, ...
startBackgroundChecks()
// Init data manager
DataManager.initialize(getDataFolder())
// Plugin startup logic
LOGGER.info("VP Server Integration plugin enabled!")
}
@ -168,54 +192,143 @@ course_commission=$DEFAULT_COURSE_COMMISSION
// VpcApi.send(sender, TotalBalanceModules.getEssentialsBalance().toString())
// return true
if (args.size == 3 && args[0] == "convert") {
if ((args.size == 3 || args.size == 4) && args[0] == "convert") {
logger.severe("Step 1")
val vpcUsername = DataManager.getPlayerVPCUsername(sender.name)
if (vpcUsername == null) {
VpcApi.send(sender, "&cНеобходимо авторизоваться через: /vpi auth")
return true
}
logger.severe("Step 2")
val direction = args[1]
val amount = abs(args[2].toFloat())
val amount = abs(args[2].toDouble())
if (!listOf<String>("vpc", "lc").contains(direction)) {
VpcApi.send(sender, "&cНе существует такого направление, правильные: vpc/lc")
return true
}
val course: Float // VPC to LC
logger.severe("Step 3")
val course: Double // VPC to LC
if (COURSE_MODE == "static") {
course = COURSE_STATIC_VALUE
} else {
if (COURSE_DYNAMIC_COMMAND == "baltop") {
logger.severe("Step 4.1")
val globalBalance = TotalBalanceModules.getEssentialsBalance()
logger.severe("Step 4.1.2")
val vpcUser = VpcApi.user_in_db(username=USERNAME)
val vpcBalance: Float
logger.severe("Step 4.1.3")
val vpcBalance: Double
logger.severe("Step 4.1.4")
if (vpcUser == null) {
throw Exception("null vpcUser")
}
vpcBalance = vpcUser["balance"] as Float
logger.severe("Step 4.1.6")
logger.info(vpcUser["balance"].toString())
vpcBalance = vpcUser["balance"].toString().toDouble()
logger.severe("Step 4.1.7")
logger.info("globalBalance: $globalBalance")
logger.info("vpcBalance: $vpcBalance")
course = globalBalance/vpcBalance
logger.info("course: $course")
} else {
val globalBalance = CommandCapture.execute(COURSE_DYNAMIC_COMMAND)[0].toFloat()
logger.severe("Step 4.2")
val globalBalance = CommandCapture.execute(COURSE_DYNAMIC_COMMAND).toString().toDouble()
logger.severe("$globalBalance")
val vpcUser = VpcApi.user_in_db(username=USERNAME)
val vpcBalance: Float
val vpcBalance: Double
if (vpcUser == null) {
throw Exception("null vpcUser")
}
vpcBalance = vpcUser["balance"] as Float
vpcBalance = vpcUser["balance"].toString().toDouble()
course = globalBalance/vpcBalance
}
}
if (direction == "vpc") {
val result: String = CommandCapture.execute(COURSE_DYNAMIC_COMMAND)[0]
val amountVPC: Double = amount/course * (1 + COURSE_COMMISSION/100)
if (args.size == 4) {
logger.severe("Step 5")
val result: String = CommandCapture.execute(COMMAND_REMOVE_COINS.replace("%player%", sender.name).replace("%amount%", amount.toString()))[0]
logger.severe("Step 6")
if (result.contains(COMMAND_REMOVE_ERROR)) {
VpcApi.send(sender, "&cОшибка, возможно недостаточно средств.")
return true
}
// VpcApi.transfer_coins()
logger.severe("Step 8")
VpcApi.transfer_coins(vpcUsername, amountVPC)
} else {
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы конвертировать &6$amount&3 в &6${String.format("%.4f", amountVPC)} VPC")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpi convert vpc $amount confirm")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpi convert vpc $amount confirm").create())
sender.spigot().sendMessage(message)
}
} else if (direction == "lc") {
if (sender.name in TO_PAY_INVOICES) {
val invoice_id = TO_PAY_INVOICES[sender.name]
val amount = INVOICES_AMOUNT[invoice_id]
if (amount == null) return true // Stupid Kotlin, it's not null
val amountLC: Double = amount*course * (1 - COURSE_COMMISSION/100)
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести &6$amount VPC &3в &6${String.format("%.4f", amountLC)}")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME $amount $invoice_id")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME $amount $invoice_id").create())
sender.spigot().sendMessage(message)
return true
}
logger.severe("amount: $amount")
logger.severe("course: $course")
val amountLC: Double = amount*course * (1 - COURSE_COMMISSION/100)
logger.severe("amountLC: $amountLC")
val invoice_id = VpcApi.create_invoice(amount).toString()
TO_PAY_INVOICES[sender.name] = invoice_id
INVOICES_AMOUNT[invoice_id] = amountLC
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести &6$amount VPC &3в &6${String.format("%.4f", amountLC)}")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME $amount $invoice_id")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME $amount $invoice_id").create())
sender.spigot().sendMessage(message)
}
} else if (args.isNotEmpty() && args[0] == "convert") {
VpcApi.send(sender, "/vpi convert <vpc/lc> <сумма>")
} else if (args.size == 2 && args[0] == "auth") {
val vpcUsername = DataManager.getPlayerVPCUsername(sender.name)
if (vpcUsername != null) {
VpcApi.send(sender, "Вы уже авторизованы!")
return true
}
if (sender.name in TO_AUTH_PLAYERS) {
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести &60.001 VPC")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME 0.001 ${TO_AUTH_PLAYERS_INVOICES[sender.name]}")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME 0.001 ${TO_AUTH_PLAYERS_INVOICES[sender.name]}").create())
sender.spigot().sendMessage(message)
return true
}
val invoice_id = VpcApi.create_invoice(0.001)
val vpc_username = args[1]
logger.severe("Adding to lists")
synchronized(TO_AUTH_PLAYERS) {
TO_AUTH_PLAYERS[sender.name] = vpc_username
TO_AUTH_PLAYERS_INVOICES[sender.name] = invoice_id.toString()
}
logger.severe("TO_AUTH_PLAYERS: $TO_AUTH_PLAYERS")
logger.severe("TO_AUTH_PLAYERS_INVOICES: $TO_AUTH_PLAYERS_INVOICES")
val colored = ChatColor.translateAlternateColorCodes('&', "${PREFIX}Кликните здесь, чтобы перевести 0.001 VPC")
val message = TextComponent(colored)
message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc pay $USERNAME 0.001 $invoice_id")
message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("/vpc pay $USERNAME 0.001 $invoice_id").create())
sender.spigot().sendMessage(message)
} else if (args.isNotEmpty() && args[0] == "auth") {
VpcApi.send(sender, "/vpi auth <ник>")
} else {
VpcApi.send(
sender, """Использование команд:
/vpi auth <ник> - Авторизация
/vpi convert <куда: vpc/lc> <сумма> - Обмен VPC на локальную валюту или наоборот
Почему 'VPC-I'? Потому что это интеграция на конечном сервере - 'VPC Integration'
@ -228,6 +341,15 @@ course_commission=$DEFAULT_COURSE_COMMISSION
}
return true
// Create a clickable message that runs /help when clicked
// val message = TextComponent("Click here to execute command")
// val colored = ChatColor.translateAlternateColorCodes('&', "&6Testing")
// val message = TextComponent(colored)
// message.clickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/vpc bal")
// message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ComponentBuilder("Click here to execute command").create())
//
// sender.spigot().sendMessage(message)
}
return false
}
@ -237,7 +359,7 @@ course_commission=$DEFAULT_COURSE_COMMISSION
if (command.name.equals("vpi", ignoreCase = true)) {
when (args.size) {
1 -> {
completions.addAll(listOf("help", "convert"))
completions.addAll(listOf("help", "convert", "auth"))
}
2 -> {
if (args[0].equals("convert", ignoreCase = true)) {
@ -254,4 +376,93 @@ course_commission=$DEFAULT_COURSE_COMMISSION
return completions.filter { it.startsWith(args.lastOrNull()?.lowercase() ?: "") }.sorted()
}
private fun startBackgroundChecks() {
object : BukkitRunnable() {
override fun run() {
// Safely check and process TO_AUTH_PLAYERS_INVOICES
synchronized(TO_AUTH_PLAYERS_INVOICES) {
if (TO_AUTH_PLAYERS_INVOICES.isNotEmpty()) {
val iterator = TO_AUTH_PLAYERS_INVOICES.iterator()
while (iterator.hasNext()) {
val entry = iterator.next()
try {
val result = VpcApi.get_invoice(entry.value) as Map<*, *>?
// Add null safety checks
if (result != null) {
val status = result["status"]
logger.severe("Invoice ${entry.value} status: $status")
if (status != null && status.toString() == "true") {
logger.severe("DELETE!!!!!!!!!!!!!!!!")
VpcApi.delete_invoice(entry.value)
DataManager.setPlayerVPCUsername(entry.key, TO_AUTH_PLAYERS[entry.key].toString())
VpcApi.send(Bukkit.getPlayer(entry.key.toString()), "&aВы успешно авторизованы!")
// Safely remove from both maps
TO_AUTH_PLAYERS.remove(entry.key)
iterator.remove() // Safe removal during iteration
}
} else {
logger.warning("Received null result for invoice ${entry.value}")
}
} catch (e: Exception) {
logger.severe("Error processing invoice ${entry.value}: ${e.message}")
e.printStackTrace()
}
}
}
}
// Safely check and process TO_PAY_INVOICES
synchronized(TO_PAY_INVOICES) {
if (TO_PAY_INVOICES.isNotEmpty()) {
val iterator = TO_PAY_INVOICES.iterator()
while (iterator.hasNext()) {
val entry = iterator.next()
try {
val result = VpcApi.get_invoice(entry.value) as Map<*, *>?
// Add null safety checks
if (result != null) {
val status = result["status"]
logger.severe("Invoice ${entry.value} status: $status")
if (status != null && status.toString() == "true") {
logger.severe("DELETE!!!!!!!!!!!!!!!!")
VpcApi.delete_invoice(entry.value)
val amountLC = INVOICES_AMOUNT[entry.value]
// Fix: Schedule command execution on main thread
val commandToAddCoins = COMMAND_ADD_COINS.replace("%player%", entry.key).replace("%amount%", amountLC.toString())
Bukkit.getScheduler().runTask(this@Vp_server_integration, Runnable {
try {
CommandCapture.execute(commandToAddCoins)
} catch (e: Exception) {
logger.severe("Error executing command: ${e.message}")
e.printStackTrace()
}
})
// Safely remove from both maps
INVOICES_AMOUNT.remove(entry.key)
iterator.remove() // Safe removal during iteration
}
} else {
logger.warning("Received null result for invoice ${entry.value}")
}
} catch (e: Exception) {
logger.severe("Error processing invoice ${entry.value}: ${e.message}")
e.printStackTrace()
}
}
}
}
}
}.runTaskTimerAsynchronously(this, 0L, 20L) // Changed to 20L (1 second) for better performance
}
}

View File

@ -8,7 +8,9 @@ import com.google.gson.Gson
import com.google.gson.JsonElement
import com.google.gson.JsonParser
import com.google.gson.JsonSyntaxException
import main.vp_server_integration.Vp_server_integration.Companion.PREFIX
import main.vp_server_integration.Vp_server_integration.Companion.USERNAME
import main.vp_server_integration.Vp_server_integration.Companion.USER_API_URL
import main.vp_server_integration.Vp_server_integration.Companion.USER_TOKEN
import org.bukkit.ChatColor
import org.bukkit.command.CommandSender
@ -20,9 +22,16 @@ import java.net.HttpURLConnection
import java.net.URI
import java.net.URISyntaxException
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.math.max
class VpcApi {
companion object {
// Rate limiting: track timestamps of requests
private val requestTimestamps = ConcurrentLinkedQueue<Long>()
private const val MAX_REQUESTS_PER_MINUTE = 60
private const val MINUTE_IN_MILLIS = 60 * 1000L
// Using Gson for JSON serialization - much cleaner than manual string building
fun jsonify(args: List<String>): String {
val map = mutableMapOf<String, String>()
@ -43,13 +52,50 @@ class VpcApi {
operator fun get(key: String): Any? = data?.get(key)
}
/**
* Enforces rate limiting by checking if we've exceeded the request limit.
* If so, sleeps until we're within the limit again.
*/
private fun enforceRateLimit() {
val now = System.currentTimeMillis()
// Remove timestamps older than 1 minute
while (requestTimestamps.isNotEmpty() && now - requestTimestamps.peek() > MINUTE_IN_MILLIS) {
requestTimestamps.poll()
}
// If we've hit the limit, calculate sleep time
if (requestTimestamps.size >= MAX_REQUESTS_PER_MINUTE) {
val oldestRequestTime = requestTimestamps.peek()
val sleepTime = max(0, MINUTE_IN_MILLIS - (now - oldestRequestTime)) + 100 // Add small buffer
try {
Thread.sleep(sleepTime)
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
}
// After sleeping, clean up old timestamps again
val afterSleep = System.currentTimeMillis()
while (requestTimestamps.isNotEmpty() && afterSleep - requestTimestamps.peek() > MINUTE_IN_MILLIS) {
requestTimestamps.poll()
}
}
// Add current timestamp
requestTimestamps.offer(now)
}
fun sendPost(urlPoint: String, json: String, customUrl: Boolean = false, baseurl: String = ""): ApiResponse {
// Enforce rate limiting before making the request
enforceRateLimit()
var uri: URI
try {
uri = if (customUrl) {
URI.create(baseurl + urlPoint)
} else {
URI.create(Vp_server_integration.DEFAULT_USER_API_URL + urlPoint)
URI.create(USER_API_URL + urlPoint)
}
} catch (e: URISyntaxException) {
return ApiResponse(-1, null, "Error: Invalid URL syntax")
@ -110,7 +156,7 @@ class VpcApi {
}
}
fun send(source: CommandSender, message: String, prefix: String = "&9[&bVPC&7-&6I&9] &3") {
fun send(source: CommandSender, message: String, prefix: String = PREFIX) {
// Translate color codes for Spigot
val coloredMessage = ChatColor.translateAlternateColorCodes('&', prefix + message)
source.sendMessage(coloredMessage)
@ -128,6 +174,10 @@ class VpcApi {
return "None"
}
}
// Simple hash function (you might want to replace this with a proper hashing algorithm)
private fun hash(input: String): String {
return UUID.nameUUIDFromBytes(input.toByteArray()).toString()
}
fun user_in_db(source: CommandSender? = null, username: String? = null): Map<String, Any>? {
var mine_uuid: String? = null
@ -141,7 +191,7 @@ class VpcApi {
val response = sendPost(
"user_in_db/", jsonify(
listOf(
"token", Vp_server_integration.DEFAULT_USER_TOKEN,
"user_token", USER_TOKEN,
userParam.first, userParam.second
)
)
@ -155,12 +205,12 @@ class VpcApi {
}
}
fun transfer_coins(dst_username: String, amount: Float): Any? {
fun transfer_coins(dst_username: String, amount: Double): Any? {
val response = sendPost(
"transfer_coins/", jsonify(
listOf(
"username", USERNAME,
"user_token", USER_TOKEN,
"src_username", USERNAME,
"dst_username", dst_username,
"amount", amount.toString()
)
@ -174,9 +224,65 @@ class VpcApi {
}
}
// Simple hash function (you might want to replace this with a proper hashing algorithm)
private fun hash(input: String): String {
return UUID.nameUUIDFromBytes(input.toByteArray()).toString()
fun create_invoice(amount: Double): Any? {
val response = sendPost(
"create_invoice/", jsonify(
listOf(
"username", USERNAME,
"user_token", USER_TOKEN,
"amount", amount.toString()
)
)
)
return if (response.status == 200) {
response.rawResponse
} else {
response.data?.get("detail")
}
}
fun delete_invoice(invoice_id: String): Any? {
val response = sendPost(
"delete_invoice/", jsonify(
listOf(
"username", USERNAME,
"user_token", USER_TOKEN,
"invoice_id", invoice_id
)
)
)
return if (response.status == 200) {
response.rawResponse
} else {
response.data?.get("detail")
}
}
fun get_invoice(invoice_id: String): Any? {
val response = sendPost(
"get_invoice/", jsonify(
listOf(
"username", USERNAME,
"user_token", USER_TOKEN,
"invoice_id", invoice_id
)
)
)
// response["someKey"] (map-like access)
// OUT: {
// "id": str,
// "dst_username": str,
// "amount": null / float,
// "status": false/true
//}
return if (response.status == 200) {
response.data
} else {
response.data?.get("detail")
}
}
}
}