/* A simple wrapper around an in memory key value store, allows to change the implementation if needed. The version using sync.Map produces strange results in the tests so we left it unused for now. */ package kademlia import ( "time" ) type storageItem struct { Value []byte TTL uint16 RepCount uint16 timeAdded time.Time } type KeyType [32]byte type ValueType storageItem type DHTStorage struct { //storageMap sync.Map storageMap map[[32]byte]ValueType } func (m *DHTStorage) GetEntry(key [32]byte) (ValueType, bool) { /*val, exists := m.storageMap.Load(key) val2, _ := val.(ValueType)*/ val2, exists := m.storageMap[key] return val2, exists } // GetValue /* Returns only the value of an entry associated with the provided key, if it exists. */ func (m *DHTStorage) GetValue(key [32]byte) ([]byte, bool) { /*val, exists := m.storageMap.Load(key) val2, _ := val.(ValueType) */ val2, exists := m.storageMap[key] return val2.Value, exists } /* Put places an entry with the fields provided and records the time it got added. */ func (m *DHTStorage) Put(key [32]byte, value []byte, ttl uint16, repCount uint16) { /*m.storageMap.Store(key, ValueType(storageItem{ Value: value, TTL: ttl, RepCount: repCount, timeAdded: time.Now(), }))*/ m.storageMap[key] = ValueType(storageItem{ Value: value, TTL: ttl, RepCount: repCount, timeAdded: time.Now(), }) } func (m *DHTStorage) UpdateAndExpireEntries(elapsedTime time.Duration) { // Iterating over a sync.Map is a bit ugly, but this is the same as including the method body in a for range loop /*m.storageMap.Range(func(k, e any) bool { key := k.([32]byte) entry := e.(ValueType) // If the entry expired: delete if (time.Duration(entry.TTL)*time.Second)-elapsedTime <= time.Second { m.storageMap.Delete(key) } else { //Otherwise: update the TTL field for the remaining time entry.TTL = entry.TTL - uint16(elapsedTime/time.Second) m.storageMap.Store(key, entry) } return true }) */ for key, entry := range m.storageMap { // If the entry expired: delete if (time.Duration(entry.TTL)*time.Second)-elapsedTime <= 0 { delete(m.storageMap, key) } else { //Otherwise: update the TTL field for the remaining time entry.TTL = entry.TTL - uint16(elapsedTime/time.Second) m.storageMap[key] = entry } } } func (m *DHTStorage) GetEntriesForRepublishing(timeLimit time.Duration) map[KeyType]ValueType { var toBeRepublished = map[KeyType]ValueType{} /*m.storageMap.Range(func(k, e any) bool { key := k.([32]byte) entry := e.(ValueType) if time.Now().Sub(entry.timeAdded) >= timeLimit { toBeRepublished[key] = entry m.storageMap.Delete(key) } return true })*/ for key, entry := range m.storageMap { if time.Now().Sub(entry.timeAdded) >= timeLimit { toBeRepublished[key] = entry delete(m.storageMap, key) } } return toBeRepublished }