taiga-front/app/coffee/modules/events.coffee

161 lines
4.3 KiB
CoffeeScript

###
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# File: modules/events.coffee
###
taiga = @.taiga
module = angular.module("taigaEvents", [])
class EventsService
constructor: (@win, @log, @config, @auth) ->
_.bindAll(@)
initialize: (sessionId) ->
@.sessionId = sessionId
@.subscriptions = {}
@.connected = false
@.error = false
@.pendingMessages = []
if @win.WebSocket is undefined
@log.info "WebSockets not supported on your browser"
setupConnection: ->
@.stopExistingConnection()
url = @config.get("eventsUrl", "ws://localhost:8888/events")
@.ws = new @win.WebSocket(url)
@.ws.addEventListener("open", @.onOpen)
@.ws.addEventListener("message", @.onMessage)
@.ws.addEventListener("error", @.onError)
@.ws.addEventListener("close", @.onClose)
stopExistingConnection: ->
if @.ws is undefined
return
@.ws.removeEventListener("open", @.onOpen)
@.ws.removeEventListener("close", @.onClose)
@.ws.removeEventListener("error", @.onError)
@.ws.removeEventListener("message", @.onMessage)
@.ws.close()
delete @.ws
serialize: (message) ->
if _.isObject(message)
return JSON.stringify(message)
return message
sendMessage: (message) ->
@.pendingMessages.push(message)
if not @.connected
return
messages = _.map(@.pendingMessages, @.serialize)
@.pendingMessages = []
for msg in messages
@.ws.send(msg)
subscribe: (scope, routingKey, callback) ->
if @.error
return
@log.debug("Subscribe to: #{routingKey}")
subscription = {
scope: scope,
routingKey: routingKey,
callback: _.debounce(callback, 500, {"leading": true, "trailing": false})
}
message = {
"cmd": "subscribe",
"routing_key": routingKey
}
@.subscriptions[routingKey] = subscription
@.sendMessage(message)
scope.$on("$destroy", => @.unsubscribe(routingKey))
unsubscribe: (routingKey) ->
if @.error
return
@log.debug("Unsubscribe from: #{routingKey}")
message = {
"cmd": "unsubscribe",
"routing_key": routingKey
}
@.sendMessage(message)
onOpen: ->
@.connected = true
@log.debug("WebSocket connection opened")
token = @auth.getToken()
message = {
cmd: "auth"
data: {token: token, sessionId: @.sessionId}
}
@.sendMessage(message)
onMessage: (event) ->
@.log.debug "WebSocket message received: #{event.data}"
data = JSON.parse(event.data)
routingKey = data.routing_key
if not @.subscriptions[routingKey]?
return
subscription = @.subscriptions[routingKey]
subscription.scope.$apply ->
subscription.callback(data.data)
onError: (error) ->
@log.error("WebSocket error: #{error}")
@.error = true
onClose: ->
@log.debug("WebSocket closed.")
@.connected = false
class EventsProvider
setSessionId: (sessionId) ->
@.sessionId = sessionId
$get: ($win, $log, $conf, $auth) ->
service = new EventsService($win, $log, $conf, $auth)
service.initialize(@.sessionId)
return service
@.prototype.$get.$inject = ["$window", "$log", "$tgConfig", "$tgAuth"]
module.provider("$tgEvents", EventsProvider)