subdomain dispatcher
This commit is contained in:
parent
27ced9d90e
commit
2906b79dfc
33
app.py
33
app.py
|
@ -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()
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in a new issue