juggernaut_rails 0.5.9

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.
@@ -0,0 +1,57 @@
1
+ // Simply overwrites prototype specific functions
2
+ // with jquery specific versions
3
+
4
+ Juggernaut.fn.fire_event = function(fx_name) {
5
+ $(document).trigger("juggernaut:" + fx_name);
6
+ };
7
+
8
+ Juggernaut.fn.bindToWindow = function() {
9
+ $(window).bind("load", this, function(e) {
10
+ juggernaut = e.data;
11
+ e.data.appendFlashObject();
12
+ });
13
+ };
14
+
15
+ Juggernaut.toJSON = function(hash) {
16
+ return $.toJSON(hash) ;
17
+ };
18
+
19
+ Juggernaut.parseJSON = function(string) {
20
+ return $.parseJSON(string);
21
+ };
22
+
23
+ Juggernaut.fn.swf = function(){
24
+ return $('#' + this.options.swf_name)[0];
25
+ };
26
+
27
+ Juggernaut.fn.appendElement = function() {
28
+ this.element = $('<div id=juggernaut>');
29
+ $("body").append(this.element);
30
+ };
31
+
32
+ Juggernaut.fn.refreshFlashObject = function(){
33
+ $(this.swf()).remove();
34
+ this.appendFlashObject();
35
+ };
36
+
37
+ Juggernaut.fn.reconnect = function(){
38
+ if(this.options.reconnect_attempts){
39
+ this.attempting_to_reconnect = true;
40
+ this.fire_event('reconnect');
41
+ this.logger('Will attempt to reconnect ' + this.options.reconnect_attempts + ' times, the first in ' + (this.options.reconnect_intervals || 3) + ' seconds');
42
+ var self = this;
43
+ for(var i=0; i < this.options.reconnect_attempts; i++){
44
+ setTimeout(function(){
45
+ if(!self.is_connected){
46
+ self.logger('Attempting reconnect');
47
+ if(!self.ever_been_connected){
48
+ self.refreshFlashObject();
49
+ } else {
50
+ self.connect();
51
+ }
52
+ }
53
+ }, (this.options.reconnect_intervals || 3) * 1000 * (i + 1));
54
+
55
+ }
56
+ }
57
+ };
data/media/json.js ADDED
@@ -0,0 +1,97 @@
1
+ (function ($) {
2
+ var m = {
3
+ '\b': '\\b',
4
+ '\t': '\\t',
5
+ '\n': '\\n',
6
+ '\f': '\\f',
7
+ '\r': '\\r',
8
+ '"' : '\\"',
9
+ '\\': '\\\\'
10
+ },
11
+ s = {
12
+ 'array': function (x) {
13
+ var a = ['['], b, f, i, l = x.length, v;
14
+ for (i = 0; i < l; i += 1) {
15
+ v = x[i];
16
+ f = s[typeof v];
17
+ if (f) {
18
+ v = f(v);
19
+ if (typeof v == 'string') {
20
+ if (b) {
21
+ a[a.length] = ',';
22
+ }
23
+ a[a.length] = v;
24
+ b = true;
25
+ }
26
+ }
27
+ }
28
+ a[a.length] = ']';
29
+ return a.join('');
30
+ },
31
+ 'boolean': function (x) {
32
+ return String(x);
33
+ },
34
+ 'null': function (x) {
35
+ return "null";
36
+ },
37
+ 'number': function (x) {
38
+ return isFinite(x) ? String(x) : 'null';
39
+ },
40
+ 'object': function (x) {
41
+ if (x) {
42
+ if (x instanceof Array) {
43
+ return s.array(x);
44
+ }
45
+ var a = ['{'], b, f, i, v;
46
+ for (i in x) {
47
+ v = x[i];
48
+ f = s[typeof v];
49
+ if (f) {
50
+ v = f(v);
51
+ if (typeof v == 'string') {
52
+ if (b) {
53
+ a[a.length] = ',';
54
+ }
55
+ a.push(s.string(i), ':', v);
56
+ b = true;
57
+ }
58
+ }
59
+ }
60
+ a[a.length] = '}';
61
+ return a.join('');
62
+ }
63
+ return 'null';
64
+ },
65
+ 'string': function (x) {
66
+ if (/["\\\x00-\x1f]/.test(x)) {
67
+ x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
68
+ var c = m[b];
69
+ if (c) {
70
+ return c;
71
+ }
72
+ c = b.charCodeAt();
73
+ return '\\u00' +
74
+ Math.floor(c / 16).toString(16) +
75
+ (c % 16).toString(16);
76
+ });
77
+ }
78
+ return '"' + x + '"';
79
+ }
80
+ };
81
+
82
+ $.toJSON = function(v) {
83
+ var f = isNaN(v) ? s[typeof v] : s['number'];
84
+ if (f) return f(v);
85
+ };
86
+
87
+ $.parseJSON = function(v, safe) {
88
+ if (safe === undefined) safe = $.parseJSON.safe;
89
+ if (safe && !/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(v))
90
+ return undefined;
91
+ return eval('('+v+')');
92
+ };
93
+
94
+ $.parseJSON.safe = false;
95
+
96
+ })(jQuery);
97
+
@@ -0,0 +1,79 @@
1
+ /*
2
+ Copyright (c) 2007 Alexander MacCaw
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ */
23
+
24
+ /*
25
+ Compile using MTACS (http://www.mtasc.org/)
26
+ mtasc -version 8 -header 1:1:1 -main -swf juggernaut.swf juggernaut.as
27
+ */
28
+
29
+ import flash.external.ExternalInterface;
30
+
31
+ class SocketServer {
32
+
33
+ static var socket : XMLSocket;
34
+
35
+ static function connect(host:String, port:Number) {
36
+ // The following line was causing crashes on Leopard
37
+ // System.security.loadPolicyFile('xmlsocket://' + host + ':' + port);
38
+
39
+ socket = new XMLSocket();
40
+ socket.onData = onData;
41
+ socket.onConnect = onConnect;
42
+ socket.onClose = onDisconnect;
43
+ socket.connect(host, port);
44
+ }
45
+
46
+ static function disconnect(){
47
+ socket.close();
48
+ }
49
+
50
+ static function onConnect(success:Boolean) {
51
+ if(success){
52
+ ExternalInterface.call("juggernaut.connected");
53
+ } else {
54
+ ExternalInterface.call("juggernaut.errorConnecting");
55
+ }
56
+ }
57
+
58
+ static function sendData(data:String){
59
+ socket.send(unescape(data));
60
+ }
61
+
62
+ static function onDisconnect() {
63
+ ExternalInterface.call("juggernaut.disconnected");
64
+ }
65
+
66
+ static function onData(data:String) {
67
+ ExternalInterface.call("juggernaut.receiveData", escape(data));
68
+ }
69
+
70
+ static function main() {
71
+ ExternalInterface.addCallback("connect", null, connect);
72
+ ExternalInterface.addCallback("sendData", null, sendData);
73
+ ExternalInterface.addCallback("disconnect", null, disconnect);
74
+
75
+ ExternalInterface.call("juggernaut.initialized");
76
+ }
77
+
78
+ }
79
+
@@ -0,0 +1,204 @@
1
+ /*
2
+ Copyright (c) 2008 Alexander MacCaw
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ */
23
+
24
+ function Juggernaut(options) {
25
+ this.is_connected = false;
26
+ this.attempting_to_reconnect = false;
27
+ this.ever_been_connected = false;
28
+ this.hasLogger = "console" in window && "log" in window.console;
29
+ this.options = options;
30
+ this.bindToWindow();
31
+ };
32
+
33
+ Juggernaut.fn = Juggernaut.prototype;
34
+
35
+ Juggernaut.fn.logger = function(msg) {
36
+ if (this.options.debug) {
37
+ msg = "Juggernaut: " + msg + " on " + this.options.host + ':' + this.options.port;
38
+ this.hasLogger ? console.log(msg) : alert(msg);
39
+ }
40
+ };
41
+
42
+ Juggernaut.fn.initialized = function(){
43
+ this.fire_event('initialized');
44
+ this.connect();
45
+ };
46
+
47
+ Juggernaut.fn.broadcast = function(body, type, client_ids, channels){
48
+ var msg = {command: 'broadcast', body: body, type: (type||'to_channels')};
49
+ if(channels) msg['channels'] = channels;
50
+ if(client_ids) msg['client_ids'] = client_ids;
51
+ this.sendData(Juggernaut.toJSON(msg));
52
+ };
53
+
54
+ Juggernaut.fn.sendData = function(data){
55
+ this.swf().sendData(escape(data));
56
+ };
57
+
58
+ Juggernaut.fn.connect = function(){
59
+ if(!this.is_connected){
60
+ this.fire_event('connect');
61
+ this.swf().connect(this.options.host, this.options.port);
62
+ }
63
+ };
64
+
65
+ Juggernaut.fn.disconnect = function(){
66
+ if(this.is_connected) {
67
+ this.swf().disconnect();
68
+ this.is_connected = false;
69
+ }
70
+ };
71
+
72
+ Juggernaut.fn.handshake = function() {
73
+ var handshake = {};
74
+ handshake['command'] = 'subscribe';
75
+ if(this.options.session_id) handshake['session_id'] = this.options.session_id;
76
+ if(this.options.client_id) handshake['client_id'] = this.options.client_id;
77
+ if(this.options.channels) handshake['channels'] = this.options.channels;
78
+ if(this.currentMsgId) {
79
+ handshake['last_msg_id'] = this.currentMsgId;
80
+ handshake['signature'] = this.currentSignature;
81
+ }
82
+
83
+ return handshake;
84
+ };
85
+
86
+ Juggernaut.fn.connected = function(e) {
87
+ var json = Juggernaut.toJSON(this.handshake());
88
+ this.sendData(json);
89
+ this.ever_been_connected = true;
90
+ this.is_connected = true;
91
+ var self = this;
92
+ setTimeout(function(){
93
+ if(self.is_connected) self.attempting_to_reconnect = false;
94
+ }, 1 * 1000);
95
+ this.logger('Connected');
96
+ this.fire_event('connected');
97
+ };
98
+
99
+ Juggernaut.fn.receiveData = function(e) {
100
+ var msg = Juggernaut.parseJSON(unescape(e.toString()));
101
+ this.currentMsgId = msg.id;
102
+ this.currentSignature = msg.signature;
103
+ this.logger("Received data:\n" + msg.body + "\n");
104
+ this.dispatchMessage(msg);
105
+ };
106
+
107
+ Juggernaut.fn.dispatchMessage = function(msg) {
108
+ eval(msg.body);
109
+ }
110
+
111
+ var juggernaut;
112
+
113
+ // Prototype specific - override for other frameworks
114
+ Juggernaut.fn.fire_event = function(fx_name) {
115
+ $(document).fire("juggernaut:" + fx_name);
116
+ };
117
+
118
+ Juggernaut.fn.bindToWindow = function() {
119
+ Event.observe(window, 'load', function() {
120
+ juggernaut = this;
121
+ this.appendFlashObject();
122
+ }.bind(this));
123
+ };
124
+
125
+ Juggernaut.toJSON = function(hash) {
126
+ return Object.toJSON(hash);
127
+ };
128
+
129
+ Juggernaut.parseJSON = function(string) {
130
+ return string.evalJSON();
131
+ };
132
+
133
+ Juggernaut.fn.swf = function(){
134
+ return $(this.options.swf_name);
135
+ };
136
+
137
+ Juggernaut.fn.appendElement = function() {
138
+ this.element = new Element('div', { id: 'juggernaut' });
139
+ $(document.body).insert({ bottom: this.element });
140
+ };
141
+
142
+ /*** END PROTOTYPE SPECIFIC ***/
143
+
144
+ Juggernaut.fn.appendFlashObject = function(){
145
+ if(this.swf()) {
146
+ throw("Juggernaut error. 'swf_name' must be unique per juggernaut instance.");
147
+ }
148
+ Juggernaut.fn.appendElement();
149
+ swfobject.embedSWF(
150
+ this.options.swf_address,
151
+ 'juggernaut',
152
+ this.options.width,
153
+ this.options.height,
154
+ String(this.options.flash_version),
155
+ this.options.ei_swf_address,
156
+ {'bridgeName': this.options.bridge_name},
157
+ {},
158
+ {'id': this.options.swf_name, 'name': this.options.swf_name}
159
+ );
160
+ };
161
+
162
+ Juggernaut.fn.refreshFlashObject = function(){
163
+ this.swf().remove();
164
+ this.appendFlashObject();
165
+ };
166
+
167
+ Juggernaut.fn.errorConnecting = function(e) {
168
+ this.is_connected = false;
169
+ if(!this.attempting_to_reconnect) {
170
+ this.logger('There has been an error connecting');
171
+ this.fire_event('errorConnecting');
172
+ this.reconnect();
173
+ }
174
+ };
175
+
176
+ Juggernaut.fn.disconnected = function(e) {
177
+ this.is_connected = false;
178
+ if(!this.attempting_to_reconnect) {
179
+ this.logger('Connection has been lost');
180
+ this.fire_event('disconnected');
181
+ this.reconnect();
182
+ }
183
+ };
184
+
185
+ Juggernaut.fn.reconnect = function(){
186
+ if(this.options.reconnect_attempts){
187
+ this.attempting_to_reconnect = true;
188
+ this.fire_event('reconnect');
189
+ this.logger('Will attempt to reconnect ' + this.options.reconnect_attempts + ' times,\
190
+ the first in ' + (this.options.reconnect_intervals || 3) + ' seconds');
191
+ for(var i=0; i < this.options.reconnect_attempts; i++){
192
+ setTimeout(function(){
193
+ if(!this.is_connected){
194
+ this.logger('Attempting reconnect');
195
+ if(!this.ever_been_connected){
196
+ this.refreshFlashObject();
197
+ } else {
198
+ this.connect();
199
+ }
200
+ }
201
+ }.bind(this), (this.options.reconnect_intervals || 3) * 1000 * (i + 1));
202
+ }
203
+ }
204
+ };
Binary file
@@ -0,0 +1,121 @@
1
+ #
2
+ # == Juggernaut Server Configuration
3
+ #
4
+
5
+ development:
6
+ :allowed_ips:
7
+ - 127.0.0.1
8
+ :port: 5001
9
+ production:
10
+ :allowed_ips:
11
+ - 127.0.0.1
12
+ :port: 5001
13
+ test:
14
+ :allowed_ips:
15
+ - 127.0.0.1
16
+ :port: 5001
17
+
18
+ # Common options:
19
+ #
20
+ # :store_messages: true
21
+ # :secret_key: your_secret_key_here
22
+ # :log_path: log/juggernaut.log # Default
23
+ # :pid_path: tmp/pids/juggernaut.5001.pid # Default
24
+ # :debug: true # Automatically turned on in development
25
+ # :host: 0.0.0.0
26
+ # :public_port: 5001
27
+ # :timeout: 10
28
+
29
+ # ======================
30
+ # Juggernaut Options
31
+ # ======================
32
+
33
+ # === Subscription authentication ===
34
+ # Leave all subscription options uncommented to allow anyone to subscribe.
35
+
36
+ # If specified, subscription_url is called everytime a client subscribes.
37
+ # Parameters passed are: session_id, client_id and an array of channels.
38
+ #
39
+ # The server should check that the session_id matches up to the client_id
40
+ # and that the client is allowed to access the specified channels.
41
+ #
42
+ # If a status code other than 200 is encountered, the subscription_request fails
43
+ # and the client is disconnected.
44
+ #
45
+ # :subscription_url: http://localhost:3000/sessions/juggernaut_subscription
46
+
47
+ # === Broadcast and query authentication ===
48
+ # Leave all broadcast/query options uncommented to allow anyone to broadcast/query.
49
+ #
50
+ # Broadcast authentication in a production environment is very importantant since broadcasters
51
+ # can execute JavaScript on subscribed clients, leaving you vulnerable to cross site scripting
52
+ # attacks if broadcasters aren't authenticated.
53
+
54
+ # 1) Via IP address
55
+ #
56
+ # If specified, if a client has an ip that is specified in allowed_ips, than it is automatically
57
+ # authenticated, even if a secret_key isn't provided.
58
+ #
59
+ # This is the recommended method for broadcast authentication.
60
+ #
61
+ #:allowed_ips:
62
+ # - 127.0.0.1
63
+ # # - 192.168.0.1
64
+ #
65
+ # 2) Via HTTP request
66
+ #
67
+ # If specified, if a client attempts a broadcast/query, without a secret_key or using an IP
68
+ # no included in allowed_ips, then broadcast_query_login_url will be called.
69
+ # Parameters passed, if given, are: session_id, client_id, channels and type.
70
+ #
71
+ # The server should check that the session_id matches up to the client id, and the client
72
+ # is allowed to perform that particular type of broadcast/query.
73
+ #
74
+ # If a status code other than 200 is encountered, the broadcast_query_login_url fails
75
+ # and the client is disconnected.
76
+ #
77
+ # :broadcast_query_login_url: http://localhost:3000/sessions/juggernaut_broadcast
78
+
79
+ # 3) Via shared secret key
80
+ #
81
+ # This secret key must be sent with any query/broadcast commands.
82
+ # It must be the same as the one in the Rails config file.
83
+ #
84
+ # You shouldn't authenticate broadcasts from subscribed clients using this method
85
+ # since the secret_key will be easily visible in the page (and not so secret any more)!
86
+ #
87
+ # :secret_key: 8a01f4941eac46fcb36354c62487ef04d113cdbe
88
+
89
+ # == Subscription Logout ==
90
+
91
+ # If specified, logout_connection_url is called everytime a specific connection from a subscribed client disconnects.
92
+ # Parameters passed are session_id, client_id and an array of channels specific to that connection.
93
+ #
94
+ # :logout_connection_url: http://localhost:3000/sessions/juggernaut_connection_logout
95
+
96
+ # Logout url is called when all connections from a subscribed client are closed.
97
+ # Parameters passed are session_id and client_id.
98
+ #
99
+ # :logout_url: http://localhost:3000/sessions/juggernaut_logout
100
+
101
+ # === Miscellaneous ===
102
+
103
+ # timeout defaults to 10. A timeout is the time between when a client closes a connection
104
+ # and a logout_request or logout_connection_request is made. The reason for this is that a client
105
+ # may only temporarily be disconnected, and may attempt a reconnect very soon.
106
+ #
107
+ # :timeout: 10
108
+
109
+ # store_messages defaults to false. If this option is true, messages send to connections will be stored.
110
+ # This is useful since a client can then receive broadcasted message that it has missed (perhaps it was disconnected).
111
+ #
112
+ # :store_messages: false
113
+
114
+ # === Server ===
115
+
116
+ # Host defaults to "0.0.0.0". You shouldn't need to change this.
117
+ # :host: 0.0.0.0
118
+
119
+ # Port is mandatory
120
+ #:port: 5001
121
+