social_stream-presence 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. data/Rakefile +7 -0
  2. data/app/assets/audio/chat/onMessageAudio.mp3 +0 -0
  3. data/app/assets/audio/chat/onMessageAudio.wav +0 -0
  4. data/app/assets/images/black_arrow3.png +0 -0
  5. data/app/assets/images/status/available.png +0 -0
  6. data/app/assets/images/status/away.png +0 -0
  7. data/app/assets/images/status/dnd.png +0 -0
  8. data/app/assets/javascripts/jquery-ui-1.8.14.custom.min.js +789 -0
  9. data/app/assets/javascripts/jquery.tools.min.js +17 -0
  10. data/app/assets/javascripts/jquery.tools.tooltip.js +11 -0
  11. data/app/assets/javascripts/jquery.ui.chatbox.js +260 -0
  12. data/app/assets/javascripts/social_stream-presence.js +2 -0
  13. data/app/assets/javascripts/store.js +20 -0
  14. data/app/assets/javascripts/strophe.js +3612 -0
  15. data/app/assets/javascripts/xmpp_client.js +494 -0
  16. data/app/assets/stylesheets/chat.css +239 -0
  17. data/app/assets/stylesheets/jquery.ui.chatbox.css +54 -0
  18. data/app/assets/stylesheets/social_stream-presence.css +3 -0
  19. data/app/controllers/xmpp_controller.rb +223 -0
  20. data/app/helpers/xmpp_helper.rb +20 -0
  21. data/app/views/xmpp/_chat.html.erb +63 -0
  22. data/app/views/xmpp/_chat_connecting.html.erb +8 -0
  23. data/app/views/xmpp/_chat_contacts.html.erb +46 -0
  24. data/app/views/xmpp/_chat_off.html.erb +35 -0
  25. data/app/views/xmpp/active_users.html.erb +33 -0
  26. data/app/views/xmpp/chat.html.erb +13 -0
  27. data/app/views/xmpp/index.html +19 -0
  28. data/app/views/xmpp/test.html.erb +11 -0
  29. data/config/routes.rb +15 -0
  30. data/db/migrate/20110711111408_add_connected_column_to_user.rb +9 -0
  31. data/db/migrate/20110928135031_add_status_column_to_user.rb +9 -0
  32. data/ejabberd/conf/ejabberd.cfg +625 -0
  33. data/ejabberd/conf/ejabberdctl.cfg +154 -0
  34. data/ejabberd/conf/inetrc +3 -0
  35. data/ejabberd/conf/server.pem +37 -0
  36. data/ejabberd/conf/ssconfig.cfg +32 -0
  37. data/ejabberd/ejabberd_scripts/authentication_script +117 -0
  38. data/ejabberd/ejabberd_scripts/authentication_script_org +114 -0
  39. data/ejabberd/ejabberd_scripts/compile_module +34 -0
  40. data/ejabberd/ejabberd_scripts/emanagement +245 -0
  41. data/ejabberd/ejabberd_scripts/generate_random_password +18 -0
  42. data/ejabberd/ejabberd_scripts/kill_authentication_script.sh +13 -0
  43. data/ejabberd/ejabberd_scripts/reset_connection_script +55 -0
  44. data/ejabberd/ejabberd_scripts/reset_logs.sh +23 -0
  45. data/ejabberd/ejabberd_scripts/set_connection_script +48 -0
  46. data/ejabberd/ejabberd_scripts/set_presence_script +48 -0
  47. data/ejabberd/ejabberd_scripts/show_config.sh +30 -0
  48. data/ejabberd/ejabberd_scripts/start_ejabberd.sh +68 -0
  49. data/ejabberd/ejabberd_scripts/stop_ejabberd.sh +12 -0
  50. data/ejabberd/ejabberd_scripts/synchronize_presence_script +57 -0
  51. data/ejabberd/ejabberd_scripts/unset_connection_script +48 -0
  52. data/ejabberd/mod_admin_extra/mod_admin_extra.beam +0 -0
  53. data/ejabberd/mod_admin_extra/mod_admin_extra.erl +1560 -0
  54. data/ejabberd/mod_sspresence/mod_sspresence.beam +0 -0
  55. data/ejabberd/mod_sspresence/mod_sspresence.erl +257 -0
  56. data/lib/social_stream-presence.rb +19 -2
  57. data/lib/social_stream/migrations/presence.rb +9 -0
  58. data/lib/social_stream/presence/engine.rb +62 -0
  59. data/lib/social_stream/presence/models/buddy_manager.rb +76 -0
  60. data/lib/social_stream/presence/version.rb +5 -0
  61. data/lib/tasks/presence/synchronize.rake +63 -0
  62. data/social_stream-presence.gemspec +4 -4
  63. metadata +69 -11
  64. data/.project +0 -17
@@ -0,0 +1,494 @@
1
+ ////////////////////
2
+ //Test functions
3
+ ////////////////////
4
+
5
+ function log(msg) {
6
+ //console.log(msg)
7
+ }
8
+
9
+
10
+ ////////////////////
11
+ //Hash table
12
+ ////////////////////
13
+ var statusMessage = new Array();
14
+ statusMessage[''] = "";
15
+ statusMessage['chat'] = "";
16
+ statusMessage['away'] = "Away";
17
+ statusMessage['xa'] = "Away";
18
+ statusMessage['dnd'] = "Busy";
19
+
20
+ ////////////////////
21
+ //Strophe functions
22
+ ////////////////////
23
+
24
+ //Global variables
25
+ var userStatus = "chat";
26
+ var awayTimerPeriod = 16000;
27
+ var timerPeriod = 5000;
28
+ var refreshMinTime = 3*timerPeriod;
29
+ var awayTime = 300000;
30
+ var awayCounter = 0;
31
+ var timerCounter = 0;
32
+ var connection = null;
33
+ var userConnected = false;
34
+ var reconnectAttempts = 3;
35
+ var awayTimer;
36
+ var timer;
37
+ var requestContacts=false;
38
+ var cyclesToRefresh = (refreshMinTime/timerPeriod);
39
+
40
+ function onConnect(status) {
41
+
42
+ //Status.ERROR An error has occurred
43
+ //Status.CONNECTING The connection is currently being made
44
+ //Status.CONNFAIL The connection attempt failed
45
+ //Status.AUTHENTICATING The connection is authenticating
46
+ //Status.AUTHFAIL The authentication attempt failed
47
+ //Status.CONNECTED The connection has succeeded
48
+ //Status.DISCONNECTED The connection has been terminated
49
+ //Status.DISCONNECTING The connection is currently being terminated
50
+ //Status.ATTACHED The connection has been attached
51
+
52
+ log('Strophe onConnect callback call with status ' + status);
53
+
54
+ if (status == Strophe.Status.ATTACHED){
55
+ log('Strophe connection attached');
56
+ return;
57
+ }
58
+
59
+ if (status == Strophe.Status.AUTHENTICATING ){
60
+ log('Strophe connection AUTHENTICATING');
61
+ return;
62
+ }
63
+
64
+ if (status == Strophe.Status.CONNECTING) {
65
+ log('Strophe is connecting.');
66
+ return;
67
+ }
68
+
69
+
70
+ clearTimeout(initialTimer);
71
+
72
+ if (status == Strophe.Status.CONNFAIL) {
73
+ log('Strophe failed to connect.');
74
+ userConnected = false;
75
+ setTimeout ("onReconnect()", 3000);
76
+ } else if (status == Strophe.Status.AUTHFAIL) {
77
+ log('Strophe authentication fail.');
78
+ if ((window.sessionStorage)&&(sessionStorage.getItem("ss_user_pass") != null)){
79
+ sessionStorage.setItem("ss_user_pass",null);
80
+ }
81
+ userConnected = false;
82
+ } else if (status == Strophe.Status.ERROR) {
83
+ log('Strophe error.');
84
+ userConnected = false;
85
+ } else if (status == Strophe.Status.DISCONNECTED) {
86
+ log('Strophe is disconnected.');
87
+ userConnected = false;
88
+ clearTimeout(awayTimer);
89
+ setTimeout ("onReconnect()", 3000);
90
+ } else if (status == Strophe.Status.CONNECTED) {
91
+ log('Strophe is connected.');
92
+ log('Presenze stanza send for:' + connection.jid);
93
+ connection.addHandler(onMessage, null, 'message', null, null, null);
94
+ connection.addHandler(onPresence, null, 'presence', null, null, null);
95
+ //addHandler:(callback, namespace to match, stanza name, stanza type, stanza id , stanza from, options)
96
+ sendStatus(userStatus);
97
+ userConnected = true;
98
+ awayTimer = setInterval("awayTimerFunction()", awayTimerPeriod);
99
+ timer = setInterval("timerFunction()", timerPeriod);
100
+ }
101
+
102
+ updateChatWindow();
103
+ }
104
+
105
+ function onReconnect(){
106
+ if ((connection != null)&&(!userConnected)) {
107
+ if (reconnectAttempts>0) {
108
+ reconnectAttempts--;
109
+ connectToServer(null);
110
+ setTimeout ("onReconnect()", 9000);
111
+ } else {
112
+ //Notify issue to Rails App Server?
113
+ }
114
+ }
115
+ }
116
+
117
+ function onMessage(msg) {
118
+ var to = msg.getAttribute('to');
119
+ var from = msg.getAttribute('from');
120
+ var type = msg.getAttribute('type');
121
+ var elems = msg.getElementsByTagName('body');
122
+
123
+ if (type == "chat" && elems.length > 0) {
124
+
125
+ var body = elems[0];
126
+ var from_slug = from.split("@")[0];
127
+ var from_name = $("#" + from_slug).attr("name");
128
+ var from_jid = from_slug + "@" + domain;
129
+
130
+ log(from + ' says: ' + Strophe.getText(body));
131
+
132
+ if (typeof ($('div.user_presence[slug=' + from_slug + ']').attr('name')) == 'undefined') {
133
+ var from_name = from_slug;
134
+ } else {
135
+ var from_name = $('div.user_presence[slug=' + from_slug + ']').attr('name');
136
+ }
137
+
138
+ if (mustPlaySoundForChatWindow(window[from_slug])){
139
+ playSound("onMessageAudio");
140
+ }
141
+
142
+ if (createChatBox(from_slug,from_name,from_jid,user_name,user_jid)) {
143
+ } else {
144
+ window[from_slug].chatbox("option", "boxManager").toggleBox(true);
145
+ }
146
+
147
+ $("#" + from_slug).chatbox("option", "boxManager").addMsg(from_name, Strophe.getText(body));
148
+ rotatePriority(from_slug);
149
+ }
150
+
151
+ // we must return true to keep the handler alive.
152
+ // returning false would remove it after it finishes.
153
+ return true;
154
+ }
155
+
156
+
157
+ function onPresence(presence) {
158
+ //log(presence);
159
+ from = $(presence).attr('from');
160
+ slug = from.split("@")[0];
161
+ if(slug != user_slug){
162
+ setTimeout("refreshChatWindow()", 2000);
163
+ }
164
+ return true;
165
+ }
166
+
167
+
168
+ function sendChatMessage(from,to,text){
169
+ var type = "chat";
170
+ var body= $build("body");
171
+ body.t(text);
172
+ var message = $msg({to: to, from: from, type: 'chat'}).cnode(body.tree());
173
+ connection.send(message.tree());
174
+ log(from + ' says: ' + text + ' to ' + to);
175
+ resumeAwayTimerIfAway();
176
+ return true;
177
+ }
178
+
179
+
180
+ ////////////////////
181
+ //Audio functions
182
+ ////////////////////
183
+
184
+ //Global audio variables
185
+ var onMessageAudio;
186
+
187
+ var html5_audiotypes=[
188
+ ["mp3","audio/mpeg"],
189
+ //["mp4","audio/mp4"],
190
+ //["ogg","audio/ogg"],
191
+ ["wav","audio/wav"]
192
+ ]
193
+
194
+ function initAudio(){
195
+ //Init all audio files
196
+ initSound("onMessageAudio");
197
+ }
198
+
199
+ function initSound(sound){
200
+
201
+ //Check support for HTML5 audio
202
+ var html5audio=document.createElement('audio')
203
+
204
+ if (html5audio.canPlayType){
205
+ path = 'assets/chat/' + sound;
206
+ window[sound] = new Audio();
207
+
208
+ for(i=0; i<html5_audiotypes.length; i++){
209
+ if (window[sound].canPlayType(html5_audiotypes[i][1])) {
210
+ var source= document.createElement('source');
211
+ source.type= html5_audiotypes[i][1];
212
+ source.src= path + '.' + html5_audiotypes[i][0];
213
+ window[sound].addEventListener('ended', endSoundListener);
214
+ window[sound].appendChild(source);
215
+ }
216
+ }
217
+ } else {
218
+ //Browser doesn't support HTML5 audio
219
+ }
220
+ }
221
+
222
+ function endSoundListener(){ }
223
+
224
+ function playSound(sound){
225
+ if (window[sound]!=null){
226
+ window[sound].play();
227
+ } else {
228
+ //Fallback option: When browser doesn't support HTML5 audio
229
+ $('body').append('<embed src="/' + sound + '.mp3" autostart="true" hidden="true" loop="false">');
230
+ }
231
+ }
232
+
233
+ function initAndPlaySound(sound){
234
+ initSound(sound);
235
+ playSound(sound);
236
+ }
237
+
238
+
239
+
240
+ ////////////////////
241
+ //Chat view jquery
242
+ ////////////////////
243
+
244
+ function setUserFunctions(){
245
+
246
+ $("div.user_presence").click(function(event, ui){
247
+ var guest_name = $(this).attr("name");
248
+ var guest_slug = $(this).attr("slug");
249
+ var guest_jid = guest_slug + "@" + domain;
250
+
251
+ if (createChatBox(guest_slug, guest_name, guest_jid, user_name, user_jid)) {
252
+ } else {
253
+ window[guest_slug].chatbox("option", "boxManager").toggleBox(true);
254
+ };
255
+ });
256
+
257
+
258
+ //JQuery DropdwanStatus
259
+
260
+ $(".dropdown dt a").click(function(event) {
261
+ event.preventDefault();
262
+ $(".dropdown dd ul").toggle();
263
+ });
264
+
265
+ $(".dropdown dd ul li a.option").click(function(event) {
266
+ event.preventDefault();
267
+ var text = $(this).html();
268
+ $(".dropdown dt a span").html(text);
269
+ userStatus = getSelectedValue("status");
270
+ sendStatus(userStatus);
271
+ $(".dropdown dd ul").hide();
272
+ });
273
+
274
+
275
+ function getSelectedValue(id) {
276
+ return $("#" + id).find("dt a span.value").html();
277
+ }
278
+
279
+ $(document).bind('click', function(e) {
280
+ var $clicked = $(e.target);
281
+ if (! $clicked.parents().hasClass("dropdown")){
282
+ //Click outside the select...
283
+ $(".dropdown dd ul").hide();
284
+ }
285
+ });
286
+ }
287
+
288
+
289
+ function awayTimerFunction(){
290
+ awayCounter++;
291
+ if (awayCounter > (awayTime/awayTimerPeriod)){
292
+ userStatus = "away";
293
+ sendStatus(userStatus);
294
+ clearTimeout(awayTimer);
295
+ } else {
296
+ userStatus = "chat";
297
+ }
298
+ }
299
+
300
+ function resumeAwayTimerIfAway(){
301
+ if (userStatus == "away"){
302
+ awayCounter = 0;
303
+ userStatus = "chat";
304
+ sendStatus(userStatus);
305
+ awayTimer = setInterval("awayTimerFunction()", awayTimerPeriod);
306
+ }
307
+ }
308
+
309
+ function timerFunction(){
310
+ timerCounter++;
311
+
312
+ if((timerCounter > cyclesToRefresh)&&(requestContacts)) {
313
+ requestContacts = false;
314
+ updateChatWindow();
315
+ }
316
+ }
317
+
318
+ function refreshChatWindow(){
319
+ if(timerCounter > cyclesToRefresh){
320
+ updateChatWindow();
321
+ } else {
322
+ requestContacts = true;
323
+ }
324
+ }
325
+
326
+ function updateChatWindow(){
327
+ timerCounter=0;
328
+ log("updateChatWindow()");
329
+ $.post("/chatWindow", { userConnected: userConnected }, function(data){
330
+ $("#chat_partial").html(data);
331
+ if (userConnected) {
332
+ $(".user_presence a[title]").tooltip();
333
+ setUserFunctions();
334
+ }
335
+ });
336
+ }
337
+
338
+ function sendStatus(status){
339
+ if (status in statusMessage){
340
+ //Send status to the XMPP Server
341
+ var pres = $pres()
342
+ .c('status')
343
+ .t(statusMessage[status]).up() //Status message
344
+ .c('show')
345
+ .t(status);
346
+ connection.send(pres.tree());
347
+ }
348
+ }
349
+
350
+
351
+ function mustPlaySoundForChatWindow(chatBox){
352
+ if(userStatus == "dnd"){
353
+ return false;
354
+ }
355
+
356
+ if (typeof chatBox == 'undefined') {
357
+ return true;
358
+ }
359
+
360
+ //Enable sounds only for new (or hidden) chatBoxes
361
+ return (chatBox.chatbox("option", "hidden") == true);
362
+ }
363
+
364
+ ////////////////////
365
+ //Chat functions
366
+ ////////////////////
367
+
368
+ var nBox = 0;
369
+ var maxBox = 5;
370
+ var chatBoxWidth = 230;
371
+ var visibleChatBoxes = new Array();
372
+ var chatBoxSeparation = chatBoxWidth+12;
373
+
374
+
375
+ function createChatBox(guest_slug,guest_name,guest_jid,user_name,user_jid){
376
+
377
+ //Create chatbox for new conversations
378
+ //Open chatbox for old conversations
379
+
380
+ //Box Variable name = guest_slug
381
+ if (typeof window[guest_slug] == 'undefined') {
382
+
383
+ //Add div with id = guest_slug
384
+ $("#chat_divs").append("<div id=" + guest_slug + " name=" + guest_name + "></div>")
385
+
386
+ //Add CSS [...]
387
+
388
+
389
+ //Offset Management for new box
390
+ boxParams = getBoxParams();
391
+ var offset = boxParams[0];
392
+ var position = boxParams[1];
393
+
394
+
395
+ window[guest_slug] = $("#" + guest_slug).chatbox({id: user_name,
396
+ user:{key : "value"},
397
+ hidden: false,
398
+ offset: offset, // relative to right edge of the browser window
399
+ width: chatBoxWidth, // width of the chatbox
400
+ title : guest_name,
401
+ position: position,
402
+ priority: visibleChatBoxes.length+1,
403
+ boxClosed: function(id) {
404
+
405
+ position = $("#" + guest_slug).chatbox("option", "position");
406
+
407
+ for (i=position+1;i<visibleChatBoxes.length+1;i++){
408
+ visibleChatBoxes[i-1].chatbox("option", "offset", visibleChatBoxes[i-1].chatbox("option", "offset") - chatBoxSeparation);
409
+ visibleChatBoxes[i-1].chatbox("option", "position", visibleChatBoxes[i-1].chatbox("option", "position") - 1 );
410
+ }
411
+
412
+ visibleChatBoxes.splice(position-1,1);
413
+ $("#" + guest_slug).chatbox("option", "hidden", true);
414
+ nBox--;
415
+ },
416
+
417
+ messageSent : function(id, user, msg) {
418
+ rotatePriority(guest_slug);
419
+ $("#" + guest_slug).chatbox("option", "boxManager").addMsg(id, msg);
420
+ sendChatMessage(user_jid,guest_jid,msg);
421
+ }});
422
+
423
+ visibleChatBoxes[position-1] = window[guest_slug];
424
+
425
+
426
+
427
+ return true;
428
+
429
+ } else {
430
+
431
+ if (visibleChatBoxes.indexOf(window[guest_slug]) == -1) {
432
+
433
+ //Offset Management for old box
434
+ boxParams = getBoxParams();
435
+ var offset = boxParams[0];
436
+ var position = boxParams[1];
437
+
438
+ window[guest_slug].chatbox("option", "offset", offset);
439
+ window[guest_slug].chatbox("option", "position", position);
440
+ visibleChatBoxes[position-1] = window[guest_slug];
441
+ }
442
+
443
+ window[guest_slug].chatbox("option", "hidden", false);
444
+ return false;
445
+ }
446
+
447
+ }
448
+
449
+ function getBoxParams(){
450
+
451
+ var boxParams = new Array(2);
452
+
453
+ if (nBox==maxBox){
454
+ //Select box to replaced
455
+ replaced = visibleChatBoxes[getBoxIndexToReplace()];
456
+ replaced.chatbox("option", "hidden", true)
457
+ index = visibleChatBoxes.indexOf(replaced);
458
+ boxParams[0] = replaced.chatbox("option", "offset")
459
+ boxParams[1] = replaced.chatbox("option", "position")
460
+ } else {
461
+ nBox++;
462
+ boxParams[0] = (nBox-1)*(chatBoxSeparation);
463
+ boxParams[1] = nBox;
464
+ }
465
+
466
+ return boxParams
467
+ }
468
+
469
+
470
+ function getBoxIndexToReplace(){
471
+
472
+ tmp = visibleChatBoxes[0];
473
+ for (i=0;i<visibleChatBoxes.length;i++){
474
+ if (visibleChatBoxes[i].chatbox("option", "priority") > tmp.chatbox("option", "priority")) {
475
+ tmp = visibleChatBoxes[i];
476
+ }
477
+ }
478
+
479
+ return visibleChatBoxes.indexOf(tmp);
480
+ }
481
+
482
+ function rotatePriority(guest_slug){
483
+ priority = $("#" + guest_slug).chatbox("option", "priority")
484
+ if(priority>1){
485
+ for (i=0;i<visibleChatBoxes.length;i++){
486
+ if(visibleChatBoxes[i].chatbox("option", "priority")<priority){
487
+ visibleChatBoxes[i].chatbox("option", "priority",visibleChatBoxes[i].chatbox("option", "priority")+1);
488
+ }
489
+ }
490
+ $("#" + guest_slug).chatbox("option", "priority", 1);
491
+ }
492
+ }
493
+
494
+