docs: update server implementation gaps
This commit is contained in:
+57
-3
@@ -20,6 +20,7 @@ type Store struct {
|
||||
tasks map[string]domain.Task
|
||||
external map[string]string
|
||||
snapshot string
|
||||
seq uint64
|
||||
}
|
||||
|
||||
func Open(dir string) (*Store, error) {
|
||||
@@ -30,6 +31,23 @@ func Open(dir string) (*Store, error) {
|
||||
if err := os.MkdirAll(s.cas, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var snapshotSeq uint64
|
||||
if b, readErr := os.ReadFile(s.snapshot); readErr == nil {
|
||||
var snap struct {
|
||||
Seq uint64 `json:"seq"`
|
||||
Tasks []domain.Task `json:"tasks"`
|
||||
}
|
||||
if json.Unmarshal(b, &snap) != nil {
|
||||
return nil, fmt.Errorf("invalid snapshot")
|
||||
}
|
||||
for _, t := range snap.Tasks {
|
||||
s.tasks[t.ID] = t
|
||||
s.external[t.Source+"\x00"+t.ExternalID] = t.ID
|
||||
}
|
||||
snapshotSeq = snap.Seq
|
||||
} else if !errors.Is(readErr, os.ErrNotExist) {
|
||||
return nil, readErr
|
||||
}
|
||||
f, err := os.Open(s.path)
|
||||
if os.IsNotExist(err) {
|
||||
return s, nil
|
||||
@@ -39,13 +57,31 @@ func Open(dir string) (*Store, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
sc := bufio.NewScanner(f)
|
||||
var expected uint64 = snapshotSeq + 1
|
||||
for sc.Scan() {
|
||||
var e domain.Event
|
||||
if err := json.Unmarshal(sc.Bytes(), &e); err == nil {
|
||||
if err := domain.ValidateEvent(e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if e.Seq < expected {
|
||||
continue
|
||||
}
|
||||
if e.Seq != expected {
|
||||
return nil, fmt.Errorf("event sequence gap: got %d, want %d", e.Seq, expected)
|
||||
}
|
||||
if t, ok := s.tasks[e.TaskID]; ok && e.Version != t.Version+1 {
|
||||
return nil, domain.ErrConflict
|
||||
}
|
||||
if _, ok := s.tasks[e.TaskID]; !ok && e.Type != "TaskCreated" {
|
||||
return nil, domain.ErrNotFound
|
||||
}
|
||||
s.events = append(s.events, e)
|
||||
s.seq = e.Seq
|
||||
if err := s.apply(e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expected++
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
@@ -64,6 +100,23 @@ func (s *Store) apply(e domain.Event) error {
|
||||
return err
|
||||
}
|
||||
t = domain.Task{ID: e.TaskID, Source: p["source"].(string), ExternalID: p["external_id"].(string), Project: p["project"].(string), State: domain.StateQueued}
|
||||
if v, ok := p["parent"].(string); ok {
|
||||
t.Parent = v
|
||||
}
|
||||
if v, ok := p["inherent_priority"].(float64); ok {
|
||||
t.InherentPriority = int(v)
|
||||
}
|
||||
if v, ok := p["due"].(string); ok {
|
||||
if d, err := time.Parse(time.RFC3339, v); err == nil {
|
||||
t.Due = &d
|
||||
}
|
||||
}
|
||||
if v, ok := p["estimate"].(map[string]any); ok {
|
||||
t.Estimate = &domain.Estimate{}
|
||||
t.Estimate.Value, _ = v["value"].(float64)
|
||||
t.Estimate.Who, _ = v["who"].(string)
|
||||
t.Estimate.Confidence, _ = v["confidence"].(float64)
|
||||
}
|
||||
if v, ok := p["capability"].([]any); ok {
|
||||
for _, x := range v {
|
||||
if z, ok := x.(string); ok {
|
||||
@@ -111,7 +164,7 @@ func (s *Store) Append(e domain.Event) error {
|
||||
e.At = time.Now().UTC()
|
||||
}
|
||||
if e.Seq == 0 {
|
||||
e.Seq = uint64(len(s.events) + 1)
|
||||
e.Seq = s.seq + 1
|
||||
}
|
||||
if e.Type == "TaskCreated" {
|
||||
var p map[string]any
|
||||
@@ -133,7 +186,7 @@ func (s *Store) Append(e domain.Event) error {
|
||||
_ = json.Unmarshal(e.Payload, &p)
|
||||
for _, k := range []string{"handoff_ref", "report_ref"} {
|
||||
if ref, ok := p[k].(string); ok {
|
||||
if _, err := os.Stat(filepath.Join(s.cas, ref)); err != nil {
|
||||
if _, err := s.Artifact(ref); err != nil {
|
||||
return fmt.Errorf("%w: missing artifact %s", domain.ErrInvalid, ref)
|
||||
}
|
||||
}
|
||||
@@ -155,6 +208,7 @@ func (s *Store) Append(e domain.Event) error {
|
||||
return err
|
||||
}
|
||||
s.events = append(s.events, e)
|
||||
s.seq = e.Seq
|
||||
if err := s.writeSnapshot(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -168,7 +222,7 @@ func (s *Store) writeSnapshot() error {
|
||||
b, err := json.Marshal(struct {
|
||||
Seq uint64 `json:"seq"`
|
||||
Tasks []domain.Task `json:"tasks"`
|
||||
}{uint64(len(s.events)), tasks})
|
||||
}{s.seq, tasks})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user