74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package system
|
|
|
|
import (
|
|
"context"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"nadir/internal/oscmd"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
)
|
|
|
|
// whenRe matches the shutdown(8) TIME forms we accept: "now", "+<minutes>", or
|
|
// "hh:mm". Validating before exec keeps a value like "-r" or "--help" from
|
|
// being read as a flag (shutdown does not honor a "--" separator), per the
|
|
// repo's input-validation rule.
|
|
var whenRe = regexp.MustCompile(`^(now|\+\d+|([01]?\d|2[0-3]):[0-5]\d)$`)
|
|
|
|
type PowerInput struct {
|
|
Body struct {
|
|
When string `json:"when,omitempty" example:"+1" doc:"When to act, as a shutdown(8) TIME (e.g. \"+5\" minutes, \"23:00\"). Empty or 'now' = immediate."`
|
|
}
|
|
}
|
|
|
|
const powerDescription = "Requires the `root` permission. The response is sent once `shutdown` " +
|
|
"accepts the request; for the immediate form it returns before the machine " +
|
|
"actually goes down, so a 200 does not guarantee a clean shutdown completed."
|
|
|
|
func registerPower(api huma.API) {
|
|
huma.Register(api, huma.Operation{
|
|
OperationID: "system-reboot",
|
|
Method: "POST",
|
|
Path: "/api/system/reboot",
|
|
Summary: "Reboot the system",
|
|
Description: powerDescription,
|
|
Tags: []string{tagSystem},
|
|
Metadata: op("root"),
|
|
Errors: []int{400, 401, 403, 500},
|
|
}, func(ctx context.Context, in *PowerInput) (*oscmd.StatusOutput, error) {
|
|
return schedulePower("reboot", in.Body.When)
|
|
})
|
|
|
|
huma.Register(api, huma.Operation{
|
|
OperationID: "system-poweroff",
|
|
Method: "POST",
|
|
Path: "/api/system/poweroff",
|
|
Summary: "Power off the system",
|
|
Description: powerDescription,
|
|
Tags: []string{tagSystem},
|
|
Metadata: op("root"),
|
|
Errors: []int{400, 401, 403, 500},
|
|
}, func(ctx context.Context, in *PowerInput) (*oscmd.StatusOutput, error) {
|
|
return schedulePower("poweroff", in.Body.When)
|
|
})
|
|
}
|
|
|
|
func schedulePower(action, when string) (*oscmd.StatusOutput, error) {
|
|
w := strings.TrimSpace(when)
|
|
if w == "" {
|
|
w = "now"
|
|
}
|
|
if !whenRe.MatchString(w) {
|
|
return nil, huma.Error400BadRequest("invalid when: " + w)
|
|
}
|
|
flag := "-h"
|
|
if action == "reboot" {
|
|
flag = "-r"
|
|
}
|
|
if _, err := oscmd.Run("shutdown", flag, w); err != nil {
|
|
return nil, huma.Error500InternalServerError("shutdown failed", err)
|
|
}
|
|
return oscmd.OK(), nil
|
|
}
|