mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
193 lines
6.4 KiB
Python
Executable File
193 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
"""
|
|
Server for realtime Galaxy communication.
|
|
|
|
|
|
At first you need to install a few requirements.
|
|
|
|
. GALAXY_ROOT/.venv/bin/activate # activate Galaxy's virtualenv
|
|
pip install flask flask-login flask-socketio eventlet # install the requirements
|
|
|
|
|
|
|
|
As a next step start the communication server with something like this:
|
|
|
|
./scripts/communication_server.py --port 7070 --host localhost
|
|
|
|
Please make sure the host and the port matches the ones on config/galaxy.ini
|
|
|
|
The communication server feature of Galaxy can be controlled on three different levels:
|
|
1. Admin can activate/deactivate communication (config/galaxy.ini)
|
|
2. User can actrivate/deactivate for one session (in the communication window)
|
|
3. User can actrivate/deactivate as personal-setting for ever (Galaxy user preferences)
|
|
|
|
|
|
"""
|
|
import argparse
|
|
import os
|
|
import sys
|
|
sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'lib')))
|
|
|
|
from flask import Flask, request, make_response, current_app, send_file
|
|
from flask_socketio import SocketIO, emit, disconnect, join_room, leave_room, close_room, rooms
|
|
import flask.ext.login as flask_login
|
|
from flask.ext.login import current_user
|
|
from datetime import timedelta
|
|
from functools import update_wrapper
|
|
|
|
import galaxy.config
|
|
from galaxy.model.orm.scripts import get_config
|
|
from galaxy.model import mapping
|
|
from galaxy.util.properties import load_app_properties
|
|
from galaxy.web.security import SecurityHelper
|
|
|
|
# Get config file and load up SA session
|
|
config = get_config( sys.argv )
|
|
model = mapping.init( '/tmp/', config['db_url'] )
|
|
sa_session = model.context.current
|
|
|
|
# With the config file we can load the full app properties
|
|
app_properties = load_app_properties(ini_file=config['config_file'])
|
|
# We need the ID secret for configuring the security helper to decrypt
|
|
# galaxysession cookies.
|
|
security_helper = SecurityHelper(id_secret=app_properties['id_secret'])
|
|
# And get access to the models
|
|
# Login manager to manager current_user functionality
|
|
login_manager = flask_login.LoginManager()
|
|
|
|
app = Flask(__name__)
|
|
app.config['SECRET_KEY'] = app_properties['id_secret']
|
|
login_manager.init_app(app)
|
|
socketio = SocketIO(app)
|
|
|
|
@login_manager.request_loader
|
|
def findUserByCookie(request):
|
|
cookie_value = request.cookies.get('galaxysession')
|
|
if not cookie_value:
|
|
return None
|
|
|
|
session_key = security_helper.decode_guid(cookie_value)
|
|
user_session = sa_session.query(model.GalaxySession) \
|
|
.filter_by(session_key=session_key).first()
|
|
|
|
if user_session:
|
|
return user_session.user
|
|
|
|
return None
|
|
|
|
# Taken from flask.pocoo.org/snippets/56/
|
|
def crossdomain(origin=None, methods=None, headers=None,
|
|
max_age=21600, attach_to_all=True,
|
|
automatic_options=True):
|
|
if methods is not None:
|
|
methods = ', '.join(sorted(x.upper() for x in methods))
|
|
if headers is not None and not isinstance(headers, basestring):
|
|
headers = ', '.join(x.upper() for x in headers)
|
|
if not isinstance(origin, basestring):
|
|
origin = ', '.join(origin)
|
|
if isinstance(max_age, timedelta):
|
|
max_age = max_age.total_seconds()
|
|
|
|
def get_methods():
|
|
if methods is not None:
|
|
return methods
|
|
|
|
options_resp = current_app.make_default_options_response()
|
|
return options_resp.headers['allow']
|
|
|
|
def decorator(f):
|
|
def wrapped_function(*args, **kwargs):
|
|
if automatic_options and request.method == 'OPTIONS':
|
|
resp = current_app.make_default_options_response()
|
|
else:
|
|
resp = make_response(f(*args, **kwargs))
|
|
if not attach_to_all and request.method != 'OPTIONS':
|
|
return resp
|
|
|
|
h = resp.headers
|
|
|
|
h['Access-Control-Allow-Origin'] = origin
|
|
h['Access-Control-Allow-Methods'] = get_methods()
|
|
h['Access-Control-Max-Age'] = str(max_age)
|
|
if headers is not None:
|
|
h['Access-Control-Allow-Headers'] = headers
|
|
return resp
|
|
|
|
f.provide_automatic_options = False
|
|
return update_wrapper(wrapped_function, f)
|
|
return decorator
|
|
|
|
script_dir = os.path.dirname(os.path.realpath( __file__))
|
|
communication_directory = os.path.join( script_dir, 'communication', 'template' )
|
|
|
|
@app.route('/')
|
|
@crossdomain(origin='*')
|
|
def index():
|
|
return send_file(os.path.join(communication_directory, 'communication.html'))
|
|
|
|
@app.route('/communication.js')
|
|
def static_script():
|
|
return send_file(os.path.join(communication_directory, 'communication.js'))
|
|
|
|
@app.route('/communication.css')
|
|
def static_style():
|
|
return send_file(os.path.join(communication_directory, 'communication.css'))
|
|
|
|
|
|
|
|
@socketio.on('event connect', namespace='/chat')
|
|
def event_connect(message):
|
|
print(current_user.username + " connected")
|
|
|
|
|
|
@socketio.on('event broadcast', namespace='/chat')
|
|
def event_broadcast(message):
|
|
print("broadcast")
|
|
emit('event response',
|
|
{'data': message['data'], 'user': current_user.username}, broadcast=True)
|
|
|
|
|
|
@socketio.on('event room', namespace='/chat')
|
|
def send_room_message(message):
|
|
print("message")
|
|
emit('event response room',
|
|
{'data': message['data'], 'user': current_user.username, 'chatroom': message['room']}, room=message['room'])
|
|
|
|
|
|
@socketio.on('event disconnect', namespace='/chat')
|
|
def event_disconnect(message):
|
|
print(current_user.username + " disconnected")
|
|
disconnect()
|
|
|
|
|
|
@socketio.on('disconnect', namespace='/chat')
|
|
def event_disconnect():
|
|
print(current_user.username + " disconnected")
|
|
|
|
|
|
@socketio.on('join', namespace='/chat')
|
|
def join(message):
|
|
print(current_user.username + " join " + message['room'])
|
|
join_room(message['room'])
|
|
emit('event response room',
|
|
{'data': message['room'], 'userjoin': current_user.username}, broadcast=True)
|
|
|
|
|
|
@socketio.on('leave', namespace='/chat')
|
|
def leave(message):
|
|
print(current_user.username + " left")
|
|
leave_room(message['room'])
|
|
emit('event response room',
|
|
{'data': message['room'], 'userleave': current_user.username}, broadcast=True)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
parser = argparse.ArgumentParser(description='Real-time communication server for Galaxy.')
|
|
parser.add_argument('--port', type=int, default="7070", help='Port number on which the server should run.')
|
|
parser.add_argument('--host', default='localhost', help='Hostname of the communication server.')
|
|
|
|
args = parser.parse_args()
|
|
socketio.run(app, host=args.host, port=args.port, debug=True)
|