Continued docs

pull/29/head
Philipp Heckel 2021-12-03 20:38:21 -05:00
parent 7ba268887b
commit 246061829b
17 changed files with 421 additions and 54 deletions

View File

@ -1,6 +1,7 @@
# Building # Building
## ntfy server ## ntfy server
The ntfy server source code is available [on GitHub](https://github.com/binwiederhier/ntfy).
To quickly build on amd64, you can use `make build-simple`: To quickly build on amd64, you can use `make build-simple`:
``` ```
@ -29,6 +30,7 @@ Releasing (requires goreleaser):
There are currently no platform-specific make targets, so they will build for all platforms (which may take a while). There are currently no platform-specific make targets, so they will build for all platforms (which may take a while).
## Android app ## Android app
The ntfy Android app source code is available [on GitHub](https://github.com/binwiederhier/ntfy-android).
The Android app has two flavors: The Android app has two flavors:
* **Google Play:** The `play` flavor includes Firebase (FCM) and requires a Firebase account * **Google Play:** The `play` flavor includes Firebase (FCM) and requires a Firebase account

View File

@ -1,10 +1,12 @@
# ntfy.sh | simple HTTP-based pub-sub # Getting started
**ntfy** (pronounce: *notify*) is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) **ntfy** (pronounce: *notify*) is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
notification service. It allows you to send notifications to your phone or desktop via scripts from any computer, notification service. It allows you to **send push notifications to your phone or desktop via scripts from any computer**,
entirely **without signup, cost or setup**. It's also [open source](https://github.com/binwiederhier/ntfy) if you want entirely **without signup, cost or setup**. It's [open source](https://github.com/binwiederhier/ntfy) if you want to run your own.
to run your own.
<figure>
<video controls muted autoplay loop width="650" src="static/img/overview.mp4"></video>
<figcaption>Sending push notifications to your Android phone</figcaption>
</figure>
(pub sub diagram)
(screenshot / video / gif)

View File

@ -15,47 +15,120 @@ We support amd64, armv7 and arm64.
Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and Please check out the [releases page](https://github.com/binwiederhier/ntfy/releases) for binaries and
deb/rpm packages. deb/rpm packages.
**x86_64/amd64:** === "x86_64/amd64"
``` ```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_x86_64.tar.gz wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_x86_64.tar.gz
sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy
``` sudo ./ntfy
```
**armv7:** === "armv7/armhf"
``` ```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_armv7.tar.gz wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_armv7.tar.gz
sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy
``` sudo ./ntfy
```
**arm64/v8:** === "arm64"
``` ```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_arm64.tar.gz wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_arm64.tar.gz
sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy sudo tar -C /usr/bin -zxf ntfy_*.tar.gz ntfy
``` sudo ./ntfy
```
## Debian/Ubuntu repository ## Debian/Ubuntu repository
Installation via Debian repository: Installation via Debian repository:
```bash
curl -sSL https://archive.heckel.io/apt/pubkey.txt | sudo apt-key add - === "x86_64/amd64"
sudo apt install apt-transport-https ```bash
sudo sh -c "echo 'deb [arch=amd64] https://archive.heckel.io/apt debian main' > /etc/apt/sources.list.d/archive.heckel.io.list" curl -sSL https://archive.heckel.io/apt/pubkey.txt | sudo apt-key add -
sudo apt update sudo apt install apt-transport-https
sudo apt install ntfy sudo sh -c "echo 'deb [arch=amd64] https://archive.heckel.io/apt debian main' \
``` > /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv7/armhf"
```bash
curl -sSL https://archive.heckel.io/apt/pubkey.txt | sudo apt-key add -
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=armhf] https://archive.heckel.io/apt debian main' \
> /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "arm64"
```bash
curl -sSL https://archive.heckel.io/apt/pubkey.txt | sudo apt-key add -
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=arm64] https://archive.heckel.io/apt debian main' \
> /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
Manually installing the .deb file: Manually installing the .deb file:
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_amd64.deb === "x86_64/amd64"
dpkg -i ntfy_1.5.0_amd64.deb ```bash
``` wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_amd64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv7/armhf"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_armv7.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "arm64"
```bash
wget https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_arm64.deb
sudo dpkg -i ntfy_*.deb
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
## Fedora/RHEL/CentOS ## Fedora/RHEL/CentOS
```bash
rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_amd64.rpm === "x86_64/amd64"
``` ```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_amd64.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "armv7/armhf"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_armv7.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
=== "arm64"
```bash
sudo rpm -ivh https://github.com/binwiederhier/ntfy/releases/download/v1.5.0/ntfy_1.5.0_linux_arm64.rpm
sudo systemctl enable ntfy
sudo systemctl start ntfy
```
## Docker ## Docker
The ntfy server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent The [ntfy image](https://hub.docker.com/r/binwiederhier/ntfy) is available for amd64, armv7 and arm64. It should be pretty
straight forward to use.
The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent
message cache, you also need to map a volume to `/var/cache/ntfy`. To change other settings, you should map `/etc/ntfy`, message cache, you also need to map a volume to `/var/cache/ntfy`. To change other settings, you should map `/etc/ntfy`,
so you can edit `/etc/ntfy/config.yml`. so you can edit `/etc/ntfy/config.yml`.
@ -88,6 +161,7 @@ To install via Go, simply run:
```bash ```bash
go install heckel.io/ntfy@latest go install heckel.io/ntfy@latest
``` ```
!!! info !!! info
Please [let me know](https://github.com/binwiederhier/ntfy/issues) if there are any issues with this installation Please [let me know](https://github.com/binwiederhier/ntfy/issues) if there are any issues with this installation
method. The SQLite bindings require CGO and it works for me, but I have the feeling it may not work for everyone. method. The SQLite bindings require CGO and it works for me, but I have the feeling it may not work for everyone.

View File

@ -1,9 +1,9 @@
# Publishing # Publishing
Publishing messages can be done via HTTP PUT or POST. Topics are created on the fly by subscribing or publishing to them.
Publishing messages can be done via PUT or POST. Topics are created on the fly by subscribing or publishing to them. Because there is no sign-up, **the topic is essentially a password**, so pick something that's not easily guessable.
Because there is no sign-up, <b>the topic is essentially a password</b>, so pick something that's not easily guessable.
Here's an example showing how to publish a simple message using a POST request: Here's an example showing how to publish a simple message using a POST request:
=== "Command line (curl)" === "Command line (curl)"
``` ```
curl -d "Backup successful 😀" ntfy.sh/mytopic curl -d "Backup successful 😀" ntfy.sh/mytopic
@ -31,7 +31,7 @@ Here's an example showing how to publish a simple message using a POST request:
``` ```
=== "PHP" === "PHP"
``` php ``` php-inline
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([ file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [ 'http' => [
'method' => 'POST', // PUT also works 'method' => 'POST', // PUT also works
@ -96,7 +96,7 @@ a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an
``` ```
=== "PHP" === "PHP"
``` php ``` php-inline
file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([ file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
'http' => [ 'http' => [
'method' => 'POST', // PUT also works 'method' => 'POST', // PUT also works
@ -152,7 +152,7 @@ you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
``` ```
=== "PHP" === "PHP"
``` php ``` php-inline
file_get_contents('https://ntfy.sh/controversial', false, stream_context_create([ file_get_contents('https://ntfy.sh/controversial', false, stream_context_create([
'http' => [ 'http' => [
'method' => 'POST', 'method' => 'POST',
@ -218,7 +218,7 @@ You can set the priority with the header `X-Priority` (or any of its aliases: `P
``` ```
=== "PHP" === "PHP"
``` php ``` php-inline
file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([ file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
'http' => [ 'http' => [
'method' => 'POST', 'method' => 'POST',
@ -315,7 +315,7 @@ them with a comma, e.g. `tag1,tag2,tag3`.
``` ```
=== "PHP" === "PHP"
``` php ``` php-inline
file_get_contents('https://ntfy.sh/backups', false, stream_context_create([ file_get_contents('https://ntfy.sh/backups', false, stream_context_create([
'http' => [ 'http' => [
'method' => 'POST', 'method' => 'POST',

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
docs/static/img/badge-fdroid.png vendored 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
docs/static/img/overview.gif vendored 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

BIN
docs/static/img/overview.mp4 vendored 100644

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -1,6 +1,235 @@
# Subscribe via API # 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).
## Fetching cached messages 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
only differ in the response format:
* [JSON stream](#subscribe-as-json-stream): `<topic>/json` returns a JSON stream, with one JSON message object per line
* [SSE stream](#subscribe-as-sse-stream): `<topic>/sse` returns messages as [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events), which
can be used with [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
* [Raw stream](#subscribe-as-raw-stream): `<topic>/raw` returns messages as raw text, with one line per message
## Subscribe as JSON stream
Here are a few examples of how to consume the JSON endpoint (`<topic>/json`). For almost all languages, **this is the
recommended way to subscribe to a topic**. The notable exception is JavaScript, for which the
[SSE/EventSource stream](#subscribe-as-sse-stream) is much easier to work with.
=== "Command line (curl)"
```
$ curl -s ntfy.sh/disk-alerts/json
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}
...
```
=== "HTTP"
``` http
GET /disk-alerts/json HTTP/1.1
Host: ntfy.sh
HTTP/1.1 200 OK
Content-Type: application/x-ndjson; charset=utf-8
Transfer-Encoding: chunked
{"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
{"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Disk full"}
{"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}
...
```
=== "Go"
``` go
resp, err := http.Get("https://ntfy.sh/disk-alerts/json")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
println(scanner.Text())
}
```
=== "PHP"
``` php-inline
$fp = fopen('https://ntfy.sh/disk-alerts/json', 'r');
if (!$fp) die('cannot open stream');
while (!feof($fp)) {
echo fgets($fp, 2048);
flush();
}
fclose($fp);
```
## Subscribe as SSE stream
Using [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) in JavaScript, you can consume
notifications via a [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) stream. It's incredibly
easy to use. Here's what it looks like. You may also want to check out the [live example](/example.html).
=== "Command line (curl)"
```
$ curl -s ntfy.sh/mytopic/sse
event: open
data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"}
data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"}
event: keepalive
data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"}
...
```
=== "HTTP"
``` http
GET /mytopic/sse HTTP/1.1
Host: ntfy.sh
HTTP/1.1 200 OK
Content-Type: text/event-stream; charset=utf-8
Transfer-Encoding: chunked
event: open
data: {"id":"weSj9RtNkj","time":1635528898,"event":"open","topic":"mytopic"}
data: {"id":"p0M5y6gcCY","time":1635528909,"event":"message","topic":"mytopic","message":"Hi!"}
event: keepalive
data: {"id":"VNxNIg5fpt","time":1635528928,"event":"keepalive","topic":"test"}
...
```
=== "JavaScript"
``` javascript
const eventSource = new EventSource('https://ntfy.sh/mytopic/sse');
eventSource.onmessage = (e) => {
console.log(e.data);
};
```
## Subscribe as raw stream
The `/raw` endpoint will output one line per message, and **will only include the message body**. It's useful for extremely
simple scripts, and doesn't include all the data. Additional fields such as [priority](../publish.md#message-priority),
[tags](../publish.md#tags--emojis--) or [message title](../publish.md#message-title) are not included in this output
format. Keepalive messages are sent as empty lines.
=== "Command line (curl)"
```
$ curl -s ntfy.sh/disk-alerts/raw
Disk full
...
```
=== "HTTP"
``` http
GET /disk-alerts/raw HTTP/1.1
Host: ntfy.sh
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Disk full
...
```
=== "Go"
``` go
resp, err := http.Get("https://ntfy.sh/disk-alerts/raw")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
println(scanner.Text())
}
```
=== "PHP"
``` php-inline
$fp = fopen('https://ntfy.sh/disk-alerts/raw', 'r');
if (!$fp) die('cannot open stream');
while (!feof($fp)) {
echo fgets($fp, 2048);
flush();
}
fclose($fp);
```
## JSON message format
Both the [`/json` endpoint](#subscribe-as-json-stream) and the [`/sse` endpoint](#subscribe-as-sse-stream) return a JSON
format of the message. It's very straight forward:
| Field | Required | Type | Example | Description |
|---|---|---|---|---|
| `id` | ✔️ | *string* | `hwQ2YpKdmg` | Randomly chosen message identifier |
| `time` | ✔️ | *int* | 1635528741 | Message date time, as Unix time stamp |
| `event` | ✔️ | `open`, `keepalive` or `message` | `message` | Message type, typically you'd be only interested in `message` |
| `topic` | ✔️ | *string* | `topic1,topic2` | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
| `message` | - | *string* | `Some message` | Message body; always present in `message` events |
| `title` | - | *string* | `Some title` | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/<topic>` |
| `tags` | - | *string array* | `["tag1","tag2"]` | List of [tags](../publish.md#tags--emojis--) that may or not map to emojis |
| `priority` | - | *1, 2, 3, 4, or 5* | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
Here's an example for each message type:
=== "Notification message"
``` json
{
"id": "wze9zgqK41",
"time": 1638542110,
"event": "message",
"topic": "phil_alerts",
"priority": 5,
"tags": [
"warning",
"skull"
],
"title": "Unauthorized access detected",
"message": "Remote access to phils-laptop detected. Act right away."
}
```
=== "Notification message (minimal)"
``` json
{
"id": "wze9zgqK41",
"time": 1638542110,
"event": "message",
"topic": "phil_alerts",
"message": "Remote access to phils-laptop detected. Act right away."
}
```
=== "Open message"
``` json
{
"id": "2pgIAaGrQ8",
"time": 1638542215,
"event": "open",
"topic": "phil_alerts"
}
```
=== "Keepalive message"
``` json
{
"id": "371sevb0pD",
"time": 1638542275,
"event": "keepalive",
"topic": "phil_alerts"
}
```
## Advanced features
### Fetching cached messages
Messages may be cached for a couple of hours (see [message caching](../config.md#message-cache)) to account for network Messages may be cached for a couple of hours (see [message caching](../config.md#message-cache)) to account for network
interruptions of subscribers. If the server has configured message caching, you can read back what you missed by using interruptions of subscribers. If the server has configured message caching, you can read back what you missed by using
the `since=` query parameter. It takes either a duration (e.g. `10m` or `30s`), a Unix timestamp (e.g. `1635528757`) the `since=` query parameter. It takes either a duration (e.g. `10m` or `30s`), a Unix timestamp (e.g. `1635528757`)
@ -10,7 +239,7 @@ or `all` (all cached messages).
curl -s "ntfy.sh/mytopic/json?since=10m" curl -s "ntfy.sh/mytopic/json?since=10m"
``` ```
## Polling ### Polling
You can also just poll for messages if you don't like the long-standing connection using the `poll=1` You can also just poll for messages if you don't like the long-standing connection using the `poll=1`
query parameter. The connection will end after all available messages have been read. This parameter can be query parameter. The connection will end after all available messages have been read. This parameter can be
combined with `since=` (defaults to `since=all`). combined with `since=` (defaults to `since=all`).
@ -19,7 +248,7 @@ combined with `since=` (defaults to `since=all`).
curl -s "ntfy.sh/mytopic/json?poll=1" curl -s "ntfy.sh/mytopic/json?poll=1"
``` ```
## Subscribing to multiple topics ### Subscribing to multiple topics
It's possible to subscribe to multiple topics in one HTTP call by providing a It's possible to subscribe to multiple topics in one HTTP call by providing a
comma-separated list of topics in the URL. This allows you to reduce the number of connections you have to maintain: comma-separated list of topics in the URL. This allows you to reduce the number of connections you have to maintain:

View File

@ -3,5 +3,20 @@ You can use the [ntfy Android App](https://play.google.com/store/apps/details?id
notifications directly on your phone. Just like the server, this app is also [open source](https://github.com/binwiederhier/ntfy-android). notifications directly on your phone. Just like the server, this app is also [open source](https://github.com/binwiederhier/ntfy-android).
Since I don't have an iPhone or a Mac, I didn't make an iOS app yet. I'd be awesome if [someone else could help out](https://github.com/binwiederhier/ntfy/issues/4). Since I don't have an iPhone or a Mac, I didn't make an iOS app yet. I'd be awesome if [someone else could help out](https://github.com/binwiederhier/ntfy/issues/4).
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="static/img/badge-googleplay.png"></a> ## Android
<a href="https://github.com/binwiederhier/ntfy/issues/4"><img src="static/img/badge-appstore.png"></a> You can get the Android app from both [Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) and
from [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/). Both are largely identical, with the one exception that
the F-Droid flavor does not use Firebase.
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="../../static/img/badge-googleplay.png"></a>
<a href="https://f-droid.org/en/packages/io.heckel.ntfy/"><img src="../../static/img/badge-fdroid.png"></a>
### Firebase + Instant delivery
## iPhone/iOS
I almost feel devious for putting the *Download on the App Store* button on this page. Currently, there is no iOS app
for ntfy, but it's in the works. You can track the status on GitHub.
<a href="https://github.com/binwiederhier/ntfy/issues/4"><img src="../../static/img/badge-appstore.png"></a>

View File

@ -1 +1,11 @@
# Subscribe from the web UI # Subscribe from the Web UI
You can use the Web UI to subscribe to topics as well. If you do, and you keep the website open, **notifications will
pop up as desktop notifications**. Simply type in the topic name and click the *Subscribe* button. The browser will
keep a connection open and listen for incoming notifications.
<figure markdown>
![web subscribe](../static/img/screenshot-web.png){ width=300 }
<figcaption>Subscribe via Web UI</figcaption>
</figure>
Once subscribed, you can [publish messages](../publish.md) via `curl` or from without any of your scripts.

View File

@ -0,0 +1,19 @@
package main
import (
"bufio"
"log"
"net/http"
)
func main() {
resp, err := http.Get("https://ntfy.sh/phil_alerts/json")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
println(scanner.Text())
}
}

View File

@ -0,0 +1,12 @@
<?php
$fp = fopen('https://ntfy.sh/phil_alerts/json', 'r');
if (!$fp) {
die('cannot open stream');
}
while (!feof($fp)) {
$buffer = fgets($fp, 2048);
echo $buffer;
flush();
}
fclose($fp);

View File

@ -33,6 +33,7 @@ theme:
- search.highlight - search.highlight
- search.share - search.share
- navigation.sections - navigation.sections
- navigation.instant
- toc.integrate - toc.integrate
- content.tabs.link - content.tabs.link
extra_javascript: extra_javascript:
@ -42,17 +43,20 @@ extra_css:
markdown_extensions: markdown_extensions:
- admonition - admonition
- codehilite
- meta - meta
- toc: - toc:
permalink: true permalink: true
- pymdownx.tabbed: - pymdownx.tabbed:
alternate_style: true alternate_style: true
- pymdownx.superfences - pymdownx.superfences
- pymdownx.highlight - pymdownx.highlight:
extend_pygments_lang:
- name: php-inline
lang: php
options:
startinline: true
- pymdownx.tasklist: - pymdownx.tasklist:
custom_checkbox: true custom_checkbox: true
- footnotes
- attr_list - attr_list
- md_in_html - md_in_html
@ -71,7 +75,7 @@ nav:
- "Publishing": - "Publishing":
- "Sending messages": publish.md - "Sending messages": publish.md
- "Subscribing": - "Subscribing":
- "From the Android/iOS app": subscribe/phone.md - "From your phone": subscribe/phone.md
- "From the Web UI": subscribe/web.md - "From the Web UI": subscribe/web.md
- "Using the API": subscribe/api.md - "Using the API": subscribe/api.md
- "Other things": - "Other things":