shooting_star 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,8 +1,28 @@
1
+ *** 3.0.0 / 2007-06-22
2
+ + 3 major enhancements:
3
+ + Added flush client.
4
+ + Implemented reconnection for flash client.
5
+ + Server side event notification.
6
+
7
+ + 2 minor enhancements:
8
+ + Sending policy file in response to flash client's request.
9
+ + Cleaning up source code.
10
+
11
+ + 1 major bugfix:
12
+ + Suppressed EBADF while flushing execution buffer.
13
+
14
+ + 1 minor bugfix:
15
+ + Closed a hole leaking messages.
16
+
17
+ + 2 minor spec changes:
18
+ + send_message returns true if succeeded.
19
+ + Renamed local variable 'channel' to 'channel_path'
20
+
1
21
  *** 2.0.2 / 2007-06-09
2
22
  + 1 major enhancement:
3
23
  + Added chat generator.
4
24
 
5
- + 1 minor enhancement:
25
+ + 2 minor enhancements:
6
26
  + Default client configuration.
7
27
  + Changed reconnecting interval from 1 sec to 3 sec.
8
28
 
data/Manifest.txt CHANGED
@@ -37,6 +37,7 @@ vendor/plugins/meteor_strike/generators/meteor/templates/view.rhtml
37
37
  vendor/plugins/meteor_strike/generators/meteor/templates/migration.rb
38
38
  vendor/plugins/meteor_strike/generators/meteor/templates/unit_test.rb
39
39
  vendor/plugins/meteor_strike/generators/meteor/templates/functional_test.rb
40
+ vendor/plugins/meteor_strike/generators/meteor/templates/meteor_strike.swf
40
41
  vendor/plugins/meteor_strike/generators/chat
41
42
  vendor/plugins/meteor_strike/generators/chat/chat_generator.rb
42
43
  vendor/plugins/meteor_strike/generators/chat/templates
data/ext/asteroid.c CHANGED
@@ -206,18 +206,26 @@ static VALUE asteroid_s_stop(VALUE Self){
206
206
 
207
207
  static VALUE asteroid_server_send_data(VALUE Self, VALUE Data){
208
208
  VALUE Fd = rb_iv_get(Self, "@fd");
209
- int fd = FIX2INT(Fd), remain = RSTRING(Data)->len, len;
209
+ int fd = FIX2INT(Fd), remain = RSTRING(Data)->len, len, trial = 100;
210
210
  char *data = StringValuePtr(Data);
211
- while((len = send(fd, data, remain, MSG_NOSIGNAL)) > 0){
212
- remain -= len;
213
- data += len;
214
- }
215
- if(len == -1 && errno != EAGAIN){
216
- if(rb_respond_to(Self, rb_intern("unbind"))){
217
- rb_funcall(Self, rb_intern("unbind"), 0);
211
+ while(remain){
212
+ len = send(fd, data, remain, MSG_NOSIGNAL);
213
+ if(len == -1){
214
+ if(errno == EAGAIN && --trial){
215
+ rb_thread_schedule();
216
+ CHECK_INTS;
217
+ }else{
218
+ if(rb_respond_to(Self, rb_intern("unbind"))){
219
+ rb_funcall(Self, rb_intern("unbind"), 0);
220
+ }
221
+ return Qnil;
222
+ }
223
+ }else{
224
+ remain -= len;
225
+ data += len;
218
226
  }
219
227
  }
220
- return Qnil;
228
+ return Qtrue;
221
229
  }
222
230
 
223
231
  static VALUE asteroid_server_write_and_close(VALUE Self){
data/lib/shooting_star.rb CHANGED
@@ -7,7 +7,7 @@ require 'shooting_star/config'
7
7
  require 'shooting_star/shooter'
8
8
 
9
9
  module ShootingStar
10
- VERSION = '2.0.2'
10
+ VERSION = '3.0.0'
11
11
  CONFIG = Config.new(
12
12
  :config => 'config/shooting_star.yml',
13
13
  :pid_file => 'log/shooting_star.pid',
@@ -113,11 +113,11 @@ module ShootingStar
113
113
  def self.report
114
114
  puts "#{'-' * 79}\nconnections channel name\n#{'-' * 79}"
115
115
  total_connections = 0
116
- shooter.channels.each do |channel|
117
- count = shooter.count(channel)
118
- puts "%11d %s" % [count, channel]
119
- puts shooter.listeners(channel).join(',') if CONFIG.with_uid
120
- puts shooter.signatures(channel).join(',') if CONFIG.with_sig
116
+ shooter.channels.each do |channel_path|
117
+ count = shooter.count(channel_path)
118
+ puts "%11d %s" % [count, channel_path]
119
+ puts shooter.listeners(channel_path).join(',') if CONFIG.with_uid
120
+ puts shooter.signatures(channel_path).join(',') if CONFIG.with_sig
121
121
  total_connections += count
122
122
  end
123
123
  puts "#{'-' * 79}\n%11d %s\n#{'-' * 79}" % [total_connections, 'TOTAL']
@@ -2,18 +2,23 @@ require 'set'
2
2
 
3
3
  module ShootingStar
4
4
  class Channel
5
- class InvalidIdError < StandardError; end
6
5
  attr_reader :path, :waiters
7
6
  @@channels = {}
8
7
 
9
- def initialize(path)
10
- @path = path
8
+ def initialize(channel_path)
9
+ @path = channel_path
11
10
  @waiters = Hash.new
12
- @event_id = 0
11
+ @observers = Set.new
13
12
  @@channels[path] = self
14
13
  end
15
14
 
16
15
  def transmit(id, params)
16
+ if event = params[:event]
17
+ @observers.each do |obs|
18
+ begin obs.__send__(event, params) if obs.respond_to?(event)
19
+ rescue Exception; @observers.delete(obs) end
20
+ end
21
+ end
17
22
  @waiters.each do |signature, server|
18
23
  server.commit if server.respond(id, params)
19
24
  end
@@ -24,19 +29,19 @@ module ShootingStar
24
29
  server.commit
25
30
  end
26
31
 
27
- def leave(server)
28
- @waiters.delete(server.signature)
29
- end
32
+ def leave(server) @waiters.delete(server.signature) end
33
+ def observe(observer) @observers << observer end
34
+ def ignore(observer) @observers.delete(observer) end
30
35
 
31
- def self.[](channel); @@channels[channel] end
36
+ def self.[](channel_path); @@channels[channel_path] end
32
37
  def self.list; @@channels.keys end
33
38
  def self.sweep; @@channels.delete_if{|k,v| v.waiters.empty?} end
34
39
 
35
- def self.cleanup(channel)
36
- if @@channels[channel] && @@channels[channel].waiters.empty?
37
- @@channels.delete(channel)
40
+ def self.cleanup(channel_path)
41
+ if @@channels[channel_path] && @@channels[channel_path].waiters.empty?
42
+ @@channels.delete(channel_path)
38
43
  end
39
- !@@channels.include?(channel)
44
+ !@@channels.include?(channel_path)
40
45
  end
41
46
  end
42
47
  end
@@ -11,7 +11,7 @@ module ShootingStar
11
11
  module Server
12
12
  class MethodNotAcceptable < StandardError; end
13
13
 
14
- attr_reader :signature
14
+ attr_reader :signature, :type
15
15
  @@servers = {}
16
16
  @@uids = {}
17
17
  @@tags = {}
@@ -25,6 +25,8 @@ module ShootingStar
25
25
 
26
26
  # receive the data sent from client.
27
27
  def receive_data(data)
28
+ return send_policy_file if @data.length == 0 &&
29
+ data == "<policy-file-request/>"
28
30
  @data += data
29
31
  header, body = @data.split(/\n\n|\r\r|\n\r\n\r|\r\n\r\n/, 2)
30
32
  return unless body
@@ -50,14 +52,15 @@ module ShootingStar
50
52
  end
51
53
  # load or create session informations
52
54
  @signature ||= @params['sig']
53
- @channel ||= path[1..-1].split('?', 2)[0]
54
- @query = "channel=#{@channel}&sig=#{@signature}"
55
+ @channel_path ||= path[1..-1].split('?', 2)[0]
56
+ @query = "channel=#{@channel_path}&sig=#{@signature}"
57
+ @type = @params['__t__']
55
58
  # process verb
56
- unless @params['__t__']
59
+ if !@type
57
60
  make_connection(path)
58
61
  else
59
- prepare_channel(@channel)
60
- unless @@servers[@signature] || @params['__t__'] == 'rc'
62
+ prepare_channel(@channel_path)
63
+ unless @@servers[@signature] || @type == 'rc'
61
64
  notify(:event => :enter, :uid => @uid, :tag => @tag)
62
65
  log "Connected: #{@uid}"
63
66
  end
@@ -78,7 +81,7 @@ module ShootingStar
78
81
  # detect disconnection from the client and clean it up.
79
82
  def unbind
80
83
  @unbound = true
81
- if channel = Channel[@channel]
84
+ if channel = Channel[@channel_path]
82
85
  channel.leave(self)
83
86
  notify(:event => :leave, :uid => @uid, :tag => @tag)
84
87
  end
@@ -87,14 +90,14 @@ module ShootingStar
87
90
  @@tags.delete(@signature)
88
91
  @@executings.delete(@signature)
89
92
  log "Disconnected: #{@uid}:#{@signature}"
90
- if Channel.cleanup(@channel)
91
- log "Channel closed: #{@channel}"
93
+ if Channel.cleanup(@channel_path)
94
+ log "Channel closed: #{@channel_path}"
92
95
  end
93
96
  end
94
97
 
95
- # respond to an execution command. it'll be buffered.
98
+ # respond to an execution command.
96
99
  def respond(id, params)
97
- return unbind && false unless @waiting || !session_timeout?
100
+ return unbind && false if !@waiting && session_timeout?
98
101
  @executing = @@executings[@signature] ||= Hash.new
99
102
  if params[:tag] && !params[:tag].empty? && !@tag.empty?
100
103
  return false if (params[:tag] & @tag).empty?
@@ -105,17 +108,19 @@ module ShootingStar
105
108
 
106
109
  # perform buffered executions.
107
110
  def commit
108
- return false if @unbound
111
+ return false if @unbound || !@waiting
109
112
  @executing.each{|id, params| execute(id, params)}
110
113
  return false if @execution.empty?
111
- send_data "HTTP/1.1 200 OK\nContent-Type: text/javascript\n\n"
112
- send_data @execution
114
+ return false unless send_data(@type == 'f' ? "#{@execution}\0" :
115
+ "HTTP/1.1 200 OK\nContent-Type: text/javascript\n\n#{@execution}")
113
116
  @committed_at = Time.now
114
- @waiting = nil
115
117
  @execution = ''
116
118
  @executing = Hash.new
117
119
  @@executings.delete(@signature)
118
- write_and_close
120
+ unless @type == 'f'
121
+ @waiting = nil
122
+ write_and_close
123
+ end
119
124
  true
120
125
  end
121
126
 
@@ -155,29 +160,29 @@ module ShootingStar
155
160
 
156
161
  # broadcast event to clients.
157
162
  def notify(params = {})
158
- return unless Channel[@channel]
163
+ return unless Channel[@channel_path]
159
164
  event_id = ShootingStar::timestamp
160
- log "Event(#{event_id}): #{@channel}:#{params.inspect}"
161
- Channel[@channel].transmit("event-#{event_id}", params)
165
+ log "Event(#{event_id}): #{@channel_path}:#{params.inspect}"
166
+ Channel[@channel_path].transmit("event-#{event_id}", params)
162
167
  end
163
168
 
164
169
  # wait for commands or events until they occur. if they're already in
165
170
  # the execution buffer, they'll be flushed and return on the spot.
166
171
  def wait_for
167
- log "Wait for: #{@channel}:#{@uid}:#{@tag.join(',')}:#{@signature}"
168
- if prepare_channel(@channel).join(self)
169
- log "Flushed: #{@channel}:#{@uid}:#{@tag.join(',')}:#{@signature}"
170
- end
171
172
  @waiting = true
173
+ log "Wait for: #{@channel_path}:#{@uid}:#{@tag.join(',')}:#{@signature}"
174
+ if prepare_channel(@channel_path).join(self)
175
+ log "Flushed: #{@channel_path}:#{@uid}:#{@tag.join(',')}:#{@signature}"
176
+ end
172
177
  end
173
178
 
174
179
  # prepare channel object.
175
- def prepare_channel(channel)
176
- unless Channel[channel]
177
- Channel.new(channel)
178
- log "Channel opened: #{channel}"
180
+ def prepare_channel(channel_path)
181
+ unless Channel[channel_path]
182
+ Channel.new(channel_path)
183
+ log "Channel opened: #{channel_path}"
179
184
  end
180
- Channel[channel]
185
+ Channel[channel_path]
181
186
  end
182
187
 
183
188
  # add execution line to the buffer.
@@ -233,5 +238,15 @@ module ShootingStar
233
238
  ensure
234
239
  write_and_close
235
240
  end
241
+
242
+ # respond to policy file request.
243
+ def send_policy_file
244
+ send_data <<-"EOH" + "\0"
245
+ <cross-domain-policy>
246
+ <allow-access-from domain="*" to-ports="*" />
247
+ </cross-domain-policy>
248
+ EOH
249
+ write_and_close
250
+ end
236
251
  end
237
252
  end
@@ -3,12 +3,14 @@ require 'shooting_star/channel'
3
3
  # DRbObject
4
4
  module ShootingStar
5
5
  class Shooter
6
- def shoot(channel, id, tag)
7
- return unless Channel[channel]
8
- log "Shot: #{channel}:#{id}:#{tag.join(',')}"
9
- Channel[channel].transmit(id, :tag => tag)
6
+ # broadcast message
7
+ def shoot(channel_path, id, tag)
8
+ return unless Channel[channel_path]
9
+ log "Shot: #{channel_path}:#{id}:#{tag.join(',')}"
10
+ Channel[channel_path].transmit(id, :tag => tag)
10
11
  end
11
12
 
13
+ # update client properties
12
14
  def update(sig, uid, tag)
13
15
  ::ShootingStar::Server[sig].update(uid, tag || [])
14
16
  rescue Exception
@@ -18,40 +20,56 @@ module ShootingStar
18
20
  def channels; Channel.list end
19
21
  def sweep; Channel.sweep end
20
22
 
21
- def count(channel, tag = nil)
22
- servers(channel, tag).size
23
+ # count up listeners
24
+ def count(channel_path, tag = nil)
25
+ servers(channel_path, tag).size
23
26
  end
24
27
 
25
- def count_with(sig, channel, tag = nil)
26
- (signatures(channel, tag) | [sig]).size
28
+ # count up listeners with specified user.
29
+ def count_with(sig, channel_path, tag = nil)
30
+ (signatures(channel_path, tag) | [sig]).size
27
31
  end
28
32
 
29
- def listeners(channel, tag = nil)
30
- servers(channel, tag).map{|s| s.uid}
33
+ # lookup listeners
34
+ def listeners(channel_path, tag = nil)
35
+ servers(channel_path, tag).map{|s| s.uid}
31
36
  end
32
37
 
33
- def listeners_with(uid, sig, channel, tag = nil)
34
- servers(channel, tag).inject([uid]) do |result, server|
38
+ # lookup listeners with specified user.
39
+ def listeners_with(uid, sig, channel_path, tag = nil)
40
+ servers(channel_path, tag).inject([uid]) do |result, server|
35
41
  result << server.uid unless server.signature == sig
36
42
  result
37
43
  end
38
44
  end
39
45
 
40
- def signatures(channel, tag = nil)
41
- servers(channel, tag).map{|s| s.signature}
46
+ # lookup signatures on specified channel.
47
+ def signatures(channel_path, tag = nil)
48
+ servers(channel_path, tag).map{|s| s.signature}
42
49
  end
43
50
 
51
+ # notification entry point of message execution.
44
52
  def executed(sig, id)
45
53
  ::ShootingStar::Server[sig].executed(id)
46
54
  rescue Exception
47
55
  end
48
56
 
57
+ # observe server side events
58
+ def observe(channel_path, observer)
59
+ Channel[channel_path].observe(observer)
60
+ end
61
+
62
+ # ignore server side events
63
+ def ignore(channel_path, observer)
64
+ Channel[channel_path].ignore(observer)
65
+ end
66
+
49
67
  private
50
68
  def log(*arg, &block) ShootingStar::log(*arg, &block) end
51
69
 
52
- def servers(channel, tag = nil)
53
- return [] unless Channel[channel]
54
- result = Channel[channel].waiters.values
70
+ def servers(channel_path, tag = nil)
71
+ return [] unless Channel[channel_path]
72
+ result = Channel[channel_path].waiters.values
55
73
  if tag && !tag.empty?
56
74
  result = result.select do |server|
57
75
  server.tag.empty? || !(server.tag & tag).empty?
@@ -6,6 +6,11 @@ require 'thread'
6
6
  $command_line = 'echo "testing"'
7
7
 
8
8
  class ShootingStarTest < Test::Unit::TestCase
9
+ module TestObserver
10
+ def self.enter(params) @params = params end
11
+ def self.params; @params end
12
+ end
13
+
9
14
  def setup
10
15
  @config = ShootingStar.configure :silent => true,
11
16
  :pid_file => 'log/shooting_star.test.pid',
@@ -16,6 +21,8 @@ class ShootingStarTest < Test::Unit::TestCase
16
21
  mutex.lock
17
22
  @thread = Thread.new{ShootingStar.start{mutex.unlock}}
18
23
  mutex.lock
24
+ @query = "sig=0123456789&execute=http://127.0.0.1:4001/meteor/strike"
25
+ @query2 = "sig=1123456789&execute=http://127.0.0.1:4001/meteor/strike"
19
26
  end
20
27
 
21
28
  def teardown
@@ -25,10 +32,70 @@ class ShootingStarTest < Test::Unit::TestCase
25
32
  @thread.join
26
33
  end
27
34
 
28
- def test_connection
35
+ def test_connection_with_invalid_method
29
36
  client = TCPSocket.open('127.0.0.1', 8081)
30
37
  assert_not_nil client
31
- send client, "GET", "test/channel"
38
+ send(client, "GET", "test/channel", @query)
39
+ assert client.read.empty?
40
+ end
41
+
42
+ def test_connection
43
+ client = TCPSocket.open('127.0.0.1', 8081)
44
+ send(client, "POST", "test/channel", @query)
45
+ assert_not_nil result = client.read
46
+ assert_not_nil result.index('xhr.getResponseHeader')
47
+ assert_not_nil result.index('test\/channel')
48
+ client.close
49
+
50
+ mutex = Mutex.new
51
+ mutex.lock
52
+ Thread.new do
53
+ client = TCPSocket.open('127.0.0.1', 8081)
54
+ send(client, "POST", "test/channel", "#{@query}&__t__=c")
55
+ mutex.unlock
56
+ end
57
+ mutex.lock
58
+ shooter = DRbObject.new_with_uri('druby://127.0.0.1:7124')
59
+ assert_not_nil shooter
60
+ shooter.shoot("test/channel", 12, [])
61
+ assert_not_nil result = client.read
62
+ assert_not_nil result.index('meteor/strike/12')
63
+ end
64
+
65
+ def test_multi_user_communication
66
+ client1 = TCPSocket.open('127.0.0.1', 8081)
67
+ client2 = TCPSocket.open('127.0.0.1', 8081)
68
+ assert_not_nil client1
69
+ assert_not_nil client2
70
+ shooter = DRbObject.new_with_uri('druby://127.0.0.1:7124')
71
+ assert_not_nil shooter
72
+ shooter.observe('test/channel', TestObserver)
73
+ mutex = Mutex.new
74
+ mutex.lock
75
+ assert_nil TestObserver.params
76
+ Thread.new do
77
+ send(client1, "POST", "test/channel", "#{@query}&__t__=c")
78
+ mutex.unlock
79
+ end
80
+ mutex.lock
81
+ assert_nil TestObserver.params
82
+ Thread.new do
83
+ send(client2, "POST", "test/channel", "#{@query2}&__t__=c")
84
+ mutex.unlock
85
+ end
86
+ mutex.lock
87
+ assert_equal :enter, TestObserver.params[:event]
88
+ assert_not_nil result1 = client1.read
89
+ assert_not_nil result1.index('meteor/strike/event-')
90
+ shooter.shoot("test/channel", 12, [])
91
+ assert_not_nil result2 = client2.read
92
+ assert_not_nil result2.index('meteor/strike/12')
93
+ end
94
+
95
+ def test_xmlsocket_server
96
+ client = TCPSocket.open('127.0.0.1', 8081)
97
+ client.write("<policy-file-request/>\0")
98
+ assert_not_nil client.read.index('allow-access-from')
32
99
  end
33
100
 
34
101
  def test_shooter_exists
@@ -46,10 +113,11 @@ class ShootingStarTest < Test::Unit::TestCase
46
113
  end
47
114
 
48
115
  private
49
- def send(client, method, path)
50
- client.write "#{method} #{path} HTTP/1.1\n\r" +
116
+ def send(client, method, path, body)
117
+ client.write "#{method} /#{path} HTTP/1.1\n\r" +
51
118
  "Host: #{@config.server.host}:#{@config.server.port}\n\r" +
52
119
  "Keep-Alive: 300\n\r" +
53
- "Connection: keep-alive\n\r\n\r"
120
+ "Content-length: #{body.length}\n\r" +
121
+ "Connection: keep-alive\n\r\n\r#{body}"
54
122
  end
55
123
  end
@@ -34,6 +34,8 @@ class MeteorGenerator < Rails::Generator::NamedBase
34
34
  m.template 'unit_test.rb',
35
35
  File.join('test/unit', class_path, "#{file_name}_test.rb")
36
36
 
37
+ m.file 'meteor_strike.swf', 'public/meteor_strike.swf'
38
+
37
39
  m.migration_template 'migration.rb', 'db/migrate',
38
40
  :migration_file_name => "create_#{file_name.pluralize}"
39
41
  end
@@ -10,15 +10,14 @@ module MeteorStrike
10
10
  end
11
11
 
12
12
  def meteor_strike(channel, options = {})
13
- unless options[:cache] || @meteor_strike
13
+ if !options[:cache] && !@meteor_strike
14
14
  cc = controller.headers['Cache-Control'] || ''
15
15
  cc += ', ' unless cc.empty?
16
16
  cc += 'no-store, no-cache, must-revalidate, max-age=0, '
17
17
  cc += 'post-check=0, pre-check=0'
18
18
  controller.headers['Cache-Control'] = cc
19
- @meteor_strike = 0
20
19
  end
21
- @meteor_strike += 1
20
+ @meteor_strike ||= 0 and @meteor_strike += 1
22
21
  config = ActiveRecord::Base.configurations[RAILS_ENV]['shooting_star']
23
22
  config ||= {}
24
23
  config['server'] ||= 'localhost:8080'
@@ -37,8 +36,10 @@ module MeteorStrike
37
36
  update_uri = "#{uri}/meteor/update"
38
37
  sig = Meteor.shooter.signature
39
38
  iframe_id = "meteor-strike-#{@meteor_strike}"
40
- iframe_body = <<-"EOH"
41
- EOH
39
+ flash_vars = [
40
+ "channel=#{channel}", "tag=#{tag}", "uid=#{uid}", "sig=#{sig}",
41
+ "base_uri=#{uri}", "server=#{server}"].join('&')
42
+ flash_html = flash_tag(flash_vars) unless options[:noflash]
42
43
  <<-"EOH"
43
44
  <div style="position: absolute; top: -99999px; left: -99999px">
44
45
  <iframe id="#{iframe_id}" name="#{iframe_id}"></iframe>
@@ -46,7 +47,7 @@ module MeteorStrike
46
47
  action="http://#{shooting_star_uri}">
47
48
  <input name="execute" value="#{uri}/meteor/strike" />
48
49
  <input name="tag" /><input name="uid" /><input name="sig" />
49
- </form></div>
50
+ </form>#{flash_html}</div>
50
51
  <script type="text/javascript">
51
52
  //<![CDATA[
52
53
  var meteorStrike = meteorStrike || $H();
@@ -75,15 +76,36 @@ module MeteorStrike
75
76
  ms.tuneOut = function(tags){
76
77
  ms.update(UID, Array.prototype.without.apply(TAGS, tags));
77
78
  };
78
- setTimeout(function(){
79
- var form = $("#{iframe_id}-form");
80
- form.uid.value = #{uid.to_json};
81
- form.tag.value = #{tag.to_json};
82
- form.sig.value = #{sig.to_json};
83
- form.submit();
84
- setTimeout(function(){#{options[:connected]}}, 0);
85
- }, 0);
79
+ try{
80
+ var noflash = #{options[:noflash].to_json};
81
+ if(noflash || !flashVersion || flashVersion < 6){
82
+ setTimeout(function(){
83
+ var form = $("#{iframe_id}-form");
84
+ form.uid.value = #{uid.to_json};
85
+ form.tag.value = #{tag.to_json};
86
+ form.sig.value = #{sig.to_json};
87
+ form.submit();
88
+ setTimeout(function(){#{options[:connected]}}, 0);
89
+ }, 0);
90
+ }
91
+ }catch(e){}
86
92
  });
93
+ function meteor_strike_#{@meteor_strike}_DoFSCommand(command, args){
94
+ if(command == 'execute') eval(args);
95
+ }
96
+ if(navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
97
+ navigator.userAgent.indexOf("Windows") != -1 &&
98
+ navigator.userAgent.indexOf("Windows 3.1") == -1)
99
+ {
100
+ document.write([
101
+ '<script language="VBScript"\\>',
102
+ 'On Error Resume Next',
103
+ ['Sub meteor_strike_', #{@meteor_strike},
104
+ '_FSCommand(ByVal command, ByVal args)'].join(''),
105
+ [' Call meteor_strike_', #{@meteor_strike},
106
+ '_DoFSCommand(command, args)'].join(''),
107
+ 'End Sub', '</script\\>'].join(#{"\n".to_json}));
108
+ }
87
109
  //]]>
88
110
  </script>
89
111
  EOH
@@ -106,5 +128,31 @@ module MeteorStrike
106
128
  ]) unless /^get$/i === options['method']
107
129
  form_tag_without_timestamp(urlop, options, *arg, &block)
108
130
  end
131
+
132
+ def flash_tag(flash_vars)
133
+ flash_code_base = ['http://fpdownload.macromedia.com/',
134
+ 'pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0'].join('')
135
+ swf_path = File.join(RAILS_ROOT, 'public/meteor_strike.swf')
136
+ swf_timestamp = File.mtime(swf_path).to_i
137
+ <<-"EOH"
138
+ <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
139
+ codebase="#{flash_code_base}" width="0" height="0"
140
+ id="meteor_strike_#{@meteor_strike}">
141
+ <param name="allowScriptAccess" value="sameDomain" />
142
+ <param name="FlashVars" value="#{flash_vars}" />
143
+ <param name="movie" value="/meteor_strike.swf?#{swf_timestamp}" />
144
+ <param name="menu" value="false" />
145
+ <param name="quality" value="high" />
146
+ <param name="devicefont" value="true" />
147
+ <param name="bgcolor" value="#ffffff" />
148
+ <embed src="/meteor_strike.swf?#{swf_timestamp}" menu="false"
149
+ quality="high" devicefont="true" bgcolor="#ffffff" width="0" height="0"
150
+ swLiveConnect="true" id="meteor_strike_#{@meteor_strike}"
151
+ name="meteor_strike_#{@meteor_strike}" flashvars="#{flash_vars}"
152
+ allowScriptAccess="sameDomain" type="application/x-shockwave-flash"
153
+ pluginspage="http://www.macromedia.com/go/getflashplayer" />
154
+ </object>
155
+ EOH
156
+ end
109
157
  end
110
158
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: shooting_star
5
5
  version: !ruby/object:Gem::Version
6
- version: 2.0.2
7
- date: 2007-06-08 00:00:00 +09:00
6
+ version: 3.0.0
7
+ date: 2007-06-22 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
@@ -69,6 +69,7 @@ files:
69
69
  - vendor/plugins/meteor_strike/generators/meteor/templates/migration.rb
70
70
  - vendor/plugins/meteor_strike/generators/meteor/templates/unit_test.rb
71
71
  - vendor/plugins/meteor_strike/generators/meteor/templates/functional_test.rb
72
+ - vendor/plugins/meteor_strike/generators/meteor/templates/meteor_strike.swf
72
73
  - vendor/plugins/meteor_strike/generators/chat
73
74
  - vendor/plugins/meteor_strike/generators/chat/chat_generator.rb
74
75
  - vendor/plugins/meteor_strike/generators/chat/templates
@@ -83,7 +84,6 @@ files:
83
84
  - vendor/plugins/meteor_strike/generators/chat/templates/functional_test.rb
84
85
  test_files:
85
86
  - test/test_helper.rb
86
- - test/test_shooting_star.rb
87
87
  rdoc_options:
88
88
  - -S
89
89
  - --template
@@ -1,64 +0,0 @@
1
- $: << File.join(File.dirname(__FILE__), '../lib')
2
- require 'test/unit'
3
- require 'shooting_star'
4
- require 'socket'
5
- require 'thread'
6
- require 'redgreen' rescue nil
7
-
8
- COMMAND_LINE = 'echo "testing"'
9
-
10
- class ShootingStarTest < Test::Unit::TestCase
11
- def setup
12
- @config = ShootingStar.configure(
13
- :silent => true,
14
- :server => {:host => '127.0.0.1', :port => 8080},
15
- :shooter => {:uri => 'druby://127.0.0.1:7123'})
16
- @thread = Thread.new do
17
- ShootingStar.start
18
- end
19
- Thread.pass while !File.exist?(@config.pid_file)
20
- @client = TCPSocket.open('127.0.0.1', 8080)
21
- @shooter = ShootingStar.shooter
22
- end
23
-
24
- def teardown
25
- ShootingStar.stop
26
- @thread.join
27
- File.rm_f(@config.pid_file)
28
- end
29
-
30
- def test_activation
31
- assert_not_nil @thread
32
- end
33
-
34
- def test_shooter
35
- assert_not_nil @shooter
36
- end
37
-
38
- def test_client
39
- assert_not_nil @client
40
- end
41
-
42
- def test_disconnection
43
- @client.close
44
- end
45
-
46
- def test_communication
47
- mutex = Mutex.new
48
- mutex.lock
49
- thread = Thread.new do
50
- #send 'GET', 'test_application/test_channel_name'
51
- mutex.unlock
52
- end
53
- mutex.lock
54
- thread.join
55
- end
56
-
57
- private
58
- def send(method, path)
59
- @client.write "#{method} #{path} HTTP/1.1\n" +
60
- "Host: #{ShootingStar.host}:#{ShootingStar.port}\n" +
61
- "Keep-Alive: 300\n" +
62
- "Connection: keep-alive\n\n"
63
- end
64
- end