141 строка
3,4 КиБ
Go
141 строка
3,4 КиБ
Go
package liquidsoap
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
)
|
|
|
|
// Client represents a telnet/unix domain connection to Liquidsoap
|
|
//
|
|
// A Client can perform low-level operations, such as Command(), or high-level operations such as Outputs()
|
|
type Client struct {
|
|
Conn net.Conn
|
|
}
|
|
|
|
// Stream represents a liquidsoap stream. It contains information about the status and the nature of it
|
|
type Stream struct {
|
|
Enabled bool `json:"enabled"`
|
|
Up bool `json:"up"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
// NewTelnet returns a liquidsoap.Client created using telnet on the given parameters
|
|
func NewTelnet(host string, port int) (Client, error) {
|
|
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
|
|
if err != nil {
|
|
return Client{}, err
|
|
}
|
|
return Client{Conn: conn}, nil
|
|
}
|
|
|
|
// Close closes the connection
|
|
func (c *Client) Close() {
|
|
if c.Conn != nil {
|
|
c.Conn.Write([]byte("quit\n"))
|
|
c.Conn.Close()
|
|
}
|
|
}
|
|
|
|
// Command run a command, wait for output response to come and returns it
|
|
func (c *Client) Command(cmdline string) (string, error) {
|
|
c.Conn.Write([]byte(cmdline + "\n"))
|
|
var out, line string
|
|
var err error
|
|
reader := bufio.NewReader(c.Conn)
|
|
for {
|
|
if line, err = reader.ReadString('\n'); err != nil {
|
|
return "", err
|
|
}
|
|
line = line[:len(line)-2] + "\n" // \r\n -> \n
|
|
if line == "END\n" {
|
|
return out, nil
|
|
}
|
|
out += line
|
|
}
|
|
}
|
|
|
|
// Outputs will return a map of outputs that liquidsoap is handling.
|
|
// An output is set to true if it is enabled
|
|
func (c *Client) Outputs() (outputs map[string]Stream, err error) {
|
|
outputs = make(map[string]Stream)
|
|
var cmdout string
|
|
cmdout, err = c.Command("list")
|
|
if err != nil {
|
|
return
|
|
}
|
|
lines := strings.Split(cmdout, "\n")
|
|
for _, l := range lines {
|
|
parts := strings.SplitN(l, " : ", 2)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
if strings.Index(parts[1], "output.") == 0 {
|
|
name := strings.TrimSpace(parts[0])
|
|
var stream Stream
|
|
stream.Type = parts[1][7:]
|
|
enabled, err := c.GetOutput(name)
|
|
if err == nil {
|
|
stream.Enabled = enabled
|
|
}
|
|
up, err := c.GetOutputUp(name)
|
|
if err == nil {
|
|
stream.Up = up
|
|
}
|
|
outputs[name] = stream
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// GetOutput checks whether an output is enabled
|
|
func (c *Client) GetOutput(name string) (bool, error) {
|
|
cmdout, err := c.Command(name + ".status")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return strings.TrimSpace(cmdout) == "on", nil
|
|
}
|
|
|
|
// GetOutput checks whether an output is up
|
|
//
|
|
// Please note that this relies on a custom convention proposed by direttoforo, where to every stream "x"
|
|
// there is an interactive boolean variable "x_up" that has its state
|
|
func (c *Client) GetOutputUp(name string) (bool, error) {
|
|
return c.GetVar(name + "_up")
|
|
}
|
|
|
|
// GetVar reads an interactive variable
|
|
func (c *Client) GetVar(name string) (bool, error) {
|
|
cmdout, err := c.Command("var.get " + name)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
cmdout = strings.TrimSpace(cmdout)
|
|
switch cmdout {
|
|
case "true":
|
|
return true, nil
|
|
case "false":
|
|
return false, nil
|
|
default:
|
|
return false, fmt.Errorf("Variable %s not set", name)
|
|
}
|
|
}
|
|
|
|
// SetOutput enables or disables an output
|
|
func (c *Client) SetOutput(name string, enabled bool) error {
|
|
action := "stop"
|
|
if enabled {
|
|
action = "start"
|
|
}
|
|
cmdout, err := c.Command(fmt.Sprintf("%s.%s", name, action))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if strings.TrimSpace(cmdout) != "OK" {
|
|
return fmt.Errorf("Error: liquidsoap replied '%s'", cmdout)
|
|
}
|
|
return nil
|
|
}
|