RedisNonceQueueRepository.kt

package io.github.psychoplasma.nonceq.queue.redis

import io.github.psychoplasma.nonceq.queue.Nonce
import io.github.psychoplasma.nonceq.queue.NonceQueueRepository
import redis.clients.jedis.JedisPool
import java.math.BigInteger

public class RedisNonceQueueRepository(
    private val jedisPool: JedisPool,
    private val keyPrefix: String = "nonceq"
) : NonceQueueRepository {

    override fun getHead(address: String): BigInteger {
        jedisPool.resource.use { jedis ->
            val head = jedis.get(headKey(address))
            return if (head != null) BigInteger(head) else BigInteger.ZERO
        }
    }

    override fun setHead(address: String, value: BigInteger) {
        jedisPool.resource.use { jedis ->
            jedis.set(headKey(address), value.toString())
        }
    }

    override fun getTail(address: String): BigInteger {
        jedisPool.resource.use { jedis ->
            val tail = jedis.get(tailKey(address))
            return if (tail != null) BigInteger(tail) else BigInteger.ZERO
        }
    }

    override fun setTail(address: String, value: BigInteger) {
        jedisPool.resource.use { jedis ->
            jedis.set(tailKey(address), value.toString())
        }
    }

    override fun getNonce(address: String, value: BigInteger): Nonce? {
        jedisPool.resource.use { jedis ->
            val nonceStr = jedis.hget(queueKey(address), value.toString())
            return if (nonceStr != null) parseNonce(nonceStr) else null
        }
    }

    override fun putNonce(address: String, value: BigInteger, nonce: Nonce) {
        jedisPool.resource.use { jedis ->
            jedis.hset(queueKey(address), value.toString(), serializeNonce(nonce))
        }
    }

    override fun deleteNonce(address: String, value: BigInteger) {
        jedisPool.resource.use { jedis ->
            jedis.hdel(queueKey(address), value.toString())
        }
    }

    override fun size(address: String): Long {
        jedisPool.resource.use { jedis ->
            return jedis.hlen(queueKey(address))
        }
    }

    override fun clear(address: String) {
        jedisPool.resource.use { jedis ->
            val pipeline = jedis.pipelined()
            pipeline.del(headKey(address))
            pipeline.del(tailKey(address))
            pipeline.del(queueKey(address))
            pipeline.sync()
        }
    }

    private fun headKey(address: String) = "$keyPrefix:$address:head"
    private fun tailKey(address: String) = "$keyPrefix:$address:tail"
    private fun queueKey(address: String) = "$keyPrefix:$address:queue"

    // Simple serialization for Nonce object
    // Format: value:used:insertedAt
    private fun serializeNonce(nonce: Nonce): String {
        return "${nonce.value}:${nonce.used}:${nonce.insertedAt}"
    }

    private fun parseNonce(str: String): Nonce {
        val parts = str.split(":")
        return Nonce(parts[0], parts[1].toBoolean(), parts[2].toLong())
    }
}