Documentation, fix test, return JSON on publish, add --quiet flag for publish
This commit is contained in:
parent
ddd5ce2c21
commit
f24855ca9a
10 changed files with 142 additions and 32 deletions
|
@ -6,6 +6,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -20,6 +21,10 @@ const (
|
|||
OpenEvent = "open"
|
||||
)
|
||||
|
||||
const (
|
||||
maxResponseBytes = 4096
|
||||
)
|
||||
|
||||
// Client is the ntfy client that can be used to publish and subscribe to ntfy topics
|
||||
type Client struct {
|
||||
Messages chan *Message
|
||||
|
@ -63,22 +68,31 @@ func New(config *Config) *Client {
|
|||
//
|
||||
// To pass title, priority and tags, check out WithTitle, WithPriority, WithTagsList, WithDelay, WithNoCache,
|
||||
// WithNoFirebase, and the generic WithHeader.
|
||||
func (c *Client) Publish(topic, message string, options ...PublishOption) error {
|
||||
func (c *Client) Publish(topic, message string, options ...PublishOption) (*Message, error) {
|
||||
topicURL := c.expandTopicURL(topic)
|
||||
req, _ := http.NewRequest("POST", topicURL, strings.NewReader(message))
|
||||
for _, option := range options {
|
||||
if err := option(req); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected response %d from server", resp.StatusCode)
|
||||
return nil, fmt.Errorf("unexpected response %d from server", resp.StatusCode)
|
||||
}
|
||||
return err
|
||||
b, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := toMessage(string(b), topicURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Poll queries a topic for all (or a limited set) of messages. Unlike Subscribe, this method only polls for
|
||||
|
@ -192,14 +206,21 @@ func performSubscribeRequest(ctx context.Context, msgChan chan *Message, topicUR
|
|||
defer resp.Body.Close()
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
for scanner.Scan() {
|
||||
var m *Message
|
||||
line := scanner.Text()
|
||||
if err := json.NewDecoder(strings.NewReader(line)).Decode(&m); err != nil {
|
||||
m, err := toMessage(scanner.Text(), topicURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.TopicURL = topicURL
|
||||
m.Raw = line
|
||||
msgChan <- m
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toMessage(s, topicURL string) (*Message, error) {
|
||||
var m *Message
|
||||
if err := json.NewDecoder(strings.NewReader(s)).Decode(&m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.TopicURL = topicURL
|
||||
m.Raw = s
|
||||
return m, nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package cmd
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/urfave/cli/v2"
|
||||
"heckel.io/ntfy/client"
|
||||
"strings"
|
||||
|
@ -9,17 +10,19 @@ import (
|
|||
|
||||
var cmdPublish = &cli.Command{
|
||||
Name: "publish",
|
||||
Aliases: []string{"pub", "send", "push", "trigger"},
|
||||
Aliases: []string{"pub", "send", "trigger"},
|
||||
Usage: "Send message via a ntfy server",
|
||||
UsageText: "ntfy send [OPTIONS..] TOPIC MESSAGE",
|
||||
UsageText: "ntfy send [OPTIONS..] TOPIC [MESSAGE]",
|
||||
Action: execPublish,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "client config file"},
|
||||
&cli.StringFlag{Name: "title", Aliases: []string{"t"}, Usage: "message title"},
|
||||
&cli.StringFlag{Name: "priority", Aliases: []string{"p"}, Usage: "priority of the message (1=min, 2=low, 3=default, 4=high, 5=max)"},
|
||||
&cli.StringFlag{Name: "tags", Aliases: []string{"ta"}, Usage: "comma separated list of tags and emojis"},
|
||||
&cli.StringFlag{Name: "delay", Aliases: []string{"at", "in"}, Usage: "delay/schedule message"},
|
||||
&cli.StringFlag{Name: "tags", Aliases: []string{"tag", "T"}, Usage: "comma separated list of tags and emojis"},
|
||||
&cli.StringFlag{Name: "delay", Aliases: []string{"at", "in", "D"}, Usage: "delay/schedule message"},
|
||||
&cli.BoolFlag{Name: "no-cache", Aliases: []string{"C"}, Usage: "do not cache message server-side"},
|
||||
&cli.BoolFlag{Name: "no-firebase", Aliases: []string{"F"}, Usage: "do not forward message to Firebase"},
|
||||
&cli.BoolFlag{Name: "quiet", Aliases: []string{"q"}, Usage: "do print message"},
|
||||
},
|
||||
Description: `Publish a message to a ntfy server.
|
||||
|
||||
|
@ -33,12 +36,19 @@ Examples:
|
|||
ntfy trigger mywebhook # Sending without message, useful for webhooks
|
||||
|
||||
Please also check out the docs on publishing messages. Especially for the --tags and --delay options,
|
||||
it has incredibly useful information: https://ntfy.sh/docs/publish/.`,
|
||||
it has incredibly useful information: https://ntfy.sh/docs/publish/.
|
||||
|
||||
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.`,
|
||||
}
|
||||
|
||||
func execPublish(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
return errors.New("topic missing")
|
||||
return errors.New("must specify topic, type 'ntfy publish --help' for help")
|
||||
}
|
||||
conf, err := loadConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
title := c.String("title")
|
||||
priority := c.String("priority")
|
||||
|
@ -46,6 +56,7 @@ func execPublish(c *cli.Context) error {
|
|||
delay := c.String("delay")
|
||||
noCache := c.Bool("no-cache")
|
||||
noFirebase := c.Bool("no-firebase")
|
||||
quiet := c.Bool("quiet")
|
||||
topic := c.Args().Get(0)
|
||||
message := ""
|
||||
if c.NArg() > 1 {
|
||||
|
@ -70,10 +81,13 @@ func execPublish(c *cli.Context) error {
|
|||
if noFirebase {
|
||||
options = append(options, client.WithNoFirebase())
|
||||
}
|
||||
conf, err := loadConfig(c)
|
||||
cl := client.New(conf)
|
||||
m, err := cl.Publish(topic, message, options...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cl := client.New(conf)
|
||||
return cl.Publish(topic, message, options...)
|
||||
if !quiet {
|
||||
fmt.Fprintln(c.App.Writer, strings.TrimSpace(m.Raw))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestCLI_Publish_Real_Server(t *testing.T) {
|
||||
func TestCLI_Publish_Subscribe_Poll_Real_Server(t *testing.T) {
|
||||
testMessage := util.RandomString(10)
|
||||
|
||||
app, _, _, _ := newTestApp()
|
||||
|
|
|
@ -47,6 +47,10 @@ Examples:
|
|||
}
|
||||
|
||||
func execServe(c *cli.Context) error {
|
||||
if c.NArg() > 0 {
|
||||
return errors.New("no arguments expected, see 'ntfy serve --help' for help")
|
||||
}
|
||||
|
||||
// Read all the options
|
||||
listenHTTP := c.String("listen-http")
|
||||
listenHTTPS := c.String("listen-https")
|
||||
|
|
|
@ -26,7 +26,7 @@ var cmdSubscribe = &cli.Command{
|
|||
},
|
||||
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "config file `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.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"},
|
||||
|
@ -72,7 +72,9 @@ ntfy subscribe --from-config
|
|||
Examples:
|
||||
ntfy sub --from-config # Read topics from config file
|
||||
ntfy sub --config=/my/client.yml --from-config # Read topics from alternate config file
|
||||
`,
|
||||
|
||||
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.`,
|
||||
}
|
||||
|
||||
func execSubscribe(c *cli.Context) error {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# Installing ntfy
|
||||
The `ntfy` CLI allows you to [publish messages](publish.md), [subscribe to topics](subscribe/cli.md) as well as to
|
||||
**self-host your own ntfy server**. It's all pretty straight forward. Just install the binary, package or Docker image,
|
||||
The `ntfy` CLI allows you to [publish messages](publish.md), [subscribe to topics](subscribe/cli.md) as well as to
|
||||
self-host your own ntfy server. It's all pretty straight forward. Just install the binary, package or Docker image,
|
||||
configure it and run it. Just like any other software. No fuzz.
|
||||
|
||||
!!! info
|
||||
The following steps are only required if you want to **self-host your own ntfy server** or you want to use the ntfy CLI.
|
||||
The following steps are only required if you want to **self-host your own ntfy server or you want to use the ntfy CLI**.
|
||||
If you just want to [send messages using ntfy.sh](publish.md), you don't need to install anything. You can just use
|
||||
`curl`.
|
||||
|
||||
|
|
4
docs/static/css/extra.css
vendored
4
docs/static/css/extra.css
vendored
|
@ -8,6 +8,10 @@
|
|||
width: unset !important;
|
||||
}
|
||||
|
||||
.admonition {
|
||||
font-size: .74rem !important;
|
||||
}
|
||||
|
||||
article {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Subscribe via API
|
||||
You can create and subscribe to a topic either in the [web UI](web.md), via the [phone app](phone.md), or in your own
|
||||
app or script by subscribing the API. This page describes how to subscribe via API. You may also want to check out the
|
||||
page that describes how to [publish messages](../publish.md).
|
||||
You can create and subscribe to a topic in the [web UI](web.md), via the [phone app](phone.md), via the [ntfy CLI](cli.md),
|
||||
or in your own app or script by subscribing the API. This page describes how to subscribe via API. You may also want to
|
||||
check out the page that describes how to [publish messages](../publish.md).
|
||||
|
||||
The subscription API relies on a simple HTTP GET request with a streaming HTTP response, i.e **you open a GET request and
|
||||
the connection stays open forever**, sending messages back as they come in. There are three different API endpoints, which
|
||||
|
@ -26,6 +26,13 @@ recommended way to subscribe to a topic**. The notable exception is JavaScript,
|
|||
...
|
||||
```
|
||||
|
||||
=== "ntfy CLI"
|
||||
```
|
||||
$ ntfy subcribe disk-alerts
|
||||
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
|
||||
...
|
||||
```
|
||||
|
||||
=== "HTTP"
|
||||
``` http
|
||||
GET /disk-alerts/json HTTP/1.1
|
||||
|
|
|
@ -1,6 +1,64 @@
|
|||
# Subscribe via CLI
|
||||
# Subscribe via ntfy CLI
|
||||
In addition to subscribing via the [web UI](web.md), the [phone app](phone.md), or the [API](api.md), you can subscribe
|
||||
to topics via the ntfy CLI. The CLI is included in the same `ntfy` binary that can be used to [self-host a server](../install.md).
|
||||
|
||||
!!! info
|
||||
The `ntfy subscribe` command is incubating. It's very much work in progress.
|
||||
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. 😀
|
||||
|
||||
## Install + configure
|
||||
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.
|
||||
|
||||
If you just want to use [ntfy.sh](https://ntfy.sh), you don't have to change anything. If you **self-host your own server**,
|
||||
you may want to edit the `default-host` option:
|
||||
|
||||
``` yaml
|
||||
# Base URL used to expand short topic names in the "ntfy publish" and "ntfy subscribe" commands.
|
||||
# If you self-host a ntfy server, you'll likely want to change this.
|
||||
#
|
||||
default-host: https://ntfy.myhost.com
|
||||
```
|
||||
|
||||
## Sending 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:
|
||||
|
||||
=== "Simple send"
|
||||
```
|
||||
ntfy publish mytopic This is a message
|
||||
ntfy publish mytopic "This is a message"
|
||||
ntfy pub mytopic "This is a message"
|
||||
```
|
||||
|
||||
=== "Send with title, priority, and tags"
|
||||
```
|
||||
ntfy publish \
|
||||
--title="Thing sold on eBay" \
|
||||
--priority=high \
|
||||
--tags=partying_face \
|
||||
mytopic \
|
||||
"Somebody just bought the thing that you sell"
|
||||
```
|
||||
|
||||
=== "Triggering a webhook"
|
||||
```
|
||||
ntfy trigger mywebhook
|
||||
ntfy pub mywebhook
|
||||
```
|
||||
|
||||
## Using the systemd 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:
|
||||
|
||||
(This page is a stub. I'll write something once I'm happy with what the command looks like.)
|
||||
|
|
|
@ -74,7 +74,7 @@ nav:
|
|||
- "Subscribing":
|
||||
- "From your phone": subscribe/phone.md
|
||||
- "From the Web UI": subscribe/web.md
|
||||
- "Using the CLI": subscribe/cli.md
|
||||
- "From the CLI": subscribe/cli.md
|
||||
- "Using the API": subscribe/api.md
|
||||
- "Self-hosting":
|
||||
- "Installation": install.md
|
||||
|
|
Loading…
Reference in a new issue