subdomain dispatcher

This commit is contained in:
Matthew Scragg 2013-10-03 21:57:19 -05:00
parent 27ced9d90e
commit 2906b79dfc
4 changed files with 215 additions and 185 deletions

33
app.py
View file

@ -1,8 +1,35 @@
from gevent import monkey, pywsgi from gevent import monkey, pywsgi
monkey.patch_all() monkey.patch_all()
import logging from realms import create_app, config
from realms import app, config from threading import Lock
class SubdomainDispatcher(object):
def __init__(self, domain, create_app):
self.domain = domain
self.create_app = create_app
self.lock = Lock()
self.instances = {}
def get_application(self, host):
host = host.split(':')[0]
assert host.endswith(self.domain), 'Configuration error'
subdomain = host[:-len(self.domain)].rstrip('.')
with self.lock:
app = self.instances.get(subdomain)
if app is None:
app = self.create_app(subdomain)
self.instances[subdomain] = app
return app
def __call__(self, environ, start_response):
app = self.get_application(environ['HTTP_HOST'])
return app(environ, start_response)
def make_app(subdomain):
return create_app(subdomain)
if __name__ == '__main__': if __name__ == '__main__':
app.logger.setLevel(logging.INFO) app = SubdomainDispatcher(config.domain, make_app)
pywsgi.WSGIServer(('', config.port), app).serve_forever() pywsgi.WSGIServer(('', config.port), app).serve_forever()

View file

@ -2,19 +2,17 @@ import logging
import os import os
import time import time
import redis
import rethinkdb as rdb
from flask import Flask, request, render_template, url_for, redirect, flash, session from flask import Flask, request, render_template, url_for, redirect, flash, session
from flask.ext.bcrypt import Bcrypt from flask.ext.bcrypt import Bcrypt
from flask.ext.login import LoginManager, login_user, logout_user from flask.ext.login import LoginManager, login_user, logout_user
from flask.ext.assets import Environment from flask.ext.assets import Environment
from recaptcha.client import captcha from recaptcha.client import captcha
from werkzeug.routing import BaseConverter from werkzeug.routing import BaseConverter
from session import RedisSessionInterface from session import RedisSessionInterface
import config import config
from wiki import Wiki from wiki import Wiki
from util import to_canonical, remove_ext, mkdir_safe, gravatar_url from util import to_canonical, remove_ext, mkdir_safe, gravatar_url
from models import Site, User, CurrentUser
class RegexConverter(BaseConverter): class RegexConverter(BaseConverter):
@ -22,6 +20,21 @@ class RegexConverter(BaseConverter):
super(RegexConverter, self).__init__(url_map) super(RegexConverter, self).__init__(url_map)
self.regex = items[0] self.regex = items[0]
def redirect_url():
return request.args.get('next') or request.referrer or url_for('index')
def validate_captcha():
response = captcha.submit(
request.form['recaptcha_challenge_field'],
request.form['recaptcha_response_field'],
config.flask['RECAPTCHA_PRIVATE_KEY'],
request.remote_addr)
return response.is_valid
def create_app(subdomain=None):
app = Flask(__name__) app = Flask(__name__)
app.config.update(config.flask) app.config.update(config.flask)
app.debug = (config.ENV is not 'PROD') app.debug = (config.ENV is not 'PROD')
@ -35,47 +48,20 @@ bcrypt = Bcrypt(app)
login_manager = LoginManager() login_manager = LoginManager()
login_manager.init_app(app) login_manager.init_app(app)
assets = Environment(app)
assets.url = app.static_url_path
assets.directory = app.static_folder
cache = redis.StrictRedis(host=config.cache['host'], port=config.cache['port'])
conn = rdb.connect(config.db['host'], config.db['port'], db=config.db['dbname'])
if not config.db['dbname'] in rdb.db_list().run(conn) and config.ENV is not 'PROD':
# Create default db and repo
print "Creating DB %s" % config.db['dbname']
rdb.db_create(config.db['dbname']).run(conn)
for tbl in ['sites', 'users', 'pages']:
rdb.table_create(tbl).run(conn)
main_repo_dir = config.repos['main']
repo_dir = config.repos['dir']
# This is down here because of dependencies above
from models import Site, User, CurrentUser
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): def load_user(user_id):
return CurrentUser(user_id) return CurrentUser(user_id)
assets = Environment(app)
w = Wiki(main_repo_dir) assets.url = app.static_url_path
assets.directory = app.static_folder
def redirect_url(): main_repo_dir = config.repos['main']
return request.args.get('next') or request.referrer or url_for('index') repo_dir = config.repos['dir']
w = Wiki(main_repo_dir) if not subdomain else Wiki(repo_dir + "/" + subdomain)
def validate_captcha():
response = captcha.submit(
request.form['recaptcha_challenge_field'],
request.form['recaptcha_response_field'],
app.config['RECAPTCHA_PRIVATE_KEY'],
request.remote_addr)
return response.is_valid
@app.template_filter('datetime') @app.template_filter('datetime')
def _jinja2_filter_datetime(ts): def _jinja2_filter_datetime(ts):
@ -236,4 +222,4 @@ def render(name):
else: else:
return redirect('/create/'+cname) return redirect('/create/'+cname)
import ratelimit return app

View file

@ -1,9 +1,25 @@
import rethinkdb as rdb import rethinkdb as rdb
import bcrypt
import redis
from flask import session from flask import session
from flask.ext.login import login_user from flask.ext.login import login_user
from rethinkORM import RethinkModel from rethinkORM import RethinkModel
from realms import conn, bcrypt from realms import config
# Default DB connection
conn = rdb.connect(config.db['host'], config.db['port'], db=config.db['dbname'])
# Default Cache connection
cache = redis.StrictRedis(host=config.cache['host'], port=config.cache['port'])
def init_db():
if not config.db['dbname'] in rdb.db_list().run(conn) and config.ENV is not 'PROD':
# Create default db and repo
print "Creating DB %s" % config.db['dbname']
rdb.db_create(config.db['dbname']).run(conn)
for tbl in ['sites', 'users', 'pages']:
rdb.table_create(tbl).run(conn)
def to_dict(cur, first=False): def to_dict(cur, first=False):
ret = [] ret = []
@ -83,7 +99,7 @@ class User(BaseModel):
if not data: if not data:
return False return False
if bcrypt.check_password_hash(data['password'], password): if bcrypt.checkpw(password, data['password']):
login_user(CurrentUser(data['id'])) login_user(CurrentUser(data['id']))
session['user'] = data session['user'] = data
return True return True

View file

@ -1,7 +1,8 @@
import time import time
from functools import update_wrapper from functools import update_wrapper
from flask import request, g from flask import request, g
from realms import app, cache from realms import app
from models import cache
class RateLimit(object): class RateLimit(object):