Philipp Heckel 4 anos atrás
pai
commit
85b4abde6c

+ 19 - 8
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:

+ 4 - 4
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

+ 7 - 12
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...)

BIN
docs/static/img/cli-subscribe-video-3.webm


+ 93 - 31
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!"}
 ```
 
 <figure>
@@ -77,15 +80,28 @@ $ ntfy sub mytopic
   <figcaption>Subscribe in JSON mode</figcaption>
 </figure>
 
-### 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'
+```
 
 <figure>
   <video controls muted autoplay loop width="650" src="../../static/img/cli-subscribe-video-2.webm"></video>
   <figcaption>Execute command on incoming messages</figcaption>
 </figure>
 
+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).
+
+Here's an example config file that subscribes to three different topics, executing a different command for each of them:
+
+=== "~/.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:
 
-     Examples: 
-       ntfy sub --from-config                           # Read topics from config file
-       ntfy sub --config=/my/client.yml --from-config   # Read topics from alternate config file
+* 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*)
 
-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.
+I hope this shows how powerful this command is. Here's a short video that demonstrates the above example:
 
+<figure>
+  <video controls muted autoplay loop width="650" src="../../static/img/cli-subscribe-video-3.webm"></video>
+  <figcaption>Execute all the things</figcaption>
+</figure>
 
 ### 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' <<EOF
 [Service]
-User=pheckel
-Group=pheckel
-Environment="DISPLAY=:0" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
-```
-
-Here's an example for a complete client config for a self-hosted server:
+User=$USER
+Group=$USER
+Environment="DISPLAY=:0" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus"
+EOF
 
+sudo systemctl daemon-reload
+sudo systemctl restart ntfy-client
+```