jscmd 0.0.2 → 0.1.0

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.
@@ -1,42 +1,38 @@
1
- $port = 19000
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
2
 
3
- $proxy_stdin, $proxy_stdin_writer = IO.pipe
4
- $proxy_stdout_reader, $proxy_stdout = IO.pipe
5
-
6
- $shell_pid = fork do
7
- at_exit {} # prevent TestRunner from running
8
- $stdin.reopen($proxy_stdin)
9
- $stdout.reopen($proxy_stdout)
10
- require File.dirname(__FILE__) + '/test_helper.rb'
11
- server = JSCommander::Broker.new(:Port => $port, :AccessLog => [])
12
- server.start
13
- end
14
-
15
- require "net/http"
16
3
  require "open-uri"
17
- require "test/unit"
18
- require "zlib"
19
4
 
20
- # wait until the server starts up
21
- 60.times do
22
- begin
23
- Net::HTTP.get("localhost", "/", $port)
24
- break
25
- rescue Exception => e
5
+ class TestProxyServer < Test::Unit::TestCase
6
+ PORT = 19000
7
+
8
+ def setup
9
+ unless $jscmd_proxy
10
+ $jscmd_broker = JSCommander::InProcessBroker.new
11
+ $jscmd_proxy = JSCommander::ProxyServer.new($jscmd_broker,
12
+ :Port => PORT, :AccessLog => [], :ProxyVia => nil)
13
+ Thread.start { $jscmd_proxy.start }
14
+ 60.times do
15
+ begin
16
+ Net::HTTP.get("localhost", "/", PORT)
17
+ break
18
+ rescue Exception => e
19
+ end
20
+ puts "waiting..."
21
+ sleep 0.5
22
+ end
23
+ end
24
+ @proxy = $jscmd_proxy
25
+ @broker = $jscmd_broker
26
26
  end
27
- puts "waiting..."
28
- sleep 0.5
29
- end
30
27
 
31
- class TestJscmd < Test::Unit::TestCase
32
28
  def test_proxy
33
- open("http://www.google.co.jp/", :proxy => "http://localhost:#{$port}/") do |f|
29
+ open("http://www.google.co.jp/", :proxy => "http://localhost:#{PORT}/") do |f|
34
30
  assert_match %r{/_remote_js_proxy/agent.js}, f.read
35
31
  end
36
32
  end
37
-
33
+
38
34
  def test_proxy_with_gzip_compression
39
- body = Net::HTTP.start("www.google.co.jp", 80, "localhost", $port) do |h|
35
+ body = Net::HTTP.start("www.google.co.jp", 80, "localhost", PORT) do |h|
40
36
  res = h.get("/",
41
37
  "Accept-Encoding" => "gzip",
42
38
  "User-Agent" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JP-mac; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3")
@@ -47,28 +43,32 @@ class TestJscmd < Test::Unit::TestCase
47
43
  end
48
44
 
49
45
  def test_get_script
50
- open("http://www.google.com/_remote_js_proxy/agent.js", :proxy => "http://localhost:#{$port}/") do |f|
46
+ open("http://www.google.com/_remote_js_proxy/agent.js", :proxy => "http://localhost:#{PORT}/") do |f|
51
47
  assert_equal File.read("lib/jscmd/agent.js"), f.read
52
48
  end
53
49
  end
54
50
 
55
51
  def test_poll_and_get_command
56
- $proxy_stdin_writer.puts "window"
57
- # assert_equal "> window\n", $proxy_stdout_reader.readline
58
- open("http://www.google.com/_remote_js_proxy/poll", :proxy => "http://localhost:#{$port}/") do |f|
59
- assert_equal "Ewindow", f.read
52
+ @broker.send "commands", JSCommander::Message.new("window", :type => "eval")
53
+ open("http://www.google.com/_remote_js_proxy/poll", :proxy => "http://localhost:#{PORT}/") do |f|
54
+ assert_equal "window", f.read
60
55
  end
61
56
  end
62
-
57
+
63
58
  def test_poll_and_post_value
64
59
  begin
60
+ q = Queue.new
61
+ s = @broker.subscribe("events") do |msg|
62
+ q.push msg.body
63
+ end
65
64
  body = nil
66
65
  t = Thread.start do
67
66
  # browser thread
68
67
  begin
69
- Net::HTTP.start("www.google.com", 80, "localhost", $port) do |h|
68
+ Net::HTTP.start("www.google.com", 80, "localhost", PORT) do |h|
70
69
  # (1) send value from browser to shell
71
- body = h.post("/_remote_js_proxy/poll", "Vabc",
70
+ body = h.post("/_remote_js_proxy/poll", "abc",
71
+ "X-JSCmd-Type" => "value",
72
72
  "Content-Type" => "application/x-www-form-urlencoded").body
73
73
  # (4) received another command and long-poll terminates
74
74
  end
@@ -76,19 +76,13 @@ class TestJscmd < Test::Unit::TestCase
76
76
  p e
77
77
  end
78
78
  end
79
- assert_match(/(sleep|run)/, t.status)
80
79
  # (2) read value sent from browser
81
- assert_equal "abc\n", $proxy_stdout_reader.readline
82
- assert_match(/(sleep|run)/, t.status)
80
+ assert_equal "abc", q.pop
83
81
  ensure
84
82
  # (3) send another command to finish long-poll in browser
85
- $proxy_stdin_writer.puts "window"
83
+ @broker.send("commands", JSCommander::Message.new("document", :type => "eval"))
86
84
  t.join
87
- assert_equal "Ewindow", body
85
+ assert_equal "document", body
88
86
  end
89
87
  end
90
88
  end
91
-
92
- END { Process.kill "TERM", $shell_pid; Process.waitall }
93
-
94
- exit Test::Unit::AutoRunner.run
@@ -0,0 +1,56 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestShell < Test::Unit::TestCase
4
+ def setup
5
+ @broker = JSCommander::InProcessBroker.new
6
+ @shell = JSCommander::Shell.new(@broker)
7
+ @output_reader, output = IO.pipe
8
+ input, @input_writer = IO.pipe
9
+ console = JSCommander::Shell::SimpleConsole.new(input)
10
+ @shell.instance_variable_set(:@console, console)
11
+ @shell.instance_variable_set(:@output, output)
12
+ def @shell.puts(msg)
13
+ @output.puts msg
14
+ end
15
+ @thread = Thread.start do
16
+ begin
17
+ @shell.run
18
+ rescue Exception
19
+ p $!
20
+ end
21
+ end
22
+ end
23
+
24
+ def teardown
25
+ @input_writer.close
26
+ @thread.join
27
+ end
28
+
29
+ def test_complete_property
30
+ @broker.subscribe("commands") do |msg|
31
+ assert_equal "this", msg.body
32
+ assert_equal "properties", msg.attributes["type"]
33
+ id = msg.attributes["id"]
34
+ @broker.send("events", JSCommander::Message.new("alert,abc,def", :type => "value",
35
+ "in-reply-to" => id))
36
+ end
37
+ assert_equal %w(alert abc), @shell.complete_property("a")
38
+ end
39
+
40
+ def test_run
41
+ q = Queue.new
42
+ @broker.subscribe("commands") do |msg|
43
+ q.push msg
44
+ end
45
+ assert q.empty?
46
+
47
+ @input_writer.puts "window"
48
+ msg = q.pop
49
+ assert_equal "window", msg.body
50
+ id = msg.attributes["id"]
51
+
52
+ @broker.send("events", JSCommander::Message.new("foobar", :type => "value",
53
+ "in-reply-to" => id))
54
+ assert_equal "foobar\n", @output_reader.readline
55
+ end
56
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: jscmd
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.2
7
- date: 2007-05-08 00:00:00 +09:00
6
+ version: 0.1.0
7
+ date: 2007-05-13 00:00:00 +09:00
8
8
  summary: JavaScript console for any browser
9
9
  require_paths:
10
10
  - lib
@@ -37,17 +37,26 @@ files:
37
37
  - Rakefile
38
38
  - bin/jscmd
39
39
  - lib/jscmd.rb
40
- - lib/jscmd/version.rb
41
- - lib/jscmd/jscommander.rb
42
40
  - lib/jscmd/asynchttpproxy.rb
41
+ - lib/jscmd/inprocessbroker.rb
42
+ - lib/jscmd/message.rb
43
+ - lib/jscmd/pipebroker.rb
44
+ - lib/jscmd/proxyserver.rb
45
+ - lib/jscmd/shell.rb
46
+ - lib/jscmd/stompproxy.rb
47
+ - lib/jscmd/urlforwarder.rb
48
+ - lib/jscmd/version.rb
43
49
  - lib/jscmd/agent.js
44
50
  - scripts/txt2html
45
51
  - setup.rb
46
52
  - test/test_helper.rb
47
- - test/test_jscmd.rb
53
+ - test/test_proxyserver.rb
54
+ - test/test_shell.rb
55
+ - examples/get_title.pl
48
56
  test_files:
49
57
  - test/test_helper.rb
50
- - test/test_jscmd.rb
58
+ - test/test_proxyserver.rb
59
+ - test/test_shell.rb
51
60
  rdoc_options: []
52
61
 
53
62
  extra_rdoc_files: []
@@ -58,5 +67,22 @@ extensions: []
58
67
 
59
68
  requirements: []
60
69
 
61
- dependencies: []
62
-
70
+ dependencies:
71
+ - !ruby/object:Gem::Dependency
72
+ name: stomp
73
+ version_requirement:
74
+ version_requirements: !ruby/object:Gem::Version::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.0.5
79
+ version:
80
+ - !ruby/object:Gem::Dependency
81
+ name: stompserver
82
+ version_requirement:
83
+ version_requirements: !ruby/object:Gem::Version::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: 0.9.7
88
+ version:
@@ -1,339 +0,0 @@
1
- #
2
- # jscommander.rb: Remote JavaScript Console
3
- #
4
- # Copyright 2007 Shinya Kasatani
5
- #
6
-
7
- require 'uri'
8
- require 'thread'
9
- require 'webrick'
10
- require 'zlib'
11
-
12
- module JSCommander
13
- SCRIPT_DIR = "/_remote_js_proxy/"
14
-
15
- class PipeQueue
16
- attr_reader :reader, :writer
17
-
18
- def initialize
19
- @reader, @writer = IO.pipe
20
- end
21
-
22
- def push(obj)
23
- data = Marshal.dump(obj)
24
- @writer.write([data.size].pack("N") + data)
25
- end
26
-
27
- def pop
28
- size = @reader.read(4).unpack("N")[0]
29
- Marshal.load(@reader.read(size))
30
- end
31
- end
32
-
33
- # types are: V: value, E: error, A: active message from proxy
34
- Message = Struct.new(:value, :type, :clients)
35
-
36
- class Broker
37
- attr_reader :cmd_queue, :msg_queue
38
-
39
- def initialize(opts = {})
40
- @cmd_queue = PipeQueue.new
41
- @msg_queue = PipeQueue.new
42
- @proxy = ProxyServer.new(self, opts)
43
- @shell = Shell.new(self)
44
- end
45
-
46
- def start
47
- @proxy_pid = fork do
48
- begin
49
- Signal.trap('INT') {}
50
- Signal.trap('TERM') { @proxy.shutdown }
51
- IO.for_fd(0).close
52
- @proxy.start
53
- rescue Exception => e
54
- p e
55
- end
56
- end
57
- Signal.trap("TERM") { shutdown }
58
- @shell.run # @shell.run should block
59
- end
60
-
61
- def shutdown
62
- $stderr.puts "shutdown"
63
- Process.kill "TERM", @proxy_pid
64
- Process.waitall
65
- exit(0)
66
- end
67
- end
68
-
69
- class Shell
70
- class SimpleConsole
71
- def show_banner
72
- end
73
-
74
- def readline
75
- line = $stdin.readline
76
- line.chomp! if line
77
- line
78
- end
79
-
80
- def close
81
- end
82
- end
83
-
84
- class ReadlineConsole
85
- HISTORY_PATH = "~/.jscmd_history"
86
-
87
- def history_path
88
- File.expand_path(HISTORY_PATH)
89
- end
90
-
91
- def initialize(shell)
92
- @shell = shell
93
- require 'readline'
94
- if File.exist?(history_path)
95
- hist = File.readlines(history_path).map{|line| line.chomp}
96
- Readline::HISTORY.push(*hist)
97
- end
98
- Readline.basic_word_break_characters = " \t\n\\`@><=;|&{([+-*/%"
99
- Readline.completion_append_character = nil
100
- Readline.completion_proc = proc do |word|
101
- if word =~ /\.$/
102
- @shell.object_props($`).map{|name| word + name}
103
- elsif word =~ /\.([^.]+)$/
104
- prefix = $1
105
- parent = $`
106
- props = @shell.object_props(parent)
107
- props.select{|name|name[0...(prefix.size)] == prefix}.map{|name| "#{parent}.#{name}"}
108
- else
109
- props = @shell.object_props("this")
110
- prefix = word
111
- props.select{|name|name[0...(prefix.size)] == prefix}
112
- end
113
- end
114
- end
115
-
116
- def show_banner
117
- puts "Press Ctrl+D to exit."
118
- end
119
-
120
- def close
121
- open(history_path, "ab") do |f|
122
- Readline::HISTORY.each{|line| f.puts(line)}
123
- end
124
- end
125
-
126
- def readline
127
- line = Readline.readline("#{@shell.clients}> ", true)
128
- Readline::HISTORY.pop if /^\s*$/ =~ line
129
- line
130
- end
131
- end
132
-
133
- def console
134
- @console ||= $stdin.tty? ? ReadlineConsole.new(self) : SimpleConsole.new
135
- end
136
-
137
- attr_reader :clients
138
-
139
- def initialize(broker)
140
- @broker = broker
141
- @clients = nil
142
- @msg_lock = Mutex.new
143
- end
144
-
145
- def send_script(line, &handler)
146
- @msg_lock.synchronize do
147
- @broker.cmd_queue.push(line)
148
- yield read_msg
149
- end
150
- end
151
-
152
- def read_msg
153
- msg = @broker.msg_queue.pop
154
- # p msg
155
- @clients = msg.clients
156
- msg
157
- end
158
-
159
- def object_props(object)
160
- send_script("P" + object) do |r|
161
- if r.type == "V" && r.value
162
- r.value.split(/,/)
163
- else
164
- []
165
- end
166
- end
167
- end
168
-
169
- def run
170
- # read and print messages in background
171
- Thread.start do
172
- while IO.select([@broker.msg_queue.reader], nil, nil, nil)
173
- @msg_lock.synchronize do
174
- if IO.select([@broker.msg_queue.reader], nil, nil, 0)
175
- msg = read_msg
176
- puts msg.value || ""
177
- Process.kill "INT", $$ # interrupt readline
178
- end
179
- end
180
- end
181
- end
182
-
183
- console.show_banner
184
-
185
- begin
186
- loop do
187
- break unless line = console.readline
188
- send_script("E" + line) do |msg|
189
- puts msg.value if msg.value
190
- end
191
- end
192
- rescue Interrupt
193
- retry
194
- rescue SystemExit
195
- return
196
- rescue Exception => e
197
- $stderr.puts "#{e.inspect} at:\n#{e.backtrace.join("\n")}"
198
- ensure
199
- begin
200
- console.close
201
- rescue Exception => e
202
- $stderr.puts "failed to close console: #{e.inspect}"
203
- end
204
- end
205
- @broker.shutdown
206
- end
207
- end
208
-
209
- class ProxyServer < WEBrick::AsyncHTTPProxyServer
210
- def initialize(broker, args = {})
211
- @broker = broker
212
- @cmd_queue = PipeQueue.new
213
- @clients = []
214
- super({:ProxyContentHandler => method(:handle_content).to_proc}.merge(args))
215
- end
216
-
217
- def start
218
- Thread.start do
219
- sleep 1
220
- begin
221
- poll_cmd_queue
222
- rescue Exception => e
223
- p e
224
- end
225
- end
226
- super
227
- end
228
-
229
- def service(req, res)
230
- if req.path == "#{SCRIPT_DIR}agent.js"
231
- res.content_type = "application/x-javascript"
232
- res.body = File.read(File.join(File.dirname(__FILE__), "agent.js"))
233
- elsif req.path == "#{SCRIPT_DIR}poll"
234
- serve_script(req, res)
235
- else
236
- if req.header["accept-encoding"] && !req.header["accept-encoding"].empty?
237
- if req.header["accept-encoding"].first.split(/,/).include?("gzip")
238
- req.header["accept-encoding"] = ["gzip"]
239
- else
240
- req.header.delete "accept-encoding"
241
- end
242
- end
243
- super
244
- end
245
- end
246
-
247
- def format_clients
248
- @clients.map{|c|"[#{URI.parse(c.header["referer"].to_s).host}]"}.join(",")
249
- end
250
-
251
- def poll_cmd_queue
252
- while @status == :Running
253
- cmd = @broker.cmd_queue.pop
254
- cmd_line = cmd[1...(cmd.size)]
255
- if cmd_line.strip.empty?
256
- @broker.msg_queue.push(Message.new(nil, "V", format_clients))
257
- else
258
- @cmd_queue.push(cmd)
259
- end
260
- end
261
- end
262
-
263
- def serve_script(req, res)
264
- # puts "serve:#{req.body}"
265
- @clients << req
266
- if req.body && req.body =~ /^(\+?)([VE])/
267
- more = $1 == '+'
268
- type = $2
269
- # V: value
270
- # E: error
271
- @broker.msg_queue.push Message.new(URI.decode($'), type, format_clients)
272
- if more
273
- res.content_type = "text/plain"
274
- res.body = ''
275
- return
276
- end
277
- else
278
- # empty message - maybe a new client connected?
279
- @broker.msg_queue.push Message.new(nil, "A", format_clients)
280
- end
281
- while @status == :Running
282
- req_socket = req.instance_eval{@socket}
283
- sockets = [req_socket, @cmd_queue.reader]
284
- if @clients.first != req
285
- # don't poll cmd_queue if this is request is not the first one
286
- sockets.pop
287
- end
288
- r = IO.select(sockets, nil, nil, 1)
289
- if r
290
- if r[0].include?(@cmd_queue.reader)
291
- line = @cmd_queue.pop
292
- res.content_type = "text/plain"
293
- res.body = line
294
- return
295
- elsif r[0].include?(req_socket)
296
- @clients.delete(req); req = nil
297
- @broker.msg_queue.push(Message.new("aborted", "A", format_clients))
298
- raise WEBrick::HTTPStatus::EOFError
299
- end
300
- end
301
- end
302
- # server is shutting down
303
- raise WEBrick::HTTPStatus::EOFError
304
- ensure
305
- @clients.delete(req) if req
306
- end
307
-
308
- def handle_content(req, res)
309
- # $stderr.puts "handle_content:type=#{res.content_type}, status=#{res.status}, encoding=#{res.header["content-encoding"]}"
310
- if res.content_type =~ %r{^text/html} && res.status == 200
311
- res.flush_body
312
- # we cannot always trust content_type, so check if the content looks like html
313
- body = res.body
314
- if res.header["content-encoding"] == "gzip"
315
- body = Zlib::GzipReader.new(StringIO.new(body)).read
316
- end
317
- if body =~ /^\s*</
318
- body = body.dup
319
- # puts "injecting javascript"
320
- script_tag = '<script type="text/javascript" src="/_remote_js_proxy/agent.js"></script>'
321
- unless body.sub!(%r{<head( .*?)?>}i){|s|s+script_tag}
322
- body = script_tag + body
323
- end
324
- if res.header["content-encoding"] == "gzip"
325
- io = StringIO.new
326
- writer = Zlib::GzipWriter.new(io)
327
- writer.write(body)
328
- writer.close
329
- res.body = io.string
330
- else
331
- res.body = body
332
- end
333
- res.content_length = res.body.size if res.content_length
334
- end
335
- end
336
- end
337
- end
338
- end
339
-