mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2025-06-15 02:20:40 +00:00
Streamline setup process and init code
This commit is contained in:
142
app/__init__.py
142
app/__init__.py
@ -14,10 +14,11 @@ from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_hashids import Hashids
|
||||
|
||||
|
||||
docker_client = DockerClient.from_env()
|
||||
|
||||
apifairy = APIFairy()
|
||||
assets = Environment()
|
||||
db = SQLAlchemy()
|
||||
docker_client = DockerClient()
|
||||
hashids = Hashids()
|
||||
login = LoginManager()
|
||||
ma = Marshmallow()
|
||||
@ -28,80 +29,129 @@ scheduler = APScheduler()
|
||||
socketio = SocketIO()
|
||||
|
||||
|
||||
# TODO: Create export for lemmatized corpora
|
||||
|
||||
|
||||
def create_app(config: Config = Config) -> Flask:
|
||||
''' Creates an initialized Flask (WSGI Application) object. '''
|
||||
''' Creates an initialized Flask object. '''
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(config)
|
||||
config.init_app(app)
|
||||
|
||||
_configure_logging(app)
|
||||
_configure_middlewares(app)
|
||||
_init_docker_client(app)
|
||||
_init_extensions(app)
|
||||
_register_blueprints(app)
|
||||
_register_socketio_namespaces(app)
|
||||
_register_db_event_listeners(app)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def _configure_logging(app: Flask):
|
||||
from flask.logging import default_handler
|
||||
from logging import Formatter, StreamHandler
|
||||
|
||||
log_date_format: str = app.config['NOPAQUE_LOG_DATE_FORMAT']
|
||||
log_format: str = app.config['NOPAQUE_LOG_FORMAT']
|
||||
log_level: str = app.config['NOPAQUE_LOG_LEVEL']
|
||||
|
||||
formatter = Formatter(fmt=log_format, datefmt=log_date_format)
|
||||
handler = StreamHandler()
|
||||
handler.setFormatter(formatter)
|
||||
handler.setLevel(log_level)
|
||||
|
||||
app.logger.removeHandler(default_handler)
|
||||
app.logger.addHandler(handler)
|
||||
|
||||
|
||||
def _configure_middlewares(app: Flask):
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
|
||||
if app.config['NOPAQUE_PROXY_FIX_ENABLED']:
|
||||
app.wsgi_app = ProxyFix(
|
||||
app.wsgi_app,
|
||||
x_for=app.config['NOPAQUE_PROXY_FIX_X_FOR'],
|
||||
x_host=app.config['NOPAQUE_PROXY_FIX_X_HOST'],
|
||||
x_port=app.config['NOPAQUE_PROXY_FIX_X_PORT'],
|
||||
x_prefix=app.config['NOPAQUE_PROXY_FIX_X_PREFIX'],
|
||||
x_proto=app.config['NOPAQUE_PROXY_FIX_X_PROTO']
|
||||
)
|
||||
|
||||
|
||||
def _init_docker_client(app: Flask):
|
||||
registry: str = app.config['NOPAQUE_DOCKER_REGISTRY']
|
||||
username: str = app.config['NOPAQUE_DOCKER_REGISTRY_USERNAME']
|
||||
password: str = app.config['NOPAQUE_DOCKER_REGISTRY_PASSWORD']
|
||||
|
||||
docker_client.login(
|
||||
app.config['NOPAQUE_DOCKER_REGISTRY_USERNAME'],
|
||||
password=app.config['NOPAQUE_DOCKER_REGISTRY_PASSWORD'],
|
||||
registry=app.config['NOPAQUE_DOCKER_REGISTRY']
|
||||
username,
|
||||
password=password,
|
||||
registry=registry
|
||||
)
|
||||
|
||||
|
||||
def _init_extensions(app: Flask):
|
||||
from typing import Callable
|
||||
from .daemon import daemon
|
||||
from .models import AnonymousUser, User
|
||||
|
||||
is_primary_instance: bool = app.config['NOPAQUE_IS_PRIMARY_INSTANCE']
|
||||
socketio_message_queue_uri: str = app.config['NOPAQUE_SOCKETIO_MESSAGE_QUEUE_URI']
|
||||
login_user_loader_callback: Callable[[int], User | None] = lambda user_id: User.query.get(int(user_id))
|
||||
|
||||
apifairy.init_app(app)
|
||||
assets.init_app(app)
|
||||
db.init_app(app)
|
||||
hashids.init_app(app)
|
||||
login.init_app(app)
|
||||
login.anonymous_user = AnonymousUser
|
||||
login.login_view = 'auth.login'
|
||||
login.user_loader(login_user_loader_callback)
|
||||
ma.init_app(app)
|
||||
mail.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
paranoid.init_app(app)
|
||||
scheduler.init_app(app)
|
||||
socketio.init_app(app, message_queue=app.config['NOPAQUE_SOCKETIO_MESSAGE_QUEUE_URI']) # noqa
|
||||
|
||||
from .models import AnonymousUser, User
|
||||
login.anonymous_user = AnonymousUser
|
||||
login.login_view = 'auth.login'
|
||||
@login.user_loader
|
||||
def load_user(user_id):
|
||||
return User.query.get(int(user_id))
|
||||
|
||||
paranoid.redirect_view = '/'
|
||||
scheduler.init_app(app)
|
||||
if is_primary_instance:
|
||||
scheduler.add_job('daemon', daemon, args=(app,), seconds=3, trigger='interval')
|
||||
socketio.init_app(app, message_queue=socketio_message_queue_uri)
|
||||
|
||||
from .models.event_listeners import register_event_listeners
|
||||
register_event_listeners()
|
||||
|
||||
def _register_blueprints(app: Flask):
|
||||
from .admin import bp as admin_blueprint
|
||||
app.register_blueprint(admin_blueprint, url_prefix='/admin')
|
||||
|
||||
from .api import bp as api_blueprint
|
||||
app.register_blueprint(api_blueprint, url_prefix='/api')
|
||||
|
||||
from .auth import bp as auth_blueprint
|
||||
app.register_blueprint(auth_blueprint)
|
||||
|
||||
from .contributions import bp as contributions_blueprint
|
||||
app.register_blueprint(contributions_blueprint, url_prefix='/contributions')
|
||||
|
||||
from .corpora import bp as corpora_blueprint
|
||||
from .corpora.cqi_over_sio import CQiNamespace
|
||||
app.register_blueprint(corpora_blueprint, cli_group='corpus', url_prefix='/corpora')
|
||||
socketio.on_namespace(CQiNamespace('/cqi_over_sio'))
|
||||
|
||||
from .errors import bp as errors_bp
|
||||
app.register_blueprint(errors_bp)
|
||||
|
||||
from .jobs import bp as jobs_blueprint
|
||||
app.register_blueprint(jobs_blueprint, url_prefix='/jobs')
|
||||
|
||||
from .main import bp as main_blueprint
|
||||
app.register_blueprint(main_blueprint, cli_group=None)
|
||||
|
||||
from .services import bp as services_blueprint
|
||||
app.register_blueprint(services_blueprint, url_prefix='/services')
|
||||
|
||||
from .settings import bp as settings_blueprint
|
||||
app.register_blueprint(settings_blueprint, url_prefix='/settings')
|
||||
|
||||
from .users import bp as users_blueprint
|
||||
app.register_blueprint(users_blueprint, cli_group='user', url_prefix='/users')
|
||||
|
||||
from .workshops import bp as workshops_blueprint
|
||||
|
||||
app.register_blueprint(admin_blueprint, url_prefix='/admin')
|
||||
app.register_blueprint(api_blueprint, url_prefix='/api')
|
||||
app.register_blueprint(auth_blueprint)
|
||||
app.register_blueprint(contributions_blueprint, url_prefix='/contributions')
|
||||
app.register_blueprint(corpora_blueprint, cli_group='corpus', url_prefix='/corpora')
|
||||
app.register_blueprint(errors_bp)
|
||||
app.register_blueprint(jobs_blueprint, url_prefix='/jobs')
|
||||
app.register_blueprint(main_blueprint, cli_group=None)
|
||||
app.register_blueprint(services_blueprint, url_prefix='/services')
|
||||
app.register_blueprint(settings_blueprint, url_prefix='/settings')
|
||||
app.register_blueprint(users_blueprint, cli_group='user', url_prefix='/users')
|
||||
app.register_blueprint(workshops_blueprint, url_prefix='/workshops')
|
||||
|
||||
return app
|
||||
|
||||
def _register_socketio_namespaces(app: Flask):
|
||||
from .corpora.cqi_over_sio import CQiOverSocketIO
|
||||
|
||||
socketio.on_namespace(CQiOverSocketIO('/cqi_over_sio'))
|
||||
|
||||
|
||||
def _register_db_event_listeners(app: Flask):
|
||||
from .models.event_listeners import register_event_listeners
|
||||
|
||||
register_event_listeners()
|
||||
|
@ -19,7 +19,7 @@ This package tunnels the Corpus Query interface (CQi) protocol through
|
||||
Socket.IO (SIO) by tunneling CQi API calls through an event called "exec".
|
||||
|
||||
Basic concept:
|
||||
1. A client connects to the "/cqi_over_sio" namespace.
|
||||
1. A client connects to the namespace.
|
||||
2. The client emits the "init" event and provides a corpus id for the corpus
|
||||
that should be analysed in this session.
|
||||
1.1 The analysis session counter of the corpus is incremented.
|
||||
@ -28,14 +28,13 @@ Basic concept:
|
||||
1.4 Connect the CQiClient to the server.
|
||||
1.5 Save the CQiClient, the Lock and the corpus id in the session for
|
||||
subsequential use.
|
||||
2. The client emits the "exec" event provides the name of a CQi API function
|
||||
arguments (optional).
|
||||
- The event "exec" handler will execute the function, make sure that the
|
||||
result is serializable and returns the result back to the client.
|
||||
4. Wait for more events
|
||||
5. The client disconnects from the "/cqi_over_sio" namespace
|
||||
1.1 The analysis session counter of the corpus is decremented.
|
||||
1.2 The CQiClient and (Mutex) Lock belonging to it are teared down.
|
||||
3. The client emits "exec" events, within which it provides the name of a CQi
|
||||
API function and the corresponding arguments.
|
||||
3.1 The "exec" event handler will execute the function, make sure that
|
||||
the result is serializable and returns the result back to the client.
|
||||
4. The client disconnects from the namespace
|
||||
4.1 The analysis session counter of the corpus is decremented.
|
||||
4.2 The CQiClient and (Mutex) Lock belonging to it are teared down.
|
||||
'''
|
||||
|
||||
CQI_API_FUNCTION_NAMES: List[str] = [
|
||||
@ -86,7 +85,7 @@ CQI_API_FUNCTION_NAMES: List[str] = [
|
||||
]
|
||||
|
||||
|
||||
class CQiNamespace(Namespace):
|
||||
class CQiOverSocketIO(Namespace):
|
||||
@socketio_login_required
|
||||
def on_connect(self):
|
||||
pass
|
||||
|
@ -1,5 +1,5 @@
|
||||
from app import db
|
||||
from flask import Flask
|
||||
from app import db
|
||||
from .corpus_utils import check_corpora
|
||||
from .job_utils import check_jobs
|
||||
|
||||
|
Reference in New Issue
Block a user