def create_app(config=None, debug=False): ''' Inicializa la aplicación Flask. Carga los siguientes módulos: - index: página de inicio - page: páginas estáticas - user: gestión del usuario - files: búsqueda y obtención de ficheros - status: servicio de monitorización de la aplicación Y además, inicializa los siguientes servicios: - Configuración: carga valores por defecto y modifica con el @param config - Web Assets: compilación y compresión de recursos estáticos - i18n: detección de idioma en la URL y catálogos de mensajes - Cache y auth: Declarados en el módulo services - Files: Clases para acceso a datos ''' app = Flask(__name__) app.config.from_object(defaults) app.debug = debug app.session_interface = NoSessionInterface() # Configuración if config: app.config.from_object(config) # Runtime config app.config["DOWNLOADER_FILES"] = { k: os.path.join(os.path.abspath(os.path.join(app.root_path,"../downloads")), v) for k, v in app.config["DOWNLOADER_FILES"].iteritems() } # Gestión centralizada de errores if app.config["SENTRY_DSN"]: sentry.init_app(app) logging.getLogger().setLevel(logging.DEBUG if debug else logging.INFO) # Configuración dependiente de la versión del código revision_filename_path = os.path.join(os.path.dirname(app.root_path), "revision") if os.path.exists(revision_filename_path): f = open(revision_filename_path, "r") data = f.read() f.close() revisions = tuple( tuple(i.strip() for i in line.split("#")[0].split()) for line in data.strip().split("\n") if line.strip() and not line.strip().startswith("#")) revision_hash = md5(data).hexdigest() app.config.update( CACHE_KEY_PREFIX = "%s%s/" % ( app.config["CACHE_KEY_PREFIX"] if "CACHE_KEY_PREFIX" in app.config else "", revision_hash ), REVISION_HASH = revision_hash, REVISION = revisions ) else: app.config.update( REVISION_HASH = None, REVISION = () ) # Registra valores/funciones para plantillas app.jinja_env.globals["u"] = u # Blueprints print "Registering blueprints." app.register_blueprint(index) register_files_converters(app) app.register_blueprint(news) app.register_blueprint(files) for blueprint in downloader_blueprints: app.register_blueprint(blueprint) # Registra filtros de plantillas register_filters(app) # Web Assets print "Web assets." if not os.path.isdir(app.static_folder+"/gen"): os.mkdir(app.static_folder+"/gen") assets = Environment(app) app.assets = assets assets.debug = app.debug assets.versions = "timestamp" register_filter(JsSlimmer) register_filter(CssSlimmer) assets.register('css_torrents', Bundle('main.css', 'jquery.treeview.css', filters='pyscss', output='gen/main.css', debug=False), '960_24_col.css', filters='css_slimmer', output='gen/torrents.css') assets.register('js_torrents', Bundle('modernizr.js', 'jquery.js', 'jquery.treeview.js', 'jquery.cookie.js', 'jquery.colorbox-min.js', 'torrents.js', 'cookies.js', filters='rjsmin', output='gen/torrents.js'), ) print "Initializing services." # CSRF protection csrf.init_app(app) # Traducciones babel.init_app(app) @babel.localeselector def get_locale(): return "en" # Cache cache.init_app(app) # Mail mail.init_app(app) print "Database accesses:" # Acceso a bases de datos filesdb.init_app(app) print "* files" torrentsdb.init_app(app, searchd) print "* torrents" pagesdb.init_app(app) print "* pages" #feedbackdb.init_app(app) #print "* feedback" configdb.init_app(app) print "* config" entitiesdb.init_app(app) print "* entities" for service_name, params in app.config["DATA_SOURCE_SHARING"].iteritems(): eval(service_name).share_connections(**{key:eval(value) for key, value in params.iteritems()}) configdb.register_action("flush_cache", cache.clear, _unique=True) print "Blacklists." # Blacklists if app.debug: blacklists.debug=True blacklist_data = torrentsdb.get_blacklists() blacklists.load_data(blacklist_data) blacklists.clone_into(blacklists_adult, lambda x:x!="misconduct") def refresh_blacklists(): ''' Refresh blacklists. ''' blacklists.load_data(torrentsdb.get_blacklists()) configdb.register_action("refresh_blacklists", refresh_blacklists) def update_downloader_properties(): ''' Downloader updated. ''' local_cache["downloader_properties"] = get_downloader_properties() configdb.register_action("update_downloader", update_downloader_properties) with app.app_context(): local_cache["downloader_properties"] = get_downloader_properties() # IPs españolas spanish_ips.load(os.path.join(os.path.dirname(app.root_path),app.config["SPANISH_IPS_FILENAME"])) @app.before_first_request def init_process(): if not eventmanager.is_alive(): # Fallback inicio del eventManager eventmanager.start() print "Event manager." # Profiler # profiler.init_app(app, feedbackdb) # Servicio de búsqueda eventmanager.once(searchd.init_app, hargs=(app, filesdb, entitiesdb, profiler)) # Refresco de conexiones eventmanager.once(filesdb.load_servers_conn) eventmanager.interval(app.config["FOOCONN_UPDATE_INTERVAL"], filesdb.load_servers_conn) # Refresco de configuración eventmanager.once(configdb.pull) eventmanager.interval(app.config["CONFIG_UPDATE_INTERVAL"], configdb.pull) # Categorias categories_cache.init_app(app.config["TORRENTS_CATEGORIES"], app.config["SUBCATEGORIES_MIN_OCCURS"]) categories_cache.update_subcategories(torrentsdb.get_subcategories()) def refresh_subcategories(): ''' Refresh subcategories. ''' categories_cache.update_subcategories(torrentsdb.get_subcategories()) configdb.register_action("refresh_subcategories", refresh_subcategories) eventmanager.interval(app.config["CATEGORIES_REFRESH_INTERVAL"], refresh_subcategories) @app.before_request def before_request(): g.cache_code = "" g.last_modified = None # No preprocesamos la peticiones a static if request.path.startswith("/static/"): g.must_cache = False return g.blacklisted_content = False init_g(current_app) if not g.domain: return multidomain.redirect_to_domain(g.domains_family[0], 301) # ignora peticiones sin blueprint if request.blueprint is None and request.path.endswith("/"): if "?" in request.url: root = request.url_root[:-1] path = request.path.rstrip("/") query = request.url if not isinstance(query, unicode): query = query.decode("utf-8") query = query[query.find(u"?"):] return redirect(root+path+query, 301) return redirect(request.url.rstrip("/"), 301) @app.after_request def after_request(response): if request.user_agent.browser == "msie": response.headers["X-UA-Compatible"] = "IE-edge" if g.must_cache: response.headers["X-Cache-Control"] = "max-age=%d"%g.must_cache if g.cache_code: response.headers["X-Cache-Code"] = g.cache_code if g.last_modified: response.headers["Last-Modified"] = utils.formatdate(time.mktime(max(g.last_modified, current_app.config["APP_LAST_MODIFIED"]).timetuple()), False, True) return response # Páginas de error errors = { 404: ("Page not found", "The requested address does not exists."), 410: ("File not available", "The file you are trying to access has been removed."), 500: ("An error happened", "We had some problems displaying this page. Maybe later we can show it to you."), 503: ("Service unavailable", "This page is temporarily unavailable. Please try again later.") } @allerrors(app, 400, 401, 403, 404, 405, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 500, 501, 502, 503) def all_errors(e): error = e.code if hasattr(e,"code") else 500 title, description = errors[error if error in errors else 500] init_g(current_app) if not g.domain: return multidomain.redirect_to_domain(g.domains_family[0], 301) g.title.append(title) return render_template('error.html', code=str(error), title=title, description=description), error print "App ready." return app
def update_downloader_properties(): ''' Downloader updated. ''' local_cache["downloader_properties"] = get_downloader_properties()