package content import ( "bytes" "encoding/binary" "fmt" "git.gammaspectra.live/S.O.N.G/FinalCommander/utilities" "github.com/ipfs/go-cid" "github.com/multiformats/go-multihash" "time" ) // HashIdentifier Main identifier type HashIdentifier multihash.DecodedMultihash func (i *HashIdentifier) IsKey() bool { return i.Code == multihash.SHA2_256 } func (i *HashIdentifier) Encode() []byte { b, _ := multihash.Encode(i.Digest, i.Code) return b } func (i *HashIdentifier) CID() cid.Cid { return cid.NewCidV1(cid.Raw, i.Hash()) } func (i *HashIdentifier) Hash() multihash.Multihash { return i.Encode() } func (i *HashIdentifier) Equals(o *HashIdentifier) bool { return i.Code == o.Code && bytes.Compare(i.Digest, o.Digest) == 0 } func NewHashIdentifierFromMultihash(mh multihash.Multihash) *HashIdentifier { d, err := multihash.Decode(mh) if err != nil { return nil } i := HashIdentifier(*d) return &i } type Entry struct { Key HashIdentifier Version uint64 // CheckTime indicates relative unix time entry was accessed AccessTime int64 // CheckTime indicates next unix time a check shall be made CheckTime int64 InvalidList []int } type Alias struct { Key HashIdentifier Identifier HashIdentifier } func (e *Alias) Encode() []byte { return e.Identifier.Encode() } func DecodeAlias(key HashIdentifier, message []byte) *Alias { buffer := bytes.NewBuffer(message) read, mh, err := multihash.MHFromBytes(buffer.Bytes()) if err != nil { return nil } buffer.Next(read) if buffer.Len() != 0 { //Unknown extra data return nil } return &Alias{ Key: key, Identifier: *NewHashIdentifierFromMultihash(mh), } } func (e *Entry) Encode() ([]byte, error) { if !e.Valid() { return nil, fmt.Errorf("invalid Entry") } message := &bytes.Buffer{} buf := make([]byte, binary.MaxVarintLen64) n := binary.PutUvarint(buf, e.Version) _, _ = message.Write(buf[:n]) if e.Version == 0 { n := binary.PutVarint(buf, e.AccessTime) _, _ = message.Write(buf[:n]) n = binary.PutVarint(buf, e.CheckTime) _, _ = message.Write(buf[:n]) message.Write(utilities.EncodeIntegerList(e.InvalidList)) } return message.Bytes(), nil } func DecodeEntry(key HashIdentifier, message []byte) *Entry { entry := Entry{ Key: key, } var err error buffer := bytes.NewBuffer(message) entry.Version, err = binary.ReadUvarint(buffer) if err != nil { return nil } if entry.Version == 0 { entry.AccessTime, err = binary.ReadVarint(buffer) if err != nil { return nil } entry.CheckTime, err = binary.ReadVarint(buffer) if err != nil { return nil } entry.InvalidList = utilities.DecodeIntegerList(buffer.Bytes()) return &entry } return nil } func (e *Entry) UpdateAccessTime(db *Database) { now := time.Now().UTC().Unix() diff := e.AccessTime - now e.AccessTime = now if diff < 0 { diff = -diff } if diff > 3600*24 { //Update max every day _ = db.SetEntry(e) } } func (e *Entry) InInvalidList(i int) bool { for _, v := range e.InvalidList { if i == v { return true } } return false } func (e *Entry) NeedsCheck() bool { return e.CheckTime < time.Now().UTC().Unix() } func (e *Entry) Valid() bool { return e.Key.IsKey() && e.AccessTime != 0 && e.CheckTime != 0 } func (e *Entry) Multihash() multihash.Multihash { return e.Key.Hash() } func (e *Entry) CID() cid.Cid { return e.Key.CID() }