Code around sleep was written into the service manager's sleep units by the module that needed it, and the mesh could not tell a sleeping machine from a lost one. power runs every module's code for the six moments, each piece bounded, owns logind's power handling from its settings, and says booted, sleeping, woke, shutting-down and the power source on the bus, sleeping under logind's delay lock before the machine sleeps.
82 lines
3.2 KiB
Go
82 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
// Tools are the module's tools over MCP (novox/hq ADR 0211): the machine's power now, the code
|
|
// modules contributed for each moment, the recent power history, running one moment on demand, and
|
|
// the module's own check.
|
|
func Tools(m *Machine, w *Watcher) []stdio.Tool {
|
|
return []stdio.Tool{
|
|
{
|
|
Name: "power_state",
|
|
Description: "This machine's power now: since when it runs, mains or battery and the charge, the lid, " +
|
|
"logind's power-key and lid settings in force, and what the watcher last saw: its delay lock, " +
|
|
"the last sleep and wake, and events still waiting for the bus.",
|
|
Run: func(map[string]any) (any, error) { return m.State(w), nil },
|
|
},
|
|
{
|
|
Name: "power_hooks",
|
|
Description: "The code every module contributed for each power moment (after boot, on mains, on battery, " +
|
|
"before sleep, after waking, before shutdown), as placed on this machine, each piece with its module.",
|
|
Run: func(map[string]any) (any, error) { return m.Hooks(), nil },
|
|
},
|
|
{
|
|
Name: "power_history",
|
|
Description: "The machine's recent power events from the journal: each boot, every sleep and wake, and " +
|
|
"every moment's run with each module's outcome.",
|
|
Input: map[string]any{
|
|
"boots": map[string]any{"type": "integer", "description": "how many boots back (default 3, at most 20)"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
n := 3
|
|
if v, ok := args["boots"].(float64); ok {
|
|
n = int(v)
|
|
}
|
|
if n < 1 || n > 20 {
|
|
return nil, fmt.Errorf("boots is 1 to 20")
|
|
}
|
|
return m.History(context.Background(), n)
|
|
},
|
|
},
|
|
{
|
|
Name: "power_run",
|
|
Description: "Run one moment's contributed code now, as the machine would, to test it: each module's " +
|
|
"piece on its own, bounded. `supply` runs on-mains or on-battery for the source the machine is on. " +
|
|
"Answers the runner's lines. Needs sudo -n.",
|
|
Input: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"moment": map[string]any{"type": "string", "enum": append(append([]string(nil), Moments...), "supply"),
|
|
"description": "the moment to run"},
|
|
},
|
|
"required": []string{"moment"},
|
|
},
|
|
Run: func(args map[string]any) (any, error) {
|
|
moment, _ := args["moment"].(string)
|
|
known := moment == "supply"
|
|
for _, mo := range Moments {
|
|
known = known || mo == moment
|
|
}
|
|
if !known {
|
|
return nil, fmt.Errorf("no moment %q; the moments are %s and supply", moment, strings.Join(Moments, ", "))
|
|
}
|
|
out, err := m.privileged(context.Background(), RunnerPath, moment, "--force")
|
|
return map[string]any{"moment": moment, "said": strings.Split(strings.TrimSpace(out), "\n")}, err
|
|
},
|
|
},
|
|
{
|
|
Name: "power_check",
|
|
Description: "Whether this machine's power handling is as the mesh declares it: the module's units enabled, " +
|
|
"the runner and every moment's file in place, logind's power file the mesh's and the only one, no " +
|
|
"hand-placed sleep hooks, the watcher's delay lock held and no events stuck before the bus.",
|
|
Run: func(map[string]any) (any, error) { return m.Check(context.Background(), w), nil },
|
|
},
|
|
}
|
|
}
|