Skip to content

Commit

Permalink
Adds user notifications, basic Kandan.Data APIs and some other re-org…
Browse files Browse the repository at this point in the history
…anization

Signed-off-by: Akash Manohar J <akash@akash.im>
  • Loading branch information
HashNuke committed Mar 12, 2012
1 parent 4472358 commit ec9b415
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 32 deletions.
6 changes: 6 additions & 0 deletions app/assets/javascripts/backbone/broadcasters/faye.js.coffee
Expand Up @@ -12,6 +12,12 @@ class Kandan.Broadcasters.FayeBroadcaster
callback(message)
}
@faye_client.addExtension(auth_extension)
@faye_client.subscribe "/app/activities", (data)=>
console.log "activities", data.data.user
Kandan.Helpers.Channels.add_activity({
user: data,
action: data.event.split("#")[1]
})


subscribe: (channel)->
Expand Down
13 changes: 13 additions & 0 deletions app/assets/javascripts/backbone/data/active_users.js.coffee
@@ -0,0 +1,13 @@
class Kandan.Data.ActiveUsers
@callbacks: []

@all: ()->
Kandan.Helpers.ActiveUsers.all()

@register_callback: (event, callback)->
@callbacks.push(callback)

@unregister_callback: (event, callback)->
delete @callbacks[@callbacks.indexOf(callback)]
@callbacks.filter (element, index, array)->
element!=undefined
3 changes: 3 additions & 0 deletions app/assets/javascripts/backbone/data/users.js.coffee
@@ -0,0 +1,3 @@
class Kandan.Data.Users
@current_user: ()->
Kandan.Helpers.Users.current_user()
@@ -0,0 +1,4 @@
class Kandan.Helpers.ActiveUsers

@all: ()->
# TODO return the active users list
2 changes: 2 additions & 0 deletions app/assets/javascripts/backbone/kandan.js.coffee
Expand Up @@ -13,6 +13,8 @@ window.Kandan =
Routers: {}
Helpers: {}
Broadcasters: {}
Data: {}

init: ->
channels = new Kandan.Collections.Channels()
channels.fetch({success: ()=>
Expand Down
6 changes: 6 additions & 0 deletions app/assets/javascripts/backbone/post_init.js.coffee
@@ -0,0 +1,6 @@

$(document).ready ->
$(document).bind "changeData", (event, name, value)->
if name == "active_users"
for callback in Kandan.Helpers.ActiveUsers.callbacks
callback()
@@ -1,9 +1,13 @@
class Kandan.Views.ShowActivity extends Backbone.View
template: JST['activity']

tagName: 'p'
className: 'activity'

render: ()->
if @options.activity.get('message')
@template = JST['activity']
else
@template = JST['user_notification']

$(@el).html(@template({activity: @options.activity}))
@
1 change: 1 addition & 0 deletions app/assets/templates/user_notification.jst.eco
@@ -0,0 +1 @@
<%= @activity.get('user').first_name %> <%= @activity.get('action') %>
10 changes: 6 additions & 4 deletions app/models/activity_observer.rb
@@ -1,9 +1,11 @@
class ActivityObserver < ActiveRecord::Observer

def after_save(activity)
faye_channel = "/channels/#{activity.channel.to_param}"
# TODO move this to a rabl template
broadcast_data = activity.attributes.merge({:user => activity.user.attributes})
Kandan::Config.broadcaster.broadcast(faye_channel, broadcast_data)
if activity.action == "message"
faye_channel = "/channels/#{activity.channel.to_param}"
# TODO move this to a rabl template
broadcast_data = activity.attributes.merge({:user => activity.user.attributes})
Kandan::Config.broadcaster.broadcast(faye_channel, broadcast_data)
end
end
end
16 changes: 16 additions & 0 deletions app/models/channel.rb
@@ -1,3 +1,19 @@
class Channel < ActiveRecord::Base
has_many :activities

class << self
def user_connected(user)
Channel.all.each do |channel|
activity = channel.activities.build(:user_id => user.id, :action => "connect")
activity.save
end
end

def user_disconnected(user)
Channel.all.each do |channel|
activity = channel.activities.build(:user_id => user.id, :action => "disconnect")
activity.save
end
end
end
end
30 changes: 3 additions & 27 deletions config.ru
Expand Up @@ -2,26 +2,8 @@

require ::File.expand_path('../config/environment', __FILE__)
require 'faye'

# TODO move this to the lib dir
class DeviseAuth
def incoming(message, callback)
if message['channel'] == "/meta/subscribe"
auth_token = message['ext']['auth_token']
user = User.find_by_authentication_token(auth_token)
if user
return callback.call(message)
else
message['error'] = "Invalid auth token"
end
end
puts "Message: #{message.inspect}"
callback.call(message)
end

#TODO disable publishing by users
end

require ::File.expand_path("../lib/active_users.rb", __FILE__)
require ::File.expand_path("../lib/faye_extensions/devise_auth.rb", __FILE__)

faye_server = Faye::RackAdapter.new(:mount => "/faye", :timeout => 5)
faye_server.add_extension(DeviseAuth.new)
Expand All @@ -31,16 +13,10 @@ faye_server.add_extension(DeviseAuth.new)
# which should then make the faye server object available
# via the get_client() method on the server


FAYE_CLIENT = faye_server.get_client

faye_server.bind(:subscribe) do |client_id|
puts "SUBSCRIBE #{client_id}"
end

faye_server.bind(:disconnect) do |client_id|
puts "DISCONNECT #{client_id}"
User
ActiveUsers.remove_by_client_id(client_id)
end

run Rack::URLMap.new({
Expand Down
58 changes: 58 additions & 0 deletions lib/active_users.rb
@@ -0,0 +1,58 @@
class ActiveUsers

# TODO has to account for users signed on from multiple devices
@@users = {}

class << self

def add(client_id, user)
publish_message "connected", user if not find_by_user_id(user.id)
@@users[client_id] = user
end

def remove_by_client_id(client_id)
disconnected_user = @@users.delete(client_id)
publish_message "disconnected", disconnected_user if not find_by_user_id(disconnected_user.id)
end

def remove_by_user_id(user_id)
client_id = find_by_user_id(user_id)
if not client_id
remove_by_client_id(client_id)
return true
end
false
end

def find_by_client_id(client_id)
@@users[client_id]
end

def find_by_user_id(user_id)
@@users.each_pair do |client_id, user|
return client_id if user.id == user_id
end
false
end

def all
@@users.values
end

def publish_message(event, user)
# TODO this is cheating.
# Have a common log (activities) with no channelID
# Or find some other way

Channel.send("user_#{event}", user)

FAYE_CLIENT.publish("/app/activities", {
:event => "user##{event}",
:data => {
:user => user,
:active_users => ActiveUsers.all
}
})
end
end
end
22 changes: 22 additions & 0 deletions lib/faye_extensions/devise_auth.rb
@@ -0,0 +1,22 @@
class DeviseAuth
def incoming(message, callback)
if message['channel'] == "/meta/subscribe"
auth_token = message['ext']['auth_token']
user = User.find_by_authentication_token(auth_token)
if user
ActiveUsers.add(message['clientId'], user) # if not meta_channels?(message['subscription'])
return callback.call(message)
else
message['error'] = "Invalid auth token"
end
end
puts "Message: #{message.inspect}"
callback.call(message)
end

# def meta_channels?(channel)
#if ("/app/activities" =~ /\/app\/.*/ || "/app/activities" =~ /\/app\/.*/
# end

#TODO disable publishing by users or use only user-published msgs
end

0 comments on commit ec9b415

Please sign in to comment.