Get the basic tutorial working completely, including reacting to server-side events
This commit is contained in:
parent
b7afc83204
commit
fa1bf94af1
20 changed files with 431 additions and 99 deletions
|
@ -5,9 +5,9 @@ import urlparse
|
|||
from flask import request, make_response, jsonify, session, Blueprint
|
||||
from functools import wraps
|
||||
|
||||
from data import model
|
||||
from data import model, userevent
|
||||
from data.queue import webhook_queue
|
||||
from app import mixpanel
|
||||
from app import mixpanel, app
|
||||
from auth.auth import (process_auth, get_authenticated_user,
|
||||
get_validated_token)
|
||||
from util.names import parse_repository_name
|
||||
|
@ -80,8 +80,16 @@ def create_user():
|
|||
if existing_user:
|
||||
verified = model.verify_user(username, password)
|
||||
if verified:
|
||||
# Mark that the user was logged in.
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event.publish_event_data('docker-cli', {'action': 'login'})
|
||||
|
||||
return make_response('Verified', 201)
|
||||
else:
|
||||
# Mark that the login failed.
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event.publish_event_data('docker-cli', {'action': 'loginfailure'})
|
||||
|
||||
abort(400, 'Invalid password.', issue='login-failure')
|
||||
|
||||
else:
|
||||
|
@ -186,9 +194,21 @@ def create_repository(namespace, repository):
|
|||
}
|
||||
|
||||
if get_authenticated_user():
|
||||
mixpanel.track(get_authenticated_user().username, 'push_repo',
|
||||
extra_params)
|
||||
metadata['username'] = get_authenticated_user().username
|
||||
username = get_authenticated_user().username
|
||||
|
||||
mixpanel.track(username, 'push_repo', extra_params)
|
||||
metadata['username'] = username
|
||||
|
||||
# Mark that the user has started pushing the repo.
|
||||
user_data = {
|
||||
'action': 'push_repo',
|
||||
'repository': repository,
|
||||
'namespace': namespace
|
||||
}
|
||||
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event.publish_event_data('docker-cli', user_data)
|
||||
|
||||
else:
|
||||
mixpanel.track(get_validated_token().code, 'push_repo', extra_params)
|
||||
metadata['token'] = get_validated_token().friendly_name
|
||||
|
@ -222,6 +242,19 @@ def update_images(namespace, repository):
|
|||
updated_tags[image['Tag']] = image['id']
|
||||
model.set_image_checksum(image['id'], repo, image['checksum'])
|
||||
|
||||
if get_authenticated_user():
|
||||
username = get_authenticated_user().username
|
||||
|
||||
# Mark that the user has pushed the repo.
|
||||
user_data = {
|
||||
'action': 'pushed_repo',
|
||||
'repository': repository,
|
||||
'namespace': namespace
|
||||
}
|
||||
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event.publish_event_data('docker-cli', user_data)
|
||||
|
||||
# Generate a job for each webhook that has been added to this repo
|
||||
webhooks = model.list_webhooks(namespace, repository)
|
||||
for webhook in webhooks:
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import logging
|
||||
import redis
|
||||
import json
|
||||
|
||||
from functools import wraps
|
||||
from flask import request, make_response, Blueprint, abort, Response
|
||||
from flask.ext.login import current_user, logout_user
|
||||
from data import model
|
||||
from data import model, userevent
|
||||
from app import app
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -29,31 +30,8 @@ def api_login_required(f):
|
|||
return decorated_view
|
||||
|
||||
|
||||
# Based off of the SSE flask snippet here: http://flask.pocoo.org/snippets/116/
|
||||
|
||||
class ServerSentEvent(object):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.event = None
|
||||
self.id = None
|
||||
self.desc_map = {
|
||||
self.data : "data",
|
||||
self.event : "event",
|
||||
self.id : "id"
|
||||
}
|
||||
|
||||
def encode(self):
|
||||
if not self.data:
|
||||
return ""
|
||||
lines = ["%s: %s" % (v, k)
|
||||
for k, v in self.desc_map.iteritems() if k]
|
||||
|
||||
return "%s\n\n" % "\n".join(lines)
|
||||
|
||||
# The current subscriptions
|
||||
subscriptions = []
|
||||
|
||||
@realtime.route("/")
|
||||
@realtime.route("/user/")
|
||||
@api_login_required
|
||||
def index():
|
||||
debug_template = """
|
||||
<html>
|
||||
|
@ -65,7 +43,7 @@ def index():
|
|||
<script type="text/javascript">
|
||||
|
||||
var eventOutputContainer = document.getElementById("event");
|
||||
var evtSrc = new EventSource("/realtime/subscribe");
|
||||
var evtSrc = new EventSource("/realtime/user/subscribe?events=docker-cli");
|
||||
|
||||
evtSrc.onmessage = function(e) {
|
||||
console.log(e.data);
|
||||
|
@ -79,18 +57,25 @@ def index():
|
|||
return(debug_template)
|
||||
|
||||
|
||||
@realtime.route("/subscribe")
|
||||
@realtime.route("/user/test")
|
||||
@api_login_required
|
||||
def subscribe():
|
||||
def gen():
|
||||
q = Queue()
|
||||
subscriptions.append(q)
|
||||
try:
|
||||
while True:
|
||||
result = q.get()
|
||||
ev = ServerSentEvent(str(result))
|
||||
yield ev.encode()
|
||||
except GeneratorExit:
|
||||
subscriptions.remove(q)
|
||||
def user_test():
|
||||
evt = userevent.UserEvent('logs.quay.io', current_user.db_user().username)
|
||||
evt.publish_event_data('test', {'foo': 2})
|
||||
return 'OK'
|
||||
|
||||
return Response(gen(), mimetype="text/event-stream")
|
||||
@realtime.route("/user/subscribe")
|
||||
@api_login_required
|
||||
def user_subscribe():
|
||||
def wrapper(listener):
|
||||
for event_id, data in listener.event_stream():
|
||||
message = {'event': event_id, 'data': data}
|
||||
json_string = json.dumps(message)
|
||||
yield 'data: %s\n\n' % json_string
|
||||
|
||||
events = request.args.get('events', '').split(',')
|
||||
if not events:
|
||||
abort(404)
|
||||
|
||||
listener = userevent.UserEventListener('logs.quay.io', current_user.db_user().username, events)
|
||||
return Response(wrapper(listener), mimetype="text/event-stream")
|
||||
|
|
Reference in a new issue