improve WebSocket handling
This commit is contained in:
parent
24d6689abe
commit
c183595124
5 changed files with 87 additions and 47 deletions
|
@ -51,7 +51,7 @@
|
||||||
<a ui-sref="event.ticket.edit({id: event._id, ticket_id: ticket._id})"><span>{{ticket.name}}</span> <span>{{ticket.surname}}</span></a>
|
<a ui-sref="event.ticket.edit({id: event._id, ticket_id: ticket._id})"><span>{{ticket.name}}</span> <span>{{ticket.surname}}</span></a>
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
<span ng-if="ticket.email"> <{{ticket.email}}></span>
|
<span ng-if="ticket.email"> <{{ticket.email}}></span><span ng-if="ticket.cancelled"> ({{'cancelled' | translate}})</span>
|
||||||
<p ng-if="ticket.company || ticket.job_title"><i ng-if="ticket.job_title">{{ticket.job_title}}</i><span ng-if="ticket.company && ticket.job_title"> @ </span><i ng-if="ticket.company">{{ticket.company}}</i></p>
|
<p ng-if="ticket.company || ticket.job_title"><i ng-if="ticket.job_title">{{ticket.job_title}}</i><span ng-if="ticket.company && ticket.job_title"> @ </span><i ng-if="ticket.company">{{ticket.company}}</i></p>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
|
|
53
angular_app/js/controllers.js
vendored
53
angular_app/js/controllers.js
vendored
|
@ -179,7 +179,7 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
|
||||||
$scope.formData = {};
|
$scope.formData = {};
|
||||||
$scope.guiOptions = {dangerousActionsEnabled: false};
|
$scope.guiOptions = {dangerousActionsEnabled: false};
|
||||||
$scope.customFields = Setting.query({setting: 'ticket_custom_field', in_event_details: true});
|
$scope.customFields = Setting.query({setting: 'ticket_custom_field', in_event_details: true});
|
||||||
$scope.registeredFilterOptions = {all: true};
|
$scope.registeredFilterOptions = {all: false};
|
||||||
|
|
||||||
$scope.formFieldsMap = {};
|
$scope.formFieldsMap = {};
|
||||||
$scope.formFieldsMapRev = {};
|
$scope.formFieldsMapRev = {};
|
||||||
|
@ -224,10 +224,12 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
|
||||||
return $scope.EventUpdates.data;
|
return $scope.EventUpdates.data;
|
||||||
}, function(new_collection, old_collection) {
|
}, function(new_collection, old_collection) {
|
||||||
if (!($scope.EventUpdates.data && $scope.EventUpdates.data.update)) {
|
if (!($scope.EventUpdates.data && $scope.EventUpdates.data.update)) {
|
||||||
|
$log.debug('no data received from the WebSocket');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var data = $scope.EventUpdates.data.update;
|
var data = $scope.EventUpdates.data.update;
|
||||||
$log.debug('received ' + data.action + ' action from websocket source ' + data.uuid);
|
$log.debug('received ' + data.action + ' action from websocket source ' + data.uuid + ' . Full data:');
|
||||||
|
$log.debug(data);
|
||||||
if ($rootScope.app_uuid == data.uuid) {
|
if ($rootScope.app_uuid == data.uuid) {
|
||||||
$log.debug('do not process our own message');
|
$log.debug('do not process our own message');
|
||||||
return false;
|
return false;
|
||||||
|
@ -235,8 +237,9 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
|
||||||
if (!$scope.event.tickets) {
|
if (!$scope.event.tickets) {
|
||||||
$scope.event.tickets = [];
|
$scope.event.tickets = [];
|
||||||
}
|
}
|
||||||
|
var ticket_id = data._id || (data.ticket && data.ticket._id);
|
||||||
var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
|
var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
|
||||||
return data._id == el._id;
|
return ticket_id && (ticket_id == el._id);
|
||||||
});
|
});
|
||||||
if (ticket_idx != -1) {
|
if (ticket_idx != -1) {
|
||||||
$log.debug('_id ' + data._id + ' found');
|
$log.debug('_id ' + data._id + ' found');
|
||||||
|
@ -415,17 +418,46 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* event listners; needed because otherwise, adding a ticket with the Quick add form,
|
||||||
|
* we'd be changing the $scope outside of the AngularJS's $digest. */
|
||||||
|
|
||||||
|
$rootScope.$on('event:ticket:new', function(evt, ticket, callback) {
|
||||||
|
$scope._localAddTicket(ticket);
|
||||||
|
if (callback) {
|
||||||
|
callback(ticket);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on('event:ticket:update', function(evt, ticket) {
|
||||||
|
if (!$scope.event.tickets) {
|
||||||
|
$scope.event.tickets = [];
|
||||||
|
}
|
||||||
|
var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
|
||||||
|
return ticket._id == el._id;
|
||||||
|
});
|
||||||
|
if (ticket_idx == -1) {
|
||||||
|
$log.debug('ticket not present: not updated');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$scope.event.tickets[ticket_idx] = ticket;
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$on('event:ticket:set-attr', function(evt, ticket, key, value, callback, hideMessage) {
|
||||||
|
$scope.setTicketAttribute(ticket, key, value, callback, hideMessage);
|
||||||
|
});
|
||||||
|
|
||||||
$scope.addTicket = function(ticket) {
|
$scope.addTicket = function(ticket) {
|
||||||
ticket.event_id = $state.params.id;
|
ticket.event_id = $state.params.id;
|
||||||
EventTicket.add(ticket, function(ret_ticket) {
|
EventTicket.add(ticket, function(ret_ticket) {
|
||||||
$log.debug('addTicket');
|
$log.debug('addTicket');
|
||||||
$log.debug(ret_ticket);
|
$log.debug(ret_ticket);
|
||||||
$scope._localAddTicket(ret_ticket, ticket);
|
$rootScope.$emit('event:ticket:new', ret_ticket, function() {
|
||||||
|
$rootScope.$emit('event:ticket:set-attr', ret_ticket, 'attended', true, null, true);
|
||||||
|
});
|
||||||
if (!$state.is('event.tickets')) {
|
if (!$state.is('event.tickets')) {
|
||||||
$state.go('event.ticket.edit', {id: $scope.event._id, ticket_id: ret_ticket._id});
|
$state.go('event.ticket.edit', {id: $scope.event._id, ticket_id: ret_ticket._id});
|
||||||
} else {
|
} else {
|
||||||
$scope.query = '';
|
$scope.query = '';
|
||||||
$scope._setAttended(ret_ticket);
|
|
||||||
if ($scope.$close) {
|
if ($scope.$close) {
|
||||||
// Close the Quick ticket modal.
|
// Close the Quick ticket modal.
|
||||||
$scope.$close();
|
$scope.$close();
|
||||||
|
@ -437,7 +469,7 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
|
||||||
$scope.updateTicket = function(ticket, cb) {
|
$scope.updateTicket = function(ticket, cb) {
|
||||||
ticket.event_id = $state.params.id;
|
ticket.event_id = $state.params.id;
|
||||||
EventTicket.update(ticket, function(t) {
|
EventTicket.update(ticket, function(t) {
|
||||||
$scope._localUpdateTicket(t.ticket);
|
$rootScope.$emit('event:ticket:update', t.ticket);
|
||||||
if (cb) {
|
if (cb) {
|
||||||
cb(t);
|
cb(t);
|
||||||
}
|
}
|
||||||
|
@ -459,8 +491,7 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
|
||||||
templateUrl: 'modal-quick-add-ticket.html',
|
templateUrl: 'modal-quick-add-ticket.html',
|
||||||
controller: 'EventTicketsCtrl'
|
controller: 'EventTicketsCtrl'
|
||||||
});
|
});
|
||||||
modalInstance.result.then(function() {
|
modalInstance.result.then(function() {});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.submitForm = function(dataModelSubmitted) {
|
$scope.submitForm = function(dataModelSubmitted) {
|
||||||
|
@ -468,10 +499,10 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
|
||||||
key = $scope.formFieldsMap[key] || key;
|
key = $scope.formFieldsMap[key] || key;
|
||||||
$scope.ticket[key] = value;
|
$scope.ticket[key] = value;
|
||||||
});
|
});
|
||||||
if (!$state.params.ticket_id) {
|
if ($state.is('event.ticket.edit')) {
|
||||||
$scope.addTicket($scope.ticket);
|
|
||||||
} else {
|
|
||||||
$scope.updateTicket($scope.ticket);
|
$scope.updateTicket($scope.ticket);
|
||||||
|
} else {
|
||||||
|
$scope.addTicket($scope.ticket);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
15
angular_app/js/services.js
vendored
15
angular_app/js/services.js
vendored
|
@ -241,8 +241,8 @@ eventManServices.factory('User', ['$resource', '$rootScope',
|
||||||
|
|
||||||
|
|
||||||
/* WebSocket collection used to update the list of tickets of an Event. */
|
/* WebSocket collection used to update the list of tickets of an Event. */
|
||||||
eventManApp.factory('EventUpdates', ['$websocket', '$location', '$log',
|
eventManApp.factory('EventUpdates', ['$websocket', '$location', '$log', '$rootScope',
|
||||||
function($websocket, $location, $log) {
|
function($websocket, $location, $log, $rootScope) {
|
||||||
var dataStream = null;
|
var dataStream = null;
|
||||||
var data = {};
|
var data = {};
|
||||||
|
|
||||||
|
@ -253,18 +253,19 @@ eventManApp.factory('EventUpdates', ['$websocket', '$location', '$log',
|
||||||
dataStream.close();
|
dataStream.close();
|
||||||
},
|
},
|
||||||
open: function() {
|
open: function() {
|
||||||
$log.debug('open WebSocket connection');
|
|
||||||
dataStream && dataStream.close();
|
|
||||||
var proto = $location.protocol() == 'https' ? 'wss' : 'ws';
|
var proto = $location.protocol() == 'https' ? 'wss' : 'ws';
|
||||||
dataStream = $websocket(proto + '://' + $location.host() + ':' + $location.port() +
|
var url = proto + '://' + $location.host() + ':' + $location.port() +
|
||||||
'/ws/' + $location.path() + '/updates');
|
'/ws/' + $location.path() + '/updates?uuid=' + $rootScope.app_uuid;
|
||||||
|
$log.debug('open WebSocket connection to ' + url);
|
||||||
|
//dataStream && dataStream.close();
|
||||||
|
dataStream = $websocket(url);
|
||||||
|
|
||||||
dataStream.onMessage(function(message) {
|
dataStream.onMessage(function(message) {
|
||||||
$log.debug('EventUpdates message received');
|
$log.debug('EventUpdates message received');
|
||||||
data.update = angular.fromJson(message.data);
|
data.update = angular.fromJson(message.data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return methods;
|
return methods;
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""print_label.py - print a label with the name, the company and the person_id (in a barcode) of an attendee
|
"""print_label.py - print a label with the name, the company and SEQ_HEX (in a barcode) of an attendee
|
||||||
|
|
||||||
Copyright 2015 Emiliano Mattioli <oloturia AT gmail.com>
|
Copyright 2015-2016 Emiliano Mattioli <oloturia AT gmail.com>
|
||||||
Davide Alberani <da@erlug.linux.it>
|
Davide Alberani <da@erlug.linux.it>
|
||||||
RaspiBO <info@raspibo.org>
|
RaspiBO <info@raspibo.org>
|
||||||
|
|
||||||
|
|
|
@ -540,7 +540,11 @@ class CollectionHandler(BaseHandler):
|
||||||
|
|
||||||
def build_ws_url(self, path, proto='ws', host=None):
|
def build_ws_url(self, path, proto='ws', host=None):
|
||||||
"""Return a WebSocket url from a path."""
|
"""Return a WebSocket url from a path."""
|
||||||
return 'ws://127.0.0.1:%s/ws/%s' % (self.listen_port + 1, path)
|
try:
|
||||||
|
args = '?uuid=%s' % self.get_argument('uuid')
|
||||||
|
except:
|
||||||
|
args = ''
|
||||||
|
return 'ws://127.0.0.1:%s/ws/%s%s' % (self.listen_port + 1, path, args)
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def send_ws_message(self, path, message):
|
def send_ws_message(self, path, message):
|
||||||
|
@ -647,12 +651,7 @@ class EventsHandler(CollectionHandler):
|
||||||
operation='appendUnique',
|
operation='appendUnique',
|
||||||
create=False)
|
create=False)
|
||||||
if doc:
|
if doc:
|
||||||
msg_ret = ret.copy()
|
self.send_ws_message('event/%s/tickets/updates' % id_, json.dumps(ret))
|
||||||
msg_ret['ticket'] = msg_ret['ticket'].copy()
|
|
||||||
# Do not send ticket IDs over the WebSocket.
|
|
||||||
if '_id' in msg_ret['ticket']:
|
|
||||||
del msg_ret['ticket']['_id']
|
|
||||||
self.send_ws_message('event/%s/tickets/updates' % id_, json.dumps(msg_ret))
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def handle_put_tickets(self, id_, ticket_id, data):
|
def handle_put_tickets(self, id_, ticket_id, data):
|
||||||
|
@ -877,32 +876,41 @@ class InfoHandler(BaseHandler):
|
||||||
|
|
||||||
|
|
||||||
class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler):
|
class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler):
|
||||||
"""Manage websockets."""
|
"""Manage WebSockets."""
|
||||||
def _clean_url(self, url):
|
def _clean_url(self, url):
|
||||||
return re_slashes.sub('/', url)
|
url = re_slashes.sub('/', url)
|
||||||
|
ridx = url.rfind('?')
|
||||||
|
if ridx != -1:
|
||||||
|
url = url[:ridx]
|
||||||
|
return url
|
||||||
|
|
||||||
def open(self, event_id, *args, **kwargs):
|
def open(self, event_id, *args, **kwargs):
|
||||||
logging.debug('WebSocketEventUpdatesHandler.on_open event_id:%s' % event_id)
|
self.uuid = self.get_argument('uuid')
|
||||||
_ws_clients.setdefault(self._clean_url(self.request.uri), set()).add(self)
|
url = self._clean_url(self.request.uri)
|
||||||
logging.debug('WebSocketEventUpdatesHandler.on_open %s clients connected' % len(_ws_clients))
|
logging.debug('WebSocketEventUpdatesHandler.on_open event_id:%s url:%s' % (event_id, url))
|
||||||
|
_ws_clients.setdefault(url, {})
|
||||||
|
if self.uuid not in _ws_clients[url]:
|
||||||
|
_ws_clients[url][self.uuid] = self
|
||||||
|
logging.debug('WebSocketEventUpdatesHandler.on_open %s clients connected' % len(_ws_clients[url]))
|
||||||
|
|
||||||
def on_message(self, message):
|
def on_message(self, message):
|
||||||
logging.debug('WebSocketEventUpdatesHandler.on_message')
|
url = self._clean_url(self.request.uri)
|
||||||
|
logging.debug('WebSocketEventUpdatesHandler.on_message url:%s' % url)
|
||||||
count = 0
|
count = 0
|
||||||
for client in _ws_clients.get(self._clean_url(self.request.uri), []):
|
_to_delete = set()
|
||||||
if client == self:
|
for uuid, client in _ws_clients.get(url, {}).iteritems():
|
||||||
continue
|
|
||||||
client.write_message(message)
|
|
||||||
count += 1
|
|
||||||
logging.debug('WebSocketEventUpdatesHandler.on_message sent message to %d clients' % count)
|
|
||||||
|
|
||||||
def on_close(self):
|
|
||||||
logging.debug('WebSocketEventUpdatesHandler.on_close')
|
|
||||||
try:
|
try:
|
||||||
if self in _ws_clients.get(self._clean_url(self.request.uri), []):
|
client.write_message(message)
|
||||||
_ws_clients[self._clean_url(self.request.uri)].remove(self)
|
except:
|
||||||
except Exception as e:
|
_to_delete.add(uuid)
|
||||||
logging.warn('WebSocketEventUpdatesHandler.on_close error closing websocket: %s', str(e))
|
continue
|
||||||
|
count += 1
|
||||||
|
for uuid in _to_delete:
|
||||||
|
try:
|
||||||
|
del _ws_clients[url][uuid]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
logging.debug('WebSocketEventUpdatesHandler.on_message sent message to %d clients' % count)
|
||||||
|
|
||||||
|
|
||||||
class LoginHandler(RootHandler):
|
class LoginHandler(RootHandler):
|
||||||
|
|
Loading…
Reference in a new issue