mirror of
https://github.com/rwinkhart/uni-nut.git
synced 2026-08-28 04:36:29 -04:00
138 lines
2.7 KiB
Go
138 lines
2.7 KiB
Go
// Package nut implements the Network UPS Tools network protocol.
|
|
//
|
|
// This package only implements those functions necessary for the
|
|
// nut_exporter; it is therefore not complete.
|
|
package nut
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// A Client wraps a connection to a NUT server.
|
|
type Client struct {
|
|
conn net.Conn
|
|
br *bufio.Reader
|
|
}
|
|
|
|
// Dial dials a NUT server using TCP. If the address does not contain
|
|
// a port number, it will default to 3493.
|
|
func Dial(addr string) (*Client, error) {
|
|
_, _, err := net.SplitHostPort(addr)
|
|
if err != nil {
|
|
addr = net.JoinHostPort(addr, "3493")
|
|
}
|
|
|
|
conn, err := net.Dial("tcp", addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewClient(conn), nil
|
|
}
|
|
|
|
// NewClient wraps an existing net.Conn.
|
|
func NewClient(conn net.Conn) *Client {
|
|
return &Client{conn, bufio.NewReader(conn)}
|
|
}
|
|
|
|
// Close closes the connection.
|
|
func (c *Client) Close() error {
|
|
return c.conn.Close()
|
|
}
|
|
|
|
func (c *Client) list(typ string) ([]string, error) {
|
|
cmd := "LIST " + typ
|
|
if err := c.write(cmd); err != nil {
|
|
return nil, err
|
|
}
|
|
l, err := c.read()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
expected := "BEGIN " + cmd
|
|
if l != expected {
|
|
return nil, fmt.Errorf("expected %q, got %q", expected, l)
|
|
}
|
|
|
|
var lines []string
|
|
expected = typ + " "
|
|
for {
|
|
l, err := c.read()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if l == "END "+cmd {
|
|
break
|
|
}
|
|
if !strings.HasPrefix(l, expected) {
|
|
return nil, fmt.Errorf("expected %q, got %q", expected, l)
|
|
}
|
|
l = l[len(expected):]
|
|
lines = append(lines, l)
|
|
}
|
|
return lines, nil
|
|
}
|
|
|
|
// UPSs returns a list of all UPSs on the server.
|
|
func (c *Client) UPSs() ([]string, error) {
|
|
lines, err := c.list("UPS")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var upss []string
|
|
for _, l := range lines {
|
|
idx := strings.IndexByte(l, ' ')
|
|
if idx == -1 {
|
|
return nil, errors.New("protocol error")
|
|
}
|
|
ups := l[:idx]
|
|
upss = append(upss, ups)
|
|
}
|
|
return upss, nil
|
|
}
|
|
|
|
// Variables returns all variables and their values for a UPS.
|
|
func (c *Client) Variables(ups string) (map[string]string, error) {
|
|
lines, err := c.list("VAR " + ups)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
vars := map[string]string{}
|
|
for _, l := range lines {
|
|
idx := strings.IndexByte(l, ' ')
|
|
if idx == -1 {
|
|
return nil, errors.New("protocol error")
|
|
}
|
|
k := l[:idx]
|
|
v := l[idx+1:]
|
|
v, err = strconv.Unquote(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
vars[k] = v
|
|
}
|
|
return vars, nil
|
|
}
|
|
|
|
func (c *Client) write(s string) error {
|
|
_, err := c.conn.Write([]byte(s + "\n"))
|
|
return err
|
|
}
|
|
|
|
func (c *Client) read() (string, error) {
|
|
l, err := c.br.ReadString('\n')
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(l) > 0 {
|
|
l = l[:len(l)-1]
|
|
}
|
|
return l, nil
|
|
}
|