summaryrefslogtreecommitdiff
path: root/Que/client.py
diff options
context:
space:
mode:
authorBen Sima <ben@bsima.me>2020-04-15 09:54:10 -0700
committerBen Sima <ben@bsima.me>2020-04-15 10:06:56 -0700
commitf4b8c0df041b063c0b47d2ec6c818a9c202fd833 (patch)
tree01ad246a83fda29c079847b3397ca6509a7f6106 /Que/client.py
parent6ed475ca94209ce92e75f48764cb9d361029ea26 (diff)
Re-namespacing
Moving away from the DNS-driven namespacing toward more condensed names, mostly because I don't like typing so much.
Diffstat (limited to 'Que/client.py')
-rwxr-xr-xQue/client.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/Que/client.py b/Que/client.py
new file mode 100755
index 0000000..3d9291d
--- /dev/null
+++ b/Que/client.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python3
+"""
+simple client for que.run
+"""
+
+import argparse
+import configparser
+import http.client
+import os
+import subprocess
+import sys
+import time
+import urllib.parse
+import urllib.request as request
+
+MAX_TIMEOUT = 99999999 # basically never timeout
+
+
+def auth(args):
+ ns = args.target.split("/")[0]
+ if ns == "pub":
+ return None
+ else:
+ conf_file = os.path.expanduser("~/.config/que.conf")
+ if not os.path.exists(conf_file):
+ sys.exit("you need a ~/.config/que.conf")
+ cfg = configparser.ConfigParser()
+ cfg.read(conf_file)
+ return cfg[ns]["key"]
+
+
+def send(args):
+ "Send a message to the que."
+ key = auth(args)
+ data = args.infile
+ req = request.Request(f"{args.host}/{args.target}")
+ req.add_header("User-AgenT", "Que/Client")
+ if key:
+ req.add_header("Authorization", key)
+ if args.serve:
+ while not time.sleep(1):
+ request.urlopen(req, data=data, timeout=MAX_TIMEOUT)
+
+ else:
+ request.urlopen(req, data=data, timeout=MAX_TIMEOUT)
+
+
+def recv(args):
+ "Receive a message from the que."
+
+ def _recv(_req):
+ msg = autodecode(_req.read())
+ print(msg)
+ if args.then:
+ subprocess.run(
+ args.then.replace("\msg", msg).replace("\que", args.target), shell=True
+ )
+
+ params = urllib.parse.urlencode({"poll": args.poll})
+ req = request.Request(f"{args.host}/{args.target}?{params}")
+ req.add_header("User-Agent", "Que/Client")
+ key = auth(args)
+ if key:
+ req.add_header("Authorization", key)
+ with request.urlopen(req) as _req:
+ if args.poll:
+ while not time.sleep(1):
+ _recv(_req)
+ else:
+ _recv(_req)
+
+
+def autodecode(b):
+ """Attempt to decode bytes `b` into common codecs, preferably utf-8. If
+ no decoding is available, just return the raw bytes.
+
+ For all available codecs, see:
+ <https://docs.python.org/3/library/codecs.html#standard-encodings>
+
+ """
+ codecs = ["utf-8", "ascii"]
+ for codec in codecs:
+ try:
+ return b.decode(codec)
+ except UnicodeDecodeError:
+ pass
+ return b
+
+
+def get_args():
+ cli = argparse.ArgumentParser(description=__doc__)
+ cli.add_argument(
+ "--host", default="http://que.run", help="where que-server is running"
+ )
+ cli.add_argument(
+ "--poll", default=False, action="store_true", help="stream data from the que"
+ )
+ cli.add_argument(
+ "--then",
+ help=" ".join(
+ [
+ "when polling, run this shell command after each response,",
+ "presumably for side effects,"
+ "replacing '\que' with the target and '\msg' with the body of the response",
+ ]
+ ),
+ )
+ cli.add_argument(
+ "--serve",
+ default=False,
+ action="store_true",
+ help=" ".join(
+ [
+ "when posting to the que, do so continuously in a loop.",
+ "this can be used for serving a webpage or other file continuously",
+ ]
+ ),
+ )
+ cli.add_argument(
+ "target", help="namespace and path of the que, like 'ns/path/subpath'"
+ )
+ cli.add_argument(
+ "infile",
+ nargs="?",
+ type=argparse.FileType("rb"),
+ help="data to put on the que. Use '-' for stdin, otherwise should be a readable file",
+ )
+ return cli.parse_args()
+
+
+if __name__ == "__main__":
+ args = get_args()
+ try:
+ if args.infile:
+ send(args)
+ else:
+ recv(args)
+ except KeyboardInterrupt:
+ sys.exit(0)
+ except urllib.error.HTTPError as e:
+ print(e)
+ sys.exit(1)
+ except http.client.RemoteDisconnected as e:
+ print("disconnected... retrying in 5 seconds")
+ time.sleep(5)
+ if args.infile:
+ send(args)
+ else:
+ recv(args)