shooting_star 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +23 -2
- data/Manifest.txt +5 -0
- data/Rakefile +15 -1
- data/lib/shooting_star.rb +18 -6
- data/lib/shooting_star/channel.rb +16 -10
- data/lib/shooting_star/server.rb +19 -4
- data/lib/shooting_star/shooter.rb +7 -10
- data/test/lib/shooting_star_test.rb +13 -8
- data/vendor/plugins/meteor_strike/generators/chat/templates/controller.rb +8 -0
- data/vendor/plugins/meteor_strike/generators/chat/templates/index.rhtml +8 -1
- data/vendor/plugins/meteor_strike/generators/meteor/templates/meteor_strike.swf +0 -0
- data/vendor/plugins/meteor_strike/generators/meteor/templates/model.rb +40 -8
- data/vendor/plugins/meteor_strike/generators/meteor/templates/view.rhtml +16 -13
- data/vendor/plugins/meteor_strike/lib/meteor_strike.rb +2 -169
- data/vendor/plugins/meteor_strike/lib/meteor_strike/helper.rb +71 -0
- data/vendor/plugins/meteor_strike/test/meteor_strike_test.rb +2 -1
- data/vendor/plugins/meteor_strike/views/flash.rhtml +23 -0
- data/vendor/plugins/meteor_strike/views/xhr.rhtml +110 -0
- metadata +7 -2
data/History.txt
CHANGED
@@ -1,8 +1,29 @@
|
|
1
|
+
*** 3.2.0 / 2007-08-09
|
2
|
+
+ 3 major enhancements:
|
3
|
+
+ Automatic activation/deactivation of flash client.
|
4
|
+
+ Ported meteor_strike.swf from CS3 to mtasc.
|
5
|
+
+ Heart beat.
|
6
|
+
- Serialized event execution.
|
7
|
+
+ 7 minor enhancements:
|
8
|
+
+ shooting_star.yml is processed by ERB.
|
9
|
+
+ Updated implementation of observers.
|
10
|
+
+ Updated chat generator with connection notification.
|
11
|
+
+ Added sample chat observer script (see script/chat_observer).
|
12
|
+
+ Separated views of xhr and flash html into views/.
|
13
|
+
+ Added an event which will fire when connection is established.
|
14
|
+
+ Added debugging mode to meteor_strike.
|
15
|
+
+ 6 minor spec changes:
|
16
|
+
+ Changed default pid file location from log/ to tmp/pids/.
|
17
|
+
+ options[:connected] obsoleted. Please use options[:event] instead.
|
18
|
+
+ Became independent from alias_method_chain in order to support applications
|
19
|
+
which use older versions (<1.2) of ruby on rails.
|
20
|
+
+ Added :debug option to meteor_strike helper.
|
21
|
+
+ Added :heartbeart option to meteor_strike helper.
|
22
|
+
+ Added :noflash option to meteor_strike helper.
|
23
|
+
|
1
24
|
*** 3.1.0 / 2007-07-18
|
2
25
|
+ 1 major enhancement:
|
3
26
|
+ Added 2 meteor_strike functions 'tuneInOut' and 'tuneOutIn'.
|
4
|
-
- Automatic activation/deactivation of flash client.
|
5
|
-
- Serialized event execution.
|
6
27
|
|
7
28
|
+ 1 minor enhancement:
|
8
29
|
+ FileUtil is used instead of `shell command`.
|
data/Manifest.txt
CHANGED
@@ -24,6 +24,11 @@ vendor/plugins/meteor_strike/Rakefile
|
|
24
24
|
vendor/plugins/meteor_strike/init.rb
|
25
25
|
vendor/plugins/meteor_strike/lib
|
26
26
|
vendor/plugins/meteor_strike/lib/meteor_strike.rb
|
27
|
+
vendor/plugins/meteor_strike/lib/meteor_strike
|
28
|
+
vendor/plugins/meteor_strike/lib/meteor_strike/helper.rb
|
29
|
+
vendor/plugins/meteor_strike/views
|
30
|
+
vendor/plugins/meteor_strike/views/xhr.rhtml
|
31
|
+
vendor/plugins/meteor_strike/views/flash.rhtml
|
27
32
|
vendor/plugins/meteor_strike/test
|
28
33
|
vendor/plugins/meteor_strike/test/meteor_strike_test.rb
|
29
34
|
vendor/plugins/meteor_strike/generators
|
data/Rakefile
CHANGED
@@ -37,7 +37,7 @@ desc 'default gem task.'
|
|
37
37
|
task :gem => 'gem:default'
|
38
38
|
|
39
39
|
desc 'update generator template files.'
|
40
|
-
task 'update_generator_template_files' do
|
40
|
+
task 'update_generator_template_files' => :swf do
|
41
41
|
templates = 'vendor/plugins/meteor_strike/generators/meteor/templates'
|
42
42
|
cp 'app/controllers/meteor_controller.rb',
|
43
43
|
templates + '/controller.rb'
|
@@ -51,7 +51,21 @@ task 'update_generator_template_files' do
|
|
51
51
|
templates + '/unit_test.rb'
|
52
52
|
cp 'test/functional/meteor_controller_test.rb',
|
53
53
|
templates + '/functional_test.rb'
|
54
|
+
cp 'public/meteor_strike.swf',
|
55
|
+
templates + '/meteor_strike.swf'
|
54
56
|
end
|
55
57
|
|
56
58
|
desc 'test all tests'
|
57
59
|
task 'test:all' => [:test, 'test:plugins', 'test:exts', 'test:libs']
|
60
|
+
|
61
|
+
desc 'default task'
|
62
|
+
task :default => 'test:all'
|
63
|
+
|
64
|
+
desc 'make swf file'
|
65
|
+
task :swf => 'public/meteor_strike.swf'
|
66
|
+
|
67
|
+
file 'public/meteor_strike.swf' => 'as/meteor_strike.as' do
|
68
|
+
sh ['mtasc -version 6 -header 300:300:30',
|
69
|
+
'-swf public/meteor_strike.swf',
|
70
|
+
'-main as/meteor_strike.as'].join(' ')
|
71
|
+
end
|
data/lib/shooting_star.rb
CHANGED
@@ -4,14 +4,15 @@ require 'drb/drb'
|
|
4
4
|
require 'yaml'
|
5
5
|
require 'ftools'
|
6
6
|
require 'fileutils'
|
7
|
+
require 'erb'
|
7
8
|
require 'shooting_star/config'
|
8
9
|
require 'shooting_star/shooter'
|
9
10
|
|
10
11
|
module ShootingStar
|
11
|
-
VERSION = '3.
|
12
|
+
VERSION = '3.2.0'
|
12
13
|
CONFIG = Config.new(
|
13
14
|
:config => 'config/shooting_star.yml',
|
14
|
-
:pid_file => '
|
15
|
+
:pid_file => 'tmp/pids/shooting_star.pid',
|
15
16
|
:log_file => 'log/shooting_star.log',
|
16
17
|
:daemon => false,
|
17
18
|
:slient => false,
|
@@ -24,12 +25,14 @@ module ShootingStar
|
|
24
25
|
@log_file = nil
|
25
26
|
end
|
26
27
|
config_file = options[:config] || CONFIG.config
|
27
|
-
|
28
|
+
if File.exist?(config_file)
|
29
|
+
CONFIG.merge!(YAML.load(ERB.new(open(config_file).read).result))
|
30
|
+
end
|
28
31
|
CONFIG.merge!(options)
|
29
32
|
end
|
30
33
|
|
31
34
|
def self.shooter
|
32
|
-
@@shooter ||= DRbObject.
|
35
|
+
@@shooter ||= DRb.start_service && DRbObject.new(nil, CONFIG.shooter.uri)
|
33
36
|
end
|
34
37
|
|
35
38
|
# install config file and plugin
|
@@ -48,6 +51,8 @@ module ShootingStar
|
|
48
51
|
end
|
49
52
|
log_dir = File.join(base_dir, 'log')
|
50
53
|
FileUtils.mkdir_p(log_dir) unless File.exist?(log_dir)
|
54
|
+
pid_dir = File.join(base_dir, 'tmp/pids')
|
55
|
+
FileUtils.mkdir_p(pid_dir) unless File.exist?(pid_dir)
|
51
56
|
plugin_dir = File.join(base_dir, 'vendor/plugins')
|
52
57
|
FileUtils.mkdir_p(plugin_dir) unless File.exist?(plugin_dir)
|
53
58
|
meteor_strike_dir = File.join(plugin_dir, 'meteor_strike')
|
@@ -84,7 +89,7 @@ module ShootingStar
|
|
84
89
|
@log_file.close if @log_file
|
85
90
|
end
|
86
91
|
log "shooting_star service started."
|
87
|
-
Process.kill(:ALRM, Process.ppid) if CONFIG.daemon
|
92
|
+
Process.kill(:ALRM, Process.ppid) rescue nil if CONFIG.daemon
|
88
93
|
block.call if block
|
89
94
|
end
|
90
95
|
end
|
@@ -111,7 +116,7 @@ module ShootingStar
|
|
111
116
|
end
|
112
117
|
|
113
118
|
def self.report
|
114
|
-
puts "#{'-' * 79}\nconnections
|
119
|
+
puts "#{'-' * 79}\nconnections channel_name\n#{'-' * 79}"
|
115
120
|
total_connections = 0
|
116
121
|
shooter.channels.each do |channel_path|
|
117
122
|
count = shooter.count(channel_path)
|
@@ -121,6 +126,13 @@ module ShootingStar
|
|
121
126
|
total_connections += count
|
122
127
|
end
|
123
128
|
puts "#{'-' * 79}\n%11d %s\n#{'-' * 79}" % [total_connections, 'TOTAL']
|
129
|
+
total_observers = 0
|
130
|
+
puts "observers channel_name\n#{'-' * 79}"
|
131
|
+
shooter.observers.each do |channel_path, observers|
|
132
|
+
puts "%11d %s" % [observers.size, channel_path]
|
133
|
+
total_observers += observers.size
|
134
|
+
end
|
135
|
+
puts "#{'-' * 79}\n%11d %s\n#{'-' * 79}" % [total_observers, 'TOTAL']
|
124
136
|
end
|
125
137
|
|
126
138
|
def self.timestamp
|
@@ -1,23 +1,22 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module ShootingStar
|
4
2
|
class Channel
|
5
3
|
attr_reader :path, :waiters
|
6
4
|
@@channels = {}
|
5
|
+
@@observers = Hash.new{|h,k| h[k] = Hash.new}
|
7
6
|
|
8
7
|
def initialize(channel_path)
|
9
8
|
@path = channel_path
|
10
9
|
@waiters = Hash.new
|
11
|
-
@observers = Set.new
|
12
10
|
@@channels[path] = self
|
13
11
|
end
|
14
12
|
|
15
13
|
def transmit(id, params)
|
16
14
|
if event = params[:event]
|
17
|
-
@observers.
|
15
|
+
observers = @@observers.has_key?(@path) ? @@observers[@path].dup : nil
|
16
|
+
observers.each do |name, obs|
|
18
17
|
begin obs.__send__(event, params) if obs.respond_to?(event)
|
19
|
-
rescue Exception;
|
20
|
-
end
|
18
|
+
rescue Exception; Channel.ignore(@path, name) end
|
19
|
+
end if observers
|
21
20
|
end
|
22
21
|
@waiters.each do |signature, server|
|
23
22
|
server.commit if server.respond(id, params)
|
@@ -30,12 +29,19 @@ module ShootingStar
|
|
30
29
|
end
|
31
30
|
|
32
31
|
def leave(server) @waiters.delete(server.signature) end
|
33
|
-
def
|
34
|
-
def ignore(observer) @observers.delete(observer) end
|
35
|
-
|
36
|
-
def self.[](channel_path); @@channels[channel_path] end
|
32
|
+
def self.[](channel_path) @@channels[channel_path] end
|
37
33
|
def self.list; @@channels.keys end
|
38
34
|
def self.sweep; @@channels.delete_if{|k,v| v.waiters.empty?} end
|
35
|
+
def self.observers; @@observers end
|
36
|
+
|
37
|
+
def self.observe(channel_path, observer)
|
38
|
+
@@observers[channel_path][observer.name] = observer
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.ignore(channel_path, name)
|
42
|
+
@@observers[channel_path].delete(name)
|
43
|
+
@@observers.delete(channel_path) if @@observers[channel_path].empty?
|
44
|
+
end
|
39
45
|
|
40
46
|
def self.cleanup(channel_path)
|
41
47
|
if @@channels[channel_path] && @@channels[channel_path].waiters.empty?
|
data/lib/shooting_star/server.rb
CHANGED
@@ -25,6 +25,7 @@ module ShootingStar
|
|
25
25
|
|
26
26
|
# receive the data sent from client.
|
27
27
|
def receive_data(data)
|
28
|
+
return if data.length == 0
|
28
29
|
return send_policy_file if @data.length == 0 &&
|
29
30
|
data == "<policy-file-request/>"
|
30
31
|
@data += data
|
@@ -64,7 +65,7 @@ module ShootingStar
|
|
64
65
|
@uid = @@uids[@signature] ||= @params['uid']
|
65
66
|
@tag = @@tags[@signature] ||=
|
66
67
|
(@params['tag'] || '').split(',').map{|i| CGI.unescape(i)}
|
67
|
-
|
68
|
+
if !@@servers[@signature] && @type != 'rc'
|
68
69
|
notify(:event => :enter, :uid => @uid, :tag => @tag)
|
69
70
|
log "Connected: #{@uid}"
|
70
71
|
end
|
@@ -165,6 +166,8 @@ module ShootingStar
|
|
165
166
|
event_id = ShootingStar::timestamp
|
166
167
|
log "Event(#{event_id}): #{@channel_path}:#{params.inspect}"
|
167
168
|
Channel[@channel_path].transmit("event-#{event_id}", params)
|
169
|
+
rescue Exception => e
|
170
|
+
log "ERROR: #{e.message}\n#{e.backtrace.join("\n")}"
|
168
171
|
end
|
169
172
|
|
170
173
|
# wait for commands or events until they occur. if they're already in
|
@@ -194,7 +197,7 @@ module ShootingStar
|
|
194
197
|
query += "&" + FormEncoder.encode(params) if params
|
195
198
|
@execution += <<-"EOH"
|
196
199
|
(function(){
|
197
|
-
var ms1 = document.getElementById('meteor-strike-1');
|
200
|
+
var ms1 = document.getElementById('meteor-strike-1-form');
|
198
201
|
var box = ms1 ? ms1.parentNode : document.body;
|
199
202
|
var iframe = document.createElement('iframe');
|
200
203
|
var remove = function(){box.removeChild(iframe)};
|
@@ -214,9 +217,16 @@ module ShootingStar
|
|
214
217
|
assets = URI.parse(@params['execute'])
|
215
218
|
assets.path = '/javascripts/prototype.js'
|
216
219
|
assets.query = assets.fragment = nil
|
220
|
+
query = @query.sub(%r[\&sig=\d+], '')
|
221
|
+
query += "&" + FormEncoder.encode(:event => :init, :type => :xhr)
|
222
|
+
heartbeat = @params['heartbeat'].to_i
|
217
223
|
send_data "HTTP/1.1 200 OK\nContent-Type: text/html\n\n" +
|
218
224
|
<<-"EOH"
|
219
|
-
|
225
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
226
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
227
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
|
228
|
+
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
229
|
+
<script type="text/javascript" src="#{assets}"></script>
|
220
230
|
<script type="text/javascript">
|
221
231
|
//<![CDATA[
|
222
232
|
var connect = function(reconnect)
|
@@ -232,10 +242,15 @@ module ShootingStar
|
|
232
242
|
request.transport.abort();
|
233
243
|
};
|
234
244
|
Event.observe(window, 'unload', disconnect);
|
245
|
+
if(#{heartbeat} > 0) setTimeout(function(){
|
246
|
+
if(request.transport.readyState == 1) disconnect(), connect(true);
|
247
|
+
}, [#{heartbeat}, 60].max() * 1000);
|
235
248
|
};
|
236
249
|
setTimeout(function(){connect(false)}, 0);
|
237
250
|
//]]>
|
238
|
-
</script></head><body
|
251
|
+
</script></head><body>
|
252
|
+
<iframe src="#{@params['execute']}/0?#{query}"></iframe>
|
253
|
+
</body></html>
|
239
254
|
EOH
|
240
255
|
rescue Exception
|
241
256
|
ensure
|
@@ -3,11 +3,11 @@ require 'shooting_star/channel'
|
|
3
3
|
# DRbObject
|
4
4
|
module ShootingStar
|
5
5
|
class Shooter
|
6
|
-
# broadcast message
|
7
|
-
def shoot(channel_path, id, tag)
|
6
|
+
# broadcast/multicast message
|
7
|
+
def shoot(channel_path, id, tag, options = {})
|
8
8
|
return unless Channel[channel_path]
|
9
|
-
log "Shot: #{channel_path}:#{id}:#{tag.join(',')}"
|
10
|
-
Channel[channel_path].transmit(id, :tag => tag)
|
9
|
+
log "Shot: #{channel_path}:#{id}:#{tag.join(',')}:#{options}"
|
10
|
+
Channel[channel_path].transmit(id, options.merge(:tag => tag))
|
11
11
|
end
|
12
12
|
|
13
13
|
# update client properties
|
@@ -18,6 +18,7 @@ module ShootingStar
|
|
18
18
|
|
19
19
|
def signature; ShootingStar::timestamp end
|
20
20
|
def channels; Channel.list end
|
21
|
+
def observers; Channel.observers end
|
21
22
|
def sweep; Channel.sweep end
|
22
23
|
|
23
24
|
# count up listeners
|
@@ -56,12 +57,8 @@ module ShootingStar
|
|
56
57
|
|
57
58
|
# observe server side events
|
58
59
|
def observe(channel_path, observer)
|
59
|
-
Channel
|
60
|
-
|
61
|
-
|
62
|
-
# ignore server side events
|
63
|
-
def ignore(channel_path, observer)
|
64
|
-
Channel[channel_path].ignore(observer)
|
60
|
+
Channel.observe(channel_path, observer)
|
61
|
+
rescue Exception
|
65
62
|
end
|
66
63
|
|
67
64
|
private
|
@@ -6,14 +6,16 @@ require 'thread'
|
|
6
6
|
$command_line = 'echo "testing"'
|
7
7
|
|
8
8
|
class ShootingStarTest < Test::Unit::TestCase
|
9
|
-
|
10
|
-
|
11
|
-
def
|
9
|
+
class TestObserver
|
10
|
+
include DRb::DRbUndumped
|
11
|
+
def name; 'test-observer' end
|
12
|
+
def enter(params) @params = params end
|
13
|
+
def params; @params end
|
12
14
|
end
|
13
15
|
|
14
16
|
def setup
|
15
17
|
@config = ShootingStar.configure :silent => true,
|
16
|
-
:pid_file => '
|
18
|
+
:pid_file => 'tmp/pids/shooting_star.test.pid',
|
17
19
|
:log_file => 'log/shooting_star.test.log',
|
18
20
|
:server => {:host => '127.0.0.1', :port => 8081},
|
19
21
|
:shooter => {:uri => 'druby://127.0.0.1:7124'}
|
@@ -69,22 +71,25 @@ class ShootingStarTest < Test::Unit::TestCase
|
|
69
71
|
assert_not_nil client2
|
70
72
|
shooter = DRbObject.new_with_uri('druby://127.0.0.1:7124')
|
71
73
|
assert_not_nil shooter
|
72
|
-
|
74
|
+
observer = TestObserver.new
|
75
|
+
assert_not_nil observer
|
76
|
+
shooter.observe('test/channel', observer)
|
73
77
|
mutex = Mutex.new
|
74
78
|
mutex.lock
|
75
|
-
assert_nil
|
79
|
+
assert_nil observer.params
|
76
80
|
Thread.new do
|
77
81
|
send(client1, "POST", "test/channel", "#{@query}&__t__=c")
|
78
82
|
mutex.unlock
|
79
83
|
end
|
80
84
|
mutex.lock
|
81
|
-
assert_nil
|
85
|
+
assert_nil observer.params
|
82
86
|
Thread.new do
|
83
87
|
send(client2, "POST", "test/channel", "#{@query2}&__t__=c")
|
84
88
|
mutex.unlock
|
85
89
|
end
|
86
90
|
mutex.lock
|
87
|
-
|
91
|
+
assert_not_nil observer.params
|
92
|
+
assert_equal :enter, observer.params[:event]
|
88
93
|
assert_not_nil result1 = client1.read
|
89
94
|
assert_not_nil result1.index('meteor/strike/event-')
|
90
95
|
shooter.shoot("test/channel", 12, [])
|
@@ -21,4 +21,12 @@ class <%= class_name %>Controller < ApplicationController
|
|
21
21
|
page[:chat_message].focus
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
def connect
|
26
|
+
@chat = <%= class_name %>.new(
|
27
|
+
:name => '(* system *)',
|
28
|
+
:created_at => Time.now,
|
29
|
+
:message => "connection established on #{params[:client_type]}.")
|
30
|
+
render :action => 'show'
|
31
|
+
end
|
24
32
|
end
|
@@ -8,4 +8,11 @@
|
|
8
8
|
<%%= render_component :action => 'show', :id => chat.id %>
|
9
9
|
<%% end %>
|
10
10
|
</ul>
|
11
|
-
<%%= meteor_strike '<%= file_name %>'
|
11
|
+
<%%= meteor_strike '<%= file_name %>', :event => %Q{
|
12
|
+
switch(params.event){
|
13
|
+
case 'init':
|
14
|
+
new Ajax.Updater('chat-list', #{url_for(:action => 'connect').to_json}, {
|
15
|
+
insertion: Insertion.Top, parameters: {client_type: params.type}});
|
16
|
+
break;
|
17
|
+
}
|
18
|
+
} %>
|
Binary file
|
@@ -1,22 +1,31 @@
|
|
1
1
|
require 'drb/drb'
|
2
2
|
|
3
3
|
class Meteor < ActiveRecord::Base
|
4
|
+
DEFAULT_SERVER_URI = 'localhost:8080'
|
5
|
+
DEFAULT_SHOOTER_URI = 'druby://localhost:7123'
|
6
|
+
|
4
7
|
class Shooter
|
5
8
|
COUNTERS = [:count, :count_with]
|
6
9
|
LISTINGS = [:listeners, :listeners_with, :channels, :signatures]
|
10
|
+
EITHEROFS = [:signature]
|
11
|
+
MAX_RETRY = 10
|
7
12
|
|
8
13
|
def initialize(config)
|
9
|
-
config['shooting_star'] ||= {'shooter' =>
|
14
|
+
config['shooting_star'] ||= {'shooter' => Meteor::DEFAULT_SHOOTER_URI}
|
10
15
|
uris = config['shooting_star']['shooter']
|
11
|
-
@shooters = [uris].flatten.map{|uri| DRbObject.
|
16
|
+
@shooters = [uris].flatten.map{|uri| DRbObject.new(nil, uri)}
|
12
17
|
end
|
13
18
|
|
14
19
|
COUNTERS.each do |m|
|
15
|
-
|
20
|
+
eval "def #{m}(*a, &b) call('#{m}',*a,&b).inject(0){|r,c| r+=c} end"
|
16
21
|
end
|
17
22
|
|
18
23
|
LISTINGS.each do |m|
|
19
|
-
|
24
|
+
eval "def #{m}(*a, &b) call('#{m}',*a,&b).inject([]){|r,c|r.concat c} end"
|
25
|
+
end
|
26
|
+
|
27
|
+
EITHEROFS.each do |m|
|
28
|
+
eval "def #{m}(*a, &b) round_robin('#{m}',*a,&b) end"
|
20
29
|
end
|
21
30
|
|
22
31
|
def method_missing(method, *args, &block)
|
@@ -29,21 +38,44 @@ class Meteor < ActiveRecord::Base
|
|
29
38
|
begin
|
30
39
|
result << shooter.__send__(method, *args, &block)
|
31
40
|
rescue Exception => e
|
32
|
-
Meteor
|
41
|
+
Meteor::logger.error "#{e.message}\n#{e.backtrace.join("\n")}"
|
33
42
|
end
|
34
43
|
result
|
35
44
|
end || []
|
36
45
|
end
|
46
|
+
|
47
|
+
def round_robin(method, *args, &block)
|
48
|
+
@round_robin_counter = (@round_robin_counter.to_i + 1) % @shooters.size
|
49
|
+
@shooters[@round_robin_counter].__send__(method, *args, &block)
|
50
|
+
rescue Exception
|
51
|
+
(@retry_counter = @retry_counter.to_i + 1) <= MAX_RETRY ? retry : raise
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.config
|
56
|
+
returning(configurations[RAILS_ENV]['shooting_star'] || {}) do |config|
|
57
|
+
config['server'] ||= DEFAULT_SERVER_URI
|
58
|
+
config['shooter'] ||= DEFAULT_SHOOTER_URI
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.servers
|
63
|
+
config['server'].kind_of?(Array) ? config['server'] : [config['server']]
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.server
|
67
|
+
@round_robin_counter = (@round_robin_counter.to_i + 1) % servers.size
|
68
|
+
servers[@round_robin_counter]
|
37
69
|
end
|
38
70
|
|
39
71
|
def self.shooter
|
40
|
-
@@shooter ||=
|
72
|
+
@@shooter ||= DRb.start_service && Shooter.new(configurations[RAILS_ENV])
|
41
73
|
end
|
42
74
|
|
43
|
-
def self.shoot(
|
75
|
+
def self.shoot(channel_path, javascript, tag = [], options = {})
|
44
76
|
meteor = Meteor.new(:javascript => javascript)
|
45
77
|
returning(meteor.save) do |succeeded|
|
46
|
-
shooter.shoot(
|
78
|
+
shooter.shoot(channel_path, meteor.id, tag, options) if succeeded
|
47
79
|
end
|
48
80
|
end
|
49
81
|
end
|
@@ -1,16 +1,19 @@
|
|
1
|
-
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
2
4
|
<head>
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
var
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
}
|
5
|
+
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
6
|
+
<%= javascript_tag %Q{
|
7
|
+
(function(){
|
8
|
+
var channel = #{@channel.to_json};
|
9
|
+
var javascript = #{@javascript.to_json};
|
10
|
+
var execute = function(){
|
11
|
+
var ms = parent.parent.meteorStrike[channel];
|
12
|
+
if(ms) ms.execute(javascript);
|
13
|
+
else setTimeout(execute, 0);
|
14
|
+
};
|
15
|
+
execute();
|
16
|
+
})();
|
17
|
+
}%>
|
15
18
|
</head>
|
16
19
|
</html>
|
@@ -1,172 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
require 'md5'
|
1
|
+
require 'meteor_strike/helper'
|
3
2
|
|
4
3
|
module MeteorStrike
|
5
|
-
|
6
|
-
def self.included(base)
|
7
|
-
base.class_eval do
|
8
|
-
alias_method_chain :form_tag, :timestamp
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def meteor_strike(channel, options = {})
|
13
|
-
if !options[:cache] && !@meteor_strike
|
14
|
-
cc = controller.headers['Cache-Control'] || ''
|
15
|
-
cc += ', ' unless cc.empty?
|
16
|
-
cc += 'no-store, no-cache, must-revalidate, max-age=0, '
|
17
|
-
cc += 'post-check=0, pre-check=0'
|
18
|
-
controller.headers['Cache-Control'] = cc
|
19
|
-
end
|
20
|
-
@meteor_strike ||= 0 and @meteor_strike += 1
|
21
|
-
config = ActiveRecord::Base.configurations[RAILS_ENV]['shooting_star']
|
22
|
-
config ||= {}
|
23
|
-
config['server'] ||= 'localhost:8080'
|
24
|
-
config['shooter'] ||= 'druby://localhost:7123'
|
25
|
-
server = config['server'].kind_of?(Array) ?
|
26
|
-
config['server'][rand(config['server'].length)] : config['server']
|
27
|
-
shooting_star_uri = "#{server}/#{channel}"
|
28
|
-
if config['random_subdomain'] && /[A-z]/ === server
|
29
|
-
subdomain = (1..6).map{(rand(26)+?a).chr}.to_s
|
30
|
-
shooting_star_uri = [subdomain, shooting_star_uri].join('.')
|
31
|
-
end
|
32
|
-
uri = url_for(:only_path => false).split('/')[0..2].join('/')
|
33
|
-
uid = options[:uid] ? CGI.escape(options[:uid].to_s) : ''
|
34
|
-
tags = options[:tag] || []
|
35
|
-
tag = tags.map{|i| CGI.escape(i.to_s)}.join(',')
|
36
|
-
update_uri = "#{uri}/meteor/update"
|
37
|
-
sig = Meteor.shooter.signature
|
38
|
-
iframe_id = "meteor-strike-#{@meteor_strike}"
|
39
|
-
host_port = (server.split(':') << '80')[0..1].join(':')
|
40
|
-
flash_vars = [
|
41
|
-
"channel=#{channel}", "tag=#{tag}", "uid=#{uid}", "sig=#{sig}",
|
42
|
-
"base_uri=#{uri}", "server=#{host_port}"].join('&')
|
43
|
-
flash_html = flash_tag(flash_vars) unless options[:noflash]
|
44
|
-
<<-"EOH"
|
45
|
-
<div style="position: absolute; top: -99999px; left: -99999px">
|
46
|
-
<iframe id="#{iframe_id}" name="#{iframe_id}"></iframe>
|
47
|
-
<form id="#{iframe_id}-form" target="#{iframe_id}" method="POST"
|
48
|
-
action="http://#{shooting_star_uri}">
|
49
|
-
<input name="execute" value="#{uri}/meteor/strike" />
|
50
|
-
<input name="tag" /><input name="uid" /><input name="sig" />
|
51
|
-
</form>
|
52
|
-
<script type="text/javascript">
|
53
|
-
//<![CDATA[
|
54
|
-
var meteorStrike = meteorStrike || $H();
|
55
|
-
Event.observe(window, 'load', function(){
|
56
|
-
var channel = #{channel.to_json};
|
57
|
-
var UID = #{uid.to_json}, TAGS = #{tags.to_json};
|
58
|
-
var encodeTags = function(tags){
|
59
|
-
var encode = function(i){return encodeURIComponent(i)};
|
60
|
-
return $A(tags).uniq().map(encode).join(',');
|
61
|
-
};
|
62
|
-
var ms = meteorStrike[channel] = meteorStrike[channel] || new Object;
|
63
|
-
ms.getTags = function(){return TAGS};
|
64
|
-
ms.getUid = function(){return UID};
|
65
|
-
ms.execute = function(js){eval(js)};
|
66
|
-
ms.event = function(params){#{options[:event]}};
|
67
|
-
ms.update = function(uid, tags){
|
68
|
-
new Ajax.Request(#{update_uri.to_json}, {postBody: $H({
|
69
|
-
channel: channel, uid: uid || UID,
|
70
|
-
tag: encodeTags(tags || TAGS), sig: #{sig.to_json}
|
71
|
-
}).toQueryString(), asynchronous: true});
|
72
|
-
UID = uid, TAGS = tags;
|
73
|
-
};
|
74
|
-
ms.tuneIn = function(tags){
|
75
|
-
ms.update(UID, TAGS.concat(tags || []).uniq());
|
76
|
-
};
|
77
|
-
ms.tuneOut = function(tags){
|
78
|
-
ms.update(UID, Array.prototype.without.apply(TAGS, tags));
|
79
|
-
};
|
80
|
-
ms.tuneInOut = function(tagsIn, tagsOut){
|
81
|
-
var tags = TAGS.concat(tagsIn || []).uniq();
|
82
|
-
ms.update(UID, Array.prototype.without.apply(tags, tagsOut));
|
83
|
-
};
|
84
|
-
ms.tuneOutIn = function(tagsOut, tagsIn){
|
85
|
-
var tags = Array.prototype.without.apply(TAGS, tagsOut);
|
86
|
-
ms.update(UID, tags.concat(tagsIn || []).uniq());
|
87
|
-
};
|
88
|
-
try{
|
89
|
-
var noflash = #{options[:noflash].to_json};
|
90
|
-
if(noflash || !flashVersion || flashVersion < 6){
|
91
|
-
setTimeout(function(){
|
92
|
-
var form = $("#{iframe_id}-form");
|
93
|
-
form.uid.value = #{uid.to_json};
|
94
|
-
form.tag.value = #{tag.to_json};
|
95
|
-
form.sig.value = #{sig.to_json};
|
96
|
-
form.submit();
|
97
|
-
setTimeout(function(){#{options[:connected]}}, 0);
|
98
|
-
}, 0);
|
99
|
-
}
|
100
|
-
}catch(e){}
|
101
|
-
});
|
102
|
-
function meteor_strike_#{@meteor_strike}_DoFSCommand(command, args){
|
103
|
-
switch(command){
|
104
|
-
case 'execute': eval(args); break;
|
105
|
-
case 'event':
|
106
|
-
if(args == 'connect') (function(){#{options[:connected]}})();
|
107
|
-
break;
|
108
|
-
}
|
109
|
-
}
|
110
|
-
if(navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
|
111
|
-
navigator.userAgent.indexOf("Windows") != -1 &&
|
112
|
-
navigator.userAgent.indexOf("Windows 3.1") == -1)
|
113
|
-
{
|
114
|
-
document.write([
|
115
|
-
'<script language="VBScript"\\>',
|
116
|
-
'On Error Resume Next',
|
117
|
-
['Sub meteor_strike_', #{@meteor_strike},
|
118
|
-
'_FSCommand(ByVal command, ByVal args)'].join(''),
|
119
|
-
[' Call meteor_strike_', #{@meteor_strike},
|
120
|
-
'_DoFSCommand(command, args)'].join(''),
|
121
|
-
'End Sub', '</script\\>'].join(#{"\n".to_json}));
|
122
|
-
}
|
123
|
-
//]]>
|
124
|
-
</script>#{flash_html}</div>
|
125
|
-
EOH
|
126
|
-
end
|
127
|
-
|
128
|
-
private
|
129
|
-
# Workaround for Safari's strange behaviour after back navigation.
|
130
|
-
# Safari never posts if form elements are not modified since back
|
131
|
-
# navigation. So we append timestamp before submitting.
|
132
|
-
def form_tag_with_timestamp(urlop = {}, options = {}, *arg, &block)
|
133
|
-
options = options.stringify_keys
|
134
|
-
(options['onsubmit'] ||= '').insert(0, %Q[
|
135
|
-
if(!this.__ts__){
|
136
|
-
var ts = document.createElement('input');
|
137
|
-
ts.name = ts.id = '__ts__';
|
138
|
-
ts.type = 'hidden';
|
139
|
-
this.appendChild(ts);
|
140
|
-
}
|
141
|
-
this.__ts__.value = new Number(new Date()).toString(32);
|
142
|
-
]) unless /^get$/i === options['method']
|
143
|
-
form_tag_without_timestamp(urlop, options, *arg, &block)
|
144
|
-
end
|
145
|
-
|
146
|
-
def flash_tag(flash_vars)
|
147
|
-
flash_code_base = ['http://fpdownload.macromedia.com/',
|
148
|
-
'pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0'].join('')
|
149
|
-
swf_path = File.join(RAILS_ROOT, 'public/meteor_strike.swf')
|
150
|
-
swf_timestamp = File.mtime(swf_path).to_i
|
151
|
-
<<-"EOH"
|
152
|
-
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
|
153
|
-
codebase="#{flash_code_base}" width="0" height="0"
|
154
|
-
id="meteor_strike_#{@meteor_strike}">
|
155
|
-
<param name="allowScriptAccess" value="sameDomain" />
|
156
|
-
<param name="FlashVars" value="#{flash_vars}" />
|
157
|
-
<param name="movie" value="/meteor_strike.swf?#{swf_timestamp}" />
|
158
|
-
<param name="menu" value="false" />
|
159
|
-
<param name="quality" value="high" />
|
160
|
-
<param name="devicefont" value="true" />
|
161
|
-
<param name="bgcolor" value="#ffffff" />
|
162
|
-
<embed src="/meteor_strike.swf?#{swf_timestamp}" menu="false"
|
163
|
-
quality="high" devicefont="true" bgcolor="#ffffff" width="0" height="0"
|
164
|
-
swLiveConnect="true" id="meteor_strike_#{@meteor_strike}"
|
165
|
-
name="meteor_strike_#{@meteor_strike}" flashvars="#{flash_vars}"
|
166
|
-
allowScriptAccess="sameDomain" type="application/x-shockwave-flash"
|
167
|
-
pluginspage="http://www.macromedia.com/go/getflashplayer" />
|
168
|
-
</object>
|
169
|
-
EOH
|
170
|
-
end
|
171
|
-
end
|
4
|
+
PLUGIN_ROOT = File.join(File.dirname(__FILE__), '..')
|
172
5
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'md5'
|
3
|
+
|
4
|
+
module MeteorStrike
|
5
|
+
module Helper
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
alias_method :form_tag_without_timestamp, :form_tag
|
9
|
+
alias_method :form_tag, :form_tag_with_timestamp
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def meteor_strike(channel, options = {})
|
14
|
+
if !options[:cache] && !@meteor_strike
|
15
|
+
cc = controller.headers['Cache-Control'] || ''
|
16
|
+
cc += ', ' unless cc.empty?
|
17
|
+
cc += 'no-store, no-cache, must-revalidate, max-age=0, '
|
18
|
+
cc += 'post-check=0, pre-check=0'
|
19
|
+
controller.headers['Cache-Control'] = cc
|
20
|
+
end
|
21
|
+
@meteor_strike ||= 0 and @meteor_strike += 1
|
22
|
+
config = Meteor::config
|
23
|
+
server = Meteor::server
|
24
|
+
shooting_star_uri = "#{server}/#{channel}"
|
25
|
+
if config['random_subdomain'] && /[A-z]/ === server
|
26
|
+
subdomain = (1..6).map{(rand(26)+?a).chr}.to_s
|
27
|
+
shooting_star_uri = [subdomain, shooting_star_uri].join('.')
|
28
|
+
end
|
29
|
+
uri = url_for(:only_path => false).split('/')[0..2].join('/')
|
30
|
+
uid = options[:uid] ? CGI.escape(options[:uid].to_s) : ''
|
31
|
+
tags = options[:tag] || []
|
32
|
+
tag = tags.map{|i| CGI.escape(i.to_s)}.join(',')
|
33
|
+
update_uri = "#{uri}/meteor/update"
|
34
|
+
sig = Meteor.shooter.signature
|
35
|
+
iframe_id = "meteor-strike-#{@meteor_strike}"
|
36
|
+
host_port = (server.split(':') << '80')[0..1].join(':')
|
37
|
+
flash_vars = ["channel=#{channel}", "tag=#{tag}", "uid=#{uid}",
|
38
|
+
"sig=#{sig}", "base_uri=#{uri}", "server=#{host_port}",
|
39
|
+
"heartbeat=#{options[:heartbeat]}", "debug=#{options[:debug].to_json}"
|
40
|
+
].join('&')
|
41
|
+
unless options[:noflash]
|
42
|
+
@flash_html = render :use_full_path => false,
|
43
|
+
:file => File.join(PLUGIN_ROOT, 'views/flash.rhtml'),
|
44
|
+
:locals => {:flash_vars => flash_vars}
|
45
|
+
end
|
46
|
+
render :file => File.join(PLUGIN_ROOT, 'views/xhr.rhtml'),
|
47
|
+
:use_full_path => false, :locals => {:iframe_id => iframe_id,
|
48
|
+
:shooting_star_uri => shooting_star_uri, :uri => uri,
|
49
|
+
:channel => channel, :uid => uid, :tag => tag, :tags => tags,
|
50
|
+
:sig => sig, :options => options, :update_uri => update_uri}
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
# Workaround for Safari's strange behaviour after back navigation.
|
55
|
+
# Safari never posts if form elements are not modified since back
|
56
|
+
# navigation. So we append timestamp before submitting.
|
57
|
+
def form_tag_with_timestamp(urlop = {}, options = {}, *arg, &block)
|
58
|
+
options = options.stringify_keys
|
59
|
+
(options['onsubmit'] ||= '').insert(0, %Q[
|
60
|
+
if(!this.__ts__){
|
61
|
+
var ts = document.createElement('input');
|
62
|
+
ts.name = ts.id = '__ts__';
|
63
|
+
ts.type = 'hidden';
|
64
|
+
this.appendChild(ts);
|
65
|
+
}
|
66
|
+
this.__ts__.value = new Number(new Date()).toString(32);
|
67
|
+
]) unless /^get$/i === options['method']
|
68
|
+
form_tag_without_timestamp(urlop, options, *arg, &block)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'rubygems'
|
3
3
|
require 'active_support'
|
4
|
-
require File.join(File.dirname(__FILE__), '../lib/meteor_strike')
|
5
4
|
begin
|
6
5
|
require 'redgreen'
|
7
6
|
rescue
|
8
7
|
end
|
8
|
+
$: << File.join(File.dirname(__FILE__), '../lib')
|
9
|
+
require 'meteor_strike'
|
9
10
|
|
10
11
|
class MeteorStrikeTest < Test::Unit::TestCase
|
11
12
|
def test_meteor_strike
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<%
|
2
|
+
flash_code_base = ['http://fpdownload.macromedia.com/',
|
3
|
+
'pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0'].join('')
|
4
|
+
swf_path = File.join(RAILS_ROOT, 'public/meteor_strike.swf')
|
5
|
+
swf_timestamp = File.mtime(swf_path).to_i
|
6
|
+
%>
|
7
|
+
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
|
8
|
+
codebase="<%= flash_code_base %>" width="300" height="300"
|
9
|
+
id="meteor_strike_<%= @meteor_strike %>">
|
10
|
+
<param name="allowScriptAccess" value="sameDomain" />
|
11
|
+
<param name="FlashVars" value="<%= flash_vars %>" />
|
12
|
+
<param name="movie" value="/meteor_strike.swf?<%= swf_timestamp %>" />
|
13
|
+
<param name="menu" value="false" />
|
14
|
+
<param name="quality" value="high" />
|
15
|
+
<param name="devicefont" value="true" />
|
16
|
+
<param name="bgcolor" value="#ffffff" />
|
17
|
+
<embed src="/meteor_strike.swf?<%= swf_timestamp %>" menu="false"
|
18
|
+
quality="high" devicefont="true" bgcolor="#ffffff" width="300" height="300"
|
19
|
+
swLiveConnect="true" id="meteor_strike_<%= @meteor_strike %>"
|
20
|
+
name="meteor_strike_<%= @meteor_strike %>" flashvars="<%= flash_vars %>"
|
21
|
+
allowScriptAccess="sameDomain" type="application/x-shockwave-flash"
|
22
|
+
pluginspage="http://www.macromedia.com/go/getflashplayer" />
|
23
|
+
</object>
|
@@ -0,0 +1,110 @@
|
|
1
|
+
<div style="position: absolute;
|
2
|
+
<%- if options[:debug] -%>
|
3
|
+
top: 0px; right: 0px;
|
4
|
+
<%- else -%>
|
5
|
+
top: -99999px; left: -99999px;
|
6
|
+
<%- end -%>">
|
7
|
+
<iframe id="<%= iframe_id %>" name="<%= iframe_id %>"></iframe>
|
8
|
+
<form id="<%= iframe_id %>-form" target="<%= iframe_id %>" method="POST"
|
9
|
+
action="http://<%= shooting_star_uri %>">
|
10
|
+
<input name="execute" value="<%= uri %>/meteor/strike" />
|
11
|
+
<input name="tag" /><input name="uid" /><input name="sig" />
|
12
|
+
<input name="heartbeat" value="<%= options[:heartbeat] %>" />
|
13
|
+
</form>
|
14
|
+
<%= javascript_tag %Q{
|
15
|
+
var meteorStrike = meteorStrike || $H();
|
16
|
+
meteorStrike.getFlashVersion = function(){
|
17
|
+
if(#{options[:noflash].to_json}) return 0;
|
18
|
+
var version = 0, ua = navigator.userAgent;
|
19
|
+
if(navigator.plugins && navigator.mimeTypes.length){
|
20
|
+
var x = navigator.plugins["Shockwave Flash"];
|
21
|
+
if(x && x.description) {
|
22
|
+
version = parseInt(x.description.replace(/([a-zA-Z]|\\s)+/, ""
|
23
|
+
).replace(/(\\s+r|\\s+b[0-9]+)/, ".").split(".")[0]);
|
24
|
+
}
|
25
|
+
}else if(!ua || ua.indexOf("Windows CE") == -1){
|
26
|
+
try{
|
27
|
+
var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
|
28
|
+
try{
|
29
|
+
axo.AllowScriptAccess = 'always';
|
30
|
+
version = axo.GetVariable('$version').split(' ')[1].split(",")[0];
|
31
|
+
}catch(e){version = 6}
|
32
|
+
}catch(e){}
|
33
|
+
}
|
34
|
+
return version;
|
35
|
+
};
|
36
|
+
(function(){
|
37
|
+
var channel = #{channel.to_json};
|
38
|
+
var UID = #{uid.to_json}, TAGS = #{tags.to_json};
|
39
|
+
var encodeTags = function(tags){
|
40
|
+
var encode = function(i){return encodeURIComponent(i)};
|
41
|
+
return $A(tags).uniq().map(encode).join(',');
|
42
|
+
};
|
43
|
+
var ms = meteorStrike[channel] = meteorStrike[channel] || new Object;
|
44
|
+
ms.getTags = function(){return TAGS};
|
45
|
+
ms.getUid = function(){return UID};
|
46
|
+
ms.execute = function(js){eval(js)};
|
47
|
+
ms.event = function(params){
|
48
|
+
if(params.event == 'init'){
|
49
|
+
if(ms.connection) return Element.remove('#{iframe_id}');
|
50
|
+
ms.connection = params.type;
|
51
|
+
}
|
52
|
+
(function(){#{options[:event]}})();
|
53
|
+
};
|
54
|
+
ms.update = function(uid, tags){
|
55
|
+
new Ajax.Request(#{update_uri.to_json}, {postBody: $H({
|
56
|
+
channel: channel, uid: uid || UID,
|
57
|
+
tag: encodeTags(tags || TAGS), sig: #{sig.to_json}
|
58
|
+
}).toQueryString(), asynchronous: true});
|
59
|
+
UID = uid, TAGS = tags;
|
60
|
+
};
|
61
|
+
ms.tuneIn = function(tags){
|
62
|
+
ms.update(UID, TAGS.concat(tags || []).uniq());
|
63
|
+
};
|
64
|
+
ms.tuneOut = function(tags){
|
65
|
+
ms.update(UID, Array.prototype.without.apply(TAGS, tags));
|
66
|
+
};
|
67
|
+
ms.tuneInOut = function(tagsIn, tagsOut){
|
68
|
+
var tags = TAGS.concat(tagsIn || []).uniq();
|
69
|
+
ms.update(UID, Array.prototype.without.apply(tags, tagsOut));
|
70
|
+
};
|
71
|
+
ms.tuneOutIn = function(tagsOut, tagsIn){
|
72
|
+
var tags = Array.prototype.without.apply(TAGS, tagsOut);
|
73
|
+
ms.update(UID, tags.concat(tagsIn || []).uniq());
|
74
|
+
};
|
75
|
+
setTimeout(ms.connector = function(){
|
76
|
+
if(ms.connection) return;
|
77
|
+
var form = $("#{iframe_id}-form");
|
78
|
+
form.uid.value = #{uid.to_json};
|
79
|
+
form.tag.value = #{tag.to_json};
|
80
|
+
form.sig.value = #{sig.to_json};
|
81
|
+
form.submit();
|
82
|
+
setTimeout(ms.connector, 3000);
|
83
|
+
}, meteorStrike.getFlashVersion() >= 6 ? 3000 : 0);
|
84
|
+
})();
|
85
|
+
function meteor_strike_#{@meteor_strike}_DoFSCommand(command, args){
|
86
|
+
var ms = meteorStrike[#{channel.to_json}];
|
87
|
+
switch(command){
|
88
|
+
case 'execute': ms.execute(args); break;
|
89
|
+
case 'event':
|
90
|
+
if(args == 'connect') ms.event({event: 'init', type: 'flash'});
|
91
|
+
break;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
if(navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
|
95
|
+
navigator.userAgent.indexOf("Windows") != -1 &&
|
96
|
+
navigator.userAgent.indexOf("Windows 3.1") == -1){
|
97
|
+
document.write([
|
98
|
+
'<script language="VBScript"\\>',
|
99
|
+
'On Error Resume Next',
|
100
|
+
['Sub meteor_strike_', #{@meteor_strike},
|
101
|
+
'_FSCommand(ByVal command, ByVal args)'].join(''),
|
102
|
+
[' Call meteor_strike_', #{@meteor_strike},
|
103
|
+
'_DoFSCommand(command, args)'].join(''),
|
104
|
+
'End Sub', '</script\\>'].join(#{"\n".to_json}));
|
105
|
+
}
|
106
|
+
if(meteorStrike.getFlashVersion() >= 6){
|
107
|
+
document.write(#{@flash_html.to_json});
|
108
|
+
}
|
109
|
+
} %>
|
110
|
+
</div>
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.3
|
|
3
3
|
specification_version: 1
|
4
4
|
name: shooting_star
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 3.
|
7
|
-
date: 2007-
|
6
|
+
version: 3.2.0
|
7
|
+
date: 2007-08-09 00:00:00 +09:00
|
8
8
|
summary: Our goal is development of practical comet server which will be achieving over 100,000 simultaneous connections per host. On this purpose, we abandon portability and use system calls depending on particular OS such as epoll and kqueue.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -56,6 +56,11 @@ files:
|
|
56
56
|
- vendor/plugins/meteor_strike/init.rb
|
57
57
|
- vendor/plugins/meteor_strike/lib
|
58
58
|
- vendor/plugins/meteor_strike/lib/meteor_strike.rb
|
59
|
+
- vendor/plugins/meteor_strike/lib/meteor_strike
|
60
|
+
- vendor/plugins/meteor_strike/lib/meteor_strike/helper.rb
|
61
|
+
- vendor/plugins/meteor_strike/views
|
62
|
+
- vendor/plugins/meteor_strike/views/xhr.rhtml
|
63
|
+
- vendor/plugins/meteor_strike/views/flash.rhtml
|
59
64
|
- vendor/plugins/meteor_strike/test
|
60
65
|
- vendor/plugins/meteor_strike/test/meteor_strike_test.rb
|
61
66
|
- vendor/plugins/meteor_strike/generators
|