From 4c4f332f55a09d7bc3d9857534b1f4440f7dbbda Mon Sep 17 00:00:00 2001 From: boyska Date: Mon, 23 Dec 2013 19:58:44 +0100 Subject: [PATCH] Forge timeout + forge from CLI Usage is different now: you must switch to calling "cli.py serve" for the previous "server.py" behaviour --- server/cli.py | 79 ++++++++++++++++++++++++++++++++++++++++ server/default_config.py | 15 ++++---- server/forge.py | 24 ++++++++++-- server/server.py | 41 +-------------------- 4 files changed, 108 insertions(+), 51 deletions(-) create mode 100644 server/cli.py diff --git a/server/cli.py b/server/cli.py new file mode 100644 index 0000000..7ed11b4 --- /dev/null +++ b/server/cli.py @@ -0,0 +1,79 @@ +import os +import sys +from argparse import ArgumentParser, Action +from datetime import datetime +import logging +logger = logging.getLogger('cli') + +import forge +from config_manager import get_config +import server + +def pre_check_permissions(): + import sys + + def is_writable(d): + return os.access(d, os.W_OK) + + if is_writable(get_config()['AUDIO_INPUT']): + yield "Audio input '%s' writable" % get_config()['AUDIO_INPUT'] + if not os.access(get_config()['AUDIO_INPUT'], os.R_OK): + yield "Audio input '%s' unreadable" % get_config()['AUDIO_INPUT'] + sys.exit(10) + if is_writable(os.getcwd()): + yield "Code writable" + if not is_writable(get_config()['AUDIO_OUTPUT']): + yield "Audio output '%s' not writable" % get_config()['AUDIO_OUTPUT'] + sys.exit(10) + +def pre_check_user(): + if os.geteuid() == 0: + yield "You're running as root; this is dangerous" + + +class DateTimeAction(Action): + def __call__(self, parser, namespace, values, option_string=None): + if len(values) == 15: + parsed_val = datetime.strptime(values, '%Y%m%d-%H%M%S') + elif len(values) == 13: + parsed_val = datetime.strptime(values, '%Y%m%d-%H%M%S') + else: + raise ValueError("'%s' is not a valid datetime" % values) + setattr(namespace, self.dest, parsed_val) + +if __name__ == "__main__": + prechecks = [pre_check_user, pre_check_permissions] + configs = ['default_config.py'] + if 'TECHREC_CONFIG' in os.environ: + for conf in os.environ['TECHREC_CONFIG'].split(':'): + if not conf: + continue + path = os.path.realpath(conf) + if not os.path.exists(path): + logger.warn("Configuration file '%s' does not exist; skipping" + % path) + continue + configs.append(path) + os.chdir(os.path.dirname(os.path.realpath(__file__))) + for conf in configs: + get_config().from_pyfile(conf) + + for check in prechecks: + for warn in check(): + logging.warn(warn) + + parser = ArgumentParser(description='creates mp3 files from live recordings') + sub = parser.add_subparsers(title='subcommands', + description='valid subcommands', + help='additional help') + serve_p = sub.add_parser('serve') + serve_p.set_defaults(func=server.main_cmd) + forge_p = sub.add_parser('forge') + forge_p.add_argument('starttime', metavar='FROM', action=DateTimeAction) + forge_p.add_argument('endtime', metavar='TO', action=DateTimeAction) + forge_p.add_argument('-o', metavar='OUTFILE', dest='outfile', + default='out.mp3', help='Path of the output mp3') + forge_p.set_defaults(func=forge.main_cmd) + + options = parser.parse_args() + options.func(options) diff --git a/server/default_config.py b/server/default_config.py index 23a899a..bd5e0ba 100644 --- a/server/default_config.py +++ b/server/default_config.py @@ -1,7 +1,8 @@ -OUTPUT_DIR='output' -HOST='localhost' -PORT='8000' -DEBUG=True -DB_URI='sqlite:///techrec.db' -AUDIO_OUTPUT='output/' -AUDIO_INPUT='rec/' +OUTPUT_DIR = 'output' +HOST = 'localhost' +PORT = '8000' +DEBUG = True +DB_URI = 'sqlite:///techrec.db' +AUDIO_OUTPUT = 'output/' +AUDIO_INPUT = 'rec/' +FORGE_TIMEOUT = 20 diff --git a/server/forge.py b/server/forge.py index c4298c1..b6ea996 100644 --- a/server/forge.py +++ b/server/forge.py @@ -1,4 +1,5 @@ from datetime import datetime, timedelta +from time import sleep import os.path from subprocess import Popen @@ -87,10 +88,25 @@ def mp3_join(named_intervals, target): def create_mp3(start, end, outfile, options={}, **kwargs): p = Popen(mp3_join([(get_timefile(begin), start_cut, end_cut) - for begin, start_cut, end_cut - in get_files_and_intervals(start, end)], - outfile)) - p.wait() + for begin, start_cut, end_cut + in get_files_and_intervals(start, end)], + outfile)) + if get_config()['FORGE_TIMEOUT'] == 0: + p.wait() + else: + start = datetime.now() + while (datetime.now() - start).total_seconds() < \ + get_config()['FORGE_TIMEOUT']: + p.poll() + if p.returncode is None: + sleep(1) + else: + break + if p.returncode is None: + raise Exception('timeout') # TODO: make a specific TimeoutError if p.returncode != 0: raise OSError("return code was %d" % p.returncode) return True + +def main_cmd(options): + create_mp3(options.starttime, options.endtime, options.outfile) diff --git a/server/server.py b/server/server.py index df8822c..1ae8595 100644 --- a/server/server.py +++ b/server/server.py @@ -261,47 +261,8 @@ class RecServer: callback=partial(static_file, 'tempo.html', root='pages/')) -def pre_check_permissions(): - import sys - def is_writable(d): - return os.access(d, os.W_OK) - - if is_writable(get_config()['AUDIO_INPUT']): - yield "Audio input '%s' writable" % get_config()['AUDIO_INPUT'] - if not os.access(get_config()['AUDIO_INPUT'], os.R_OK): - yield "Audio input '%s' unreadable" % get_config()['AUDIO_INPUT'] - sys.exit(1) - if is_writable(os.getcwd()): - yield "Code writable" - if not is_writable(get_config()['AUDIO_OUTPUT']): - yield "Audio output '%s' not writable" % get_config()['AUDIO_OUTPUT'] - sys.exit(1) - -def pre_check_user(): - if os.geteuid() == 0: - yield "You're running as root; this is dangerous" - -if __name__ == "__main__": - prechecks=[pre_check_user, pre_check_permissions] - configs = ['default_config.py'] - if 'TECHREC_CONFIG' in os.environ: - for conf in os.environ['TECHREC_CONFIG'].split(':'): - if not conf: - continue - path = os.path.realpath(conf) - if not os.path.exists(path): - logger.warn("Configuration file '%s' does not exist; skipping" - % path) - continue - configs.append(path) - os.chdir(os.path.dirname(os.path.realpath(__file__))) - for conf in configs: - get_config().from_pyfile(conf) - - for check in prechecks: - for warn in check(): - logging.warn(warn) +def main_cmd(*args): c = RecServer() c._app.mount('/date', DateApp()) c._app.mount('/api', RecAPI())