social_stream-presence 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
+