Philipp Heckel hace 4 años
padre
commit
85b4abde6c
Se han modificado 5 ficheros con 123 adiciones y 55 borrados
  1. 19 8
      client/client.yml
  2. 4 4
      client/config.go
  3. 7 12
      cmd/subscribe.go
  4. BIN
      docs/static/img/cli-subscribe-video-3.webm
  5. 93 31
      docs/subscribe/cli.md

+ 19 - 8
client/client.yml

@@ -5,14 +5,25 @@
 #
 #
 # default-host: https://ntfy.sh
 # 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:
 # subscribe:

+ 4 - 4
client/config.go

@@ -7,12 +7,12 @@ const (
 
 
 // Config is the config struct for a Client
 // Config is the config struct for a Client
 type Config struct {
 type Config struct {
-	DefaultHost string
+	DefaultHost string `yaml:"default-host"`
 	Subscribe   []struct {
 	Subscribe   []struct {
-		Topic   string
-		Command string
+		Topic   string `yaml:"topic"`
+		Command string `yaml:"command"`
 		// If []map[string]string TODO This would be cool
 		// If []map[string]string TODO This would be cool
-	}
+	} `yaml:"subscribe"`
 }
 }
 
 
 // NewConfig creates a new Config struct for a Client
 // 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",
 	Usage:     "Subscribe to one or more topics on a ntfy server",
 	UsageText: "ntfy subscribe [OPTIONS..] [TOPIC]",
 	UsageText: "ntfy subscribe [OPTIONS..] [TOPIC]",
 	Action:    execSubscribe,
 	Action:    execSubscribe,
-	OnUsageError: func(context *cli.Context, err error, isSubcommand bool) error {
-		println("ee")
-		return nil
-	},
-
 	Flags: []cli.Flag{
 	Flags: []cli.Flag{
 		&cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "client config file"},
 		&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)"},
 		&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
 	// Execute poll or subscribe
 	if poll {
 	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
 	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
 			return err
 		}
 		}
 	}
 	}
 	if topic != "" {
 	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 err
 		}
 		}
 	}
 	}
 	return nil
 	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...)
 	messages, err := cl.Poll(topic, options...)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -139,7 +134,7 @@ func execPollSingle(c *cli.Context, cl *client.Client, topic, command string, op
 	return nil
 	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)
 	commands := make(map[string]string)
 	for _, s := range conf.Subscribe { // May be nil
 	for _, s := range conf.Subscribe { // May be nil
 		topicURL := cl.Subscribe(s.Topic, options...)
 		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
 !!! info
     The **ntfy CLI is not required to send or receive messages**. You can instead [send messages with curl](../publish.md),
     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 
     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
 ## 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 
 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 
 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. 
 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
 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 
 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
 `trigger`). There are a lot of examples on the page about [publishing messages](../publish.md), but here are a few
 quick ones:
 quick ones:
@@ -56,20 +56,23 @@ quick ones:
     ntfy pub mywebhook
     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
 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 
 will either print or execute a command for every arriving message. There are a few different ways 
 in which the command can be run:
 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
 $ ntfy sub mytopic
 {"id":"nZ8PjH5oox","time":1639971913,"event":"message","topic":"mytopic","message":"hi there"}
 {"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>
 <figure>
@@ -77,15 +80,28 @@ $ ntfy sub mytopic
   <figcaption>Subscribe in JSON mode</figcaption>
   <figcaption>Subscribe in JSON mode</figcaption>
 </figure>
 </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>
 <figure>
   <video controls muted autoplay loop width="650" src="../../static/img/cli-subscribe-video-2.webm"></video>
   <video controls muted autoplay loop width="650" src="../../static/img/cli-subscribe-video-2.webm"></video>
   <figcaption>Execute command on incoming messages</figcaption>
   <figcaption>Execute command on incoming messages</figcaption>
 </figure>
 </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 |
 | Variable | Aliases | Description |
 |---|---|---
 |---|---|---
 | `$NTFY_ID` | `$id` | Unique message ID |
 | `$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_PRIORITY` | `$priority`, `$p` | Message priority (1=min, 5=max) |
 | `$NTFY_TAGS` | `$tags`, `$ta` | Message tags (comma separated list) |
 | `$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
 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
 ### 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]
 [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
+```