Browse Source

home redirect + http port configurable

boyska 4 years ago
parent
commit
0a7cad0e2d
3 changed files with 140 additions and 126 deletions
  1. 31 28
      larigira/config.py
  2. 34 29
      larigira/larigira.py
  3. 75 69
      larigira/rpc.py

+ 31 - 28
larigira/config.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python
-'''
+"""
 Taken from flask-appconfig
-'''
+"""
 
 import json
 import os
@@ -9,30 +9,32 @@ import os
 from xdg import BaseDirectory
 
 
-def get_conf(prefix='LARIGIRA_'):
-    '''This is where everyone should get configuration from'''
-    conf_dir = BaseDirectory.save_config_path('larigira')
+def get_conf(prefix="LARIGIRA_"):
+    """This is where everyone should get configuration from"""
+    conf_dir = BaseDirectory.save_config_path("larigira")
     conf = {}
-    conf['CONTINOUS_AUDIOSPEC'] = dict(kind='mpd', howmany=1)
-    conf['MPD_HOST'] = os.getenv('MPD_HOST', 'localhost')
-    conf['MPD_PORT'] = int(os.getenv('MPD_PORT', '6600'))
-    conf['CACHING_TIME'] = 10
-    conf['DB_URI'] = os.path.join(conf_dir, 'db.json')
-    conf['SCRIPTS_PATH'] = os.path.join(conf_dir, 'scripts')
-    conf['ROUTE_PREFIX'] = ''
-    conf['BOOTSTRAP_SERVE_LOCAL'] = True
-    conf['SECRET_KEY'] = 'Please replace me!'
-    conf['MPD_WAIT_START'] = True
-    conf['MPD_WAIT_START_RETRYSECS'] = 5
-    conf['CHECK_SECS'] = 20   # period for checking playlist length
-    conf['EVENT_TICK_SECS'] = 30  # period for scheduling events
-    conf['DEBUG'] = False
-    conf['LOG_CONFIG'] = False
-    conf['TMPDIR'] = os.getenv('TMPDIR', '/tmp/')
-    conf['FILE_PATH_SUGGESTION'] = ()  # tuple of paths
-    conf['UI_CALENDAR_FREQUENCY_THRESHOLD'] = 4*60*60  # 4 hours
-    conf['UI_CALENDAR_DATE_FMT'] = 'medium'
-    conf['EVENT_FILTERS'] = []
+    conf["CONTINOUS_AUDIOSPEC"] = dict(kind="mpd", howmany=1)
+    conf["MPD_HOST"] = os.getenv("MPD_HOST", "localhost")
+    conf["MPD_PORT"] = int(os.getenv("MPD_PORT", "6600"))
+    conf["CACHING_TIME"] = 10
+    conf["DB_URI"] = os.path.join(conf_dir, "db.json")
+    conf["SCRIPTS_PATH"] = os.path.join(conf_dir, "scripts")
+    conf["ROUTE_PREFIX"] = ""
+    conf["BOOTSTRAP_SERVE_LOCAL"] = True
+    conf["SECRET_KEY"] = "Please replace me!"
+    conf["MPD_WAIT_START"] = True
+    conf["MPD_WAIT_START_RETRYSECS"] = 5
+    conf["CHECK_SECS"] = 20  # period for checking playlist length
+    conf["EVENT_TICK_SECS"] = 30  # period for scheduling events
+    conf["DEBUG"] = False
+    conf["LOG_CONFIG"] = False
+    conf["TMPDIR"] = os.getenv("TMPDIR", "/tmp/")
+    conf["FILE_PATH_SUGGESTION"] = ()  # tuple of paths
+    conf["UI_CALENDAR_FREQUENCY_THRESHOLD"] = 4 * 60 * 60  # 4 hours
+    conf["UI_CALENDAR_DATE_FMT"] = "medium"
+    conf["EVENT_FILTERS"] = []
+    conf["HTTP_PORT"] = 5000
+    conf["HOME_URL"] = "/db/calendar"
     conf.update(from_envvars(prefix=prefix))
     return conf
 
@@ -54,15 +56,16 @@ def from_envvars(prefix=None, envvars=None, as_json=True):
     """
     conf = {}
     if prefix is None and envvars is None:
-        raise RuntimeError('Must either give prefix or envvars argument')
+        raise RuntimeError("Must either give prefix or envvars argument")
 
     # if it's a list, convert to dict
     if isinstance(envvars, list):
         envvars = {k: None for k in envvars}
 
     if not envvars:
-        envvars = {k: k[len(prefix):] for k in os.environ.keys()
-                   if k.startswith(prefix)}
+        envvars = {
+            k: k[len(prefix) :] for k in os.environ.keys() if k.startswith(prefix)
+        }
 
     for env_name, name in envvars.items():
         if name is None:

+ 34 - 29
larigira/larigira.py

@@ -1,8 +1,9 @@
-'''
+"""
 This module is for the main application logic
-'''
+"""
 from __future__ import print_function
 from gevent import monkey
+
 monkey.patch_all(subprocess=True)
 
 import sys
@@ -29,12 +30,13 @@ def on_main_crash(*args, **kwargs):
 
 class Larigira(object):
     def __init__(self):
-        self.log = logging.getLogger('larigira')
+        self.log = logging.getLogger("larigira")
         self.conf = get_conf()
         self.controller = Controller(self.conf)
         self.controller.link_exception(on_main_crash)
-        self.http_server = WSGIServer(('', 5000),
-                                      create_app(self.controller.q, self))
+        self.http_server = WSGIServer(
+            ("", int(self.conf["HTTP_PORT"])), create_app(self.controller.q, self)
+        )
 
     def start(self):
         self.controller.start()
@@ -42,11 +44,11 @@ class Larigira(object):
 
 
 def sd_notify(ready=False, status=None):
-    args = ['systemd-notify']
+    args = ["systemd-notify"]
     if ready:
-        args.append('--ready')
+        args.append("--ready")
     if status is not None:
-        args.append('--status')
+        args.append("--status")
         args.append(status)
     try:
         subprocess.check_call(args)
@@ -55,43 +57,46 @@ def sd_notify(ready=False, status=None):
 
 
 def main():
-    tempfile.tempdir = os.environ['TMPDIR'] = os.path.join(
-        os.getenv('TMPDIR', '/tmp'),
-        'larigira.%d' % os.getuid())
-    if not os.path.isdir(os.environ['TMPDIR']):
-        os.makedirs(os.environ['TMPDIR'])
-    if get_conf()['LOG_CONFIG']:
-        logging.config.fileConfig(get_conf()['LOG_CONFIG'],
-                                  disable_existing_loggers=True)
+    tempfile.tempdir = os.environ["TMPDIR"] = os.path.join(
+        os.getenv("TMPDIR", "/tmp"), "larigira.%d" % os.getuid()
+    )
+    if not os.path.isdir(os.environ["TMPDIR"]):
+        os.makedirs(os.environ["TMPDIR"])
+    if get_conf()["LOG_CONFIG"]:
+        logging.config.fileConfig(
+            get_conf()["LOG_CONFIG"], disable_existing_loggers=True
+        )
     else:
-        log_format = '%(asctime)s|%(levelname)s[%(name)s:%(lineno)d] %(message)s'
-        logging.basicConfig(level=logging.DEBUG if get_conf()['DEBUG'] else logging.INFO,
-                            format=log_format,
-                            datefmt='%H:%M:%S')
-    if(get_conf()['MPD_WAIT_START']):
+        log_format = "%(asctime)s|%(levelname)s[%(name)s:%(lineno)d] %(message)s"
+        logging.basicConfig(
+            level=logging.DEBUG if get_conf()["DEBUG"] else logging.INFO,
+            format=log_format,
+            datefmt="%H:%M:%S",
+        )
+    if get_conf()["MPD_WAIT_START"]:
         while True:
             try:
                 get_mpd_client(get_conf())
             except Exception:
                 logging.debug("Could not connect to MPD, waiting")
-                sd_notify(status='Waiting MPD connection')
-                sleep(int(get_conf()['MPD_WAIT_START_RETRYSECS']))
+                sd_notify(status="Waiting MPD connection")
+                sleep(int(get_conf()["MPD_WAIT_START_RETRYSECS"]))
             else:
                 logging.info("MPD ready!")
-                sd_notify(ready=True, status='Ready')
+                sd_notify(ready=True, status="Ready")
                 break
 
-
-
     larigira = Larigira()
     larigira.start()
 
     def sig(*args):
-        print('invoked sig', args)
-        larigira.controller.q.put(dict(kind='signal', args=args))
+        print("invoked sig", args)
+        larigira.controller.q.put(dict(kind="signal", args=args))
+
     for signum in (signal.SIGHUP, signal.SIGALRM):
         gevent.signal(signum, sig, signum)
     gevent.wait()
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     main()

+ 75 - 69
larigira/rpc.py

@@ -3,8 +3,16 @@ import gc
 from copy import deepcopy
 
 from greenlet import greenlet
-from flask import current_app, Blueprint, Flask, jsonify, render_template, \
-        request, abort
+from flask import (
+    current_app,
+    Blueprint,
+    Flask,
+    jsonify,
+    render_template,
+    request,
+    abort,
+    redirect,
+)
 from flask_bootstrap import Bootstrap
 from flask.ext.babel import Babel
 from werkzeug.contrib.cache import SimpleCache
@@ -12,79 +20,80 @@ from werkzeug.contrib.cache import SimpleCache
 from .dbadmin import db
 from .config import get_conf
 
-rpc = Blueprint('rpc', __name__,
-                url_prefix=get_conf()['ROUTE_PREFIX'] + '/api')
-viewui = Blueprint('view', __name__,
-                   url_prefix=get_conf()['ROUTE_PREFIX'] + '/view',
-                   template_folder='templates')
+rpc = Blueprint("rpc", __name__, url_prefix=get_conf()["ROUTE_PREFIX"] + "/api")
+viewui = Blueprint(
+    "view",
+    __name__,
+    url_prefix=get_conf()["ROUTE_PREFIX"] + "/view",
+    template_folder="templates",
+)
 
 
 def send_to_parent(kind, *args):
-    '''similar to the behaviour of a ParentedLet'''
-    if not hasattr(current_app, 'queue'):
-        logging.debug('no parent queue; aborting send')
+    """similar to the behaviour of a ParentedLet"""
+    if not hasattr(current_app, "queue"):
+        logging.debug("no parent queue; aborting send")
         return
     msg = {
-        'emitter': current_app._get_current_object(),
-        'class': current_app._get_current_object().__class__.__name__,
-        'kind': kind,
-        'args': args
+        "emitter": current_app._get_current_object(),
+        "class": current_app._get_current_object().__class__.__name__,
+        "kind": kind,
+        "args": args,
     }
     current_app.queue.put(msg)
 
 
-@rpc.route('/')
+@rpc.route("/")
 def rpc_index():
     rules = list(current_app.url_map.iter_rules())
-    return jsonify({'rules': [r.rule for r in rules
-                              if r.rule.startswith('/api')]})
+    return jsonify({"rules": [r.rule for r in rules if r.rule.startswith("/api")]})
 
 
-@rpc.route('/refresh')
+@rpc.route("/refresh")
 def rpc_refresh():
-    send_to_parent('refresh')
-    return jsonify(dict(status='ok'))
+    send_to_parent("refresh")
+    return jsonify(dict(status="ok"))
 
 
-@rpc.route('/audiospec', methods=['GET'])
+@rpc.route("/audiospec", methods=["GET"])
 def get_audiospec():
     return jsonify(current_app.larigira.controller.player.continous_audiospec)
 
 
-@rpc.route('/audiospec', methods=['PUT'])
+@rpc.route("/audiospec", methods=["PUT"])
 def change_audiospec():
     player = current_app.larigira.controller.player
     if request.json is None:
         abort(400, "Must send application/json data")
-    if 'spec' not in request.json or type(request.json['spec']) is not dict:
+    if "spec" not in request.json or type(request.json["spec"]) is not dict:
         abort(400, "Object must have a key 'spec' whose value is an object")
-    player.continous_audiospec = request.json['spec']
-    if 'kind' not in request.json['spec']:
+    player.continous_audiospec = request.json["spec"]
+    if "kind" not in request.json["spec"]:
         abort(400, "invalid audiospec")
     return jsonify(player.continous_audiospec)
 
 
-@rpc.route('/audiospec', methods=['DELETE'])
+@rpc.route("/audiospec", methods=["DELETE"])
 def reset_audiospec():
     player = current_app.larigira.controller.player
     player.continous_audiospec = None
     return jsonify(player.continous_audiospec)
 
 
-@rpc.route('/eventsenabled/toggle', methods=['POST'])
+@rpc.route("/eventsenabled/toggle", methods=["POST"])
 def toggle_events_enabled():
     status = current_app.larigira.controller.player.events_enabled
     current_app.larigira.controller.player.events_enabled = not status
     return jsonify(dict(events_enabled=not status))
 
 
-@rpc.route('/eventsenabled', methods=['GET'])
+@rpc.route("/eventsenabled", methods=["GET"])
 def get_events_enabled():
     status = current_app.larigira.controller.player.events_enabled
     return jsonify(dict(events_enabled=status))
 
 
-@rpc.route('/eventsenabled', methods=['PUT'])
+@rpc.route("/eventsenabled", methods=["PUT"])
 def set_events_enabled():
     player = current_app.larigira.controller.player
     if request.json is None:
@@ -102,45 +111,42 @@ def get_scheduled_audiogen():
     for timespec_eid in events:
         orig_info = running[timespec_eid]
         info = events[timespec_eid]
-        info['running_time'] = orig_info['running_time'].isoformat()
-        info['audiospecs'] = orig_info['audiospecs']
-        info['timespec'] = orig_info['timespec']
-        info['timespec']['actions'] = {aid: spec
-                                       for aid, spec
-                                       in zip(info['timespec']['actions'],
-                                              info['audiospecs'])
-                                       }
-        info['greenlet'] = hex(id(orig_info['greenlet']))
+        info["running_time"] = orig_info["running_time"].isoformat()
+        info["audiospecs"] = orig_info["audiospecs"]
+        info["timespec"] = orig_info["timespec"]
+        info["timespec"]["actions"] = {
+            aid: spec
+            for aid, spec in zip(info["timespec"]["actions"], info["audiospecs"])
+        }
+        info["greenlet"] = hex(id(orig_info["greenlet"]))
     return events
 
 
-@viewui.route('/status/running')
+@viewui.route("/status/running")
 def ui_wip():
     audiogens = get_scheduled_audiogen()
-    return render_template('running.html',
-                           audiogens=sorted(
-                               audiogens.items(),
-                               key=lambda x: x[1]['running_time'])
-                           )
+    return render_template(
+        "running.html",
+        audiogens=sorted(audiogens.items(), key=lambda x: x[1]["running_time"]),
+    )
 
 
-@rpc.route('/debug/running')
+@rpc.route("/debug/running")
 def rpc_wip():
     def treeify(flat):
-        roots = [obid for obid in flat if flat[obid]['parent'] not in flat]
+        roots = [obid for obid in flat if flat[obid]["parent"] not in flat]
         tree = deepcopy(flat)
         for obid in tree:
-            tree[obid]['children'] = {}
+            tree[obid]["children"] = {}
 
         to_remove = []
         for obid in tree:
             if obid in roots:
                 continue
             if obid not in tree:
-                current_app.logger.warning('How strange, {} not in tree'
-                                        .format(obid))
+                current_app.logger.warning("How strange, {} not in tree".format(obid))
                 continue
-            tree[tree[obid]['parent']]['children'][obid] = tree[obid]
+            tree[tree[obid]["parent"]]["children"][obid] = tree[obid]
             to_remove.append(obid)
 
         for obid in to_remove:
@@ -148,30 +154,28 @@ def rpc_wip():
         return tree
 
     greenlets = {}
-    for ob in filter(lambda obj: isinstance(obj, greenlet),
-                     gc.get_objects()):
-        objrepr = {
-            'repr': repr(ob),
-            'class': ob.__class__.__name__,
-        }
-        if hasattr(ob, 'parent_greenlet') and ob.parent_greenlet is not None:
-            objrepr['parent'] = hex(id(ob.parent_greenlet))
+    for ob in filter(lambda obj: isinstance(obj, greenlet), gc.get_objects()):
+        objrepr = {"repr": repr(ob), "class": ob.__class__.__name__}
+        if hasattr(ob, "parent_greenlet") and ob.parent_greenlet is not None:
+            objrepr["parent"] = hex(id(ob.parent_greenlet))
         else:
-            objrepr['parent'] = hex(id(ob.parent)) \
-                    if ob.parent is not None else None
-        if hasattr(ob, 'doc'):
-            objrepr['doc'] = ob.doc.split('\n')[0]
+            objrepr["parent"] = hex(id(ob.parent)) if ob.parent is not None else None
+        if hasattr(ob, "doc"):
+            objrepr["doc"] = ob.doc.split("\n")[0]
         elif ob.__doc__:
-            objrepr['doc'] = ob.__doc__.split('\n')[0]
+            objrepr["doc"] = ob.__doc__.split("\n")[0]
 
         greenlets[hex(id(ob))] = objrepr
 
     # TODO: make it a tree
 
-    return jsonify(dict(greenlets=greenlets,
-                        greenlets_tree=treeify(greenlets),
-                        audiogens=get_scheduled_audiogen(),
-                        ))
+    return jsonify(
+        dict(
+            greenlets=greenlets,
+            greenlets_tree=treeify(greenlets),
+            audiogens=get_scheduled_audiogen(),
+        )
+    )
 
 
 def babel_get_locale():
@@ -183,8 +187,7 @@ def babel_get_locale():
 
 
 def create_app(queue, larigira):
-    app = Flask('larigira',
-                static_url_path=get_conf()['ROUTE_PREFIX'] + '/static')
+    app = Flask("larigira", static_url_path=get_conf()["ROUTE_PREFIX"] + "/static")
     app.config.update(get_conf())
     Bootstrap(app)
     babel = Babel(app)
@@ -192,6 +195,9 @@ def create_app(queue, larigira):
     app.register_blueprint(rpc)
     app.register_blueprint(viewui)
     app.register_blueprint(db)
+    app.route("/")(
+        lambda: redirect(get_conf()["ROUTE_PREFIX"] + get_conf()["HOME_URL"])
+    )
     app.queue = queue
     app.larigira = larigira
     app.cache = SimpleCache()