vbantxt-cli/main.go
2022-11-05 18:58:36 +00:00

156 lines
3.6 KiB
Go

package main
import (
"bytes"
"encoding/binary"
"errors"
"flag"
"fmt"
"net"
"os"
"path/filepath"
"time"
"github.com/BurntSushi/toml"
log "github.com/sirupsen/logrus"
)
var (
host string
port int
streamname string
bps int
channel int
delay int
loglevel int
bpsOpts = []int{0, 110, 150, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 31250,
38400, 57600, 115200, 128000, 230400, 250000, 256000, 460800, 921600,
1000000, 1500000, 2000000, 3000000}
)
type (
// connection represents the configurable fields of a config.toml
connection struct {
Host string
Port int
Streamname string
}
// config maps toml headers
config struct {
Connection map[string]connection
}
)
func setLogLevel(loglevel int) {
switch loglevel {
case 0:
log.SetLevel(log.WarnLevel)
case 1:
log.SetLevel(log.InfoLevel)
case 2:
log.SetLevel(log.DebugLevel)
}
}
func main() {
flag.StringVar(&host, "host", "", "vban host")
flag.StringVar(&host, "h", "", "vban host (shorthand)")
flag.IntVar(&port, "port", 6980, "vban server port")
flag.IntVar(&port, "p", 6980, "vban server port (shorthand)")
flag.StringVar(&streamname, "streamname", "Command1", "stream name for text requests")
flag.StringVar(&streamname, "s", "Command1", "stream name for text requests (shorthand)")
flag.IntVar(&bps, "bps", 0, "vban bps")
flag.IntVar(&bps, "b", 0, "vban bps (shorthand)")
flag.IntVar(&channel, "channel", 0, "vban channel")
flag.IntVar(&channel, "c", 0, "vban channel (shorthand)")
flag.IntVar(&delay, "delay", 20, "delay between requests")
flag.IntVar(&delay, "d", 20, "delay between requests (shorthand)")
flag.IntVar(&loglevel, "loglevel", 0, "log level")
flag.IntVar(&loglevel, "l", 0, "log level (shorthand)")
flag.Parse()
setLogLevel(loglevel)
c, err := vbanConnect()
if err != nil {
log.Fatal(err)
}
defer c.Close()
header := newRequestHeader(streamname, indexOf(bpsOpts, bps), channel)
for _, arg := range flag.Args() {
err := send(c, header, arg)
if err != nil {
log.Error(err)
}
}
}
// vbanConnect establishes a VBAN connection to remote host
func vbanConnect() (*net.UDPConn, error) {
if host == "" {
conn, err := connFromToml()
if err != nil {
return nil, err
}
host = conn.Host
port = conn.Port
streamname = conn.Streamname
if host == "" {
err := errors.New("must provide a host with --host flag or config.toml")
return nil, err
}
}
CONNECT := fmt.Sprintf("%s:%d", host, port)
s, _ := net.ResolveUDPAddr("udp4", CONNECT)
c, err := net.DialUDP("udp4", nil, s)
if err != nil {
return nil, err
}
log.Info("Connected to ", c.RemoteAddr().String())
return c, nil
}
// connFromToml parses connection info from config.toml
func connFromToml() (*connection, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
f := filepath.Join(homeDir, ".vbantxt_cli", "config.toml")
if _, err := os.Stat(f); err != nil {
err := fmt.Errorf("unable to locate %s", f)
return nil, err
}
var c config
_, err = toml.DecodeFile(f, &c.Connection)
if err != nil {
return nil, err
}
conn := c.Connection["connection"]
return &conn, nil
}
// send sends a VBAN text request over UDP to remote host
func send(c *net.UDPConn, h *requestHeader, msg string) error {
log.Debug("Sending '", msg, "' to: ", c.RemoteAddr().String())
data := []byte(msg)
_, err := c.Write(append(h.header(), data...))
if err != nil {
return err
}
var a uint32
_ = binary.Read(bytes.NewReader(h.framecounter[:]), binary.LittleEndian, &a)
binary.LittleEndian.PutUint32(h.framecounter[:], a+1)
time.Sleep(time.Duration(delay) * time.Millisecond)
return nil
}