diff --git a/r2/r2/config/middleware.py b/r2/r2/config/middleware.py index 075f3f5cb..fbcd3107f 100644 --- a/r2/r2/config/middleware.py +++ b/r2/r2/config/middleware.py @@ -41,6 +41,7 @@ from r2.lib.html_source import HTMLValidationParser from cStringIO import StringIO import sys, tempfile, urllib, re, os, sha, subprocess from httplib import HTTPConnection +from threading import Lock # hack in Paste support for HTTP 429 "Too Many Requests" from paste import httpexceptions, wsgiwrappers @@ -519,18 +520,29 @@ class CleanupMiddleware(object): #god this shit is disorganized and confusing class RedditApp(PylonsBaseWSGIApp): - def find_controller(self, controller): - if controller in self.controller_classes: - return self.controller_classes[controller] + def __init__(self, *args, **kwargs): + super(RedditApp, self).__init__(*args, **kwargs) + self._loading_lock = Lock() + self._controllers = None - full_module_name = self.package_name + '.controllers' - class_name = controller.capitalize() + 'Controller' + def load_controllers(self): + with self._loading_lock: + if not self._controllers: + controllers = __import__(self.package_name + '.controllers').controllers + controllers.load_controllers() + config['r2.plugins'].load_controllers() + self._controllers = controllers - __import__(self.package_name + '.controllers') - config['r2.plugins'].load_controllers() - mycontroller = getattr(sys.modules[full_module_name], class_name) - self.controller_classes[controller] = mycontroller - return mycontroller + return self._controllers + + def find_controller(self, controller_name): + if controller_name in self.controller_classes: + return self.controller_classes[controller_name] + + controllers = self.load_controllers() + controller_cls = controllers.get_controller(controller_name) + self.controller_classes[controller_name] = controller_cls + return controller_cls def make_app(global_conf, full_stack=True, **app_conf): """Create a Pylons WSGI application and return it diff --git a/r2/r2/controllers/__init__.py b/r2/r2/controllers/__init__.py index 68a93660b..4ebec0c3a 100644 --- a/r2/r2/controllers/__init__.py +++ b/r2/r2/controllers/__init__.py @@ -19,55 +19,72 @@ # All portions of the code written by CondeNet are Copyright (c) 2006-2010 # CondeNet, Inc. All Rights Reserved. ################################################################################ -from listingcontroller import ListingController -from listingcontroller import HotController -from listingcontroller import NewController -from listingcontroller import BrowseController -from listingcontroller import MessageController -from listingcontroller import RedditsController -from listingcontroller import ByIDController as ByidController -from listingcontroller import RandomrisingController -from listingcontroller import UserController -from listingcontroller import CommentsController -from listingcontroller import MyredditsController +_reddit_controllers = {} +_plugin_controllers = {} -from feedback import FeedbackController -from front import FormsController -from front import FrontController -from health import HealthController -from buttons import ButtonsController -from buttons import ButtonjsController -from captcha import CaptchaController -from embed import EmbedController -from error import ErrorController -from post import PostController -from toolbar import ToolbarController -from awards import AwardsController -from ads import AdsController -from usage import UsageController -from errorlog import ErrorlogController -from promotecontroller import PromoteController -from mediaembed import MediaembedController -from mediaembed import AdController - -from querycontroller import QueryController - -try: - from r2admin.controllers.adminapi import ApiController -except ImportError: - from api import ApiController - -from api import ApiminimalController -from api_docs import ApidocsController -from apiv1 import APIv1Controller as Apiv1Controller -from oauth2 import OAuth2FrontendController as Oauth2frontendController -from oauth2 import OAuth2AccessController as Oauth2accessController -from admin import AdminController -from redirect import RedirectController -from ipn import IpnController +def get_controller(name): + name = name.lower() + 'controller' + if name in _reddit_controllers: + return _reddit_controllers[name] + elif name in _plugin_controllers: + return _plugin_controllers[name] + else: + raise KeyError(name) def add_controller(controller): - assert controller.__name__ not in globals() - globals()[controller.__name__] = controller + name = controller.__name__.lower() + assert name not in _plugin_controllers + _plugin_controllers[name] = controller return controller + +def load_controllers(): + from listingcontroller import ListingController + from listingcontroller import HotController + from listingcontroller import NewController + from listingcontroller import BrowseController + from listingcontroller import MessageController + from listingcontroller import RedditsController + from listingcontroller import ByIDController + from listingcontroller import RandomrisingController + from listingcontroller import UserController + from listingcontroller import CommentsController + + from listingcontroller import MyredditsController + + from feedback import FeedbackController + from front import FormsController + from front import FrontController + from health import HealthController + from buttons import ButtonsController + from buttons import ButtonjsController + from captcha import CaptchaController + from embed import EmbedController + from error import ErrorController + from post import PostController + from toolbar import ToolbarController + from awards import AwardsController + from ads import AdsController + from usage import UsageController + from errorlog import ErrorlogController + from promotecontroller import PromoteController + from mediaembed import MediaembedController + from mediaembed import AdController + + from querycontroller import QueryController + + try: + from r2admin.controllers.adminapi import ApiController + except ImportError: + from api import ApiController + + from api import ApiminimalController + from api_docs import ApidocsController + from apiv1 import APIv1Controller + from oauth2 import OAuth2FrontendController + from oauth2 import OAuth2AccessController + from admin import AdminController + from redirect import RedirectController + from ipn import IpnController + + _reddit_controllers.update((name.lower(), obj) for name, obj in locals().iteritems()) diff --git a/r2/r2/controllers/promotecontroller.py b/r2/r2/controllers/promotecontroller.py index fbf7e19ae..5b711b8a8 100644 --- a/r2/r2/controllers/promotecontroller.py +++ b/r2/r2/controllers/promotecontroller.py @@ -27,7 +27,7 @@ from r2.lib.pages import * from r2.lib.pages.things import wrap_links from r2.lib.strings import strings from r2.lib.menus import * -from r2.controllers import ListingController +from r2.controllers.listingcontroller import ListingController from r2.lib.db import queries import sha diff --git a/r2/r2/lib/plugin.py b/r2/r2/lib/plugin.py index ee00f5501..99dd9eab5 100644 --- a/r2/r2/lib/plugin.py +++ b/r2/r2/lib/plugin.py @@ -46,7 +46,6 @@ class Plugin(object): class PluginLoader(object): def __init__(self): self.plugins = {} - self.controllers_loaded = False def __len__(self): return len(self.plugins) @@ -78,11 +77,8 @@ class PluginLoader(object): return self def load_controllers(self): - if self.controllers_loaded: - return for plugin in self: plugin.load_controllers() - self.controllers_loaded = True if __name__ == '__main__': if sys.argv[1] == 'list':