Something went wrong. Try again.
small gleam coding and persistent agent daemon with a detachable cli and a canvas ui forked from okami.mom/albedo
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128package storage
import ( "albedo/cli/internal/daemon" "bytes" "context" "encoding/json" "errors" "fmt" "io" "os/exec" "strings")
// maintenance owns both mutations and the lock. Closing input revokes ownership.type maintenance struct { command *exec.Cmd input io.WriteCloser output *json.Decoder stderr bytes.Buffer waited bool}
type maintenanceMessage struct { Result *CleanupResult `json:"result"` Ready bool `json:"ready"`}
func (s *Service) startMaintenance(ctx context.Context, files []daemon.StorageFile) (*maintenance, error) { command, err := s.command(ctx, "storage", "maintain", s.Home) if err != nil { return nil, err } helper := &maintenance{command: command} helper.command.Stderr = &helper.stderr input, err := helper.command.StdinPipe() if err != nil { return nil, err } helper.input = input output, err := helper.command.StdoutPipe() if err != nil { _ = input.Close() return nil, err } helper.output = json.NewDecoder(output) helper.output.DisallowUnknownFields() if err := helper.command.Start(); err != nil { _ = input.Close() return nil, err } paths := make([]string, 0, len(files)) for _, file := range files { paths = append(paths, file.Path) } if err := json.NewEncoder(input).Encode(struct { Paths []string `json:"paths"` }{paths}); err != nil { helper.close() return nil, helper.failure(ctx, err) } var message maintenanceMessage if err := helper.output.Decode(&message); err != nil { helper.close() return nil, helper.failure(ctx, err) } if !message.Ready || message.Result != nil { helper.close() return nil, helper.failure(ctx, errors.New("invalid maintenance readiness")) } return helper, nil}
// close always reaps the child, including revalidation failures before authorization.func (m *maintenance) close() { _ = m.input.Close() if !m.waited { _ = m.command.Process.Kill() _ = m.command.Wait() m.waited = true }}
func (m *maintenance) failure(ctx context.Context, err error) error { if ctx.Err() != nil { return ctx.Err() } return fmt.Errorf("storage maintenance: %w: %s", err, strings.TrimSpace(m.stderr.String()))}
func (m *maintenance) apply(ctx context.Context, vacuum bool, fresh daemon.StorageReport) (CleanupResult, error) { var result CleanupResult if err := ctx.Err(); err != nil { m.close() return result, err } err := json.NewEncoder(m.input).Encode(struct { Apply bool `json:"apply"` Vacuum bool `json:"vacuum"` Before int64 `json:"before"` FreePages int64 `json:"free_pages"` }{true, vacuum, fresh.Database, fresh.DB.FreePages}) if err != nil { m.close() return result, m.failure(ctx, err) } var message maintenanceMessage if err = m.output.Decode(&message); err != nil { m.close() return result, m.failure(ctx, err) } if message.Ready || message.Result == nil { m.close() return result, m.failure(ctx, errors.New("invalid maintenance result")) } // Keep input open until the helper finishes, so its EOF watcher cannot // interrupt successful work. A valid result alone does not prove success. err = m.command.Wait() m.waited = true if ctx.Err() != nil { return result, ctx.Err() } if err != nil { return result, m.failure(ctx, err) } return *message.Result, nil}