I think we're getting there
This commit is contained in:
parent
f266afa1de
commit
2c1989beb0
3 changed files with 73 additions and 58 deletions
|
@ -11,8 +11,8 @@
|
||||||
# Here's a (hopefully self-explanatory) example:
|
# Here's a (hopefully self-explanatory) example:
|
||||||
# subscribe:
|
# subscribe:
|
||||||
# - topic: mytopic
|
# - topic: mytopic
|
||||||
# exec: /usr/local/bin/mytopic-triggered.sh
|
# command: /usr/local/bin/mytopic-triggered.sh
|
||||||
# - topic: myserver.com/anothertopic
|
# - topic: myserver.com/anothertopic
|
||||||
# exec: 'echo "$message"'
|
# command: 'echo "$message"'
|
||||||
#
|
#
|
||||||
# subscribe:
|
# subscribe:
|
||||||
|
|
|
@ -8,7 +8,7 @@ type Config struct {
|
||||||
DefaultHost string
|
DefaultHost string
|
||||||
Subscribe []struct {
|
Subscribe []struct {
|
||||||
Topic string
|
Topic string
|
||||||
Exec string
|
Command string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
109
cmd/subscribe.go
109
cmd/subscribe.go
|
@ -27,6 +27,7 @@ var cmdSubscribe = &cli.Command{
|
||||||
&cli.BoolFlag{Name: "from-config", Aliases: []string{"C"}, Usage: "read subscriptions from config file (service mode)"},
|
&cli.BoolFlag{Name: "from-config", Aliases: []string{"C"}, Usage: "read subscriptions from config file (service mode)"},
|
||||||
&cli.BoolFlag{Name: "poll", Aliases: []string{"p"}, Usage: "return events and exit, do not listen for new events"},
|
&cli.BoolFlag{Name: "poll", Aliases: []string{"p"}, Usage: "return events and exit, do not listen for new events"},
|
||||||
&cli.BoolFlag{Name: "scheduled", Aliases: []string{"sched", "S"}, Usage: "also return scheduled/delayed events"},
|
&cli.BoolFlag{Name: "scheduled", Aliases: []string{"sched", "S"}, Usage: "also return scheduled/delayed events"},
|
||||||
|
&cli.BoolFlag{Name: "verbose", Aliases: []string{"v"}, Usage: "print verbose output"},
|
||||||
},
|
},
|
||||||
Description: `Subscribe to a topic from a ntfy server, and either print or execute a command for
|
Description: `Subscribe to a topic from a ntfy server, and either print or execute a command for
|
||||||
every arriving message. There are 3 modes in which the command can be run:
|
every arriving message. There are 3 modes in which the command can be run:
|
||||||
|
@ -71,39 +72,9 @@ ntfy subscribe --from-config
|
||||||
}
|
}
|
||||||
|
|
||||||
func execSubscribe(c *cli.Context) error {
|
func execSubscribe(c *cli.Context) error {
|
||||||
fromConfig := c.Bool("from-config")
|
|
||||||
if fromConfig {
|
|
||||||
return execSubscribeFromConfig(c)
|
|
||||||
}
|
|
||||||
return execSubscribeWithoutConfig(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func execSubscribeFromConfig(c *cli.Context) error {
|
|
||||||
conf, err := loadConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cl := client.New(conf)
|
|
||||||
commands := make(map[string]string)
|
|
||||||
for _, s := range conf.Subscribe {
|
|
||||||
topicURL := cl.Subscribe(s.Topic)
|
|
||||||
commands[topicURL] = s.Exec
|
|
||||||
}
|
|
||||||
for m := range cl.Messages {
|
|
||||||
command, ok := commands[m.TopicURL]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
_ = dispatchMessage(c, command, m)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func execSubscribeWithoutConfig(c *cli.Context) error {
|
|
||||||
if c.NArg() < 1 {
|
|
||||||
return errors.New("topic missing")
|
|
||||||
}
|
|
||||||
fmt.Fprintln(c.App.ErrWriter, "\x1b[1;33mThis command is incubating. The interface may change without notice.\x1b[0m")
|
fmt.Fprintln(c.App.ErrWriter, "\x1b[1;33mThis command is incubating. The interface may change without notice.\x1b[0m")
|
||||||
|
|
||||||
|
// Read config and options
|
||||||
conf, err := loadConfig(c)
|
conf, err := loadConfig(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -112,8 +83,12 @@ func execSubscribeWithoutConfig(c *cli.Context) error {
|
||||||
since := c.String("since")
|
since := c.String("since")
|
||||||
poll := c.Bool("poll")
|
poll := c.Bool("poll")
|
||||||
scheduled := c.Bool("scheduled")
|
scheduled := c.Bool("scheduled")
|
||||||
|
fromConfig := c.Bool("from-config")
|
||||||
topic := c.Args().Get(0)
|
topic := c.Args().Get(0)
|
||||||
command := c.Args().Get(1)
|
command := c.Args().Get(1)
|
||||||
|
if !fromConfig {
|
||||||
|
conf.Subscribe = nil // wipe if --from-config not passed
|
||||||
|
}
|
||||||
var options []client.SubscribeOption
|
var options []client.SubscribeOption
|
||||||
if since != "" {
|
if since != "" {
|
||||||
options = append(options, client.WithSince(since))
|
options = append(options, client.WithSince(since))
|
||||||
|
@ -124,41 +99,78 @@ func execSubscribeWithoutConfig(c *cli.Context) error {
|
||||||
if scheduled {
|
if scheduled {
|
||||||
options = append(options, client.WithScheduled())
|
options = append(options, client.WithScheduled())
|
||||||
}
|
}
|
||||||
|
if topic == "" && len(conf.Subscribe) == 0 {
|
||||||
|
return errors.New("must specify topic, or have at least one topic defined in config")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute poll or subscribe
|
||||||
if poll {
|
if poll {
|
||||||
|
return execPoll(c, cl, conf, topic, command, options...)
|
||||||
|
}
|
||||||
|
return execSubscribeInternal(c, cl, conf, topic, command, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func execPoll(c *cli.Context, cl *client.Client, conf *client.Config, topic, command string, options ...client.SubscribeOption) error {
|
||||||
|
for _, s := range conf.Subscribe { // may be nil
|
||||||
|
if err := execPollSingle(c, cl, s.Topic, s.Command, options...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if topic != "" {
|
||||||
|
if err := execPollSingle(c, cl, topic, command, options...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func execPollSingle(c *cli.Context, cl *client.Client, topic, command string, options ...client.SubscribeOption) error {
|
||||||
messages, err := cl.Poll(topic, options...)
|
messages, err := cl.Poll(topic, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, m := range messages {
|
for _, m := range messages {
|
||||||
_ = dispatchMessage(c, command, m)
|
printMessageOrRunCommand(c, m, command)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func execSubscribeInternal(c *cli.Context, cl *client.Client, conf *client.Config, topic, command string, options ...client.SubscribeOption) error {
|
||||||
|
commands := make(map[string]string)
|
||||||
|
for _, s := range conf.Subscribe { // May be nil
|
||||||
|
topicURL := cl.Subscribe(s.Topic, options...)
|
||||||
|
commands[topicURL] = s.Command
|
||||||
|
}
|
||||||
|
if topic != "" {
|
||||||
|
topicURL := cl.Subscribe(topic, options...)
|
||||||
|
commands[topicURL] = command
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
cl.Subscribe(topic, options...)
|
|
||||||
for m := range cl.Messages {
|
for m := range cl.Messages {
|
||||||
_ = dispatchMessage(c, command, m)
|
command, ok := commands[m.TopicURL]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
printMessageOrRunCommand(c, m, command)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dispatchMessage(c *cli.Context, command string, m *client.Message) error {
|
func printMessageOrRunCommand(c *cli.Context, m *client.Message, command string) {
|
||||||
|
if m.Event != client.MessageEvent {
|
||||||
|
return
|
||||||
|
}
|
||||||
if command != "" {
|
if command != "" {
|
||||||
return execCommand(c, command, m)
|
runCommand(c, command, m)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(c.App.Writer, m.Raw)
|
||||||
}
|
}
|
||||||
fmt.Println(m.Raw)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func execCommand(c *cli.Context, command string, m *client.Message) error {
|
func runCommand(c *cli.Context, command string, m *client.Message) {
|
||||||
if m.Event == client.OpenEvent {
|
|
||||||
log.Printf("[%s] Connection opened, subscribed to topic", collapseTopicURL(m.TopicURL))
|
|
||||||
} else if m.Event == client.MessageEvent {
|
|
||||||
if err := runCommandInternal(c, command, m); err != nil {
|
if err := runCommandInternal(c, command, m); err != nil {
|
||||||
log.Printf("[%s] Command failed: %s", collapseTopicURL(m.TopicURL), err.Error())
|
fmt.Fprintf(c.App.ErrWriter, "Command failed: %s\n", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCommandInternal(c *cli.Context, command string, m *client.Message) error {
|
func runCommandInternal(c *cli.Context, command string, m *client.Message) error {
|
||||||
scriptFile, err := createTmpScript(command)
|
scriptFile, err := createTmpScript(command)
|
||||||
|
@ -166,7 +178,10 @@ func runCommandInternal(c *cli.Context, command string, m *client.Message) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer os.Remove(scriptFile)
|
defer os.Remove(scriptFile)
|
||||||
|
verbose := c.Bool("verbose")
|
||||||
|
if verbose {
|
||||||
log.Printf("[%s] Executing: %s (for message: %s)", collapseTopicURL(m.TopicURL), command, m.Raw)
|
log.Printf("[%s] Executing: %s (for message: %s)", collapseTopicURL(m.TopicURL), command, m.Raw)
|
||||||
|
}
|
||||||
cmd := exec.Command("sh", "-c", scriptFile)
|
cmd := exec.Command("sh", "-c", scriptFile)
|
||||||
cmd.Stdin = c.App.Reader
|
cmd.Stdin = c.App.Reader
|
||||||
cmd.Stdout = c.App.Writer
|
cmd.Stdout = c.App.Writer
|
||||||
|
|
Loading…
Reference in a new issue