Files
chron/core/ledger.go

129 lines
2.7 KiB
Go

package core
import (
"context"
"errors"
"time"
)
type Ledger struct {
entryStore EntryStore
referenceStore ReferenceStore
}
func NewLedger(entryStore EntryStore, referenceStore ReferenceStore) (*Ledger, error) {
return &Ledger{
entryStore: entryStore,
referenceStore: referenceStore,
}, nil
}
func (l *Ledger) Append(ctx context.Context, payload []byte) error {
currentHeadEntryID, ok, err := l.referenceStore.Get(ctx, "HEAD")
if err != nil {
return err
}
if !ok {
l.referenceStore.Set(ctx, "HEAD", EntryID{})
currentHeadEntryID = EntryID{}
}
entryTime := time.Now()
entryID := ComputeEntryID(currentHeadEntryID, entryTime, payload)
entry := Entry{
EntryID: entryID,
Previous: currentHeadEntryID,
Timestamp: entryTime,
Payload: payload,
}
if ComputeEntryID(entry.Previous, entry.Timestamp, entry.Payload) != entryID {
panic("EntryID hash mismatch fuckup")
}
err = l.entryStore.Store(ctx, entry)
if err != nil {
return err
}
err = l.referenceStore.Set(ctx, "HEAD", entry.EntryID)
if err != nil {
return err
}
return nil
}
func (l *Ledger) AppendTo(ctx context.Context, prevEntryID EntryID, payload []byte) error {
entryTime := time.Now()
entryID := ComputeEntryID(prevEntryID, entryTime, payload)
entry := Entry{
EntryID: entryID,
Previous: prevEntryID,
Timestamp: entryTime,
Payload: payload,
}
if ComputeEntryID(entry.Previous, entry.Timestamp, entry.Payload) != entryID {
panic("EntryID hash mismatch fuckup")
}
err := l.entryStore.Store(ctx, entry)
if err != nil {
return err
}
return nil
}
func (l *Ledger) Get(ctx context.Context) (Entry, error) {
headEntryID, ok, err := l.referenceStore.Get(ctx, "HEAD")
if err != nil {
return Entry{}, err
}
if !ok {
return Entry{}, errors.New("HEAD not set")
}
entry, err := l.entryStore.Load(ctx, headEntryID)
if err != nil {
return Entry{}, err
}
return entry, nil
}
func (l *Ledger) GetFromReference(ctx context.Context, reference string) (Entry, error) {
referenceEntryID, ok, err := l.referenceStore.Get(ctx, reference)
if err != nil {
return Entry{}, err
}
if !ok {
return Entry{}, errors.New("HEAD not set")
}
entry, err := l.entryStore.Load(ctx, referenceEntryID)
if err != nil {
return Entry{}, err
}
return entry, nil
}
func (l *Ledger) SetHead(ctx context.Context, entryID EntryID) error {
return l.referenceStore.Set(ctx, "HEAD", entryID)
}
func (l *Ledger) SetReference(ctx context.Context, reference string, entryID EntryID) error {
return l.referenceStore.Set(ctx, reference, entryID)
}
func (l *Ledger) RemoveReference(ctx context.Context, reference string) error {
return l.referenceStore.Delete(ctx, reference)
}