diff --git a/client/client.yml b/client/client.yml index 0a38a9b..2fbe17a 100644 --- a/client/client.yml +++ b/client/client.yml @@ -5,14 +5,25 @@ # # default-host: https://ntfy.sh -# Subscriptions to topics and their actions. This option is only used by the "ntfy subscribe --from-config" -# command. +# Subscriptions to topics and their actions. This option is primarily used by the systemd service, +# or if you cann "ntfy subscribe --from-config" directly. # -# Here's a (hopefully self-explanatory) example: -# subscribe: -# - topic: mytopic -# command: /usr/local/bin/mytopic-triggered.sh -# - topic: myserver.com/anothertopic -# command: 'echo "$message"' +# Example: +# subscribe: +# - topic: mytopic +# command: /usr/local/bin/mytopic-triggered.sh +# - topic: myserver.com/anothertopic +# command: 'echo "$message"' +# +# Variables: +# Variable Aliases Description +# --------------- --------------- ----------------------------------- +# $NTFY_ID $id Unique message ID +# $NTFY_TIME $time Unix timestamp of the message delivery +# $NTFY_TOPIC $topic Topic name +# $NTFY_MESSAGE $message, $m Message body +# $NTFY_TITLE $title, $t Message title +# $NTFY_PRIORITY $priority, $p Message priority (1=min, 5=max) +# $NTFY_TAGS $tags, $ta Message tags (comma separated list) # # subscribe: diff --git a/client/config.go b/client/config.go index 76fcc1f..8c19611 100644 --- a/client/config.go +++ b/client/config.go @@ -7,12 +7,12 @@ const ( // Config is the config struct for a Client type Config struct { - DefaultHost string + DefaultHost string `yaml:"default-host"` Subscribe []struct { - Topic string - Command string + Topic string `yaml:"topic"` + Command string `yaml:"command"` // If []map[string]string TODO This would be cool - } + } `yaml:"subscribe"` } // NewConfig creates a new Config struct for a Client diff --git a/cmd/subscribe.go b/cmd/subscribe.go index 8d61477..a45b9c2 100644 --- a/cmd/subscribe.go +++ b/cmd/subscribe.go @@ -20,11 +20,6 @@ var cmdSubscribe = &cli.Command{ Usage: "Subscribe to one or more topics on a ntfy server", UsageText: "ntfy subscribe [OPTIONS..] [TOPIC]", Action: execSubscribe, - OnUsageError: func(context *cli.Context, err error, isSubcommand bool) error { - println("ee") - return nil - }, - Flags: []cli.Flag{ &cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "client config file"}, &cli.StringFlag{Name: "since", Aliases: []string{"s"}, Usage: "return events since `SINCE` (Unix timestamp, or all)"}, @@ -109,26 +104,26 @@ func execSubscribe(c *cli.Context) error { // Execute poll or subscribe if poll { - return execPoll(c, cl, conf, topic, command, options...) + return doPoll(c, cl, conf, topic, command, options...) } - return execSubscribeInternal(c, cl, conf, topic, command, options...) + return doSubscribe(c, cl, conf, topic, command, options...) } -func execPoll(c *cli.Context, cl *client.Client, conf *client.Config, topic, command string, options ...client.SubscribeOption) error { +func doPoll(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 { + if err := doPollSingle(c, cl, s.Topic, s.Command, options...); err != nil { return err } } if topic != "" { - if err := execPollSingle(c, cl, topic, command, options...); err != nil { + if err := doPollSingle(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 { +func doPollSingle(c *cli.Context, cl *client.Client, topic, command string, options ...client.SubscribeOption) error { messages, err := cl.Poll(topic, options...) if err != nil { return err @@ -139,7 +134,7 @@ func execPollSingle(c *cli.Context, cl *client.Client, topic, command string, op return nil } -func execSubscribeInternal(c *cli.Context, cl *client.Client, conf *client.Config, topic, command string, options ...client.SubscribeOption) error { +func doSubscribe(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...) diff --git a/docs/static/img/cli-subscribe-video-3.webm b/docs/static/img/cli-subscribe-video-3.webm new file mode 100644 index 0000000..8a07f41 Binary files /dev/null and b/docs/static/img/cli-subscribe-video-3.webm differ diff --git a/docs/subscribe/cli.md b/docs/subscribe/cli.md index 334611f..29416c3 100644 --- a/docs/subscribe/cli.md +++ b/docs/subscribe/cli.md @@ -5,10 +5,10 @@ to topics via the ntfy CLI. The CLI is included in the same `ntfy` binary that c !!! info The **ntfy CLI is not required to send or receive messages**. You can instead [send messages with curl](../publish.md), and even use it to [subscribe to topics](api.md). It may be a little more convenient to use the ntfy CLI than writing - your own script. Or it may not be. It all depends on the use case. 😀 + your own script. It all depends on the use case. 😀 ## Install + configure -To install the ntfy CLI, simply follow the steps outlined on the [install page](../install.md). The ntfy server and +To install the ntfy CLI, simply **follow the steps outlined on the [install page](../install.md)**. The ntfy server and client are the same binary, so it's all very convenient. After installing, you can (optionally) configure the client by creating `~/.config/ntfy/client.yml` (for the non-root user), or `/etc/ntfy/client.yml` (for the root user). You can find a [skeleton config](https://github.com/binwiederhier/ntfy/blob/main/client/client.yml) on GitHub. @@ -23,7 +23,7 @@ you may want to edit the `default-host` option: default-host: https://ntfy.myhost.com ``` -## Publish using the ntfy CLI +## Publish messages You can send messages with the ntfy CLI using the `ntfy publish` command (or any of its aliases `pub`, `send` or `trigger`). There are a lot of examples on the page about [publishing messages](../publish.md), but here are a few quick ones: @@ -56,20 +56,23 @@ quick ones: ntfy pub mywebhook ``` -## Subscribe using the ntfy CLI +## Subscribe to topics You can subscribe to topics using `ntfy subscribe`. Depending on how it is called, this command will either print or execute a command for every arriving message. There are a few different ways in which the command can be run: -### Stream messages and print JSON -If run like this `ntfy subscribe TOPIC`, the command prints the JSON representation of every incoming -message. This is useful when you have a command that wants to stream-read incoming JSON messages. -Unless `--poll` is passed, this command stays open forever. +### Stream messages as JSON +``` +ntfy subscribe TOPIC +``` +If you run the command like this, it prints the JSON representation of every incoming message. This is useful +when you have a command that wants to stream-read incoming JSON messages. Unless `--poll` is passed, this command +stays open forever. ``` $ ntfy sub mytopic {"id":"nZ8PjH5oox","time":1639971913,"event":"message","topic":"mytopic","message":"hi there"} -{"id":"sekSLWTujn","time":1639972063,"event":"message","topic":"mytopic","tags":["warning","skull"],"message":"Oh no, something went wrong"} +{"id":"sekSLWTujn","time":1639972063,"event":"message","topic":"mytopic",priority:5,"message":"Oh no!"} ```
@@ -77,15 +80,28 @@ $ ntfy sub mytopic
Subscribe in JSON mode
-### Execute a command for every incoming message -If run like this `ntfy subscribe TOPIC COMMAND`, a COMMAND is executed for every incoming messages. -The message fields are passed to the command as environment variables and can be used in scripts: +### Run command for every message +``` +ntfy subscribe TOPIC COMMAND +``` +If you run it like this, a COMMAND is executed for every incoming messages. Here are a few +examples: + +``` +ntfy sub mytopic 'notify-send "$m"' +ntfy sub topic1 /my/script.sh +ntfy sub topic1 'echo "Message $m was received. Its title was $t and it had priority $p' +```
Execute command on incoming messages
+The message fields are passed to the command as environment variables and can be used in scripts. Note that since +these are environment variables, you typically don't have to worry about quoting too much, as long as you enclose them +in double-quotes, you should be fine: + | Variable | Aliases | Description | |---|---|--- | `$NTFY_ID` | `$id` | Unique message ID | @@ -96,32 +112,78 @@ The message fields are passed to the command as environment variables and can be | `$NTFY_PRIORITY` | `$priority`, `$p` | Message priority (1=min, 5=max) | | `$NTFY_TAGS` | `$tags`, `$ta` | Message tags (comma separated list) | - Examples: - ntfy sub mytopic 'notify-send "$m"' # Execute command for incoming messages - ntfy sub topic1 /my/script.sh # Execute script for incoming messages - -### Using a config file +### Subscribing to multiple topics +``` ntfy subscribe --from-config -Service mode (used in ntfy-client.service). This reads the config file (/etc/ntfy/client.yml -or ~/.config/ntfy/client.yml) and sets up subscriptions for every topic in the "subscribe:" -block (see config file). +``` +To subscribe to multiple topics at once, and run different commands for each one, you can use `ntfy subscribe --from-config`, +which will read the `subscribe` config from the config file. Please also check out the [ntfy-client systemd service](#using-the-systemd-service). - Examples: - ntfy sub --from-config # Read topics from config file - ntfy sub --config=/my/client.yml --from-config # Read topics from alternate config file +Here's an example config file that subscribes to three different topics, executing a different command for each of them: -The default config file for all client commands is /etc/ntfy/client.yml (if root user), -or ~/.config/ntfy/client.yml for all other users. +=== "~/.config/ntfy/client.yml" + ```yaml + subscribe: + - topic: echo-this + command: 'echo "Message received: $message"' + - topic: get-temp + command: | + temp="$(sensors | awk '/Package/ { print $4 }')" + ntfy publish --quiet temp "$temp"; + echo "CPU temp is $temp; published to topic 'temp'" + - topic: alerts + command: notify-send "$m" + - topic: calc + command: 'gnome-calculator 2>/dev/null &' + ``` +In this example, when `ntfy subscribe --from-config` is executed: + +* Messages to topic `echo-this` will be simply echoed to standard out +* Messages to topic `get-temp` will publish the CPU core temperature to topic `temp` +* Messages to topic `alerts` will be displayed as desktop notification using `notify-send` +* And messages to topic `calc` will open the gnome calculator 😀 (*because, why not*) + +I hope this shows how powerful this command is. Here's a short video that demonstrates the above example: + +
+ +
Execute all the things
+
### Using the systemd service +You can use the `ntfy-client` systemd service (see [ntfy-client.service](https://github.com/binwiederhier/ntfy/blob/main/client/ntfy-client.service)) +to subscribe to multiple topics just like in the example above. The service is automatically installed (but not started) +if you install the deb/rpm package. To configure it, simply edit `/etc/ntfy/client.yml` and run `sudo systemctl restart ntfy-client`. + +!!! info + The `ntfy-client.service` runs as user `ntfy`, meaning that typical Linux permission restrictions apply. See below + for how to fix this. + +If it runs on your personal desktop machine, you may want to override the service user/group (`User=` and `Group=`), and +adjust the `DISPLAY` and DBUS environment variables. This will allow you to run commands in your X session as the primary +machine user. + +You can either manually override these systemd service entries with `sudo systemctl edit ntfy-client`, and add this +(assuming your user is `pheckel`): + +=== "/etc/systemd/system/ntfy-client.service.d/override.conf" + ``` + [Service] + User=pheckel + Group=pheckel + Environment="DISPLAY=:0" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus" + ``` +Or you can run the following script that creates this override config for you: ``` +sudo sh -c 'cat > /etc/systemd/system/ntfy-client.service.d/override.conf' <