Skip to content

Instantly share code, notes, and snippets.

@kane-c
Created June 21, 2016 05:05
Show Gist options
  • Save kane-c/9f18088b77c3019d6e4488ca197361c7 to your computer and use it in GitHub Desktop.
Save kane-c/9f18088b77c3019d6e4488ca197361c7 to your computer and use it in GitHub Desktop.
Create OS level notifications via Python through a web server
#!/usr/bin/env python
"""
Simple server to create OS notifications.
Example usage with Django:
To get a notification when the Django development server is running or has just
reloaded in resoonse to a code change, append this to `wsgi.py`:
```
import requests
try:
requests.post('http://127.0.0.1:31337', json={
'message': "Django server ready",
'title': "My app",
}, timeout=1)
except:
pass
```
In JS:
```
function notify(title, message) {
const http = require('http');
const body = JSON.stringify({
'message': message,
'title': title,
});
const req = new http.ClientRequest({
hostname: '127.0.0.1',
port: 31337,
path: '/',
method: 'POST',
headers: {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'application/json',
},
});
req.end(body);
}
```
To notify when webpack compiles (e.g. during hot reloading):
```
const compiler = webpack(webpackConfig);
compiler.plugin('done', function() {
notify("My app", "webpack ready");
});
new WebpackDevServer(compiler, ...);
```
"""
import argparse
import json
import os
import SimpleHTTPServer
import SocketServer
import subprocess
import sys
__version__ = '1.0.0'
parser = argparse.ArgumentParser(
description="Simple server to create OS notifications."
)
parser.add_argument('ip', nargs='?', default='0.0.0.0',
help="IP address to bind to (default: 0.0.0.0)")
parser.add_argument('-p', '--port', dest='port', default=31337, type=int,
help='The port to listen on (default: 31337)')
def escape(string):
"""Escape a string for use in AppleScript."""
return str(string).replace('"', '\\"')
def send_notification(title, message):
"""Trigger an OS level notification."""
if sys.platform == 'darwin':
# macOS (OS X) 10.8 and above
args = (
'osascript', '-e', 'display notification "%s" with title "%s"' % (
escape(message), escape(title),
)
)
popen = subprocess.Popen(args, stdout=subprocess.PIPE)
popen.wait()
else:
raise NotImplementedError(
"Notifications are not supported for this OS."
)
class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""Handle POST requests."""
def send_status_code(self, code=200):
"""Send a status code and end the headers."""
self.send_response(code)
self.end_headers()
def do_GET(self):
"""Do nothing."""
self.send_response(405)
# Don't handle other standard methods
do_DELETE = do_HEAD = do_OPTIONS = do_PATCH = do_PUT = do_GET
def do_POST(self):
"""Trigger an OS notification."""
content_length = int(self.headers.getheader('content-length', 0))
content_type = self.headers.getheader('content-type',
'application/json').lower()
if not content_type.startswith('application/json'):
return self.send_status_code(415)
try:
body = json.loads(self.rfile.read(content_length))
if 'message' not in body or 'title' not in body:
raise KeyError
except (KeyError, ValueError):
self.send_status_code(400)
return
send_notification(body['title'], body['message'])
self.send_status_code(200)
if __name__ == '__main__':
args = parser.parse_args()
server = SocketServer.TCPServer((args.ip, args.port), RequestHandler)
print("Notification server %s" % __version__)
print("Listening for notifications on %s:%s" % (args.ip, args.port))
try:
server.serve_forever()
except KeyboardInterrupt:
server.server_close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment