package qmp import ( "encoding/json" "fmt" "time" "github.com/digitalocean/go-qemu/qmp" "github.com/samber/mo" ) type Client struct { monitor qmp.Monitor } type VMStatus struct { Running bool Singlestep bool Status string } func Connect(socketPath string) mo.Result[*Client] { monitor, err := qmp.NewSocketMonitor("unix", socketPath, 2*time.Second) if err != nil { return mo.Err[*Client](fmt.Errorf("failed to create socket monitor: %w", err)) } if err := monitor.Connect(); err != nil { return mo.Err[*Client](fmt.Errorf("failed to connect to QMP socket: %w", err)) } return mo.Ok(&Client{monitor: monitor}) } func (c *Client) Status() mo.Result[VMStatus] { type statusResult struct { ID string `json:"id"` Return struct { Running bool `json:"running"` Singlestep bool `json:"singlestep"` Status string `json:"status"` } `json:"return"` } cmd := []byte(`{"execute":"query-status"}`) raw, err := c.monitor.Run(cmd) if err != nil { return mo.Err[VMStatus](fmt.Errorf("failed to execute query-status: %w", err)) } var result statusResult if err := json.Unmarshal(raw, &result); err != nil { return mo.Err[VMStatus](fmt.Errorf("failed to parse status response: %w", err)) } return mo.Ok(VMStatus{ Running: result.Return.Running, Singlestep: result.Return.Singlestep, Status: result.Return.Status, }) } func (c *Client) Shutdown() mo.Result[struct{}] { cmd := []byte(`{"execute":"system_powerdown"}`) _, err := c.monitor.Run(cmd) if err != nil { return mo.Err[struct{}](fmt.Errorf("failed to execute system_powerdown: %w", err)) } return mo.Ok(struct{}{}) } func (c *Client) Close() error { return c.monitor.Disconnect() }