Skip to content

Commit 6d7fec5

Browse files
author
Philipp Heckel
committed
Examples and anchors on website
1 parent ba2f6e0 commit 6d7fec5

File tree

8 files changed

+159
-20
lines changed

8 files changed

+159
-20
lines changed

examples/web-example-eventsource/example-ssh.html

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<title>ntfy.sh: EventSource Example</title>
6+
<meta name="robots" content="noindex, nofollow" />
67
<style>
78
body { font-size: 1.2em; line-height: 130%; }
89
#events { font-family: monospace; }
@@ -13,6 +14,7 @@ <h1>ntfy.sh: EventSource Example</h1>
1314
<p>
1415
This is an example showing how to use <a href="https://ntfy.sh">ntfy.sh</a> with
1516
<a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource">EventSource</a>.<br/>
17+
This example doesn't need a server. You can just save the HTML page and run it from anywhere.
1618
</p>
1719
<button id="publishButton">Send test notification</button>
1820
<p><b>Log:</b></p>

server/example.html

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>ntfy.sh: EventSource Example</title>
6+
<meta name="robots" content="noindex, nofollow" />
7+
<style>
8+
body { font-size: 1.2em; line-height: 130%; }
9+
#events { font-family: monospace; }
10+
</style>
11+
</head>
12+
<body>
13+
<h1>ntfy.sh: EventSource Example</h1>
14+
<p>
15+
This is an example showing how to use <a href="https://ntfy.sh">ntfy.sh</a> with
16+
<a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource">EventSource</a>.<br/>
17+
This example doesn't need a server. You can just save the HTML page and run it from anywhere.
18+
</p>
19+
<button id="publishButton">Send test notification</button>
20+
<p><b>Log:</b></p>
21+
<div id="events"></div>
22+
23+
<script type="text/javascript">
24+
const publishURL = `https://ntfy.sh/example`;
25+
const subscribeURL = `https://ntfy.sh/example/sse`;
26+
const events = document.getElementById('events');
27+
const eventSource = new EventSource(subscribeURL);
28+
29+
// Publish button
30+
document.getElementById("publishButton").onclick = () => {
31+
fetch(publishURL, {
32+
method: 'POST', // works with PUT as well, though that sends an OPTIONS request too!
33+
body: `It is ${new Date().toString()}. This is a test.`
34+
})
35+
};
36+
37+
// Incoming events
38+
eventSource.onopen = () => {
39+
let event = document.createElement('div');
40+
event.innerHTML = `EventSource connected to ${subscribeURL}`;
41+
events.appendChild(event);
42+
};
43+
eventSource.onerror = (e) => {
44+
let event = document.createElement('div');
45+
event.innerHTML = `EventSource error: Failed to connect to ${subscribeURL}`;
46+
events.appendChild(event);
47+
};
48+
eventSource.onmessage = (e) => {
49+
let event = document.createElement('div');
50+
event.innerHTML = e.data;
51+
events.appendChild(event);
52+
};
53+
</script>
54+
55+
</body>
56+
</html>

server/index.gohtml

+88-18
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
<h1><img src="static/img/ntfy.png" alt="ntfy"/><br/>ntfy.sh | simple HTTP-based pub-sub</h1>
3939
<p>
4040
<b>Ntfy</b> (pronounce: <i>notify</i>) is a simple HTTP-based <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">pub-sub</a> notification service.
41-
It allows you to send notifications <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy">to your phone</a> or desktop via scripts from any computer,
41+
It allows you to send notifications <a href="#subscribe-phone">to your phone</a> or desktop via scripts from any computer,
4242
entirely <b>without signup or cost</b>. It's also <a href="https://github.com/binwiederhier/ntfy">open source</a> if you want to run your own.
4343
</p>
4444

@@ -53,9 +53,9 @@
5353
</div>
5454

5555
<p>
56-
There are many ways to use Ntfy. You can send yourself messages for all sorts of things: When a long process finishes or fails (a backup, a long rsync job, ...),
56+
There are many ways to use Ntfy. You can send yourself messages for all sorts of things: When a long process finishes or fails,
5757
or to notify yourself when somebody logs into your server(s). Or you may want to use it in your own app to distribute messages to subscribed clients.
58-
Endless possibilities 😀. Be sure to check out the <a href="https://github.com/binwiederhier/ntfy/tree/main/examples">example on GitHub</a>!
58+
Endless possibilities 😀. Be sure to check out the <a href="#examples">examples below</a>.
5959
</p>
6060

6161
<h2 id="publish" class="anchor">Publishing messages</h2>
@@ -104,16 +104,21 @@
104104
<audio id="notifySound" src="static/sound/mixkit-message-pop-alert-2354.mp3"></audio>
105105
</div>
106106

107-
<h3 id="android-app" class="anchor">Subscribe via Android App</h3>
107+
<h3 id="subscribe-phone" class="anchor">Subscribe from your phone</h3>
108108
<p>
109109
You can use the <a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy">Ntfy Android App</a>
110110
to receive notifications directly on your phone. Just like the server, this app is also <a href="https://github.com/binwiederhier/ntfy-android">open source</a>.
111+
Since I don't have an iPhone or a Mac, I didn't make an iOS app yet. I'd be awesome if <a href="https://github.com/binwiederhier/ntfy/issues/4">someone else could help out</a>.
112+
</p>
113+
<p>
114+
<a href="https://play.google.com/store/apps/details?id=io.heckel.ntfy"><img src="static/img/badge-googleplay.png"></a>
115+
<a href="https://github.com/binwiederhier/ntfy/issues/4"><img src="static/img/badge-appstore.png"></a>
111116
</p>
112117

113118
<h3 id="subscribe-api" class="anchor">Subscribe via your app, or via the CLI</h3>
114119
<p class="smallMarginBottom">
115120
Using <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource">EventSource</a> in JS, you can consume
116-
notifications like this (see <a href="https://github.com/binwiederhier/ntfy/tree/main/examples">full example</a>):
121+
notifications like this (see <a href="example.html">live example</a>):
117122
</p>
118123
<code>
119124
const eventSource = new EventSource('https://ntfy.sh/mytopic/sse');<br/>
@@ -149,19 +154,12 @@
149154
<code>
150155
$ curl -s ntfy.sh/mytopic/raw<br/>
151156
<br/>
152-
This is a notification
153-
</code>
154-
<p class="smallMarginBottom">
155-
Here's an example of how to use this endpoint to send desktop notifications for every incoming message:
156-
</p>
157-
<code>
158-
while read msg; do<br/>
159-
&nbsp;&nbsp;[ -n "$msg" ] && notify-send "$msg"<br/>
160-
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/mytopic/raw)
157+
This is a notification<br/>
158+
And another one with a smiley face 😀
161159
</code>
162160

163161
<h2 id="other-features" class="anchor">Other features</h2>
164-
<h3 id="fetching-cached-messages" class="anchor">Fetching cached messages</h3>
162+
<h3 id="fetching-cached-messages" class="anchor">Fetching cached messages (<tt>since=</tt>)</h3>
165163
<p class="smallMarginBottom">
166164
Messages are cached on disk for {{.CacheDuration}} to account for network interruptions of subscribers.
167165
You can read back what you missed by using the <tt>since=</tt> query parameter. It takes either a
@@ -172,7 +170,7 @@
172170
curl -s "ntfy.sh/mytopic/json?since=10m"
173171
</code>
174172

175-
<h3 id="polling" class="anchor">Fetching cached messages</h3>
173+
<h3 id="polling" class="anchor">Polling (<tt>poll=1</tt>)</h3>
176174
<p class="smallMarginBottom">
177175
You can also just poll for messages if you don't like the long-standing connection using the <tt>poll=1</tt>
178176
query parameter. The connection will end after all available messages have been read. This parameter can be
@@ -182,7 +180,7 @@
182180
curl -s "ntfy.sh/mytopic/json?poll=1"
183181
</code>
184182

185-
<h3 id="multiple-topics" class="anchor">Subscribing to multiple topics</h3>
183+
<h3 id="multiple-topics" class="anchor">Subscribing to multiple topics (<tt>topic1,topic2,...</tt>)</h3>
186184
<p class="smallMarginBottom">
187185
It's possible to subscribe to multiple topics in one HTTP call by providing a
188186
comma-separated list of topics in the URL. This allows you to reduce the number of connections you have to maintain:
@@ -194,6 +192,65 @@
194192
{"id":"Cm02DsxUHb","time":1637182643,"event":"message","topic":"mytopic2","message":"for topic 2"}
195193
</code>
196194

195+
<h2 id="examples" class="anchor">Examples</h2>
196+
<p>
197+
There are a million ways to use Ntfy, but here are some inspirations. I try to collect
198+
<a href="https://github.com/binwiederhier/ntfy/tree/main/examples">examples on GitHub</a>, so be sure to check
199+
those out, too.
200+
</p>
201+
202+
<h3 id="example-alerts" class="anchor">Example: A long process is done: backups, copying data, pipelines, ...</h3>
203+
<p class="smallMarginBottom">
204+
I started adding notifications pretty much all of my scripts. Typically, I just chain the <tt>curl</tt> call
205+
directly to the command I'm running. The following example will either send <i>Laptop backup succeeded</i>
206+
or ⚠️ <i>Laptop backup failed</i> directly to my phone:
207+
</p>
208+
<code>
209+
rsync -a root@laptop /backups/laptop \<br/>
210+
&nbsp;&nbsp;&& zfs snapshot ... \<br/>
211+
&nbsp;&nbsp;&& curl -d "Laptop backup succeeded" ntfy.sh/backups \<br/>
212+
&nbsp;&nbsp;|| echo -en "\u26A0\uFE0F Laptop backup failed" | curl -sT- ntfy.sh/backups
213+
</code>
214+
215+
<h3 id="example-web" class="anchor">Example: Server-sent messages in your web app</h3>
216+
<p>
217+
Just as you can <a href="#subscribe-web">subscribe to topics in this Web UI</a>, you can use Ntfy in your own
218+
web application. Check out the <a href="example.html">live example</a> or just look the source of this page.
219+
</p>
220+
221+
<h3 id="example-notify-ssh" class="anchor">Example: Notify on SSH login</h3>
222+
<p>
223+
Years ago my home server was broken into. That shook me hard, so every time someone logs into any machine that I
224+
own, I now message myself. Here's an example of how to use <a href="https://en.wikipedia.org/wiki/Linux_PAM">PAM</a>
225+
to notify yourself on SSH login.
226+
</p>
227+
<p class="smallMarginBottom">
228+
<b>/etc/pam.d/sshd</b> (at the end of the file):
229+
</p>
230+
<code>
231+
session optional pam_exec.so /usr/local/bin/ntfy-ssh-login.sh
232+
</code>
233+
<p class="smallMarginBottom">
234+
<b>/usr/local/bin/ntfy-ssh-login.sh</b>:
235+
</p>
236+
<code>
237+
#!/bin/bash<br/>
238+
if [ "${PAM_TYPE}" = "open_session" ]; then<br/>
239+
&nbsp;&nbsp;echo -en "\u26A0\uFE0F SSH login: ${PAM_USER} from ${PAM_RHOST}" | curl -T- ntfy.sh/alerts<br/>
240+
fi
241+
</code>
242+
243+
<h3 id="example-collect-data" class="anchor">Example: Collect data from multiple machines</h3>
244+
<p>
245+
The other day I was running tasks on 20 servers and I wanted to collect the interim results
246+
as a CSV in one place. Here's the script I wrote:
247+
</p>
248+
<code>
249+
while read result; do<br/>
250+
&nbsp;&nbsp;[ -n "$result" ] && echo "result" >> results.csv<br/>
251+
done < <(stdbuf -i0 -o0 curl -s ntfy.sh/results/raw)
252+
</code>
253+
197254
<h2 id="faq" class="anchor">FAQ</h2>
198255
<p>
199256
<b id="isnt-this-like" class="anchor">Isn't this like ...?</b><br/>
@@ -225,14 +282,27 @@
225282
client network disruptions.
226283
</p>
227284

285+
<p>
286+
<b id="selfhosted" class="anchor">Can I self-host it?</b><br/>
287+
Yes. The server (including this Web UI) can be self-hosted, and the Android app supports adding topics from
288+
your own server as well. There are <a href="https://github.com/binwiederhier/ntfy#installation">install instructions</a>
289+
on GitHub.
290+
</p>
291+
228292
<p>
229293
<b id="why-firebase" class="anchor">Why is Firebase used?</b><br/>
230294
In addition to caching messages locally and delivering them to long-polling subscribers, all messages are also
231295
published to Firebase Cloud Messaging (FCM) (if <tt>FirebaseKeyFile</tt> is set, which it is on ntfy.sh). This
232296
is to facilitate instant notifications on Android.
233297
</p>
234298

235-
<h2 id="#privacy" class="anchor">Privacy policy</h2>
299+
<p>
300+
<b id="why-no-ios" class="anchor">Why is there no iOS app (yet)?</b><br/>
301+
I don't have an iPhone or a Mac, so I didn't make an iOS app yet. I'd be awesome if
302+
<a href="https://github.com/binwiederhier/ntfy/issues/4">someone else could help out</a>.
303+
</p>
304+
305+
<h2 id="privacy" class="anchor">Privacy policy</h2>
236306
<p>
237307
Neither the server nor the app record any personal information, or share any of the messages and topics with
238308
any outside service. All data is exclusively used to make the service function properly. The one exception

server/server.go

+10
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ var (
8888
indexSource string
8989
indexTemplate = template.Must(template.New("index").Parse(indexSource))
9090

91+
//go:embed "example.html"
92+
exampleSource string
93+
9194
//go:embed static
9295
webStaticFs embed.FS
9396

@@ -188,6 +191,8 @@ func (s *Server) handle(w http.ResponseWriter, r *http.Request) {
188191
func (s *Server) handleInternal(w http.ResponseWriter, r *http.Request) error {
189192
if r.Method == http.MethodGet && (r.URL.Path == "/" || topicRegex.MatchString(r.URL.Path)) {
190193
return s.handleHome(w, r)
194+
} else if r.Method == http.MethodGet && r.URL.Path == "/example.html" {
195+
return s.handleExample(w, r)
191196
} else if r.Method == http.MethodHead && r.URL.Path == "/" {
192197
return s.handleEmpty(w, r)
193198
} else if r.Method == http.MethodGet && staticRegex.MatchString(r.URL.Path) {
@@ -217,6 +222,11 @@ func (s *Server) handleEmpty(w http.ResponseWriter, r *http.Request) error {
217222
return nil
218223
}
219224

225+
func (s *Server) handleExample(w http.ResponseWriter, r *http.Request) error {
226+
_, err := io.WriteString(w, exampleSource)
227+
return err
228+
}
229+
220230
func (s *Server) handleStatic(w http.ResponseWriter, r *http.Request) error {
221231
http.FileServer(http.FS(webStaticFs)).ServeHTTP(w, r)
222232
return nil

server/static/css/app.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ h1 {
2828
}
2929

3030
h2 {
31-
margin-top: 20px;
31+
margin-top: 30px;
3232
margin-bottom: 5px;
3333
font-size: 1.8em;
3434
}
3535

3636
h3 {
37-
margin-top: 20px;
37+
margin-top: 25px;
3838
margin-bottom: 5px;
3939
font-size: 1.3em;
4040
}

server/static/img/badge-appstore.png

5.78 KB
Loading
3.72 KB
Loading

server/static/js/app.js

+1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ if (match) {
338338
}
339339
}
340340

341+
// Add anchor links
341342
document.querySelectorAll('.anchor').forEach((el) => {
342343
if (el.hasAttribute('id')) {
343344
const id = el.getAttribute('id');

0 commit comments

Comments
 (0)