diff --git a/README.md b/README.md index 6eec74d..6e2b1b8 100644 --- a/README.md +++ b/README.md @@ -215,6 +215,8 @@ Some way to mass process photos in batches. For example, the batch jobs could: - create a downloadable mini-album - proactively generate thumbnails - replace thumbservice, the video thumb service + - import photos + - also by grabbing them from a foreign source e.g. sftp Could also have: - a session-based mechanism to "select" photos @@ -243,3 +245,5 @@ Design notes: - there is a numeric ID in the `target` column that can be any of a Photo, PhotoSet, or Tag - which it is, is determined by the `type` column - therefore the code can know which method to locate the file with + + - need testing to ensure the program is usable without having a dedicated executor etc diff --git a/photoapp/daemon.py b/photoapp/daemon.py index 065796a..8aa1c66 100644 --- a/photoapp/daemon.py +++ b/photoapp/daemon.py @@ -1,7 +1,9 @@ import os import math import time +import signal import logging +import argparse import cherrypy from collections import defaultdict from urllib.parse import urlparse @@ -617,10 +619,60 @@ class SearchView(object): ) -def main(): - import argparse - import signal +def setup_webapp(database_url, library_url, cache_url, thumb_service_url, debug=False, max_upload=1024**3): + # Get database connection + engine = get_db_engine(database_url) + + # Setup database in web framework + cherrypy.tools.db = SATool() + SAEnginePlugin(cherrypy.engine, engine).subscribe() + + # Create various internal tools + library_storage = uri_to_storage(library_url) + library_manager = LibraryManager(library_storage) + thumbnail_tool = ThumbGenerator(library_manager, uri_to_storage(cache_url), thumb_service_url) + + # Setup and mount web ui + tpl_dir = os.path.join(APPROOT, "templates") if not debug else "templates" + web = PhotosWeb(library_manager, thumbnail_tool, tpl_dir) + cherrypy.tree.mount(web, '/', {'/': {'tools.trailing_slash.on': False, + 'tools.db.on': True, + 'error_page.403': web.error, + 'error_page.404': web.error}, + '/static': {"tools.staticdir.on": True, + "tools.staticdir.dir": os.path.join(APPROOT, "styles/dist") + if not debug else os.path.abspath("styles/dist")}, + '/thumb': {'tools.expires.on': True, + 'tools.expires.secs': 7 * 86400}, + '/login': {'tools.auth_basic.on': True, + 'tools.auth_basic.realm': 'photolib', + 'tools.auth_basic.checkpassword': validate_password}}) + + # Setup and mount API + api = PhotosApi(library_manager) + cherrypy.tree.mount(api, '/api', {'/': {'tools.sessions.on': False, + 'tools.trailing_slash.on': False, + 'tools.auth_basic.on': True, + 'tools.auth_basic.realm': 'photolib', + 'tools.auth_basic.checkpassword': validate_password, + 'tools.db.on': True, + 'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}) + + # General config options + cherrypy.config.update({ + 'tools.sessions.storage_class': DatabaseSession, + 'tools.sessions.on': True, + 'tools.sessions.locking': 'explicit', + 'tools.sessions.timeout': 525600, + 'request.show_tracebacks': True, + 'server.show_tracebacks': True, + 'log.screen': False, + 'server.max_request_body_size': max_upload + }) + + +def main(): parser = argparse.ArgumentParser(description="Photod photo server") parser.add_argument('-p', '--port', help="tcp port to listen on", @@ -654,58 +706,21 @@ def main(): if not args.thumb_service: logging.warning("THUMB_SERVICE_URL not set. Video thumbnails will be unavailable") - # Get database connection - engine = get_db_engine(args.database) + setup_webapp( + args.database, + args.library, + args.cache, + args.thumb_service, + debug=args.debug, + max_upload=args.max_upload + ) - # Setup database in web framework - cherrypy.tools.db = SATool() - SAEnginePlugin(cherrypy.engine, engine).subscribe() - - # Create various internal tools - library_storage = uri_to_storage(args.library) - library_manager = LibraryManager(library_storage) - thumbnail_tool = ThumbGenerator(library_manager, uri_to_storage(args.cache), args.thumb_service) - - # Setup and mount web ui - tpl_dir = os.path.join(APPROOT, "templates") if not args.debug else "templates" - web = PhotosWeb(library_manager, thumbnail_tool, tpl_dir) - cherrypy.tree.mount(web, '/', {'/': {'tools.trailing_slash.on': False, - 'tools.db.on': True, - 'error_page.403': web.error, - 'error_page.404': web.error}, - '/static': {"tools.staticdir.on": True, - "tools.staticdir.dir": os.path.join(APPROOT, "styles/dist") - if not args.debug else os.path.abspath("styles/dist")}, - '/thumb': {'tools.expires.on': True, - 'tools.expires.secs': 7 * 86400}, - '/login': {'tools.auth_basic.on': True, - 'tools.auth_basic.realm': 'photolib', - 'tools.auth_basic.checkpassword': validate_password}}) - - # Setup and mount API - api = PhotosApi(library_manager) - cherrypy.tree.mount(api, '/api', {'/': {'tools.sessions.on': False, - 'tools.trailing_slash.on': False, - 'tools.auth_basic.on': True, - 'tools.auth_basic.realm': 'photolib', - 'tools.auth_basic.checkpassword': validate_password, - 'tools.db.on': True, - 'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}) - - # General config options + # Server config options cherrypy.config.update({ - 'tools.sessions.storage_class': DatabaseSession, - 'tools.sessions.on': True, - 'tools.sessions.locking': 'explicit', - 'tools.sessions.timeout': 525600, - 'request.show_tracebacks': True, 'server.socket_port': args.port, 'server.thread_pool': 25, 'server.socket_host': '0.0.0.0', - 'server.show_tracebacks': True, - 'log.screen': False, 'engine.autoreload.on': args.debug, - 'server.max_request_body_size': args.max_upload }) # Setup signal handling and run it.