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 +21 -1
- data/Manifest.txt +1 -0
- data/ext/asteroid.c +17 -9
- data/lib/shooting_star.rb +6 -6
- data/lib/shooting_star/channel.rb +17 -12
- data/lib/shooting_star/server.rb +43 -28
- data/lib/shooting_star/shooter.rb +35 -17
- data/test/lib/shooting_star_test.rb +73 -5
- data/vendor/plugins/meteor_strike/generators/meteor/meteor_generator.rb +2 -0
- data/vendor/plugins/meteor_strike/generators/meteor/templates/meteor_strike.swf +0 -0
- data/vendor/plugins/meteor_strike/lib/meteor_strike.rb +62 -14
- metadata +3 -3
- data/test/test_shooting_star.rb +0 -64
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
|
-
+
|
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(
|
212
|
-
remain
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
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
|
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 = '
|
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 |
|
117
|
-
count = shooter.count(
|
118
|
-
puts "%11d %s" % [count,
|
119
|
-
puts shooter.listeners(
|
120
|
-
puts shooter.signatures(
|
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(
|
10
|
-
@path =
|
8
|
+
def initialize(channel_path)
|
9
|
+
@path = channel_path
|
11
10
|
@waiters = Hash.new
|
12
|
-
@
|
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
|
-
|
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.[](
|
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(
|
36
|
-
if @@channels[
|
37
|
-
@@channels.delete(
|
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?(
|
44
|
+
!@@channels.include?(channel_path)
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|
data/lib/shooting_star/server.rb
CHANGED
@@ -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
|
-
@
|
54
|
-
@query = "channel=#{@
|
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
|
-
|
59
|
+
if !@type
|
57
60
|
make_connection(path)
|
58
61
|
else
|
59
|
-
prepare_channel(@
|
60
|
-
unless @@servers[@signature] || @
|
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[@
|
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(@
|
91
|
-
log "Channel closed: #{@
|
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.
|
98
|
+
# respond to an execution command.
|
96
99
|
def respond(id, params)
|
97
|
-
return unbind && false
|
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
|
112
|
-
|
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
|
-
|
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[@
|
163
|
+
return unless Channel[@channel_path]
|
159
164
|
event_id = ShootingStar::timestamp
|
160
|
-
log "Event(#{event_id}): #{@
|
161
|
-
Channel[@
|
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(
|
176
|
-
unless Channel[
|
177
|
-
Channel.new(
|
178
|
-
log "Channel opened: #{
|
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[
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
22
|
-
|
23
|
+
# count up listeners
|
24
|
+
def count(channel_path, tag = nil)
|
25
|
+
servers(channel_path, tag).size
|
23
26
|
end
|
24
27
|
|
25
|
-
|
26
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
34
|
-
|
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
|
-
|
41
|
-
|
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(
|
53
|
-
return [] unless Channel[
|
54
|
-
result = Channel[
|
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
|
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
|
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}
|
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
|
-
"
|
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
|
-
|
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
|
-
|
41
|
-
|
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
|
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
|
-
|
79
|
-
var
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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:
|
7
|
-
date: 2007-06-
|
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
|
data/test/test_shooting_star.rb
DELETED
@@ -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
|