Browse code

Stahovanie vcardu a statusy asynchronne zo servera

Cinan Rakosnik authored on 24/03/2013 at 17:05:52
Showing 9 changed files
... ...
@@ -1,4 +1,7 @@
1 1
 this.App =
2
+  debug: (msg) ->
3
+    console.log msg
4
+
2 5
   UI:
3 6
     setAutoHeight: ->
4 7
       height = $(window).height()
... ...
@@ -10,24 +13,42 @@ this.App =
10 10
       App._dispatcher = new WebSocketRails('www.xmpp.dev:3000/websocket')
11 11
       App._dispatcher.on_open = =>
12 12
         @_setupBackboneComponents()
13
+        @_bindEvents()
13 14
         callback?()
14 15
 
15 16
     fetch: (options) ->
16 17
       _.defaults(options, {data: {} })
17 18
       App._dispatcher.trigger(options.event, options.data, options.success, options.error)
18 19
 
19
-    getRoster: ->
20
-      App.Com.fetch({
21
-        event: 'app.roster.contacts'
22
-        success: (data, contacts = data.contacts) ->
23
-          _.each(contacts, (contact) ->
24
-            newContact = new Xmpp.Models.Contact(contact)
20
+    initRoster: ->
21
+      App.Com.fetch(
22
+        event: 'app.roster.initRoster'
23
+        success: (data) ->
24
+          _.each(data.contacts, (jid) ->
25
+            newContact = new Xmpp.Models.Contact(id: jid, jid: jid)
25 26
             App.Collections.Contacts.add newContact
26 27
           )
27
-      })
28
+      )
29
+
30
+    startFetchingVcards: ->
31
+      App.Com.fetch(event: 'app.roster.startFetchingVcards')
32
+
33
+    startPollingRoster: ->
34
+      App.Com.fetch(event: 'app.roster.startPolling')
28 35
 
29 36
     _setupBackboneComponents: ->
30 37
       App.Collections.Contacts = new Xmpp.Collections.ContactsCollection()
31 38
 
39
+    _bindEvents: ->
40
+      App._dispatcher.bind('app.roster.statusChanged', (result) ->
41
+        App.debug 'change contact state'
42
+        App.Collections.Contacts.updateStatus(result)
43
+      )
44
+
45
+      App._dispatcher.bind('app.roster.vcard', (result) ->
46
+        App.debug 'got vcard'
47
+        App.Collections.Contacts.udpateVcard(result)
48
+      )
49
+
32 50
   Collections:
33 51
     Contacts: null
... ...
@@ -10,7 +10,9 @@
10 10
 #= require chat
11 11
 
12 12
 App.Com.connect(->
13
-  App.Com.getRoster()
13
+  App.Com.initRoster()
14
+  App.Com.startFetchingVcards()
15
+  App.Com.startPollingRoster()
14 16
   #= require i18n
15 17
   #= require i18n/translations
16 18
 )
... ...
@@ -2,12 +2,18 @@ class Xmpp.Models.Contact extends Xmpp.Models.Model
2 2
   namespace: 'app.roster'
3 3
 
4 4
   defaults:
5
-    status: ''
6
-    state: 'online'
5
+    jid: ''
6
+    name: ''
7
+    status: 'offline'
8
+    message: ''
7 9
 
8 10
   initialize: ->
9 11
     _.bindAll(this)
10 12
 
13
+    if ! @get('name')
14
+      @set(name: @get('jid'))
15
+
16
+
11 17
 class Xmpp.Collections.ContactsCollection extends Backbone.Collection
12 18
   model: Xmpp.Models.Contact
13 19
 
... ...
@@ -21,4 +27,10 @@ class Xmpp.Collections.ContactsCollection extends Backbone.Collection
21 21
 
22 22
   appendContact: (contact) ->
23 23
     @counter++
24
-    @friendsList.appendContact(contact)
25 24
\ No newline at end of file
25
+    @friendsList.appendContact(contact)
26
+
27
+  updateStatus: (response) ->
28
+    @get(response.jid).set(message: response.status.message, status: response.status.status)
29
+
30
+  udpateVcard: (response) ->
31
+    @get(response.jid).set(name: response.vcard.name)
26 32
\ No newline at end of file
... ...
@@ -1,15 +1,13 @@
1
-%li.clear.user
2
-  .avatar
3
-    %img{src: 'assets/avatar.png', alt: ("t chat.roster.avatar_alt") }
4
-  %h1
5
-    #{@jid}
6
-    -#{@state}
7
-    %span.status.icon-record{class: "#{@state}"}
8
-  %h2 #{@jid}
9
-  -#%span.action
10
-    %span.icon-bubbles
11
-      %span invite
12
--#%li.clear.user
1
+.avatar
2
+  %img{src: 'assets/avatar.png', alt: ("t chat.roster.avatar_alt") }
3
+%h1
4
+  #{@name}
5
+  %span.status.icon-record{class: "#{@status}"}
6
+%h2 #{@message}  
7
+%span.action
8
+  -#%span.icon-bubbles
9
+    %span invite
10
+
13 11
 -#  .avatar
14 12
 -#    %img{src: 'assets/avatar.png', alt: t("chat.avatar_alt")}
15 13
 -#  %h1
... ...
@@ -1,4 +1,2 @@
1 1
 %h1.group-header #{@title}
2 2
 %ul
3
-  -for contact in @contacts
4
-    != JST['backbone/templates/contacts/contact'](contact)
... ...
@@ -2,6 +2,8 @@ Xmpp.Views.Contacts ||= {}
2 2
 
3 3
 class Xmpp.Views.Contacts.ContactView extends Backbone.View
4 4
   template: JST["backbone/templates/contacts/contact"]
5
+  tagName: 'li'
6
+  className: 'clear user'
5 7
 
6 8
 #  events:
7 9
 #    'click li.user': 'something'
... ...
@@ -9,10 +11,16 @@ class Xmpp.Views.Contacts.ContactView extends Backbone.View
9 9
   initialize: () ->
10 10
     _.bindAll(this)
11 11
 
12
-    @el = '#' + @attributes['listView'].attributes['id'] + ' ul'
12
+    # Patrim nejakemu zoznamu
13
+    @parentList = @attributes['listView']
13 14
 
15
+    @model.on('change', @updateContact, this)
16
+
17
+  updateContact: (contact) ->
18
+    @model = contact
14 19
     @render()
15 20
 
16 21
   render: ->
17 22
     contact = @model.toJSON()
18
-    $(@el).append(@template(contact))
23
+    $(@el).html(@template(contact))
24
+    return this
19 25
\ No newline at end of file
... ...
@@ -9,18 +9,24 @@ class Xmpp.Views.Contacts.ListView extends Backbone.View
9 9
     @el = '#' + @attributes['id']
10 10
     @title = @attributes['title']
11 11
 
12
-    @contacts = []
12
+    @contactViews = []
13 13
 
14
-    @render()
14
+    @createListContainer()
15 15
 
16
-  appendContact: (contact) ->
17
-    @contacts.push = new Xmpp.Views.Contacts.ContactView(model: contact, attributes: {listView: this})
18
-
19
-  render: (contacts) ->
20
-    contacts ||= []
21
-    json_contacts = new Array(contacts.length)
22
-    _.each(contacts, (i, v) ->
23
-      json_contacts[i] = v.toJSON()
24
-    )
16
+  createListContainer: ->
17
+    $(@el).html(@template(title: @title))
25 18
 
26
-    $(@el).html(@template(title: @title, contacts: json_contacts))
27 19
\ No newline at end of file
20
+  appendContact: (contact) ->
21
+    view =  new Xmpp.Views.Contacts.ContactView(model: contact, attributes: {listView: this})
22
+    @contactViews.push view
23
+    @render(view.render().el)
24
+
25
+  render: (contactHtml) ->
26
+    if (contactHtml?)
27
+      $(@el).find('ul').append(contactHtml)
28
+    else
29
+      _.each(@contactViews, (i, contact) =>
30
+        @render(contact.render().el)
31
+      )
32
+
33
+    return this
28 34
\ No newline at end of file
... ...
@@ -11,8 +11,12 @@ class WsRosterController < WebsocketRails::BaseController
11 11
         @storages.each do |storage|
12 12
             connection_store[storage] = []
13 13
         end
14
+
15
+        connection_store[:link_roster_client] = {}
14 16
     end
15 17
 
18
+    ##
19
+    # Pripoj sa na jabber ucty.
16 20
     def connect
17 21
         initialize_storage()
18 22
 
... ...
@@ -21,40 +25,83 @@ class WsRosterController < WebsocketRails::BaseController
21 21
         clients.each do |credentials|
22 22
             begin
23 23
                 client = Signin.try_login(credentials["jid"], credentials["pass"])
24
-                client.send(Jabber::Presence.new.set_type(:available))
25
-
26 24
                 connection_store[:clients] << client
27
-                connection_store[:rosters] << Jabber::Roster::Helper.new(client)
28 25
             rescue Signin::LoginError
29
-                trigger_failure msg: credentials["jid"]
26
+                send_message 'app.client.cannot_connect', true
30 27
             end
31 28
         end
32 29
     end
33 30
 
34 31
     ##
35
-    # Vrat vsetkych priatelov v rosteri
36
-    def get_contacts
37
-        all_contacts = []
32
+    # Inicializuj roster so zoznamom ludi v nom.
33
+    # Vrat zoznam ludi (ich JID).
34
+    def init_roster
35
+        all_jids = []
36
+
37
+        connection_store[:clients].each do |client|
38
+            roster = Jabber::Roster::Helper.new(client)
39
+
40
+            connection_store[:rosters] << roster
41
+            connection_store[:link_roster_client][roster] = client
38 42
 
39
-        connection_store[:rosters].each do |roster|
40
-            roster.wait_for_roster
41 43
             roster.get_roster()
44
+            roster.wait_for_roster()
42 45
 
43 46
             roster.items.each do |jid, contact|
44
-                all_contacts << {
45
-                    jid: jid.to_s
46
-                }
47
+                all_jids << jid.to_s
47 48
             end
48 49
         end
49 50
 
50
-        trigger_success contacts: all_contacts
51
+        trigger_success contacts: all_jids
51 52
     end
52 53
 
53
-    def disconnect
54
-        if connection_store[:clients]
55
-            connection_store[:clients].each do |client|
56
-                client.send(Jabber::Presence.new.set_type(:unavailable))
54
+    ##
55
+    # Stiahni vcard ludi v rosteri
56
+    def start_fetching_vcards
57
+        connection_store[:rosters].each do |roster|
58
+            client = connection_store[:link_roster_client][roster]
59
+
60
+            roster.items.each do |jid, contact|
61
+                Thread.new do
62
+                    vcard = get_vcard(client, jid.to_s)
63
+                    send_message 'app.roster.vcard', jid: jid.to_s, vcard: vcard
64
+                end
65
+            end
66
+        end
67
+    end
68
+
69
+    ##
70
+    # Zacni pocuvat zmeny stavov v rosteri
71
+    def start_polling_contacts_state
72
+        connection_store[:rosters].each do |roster|
73
+            roster.add_presence_callback do |roster_item, old_presence, new_presence|
74
+                if new_presence.type == :unavailable
75
+                    result = {status: :offline, message: ''}
76
+                else
77
+                    status = new_presence.show
78
+                    status = case status
79
+                        when :away, :xa then :away
80
+                        when :dnd       then :dnd
81
+                        else                 :online
82
+                    end
83
+
84
+                    result = { status: status, message: new_presence.status.to_s }
85
+                end
86
+
87
+                send_message 'app.roster.statusChanged',
88
+                             jid: roster_item.jid.strip.to_s, status: result
57 89
             end
90
+
91
+            # ak by som poslal svoju Presence, tak add_presence_callback nezachyti
92
+            # stav ludi, ktore sa odosielaju hned po zadani mojej Presence
93
+            client = connection_store[:link_roster_client][roster]
94
+            client.send(Jabber::Presence.new.set_type(:available))
95
+        end
96
+    end
97
+
98
+    def disconnect
99
+        connection_store[:clients] && connection_store[:clients].each do |client|
100
+            client.close()
58 101
         end
59 102
 
60 103
         @storages.each do |storage|
... ...
@@ -67,4 +114,14 @@ class WsRosterController < WebsocketRails::BaseController
67 67
     def add_friend(data)
68 68
 
69 69
     end
70
+
71
+    private
72
+
73
+    def get_vcard(my_client, contacts_jid)
74
+        vcard = Jabber::Vcard::Helper.get(my_client, contacts_jid)
75
+
76
+        { name: vcard && (vcard["FN"] || vcard["NICKNAME"]) || contacts_jid,
77
+          avatar: '' #TODO avatar
78
+        }
79
+    end
70 80
 end
... ...
@@ -42,14 +42,16 @@ WebsocketRails::EventMap.describe do
42 42
   #   end
43 43
   # The above will handle an event triggered on the client like `product.new`.
44 44
 
45
+    #toto asi poide do nadtriedy spajajucej roster a chat a ine veci
45 46
     subscribe :client_connected, to: WsRosterController, with_method: :connect
46 47
     subscribe :client_disconnected, to: WsRosterController, with_method: :disconnect
47 48
 
48 49
     namespace :app do
49 50
 
50 51
         namespace :roster do
51
-            subscribe :connect, to: WsRosterController, with_method: :connect
52
-            subscribe :contacts, to: WsRosterController, with_method: :get_contacts
52
+            subscribe :initRoster,          to: WsRosterController, with_method: :init_roster
53
+            subscribe :startFetchingVcards, to: WsRosterController, with_method: :start_fetching_vcards
54
+            subscribe :startPolling,        to: WsRosterController, with_method: :start_polling_contacts_state
53 55
         end
54 56
 
55 57
     end