129 lines
2.7 KiB
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)
|
|
}
|