package keeper
import (
"encoding/binary"
"io"
"github.com/cosmos/cosmos-sdk/telemetry"
"github.com/cybercongress/go-cyber/v7/utils"
"github.com/cybercongress/go-cyber/v7/x/graph/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
CidLengthBytesSize = uint64(1)
CidNumberBytesSize = uint64(8)
CidCountBytesSize = uint64(8)
)
func (gk GraphKeeper) GetCidNumber(ctx sdk.Context, cid types.Cid) (types.CidNumber, bool) {
store := ctx.KVStore(gk.key)
cidIndexAsBytes := store.Get(types.CidStoreKey(cid))
if cidIndexAsBytes != nil {
return types.CidNumber(sdk.BigEndianToUint64(cidIndexAsBytes)), true
}
return 0, false
}
func (gk GraphKeeper) GetCid(ctx sdk.Context, num types.CidNumber) types.Cid {
store := ctx.KVStore(gk.key)
cidAsBytes := store.Get(types.CidReverseStoreKey(num))
return types.Cid(cidAsBytes)
}
func (gk GraphKeeper) GetOrPutCidNumber(ctx sdk.Context, cid types.Cid) types.CidNumber {
store := ctx.KVStore(gk.key)
cidIndexAsBytes := store.Get(types.CidStoreKey(cid))
if cidIndexAsBytes == nil {
lastIndex := gk.GetCidsCount(ctx)
store.Set(types.CidStoreKey(cid), sdk.Uint64ToBigEndian(lastIndex))
store.Set(types.CidReverseStoreKey(types.CidNumber(lastIndex)), []byte(cid))
store.Set(types.LastCidNumber, sdk.Uint64ToBigEndian(lastIndex))
telemetry.IncrCounter(1.0, types.ModuleName, "cids")
return types.CidNumber(lastIndex)
}
return types.CidNumber(sdk.BigEndianToUint64(cidIndexAsBytes))
}
func (gk GraphKeeper) GetCidsCount(ctx sdk.Context) uint64 {
store := ctx.KVStore(gk.key)
lastIndexAsBytes := store.Get(types.LastCidNumber)
if lastIndexAsBytes == nil {
return 0
}
return sdk.BigEndianToUint64(lastIndexAsBytes) + 1
}
func (gk GraphKeeper) SetLastCidIndex(ctx sdk.Context, lastCidIndex uint64) {
store := ctx.KVStore(gk.key)
store.Set(types.LastCidNumber, sdk.Uint64ToBigEndian(lastCidIndex))
}
func (gk GraphKeeper) PutCid(ctx sdk.Context, cid types.Cid, cidNumber types.CidNumber) {
store := ctx.KVStore(gk.key)
store.Set(types.CidStoreKey(cid), sdk.Uint64ToBigEndian(uint64(cidNumber)))
store.Set(types.CidReverseStoreKey(cidNumber), []byte(cid))
}
func (gk GraphKeeper) IterateCids(ctx sdk.Context, process func(types.Cid, types.CidNumber)) {
store := ctx.KVStore(gk.key)
iterator := sdk.KVStorePrefixIterator(store, types.CidStoreKeyPrefix)
defer iterator.Close()
for iterator.Valid() {
process(types.Cid(iterator.Key()[1:]), types.CidNumber(sdk.BigEndianToUint64(iterator.Value())))
iterator.Next()
}
}
func (gk GraphKeeper) WriteCids(ctx sdk.Context, writer io.Writer) (err error) {
uintAsBytes := make([]byte, 8)
cidsCount := gk.GetCidsCount(ctx)
binary.LittleEndian.PutUint64(uintAsBytes, cidsCount)
_, err = writer.Write(uintAsBytes)
if err != nil {
return
}
gk.IterateCids(ctx, func(cid types.Cid, number types.CidNumber) {
cidLength := len(cid)
if cidLength > 255 {
return
}
_, err = writer.Write([]byte{byte(cidLength)})
if err != nil {
return
}
_, err = writer.Write([]byte(cid))
if err != nil {
return
}
binary.LittleEndian.PutUint64(uintAsBytes, uint64(number))
_, err = writer.Write(uintAsBytes)
if err != nil {
return
}
})
return }
func (gk GraphKeeper) LoadFromReader(ctx sdk.Context, reader io.Reader) (err error) {
cidCountBytes, err := utils.ReadExactlyNBytes(reader, CidCountBytesSize)
if err != nil {
return
}
cidCount := binary.LittleEndian.Uint64(cidCountBytes)
for i := uint64(0); i < cidCount; i++ {
cidLengthBytes, err := utils.ReadExactlyNBytes(reader, CidLengthBytesSize)
if err != nil {
return err
}
cidBytes, err := utils.ReadExactlyNBytes(reader, uint64(cidLengthBytes[0]))
if err != nil {
return err
}
cid := types.Cid(cidBytes)
cidNumberBytes, err := utils.ReadExactlyNBytes(reader, CidNumberBytesSize)
if err != nil {
return err
}
cidNumber := types.CidNumber(binary.LittleEndian.Uint64(cidNumberBytes))
gk.PutCid(ctx, cid, cidNumber)
}
lastCidIndex := cidCount - 1
gk.SetLastCidIndex(ctx, lastCidIndex)
return
}