75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
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()
|
|
}
|