Created
June 21, 2016 05:05
-
-
Save kane-c/9f18088b77c3019d6e4488ca197361c7 to your computer and use it in GitHub Desktop.
Create OS level notifications via Python through a web server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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