Files
mesh-catalog/modules/gitea/cmd/package-registry/incoming.go
T
jschoubben bccaf75556 F-catalog-B: npm_incoming and go_incoming read and drop the package seats' transfers; an idle one drops by its key
The package seats kept incoming, transfers and findings with no read or drop tool (tools review F4).
npm_incoming and go_incoming list a seat's open transfers, incoming's fill and the cap its binding carries,
and drop one by hand. The same fault as distribution's (running review F2, its second instance): the
transfers state's own lifetime dropped a transfer's key and left its chunks, and the drop otherwise waited
for the next publish. transfers keeps for good; each open transfer has a key in the new state idle with its
own time to live, whose end drops it. The holder counts against its binding's cap.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 17:14:04 +01:00

106 lines
3.7 KiB
Go

package main
// The package seats' incoming, read and steered (design 51 *Publishing*; tools review F4): npm_incoming and
// go_incoming list a seat's open transfers, incoming's fill and the cap its binding carries, and drop one by hand.
// The holder counts against that cap, never a number of its own, and drops a transfer left with no chunk for 24 hours
// when its idle key ends (the bus's marker), never on a timer.
import (
"errors"
"fmt"
"os"
"strings"
"sync/atomic"
"time"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/busstate"
"gitea/internal/packageseats"
)
// incomingTool is a seat's <type>_incoming.
func incomingTool(typ, seat string, holder func() (*packageseats.Holder, error)) stdio.Tool {
str := func(args map[string]any, k string) string { s, _ := args[k].(string); return strings.TrimSpace(s) }
return stdio.Tool{
Name: typ + "_incoming",
Description: "The " + seat + " seat's open transfers in the forge module's object store incoming (each with its " +
"opener, its parts and when it last took a chunk), incoming's fill and the cap its binding carries; a " +
"transfer with no chunk for 24 hours is dropped on its own. With drop, drops one by hand, its chunks with " +
"it (a hand act, why required). (a)",
Input: map[string]any{"type": "object", "properties": map[string]any{
"drop": map[string]any{"type": "string", "description": "a transfer id (the caller's own name) to drop"},
"why": map[string]any{"type": "string", "description": "why it is dropped"},
}},
Run: func(args map[string]any) (any, error) {
h, err := holder()
if err != nil {
return nil, err
}
if id := str(args, "drop"); id != "" {
if str(args, "why") == "" {
return nil, errors.New("a drop is a hand act: say why")
}
t, err := h.Drop(seat, id)
if err != nil {
return nil, err
}
fmt.Fprintf(os.Stderr, "transfer %s of %s dropped by hand by %s: %s\n", id, seat, stdio.CallerOf(args), str(args, "why"))
return map[string]any{"dropped": t.ID}, nil
}
return h.IncomingOf(seat)
},
}
}
// incomingCap reads incoming's cap from its binding (the bus's bound of the object store), once it answers one.
func incomingCap() func() (uint64, error) {
var known atomic.Uint64
return func() (uint64, error) {
if c := known.Load(); c > 0 {
return c, nil
}
f, err := busstate.ObjectsOf(packageseats.IncomingObjects).Fill()
if err != nil {
return 0, fmt.Errorf("incoming's cap cannot be read from its binding: %w", err)
}
if f.MaxBytes == 0 {
return 0, errors.New("incoming's binding carries no cap")
}
known.Store(f.MaxBytes)
return f.MaxBytes, nil
}
}
// armIdle writes a transfer's idle key with its own time to live; one already there is the same bound, kept.
func armIdle(key string, ttl time.Duration) error {
if _, err := stdio.State(packageseats.IdleState).CreateTTL(key, map[string]any{"transfer": key}, ttl); err != nil && !errors.Is(err, stdio.ErrChanged) {
return err
}
return nil
}
// followIdle drops a transfer when its idle key ends (packageseats.Holder.Expired): the bus's marker is the event.
func followIdle(holder func() (*packageseats.Holder, error)) {
<-stdio.Served()
stdio.State(packageseats.IdleState).Follow("", func(ch stdio.StateChange) error {
if ch.Op != stdio.OpExpire {
return nil
}
h, err := holder()
if err != nil {
fmt.Fprintf(os.Stderr, "transfer %s's idle bound ended, but the holder cannot be made: %v\n", ch.Key, err)
return err
}
dropped, err := h.Expired(ch.Key)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return err
}
if dropped {
fmt.Fprintf(os.Stderr, "transfer %s had no chunk for %s: dropped with its chunks\n", ch.Key, packageseats.TransferIdle)
}
return nil
})
}