diff --git a/cmd/vbantxt/config.go b/cmd/vbantxt/config.go new file mode 100644 index 0000000..b5cab06 --- /dev/null +++ b/cmd/vbantxt/config.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "os" + + "github.com/BurntSushi/toml" + log "github.com/sirupsen/logrus" +) + +type config struct { + Connection connection `toml:"connection"` +} + +func (c config) String() string { + return fmt.Sprintf( + "host: %s port: %d streamname: %s", + c.Connection.Host, c.Connection.Port, c.Connection.Streamname) +} + +type connection struct { + Host string `toml:"host"` + Port int `toml:"port"` + Streamname string `toml:"streamname"` +} + +func loadConfig(configPath string) (*connection, error) { + _, err := os.Stat(configPath) + if err != nil { + return nil, err + } + + var config config + + _, err = toml.DecodeFile(configPath, &config) + if err != nil { + return nil, err + } + log.Debug(config) + + return &config.Connection, nil +} diff --git a/cmd/vbantxt/config_internal_test.go b/cmd/vbantxt/config_internal_test.go new file mode 100644 index 0000000..6358bcf --- /dev/null +++ b/cmd/vbantxt/config_internal_test.go @@ -0,0 +1,39 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLoadConfig_Success(t *testing.T) { + conn, err := loadConfig("testdata/config.toml") + require.NoError(t, err) + + assert.Equal(t, conn.Host, "localhost") + assert.Equal(t, conn.Port, 7000) + assert.Equal(t, conn.Streamname, "vbantxt") +} + +func TestLoadConfig_Errors(t *testing.T) { + tt := map[string]struct { + input string + err string + }{ + "no such file": { + input: "/no/such/dir/config.toml", + err: "no such file or directory", + }, + } + + for name, tc := range tt { + _, err := loadConfig("/no/such/dir/config.toml") + + t.Run(name, func(t *testing.T) { + assert.Error(t, err) + assert.ErrorContains(t, err, tc.err) + }) + } + +} diff --git a/cmd/vbantxt/main.go b/cmd/vbantxt/main.go new file mode 100644 index 0000000..4f17e36 --- /dev/null +++ b/cmd/vbantxt/main.go @@ -0,0 +1,97 @@ +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + "slices" + "time" + + "github.com/onyx-and-iris/vbantxt" + log "github.com/sirupsen/logrus" +) + +func exit(err error) { + _, _ = fmt.Fprintf(os.Stderr, "Error: %s", err) + os.Exit(1) +} + +func main() { + var ( + host string + port int + streamname string + loglevel int + configPath string + bps int + channel int + ratelimit int + ) + + flag.StringVar(&host, "host", "localhost", "vban host") + flag.StringVar(&host, "h", "localhost", "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(&ratelimit, "ratelimit", 20, "request ratelimit in milliseconds") + flag.IntVar(&ratelimit, "r", 20, "request ratelimit in milliseconds (shorthand)") + + homeDir, err := os.UserHomeDir() + if err != nil { + exit(err) + } + defaultConfigPath := filepath.Join(homeDir, ".config", "vbantxt", "config.toml") + flag.StringVar(&configPath, "config", defaultConfigPath, "config path") + flag.StringVar(&configPath, "C", defaultConfigPath, "config path (shorthand)") + flag.IntVar(&loglevel, "loglevel", int(log.WarnLevel), "log level") + flag.IntVar(&loglevel, "l", int(log.WarnLevel), "log level (shorthand)") + flag.Parse() + + if slices.Contains(log.AllLevels, log.Level(loglevel)) { + log.SetLevel(log.Level(loglevel)) + } + + if !flagsPassed([]string{"host", "h", "port", "p", "streamname", "s"}) { + config, err := loadConfig(configPath) + if err != nil { + exit(err) + } + host = config.Host + port = config.Port + streamname = config.Streamname + } + + client, err := createClient(host, port, streamname, bps, channel, ratelimit) + if err != nil { + exit(err) + } + defer client.Close() + + for _, arg := range flag.Args() { + err := client.Send(arg) + if err != nil { + log.Error(err) + } + } +} + +func createClient(host string, port int, streamname string, bps int, channel, ratelimit int) (*vbantxt.VbanTxt, error) { + client, err := vbantxt.New( + host, + port, + streamname, + vbantxt.WithBPSOpt(indexOf(vbantxt.BpsOpts, bps)), + vbantxt.WithChannel(channel), + vbantxt.WithRateLimit(time.Duration(ratelimit)*time.Millisecond)) + if err != nil { + return nil, err + } + return client, err +} diff --git a/cmd/vbantxt/testdata/config.toml b/cmd/vbantxt/testdata/config.toml new file mode 100644 index 0000000..5d0c895 --- /dev/null +++ b/cmd/vbantxt/testdata/config.toml @@ -0,0 +1,4 @@ +[connection] +host = "localhost" +port = 7000 +streamname = "vbantxt" diff --git a/cmd/vbantxt/util.go b/cmd/vbantxt/util.go new file mode 100644 index 0000000..bb0ac6d --- /dev/null +++ b/cmd/vbantxt/util.go @@ -0,0 +1,26 @@ +package main + +import ( + "flag" + "slices" +) + +func flagsPassed(flags []string) bool { + found := false + flag.Visit(func(f *flag.Flag) { + if slices.Contains(flags, f.Name) { + found = true + return + } + }) + return found +} + +func indexOf[T comparable](collection []T, e T) int { + for i, x := range collection { + if x == e { + return i + } + } + return -1 +}