Class: JsshSocket
Constant Summary collapse
- PROMPT =
end
"\n> "
- PrototypeFile =
File.join(File.dirname(__FILE__), "prototype.functional.js")
- DEFAULT_SOCKET_TIMEOUT =
64
- SHORT_SOCKET_TIMEOUT =
(2**-2).to_f
- @@default_jssh_ip =
IP Address of the machine where the script is to be executed. Default to localhost.
"127.0.0.1"
- @@default_jssh_port =
9997
Instance Attribute Summary collapse
-
#ip ⇒ Object
readonly
Returns the value of attribute ip.
-
#port ⇒ Object
readonly
Returns the value of attribute port.
-
#prototype ⇒ Object
readonly
Returns the value of attribute prototype.
Instance Method Summary collapse
-
#assert_socket ⇒ Object
raises an informative error if the socket is down for some reason.
-
#assign(js_left, js_right) ⇒ Object
assigns to the javascript reference on the left the javascript expression on the right.
-
#assign_json(js_left, rb_right) ⇒ Object
assigns to the javascript reference on the left the object on the right.
-
#call(js_function, *js_args) ⇒ Object
calls to the given function (javascript reference to a function) passing it the given arguments (javascript expressions).
-
#call_json(js_function, *rb_args) ⇒ Object
calls to the given function (javascript reference to a function) passing it the given arguments, each argument being converted from a ruby object to a javascript object via JSON.
- #Components ⇒ Object
-
#ensure_prototype ⇒ Object
raises error if the prototype library (needed for JSON stuff in javascript) has not been loaded.
- #error_or_val_json(val, js) ⇒ Object
- #getWindows ⇒ Object
-
#handle(js_expr, *args) ⇒ Object
if the given javascript expression ends with an = symbol, #handle calls to #assign assuming it is given one argument; if the expression refers to a function, calls that function with the given arguments using #call; if the expression is some other value, returns that value (its javascript toString), calling #value, assuming given no arguments.
-
#handle_json(js_expr, *args) ⇒ Object
does the same thing as #handle, but with json, calling #assign_json, #value_json, or #call_json.
-
#initialize(options = {}) ⇒ JsshSocket
constructor
Connects a new socket to jssh Takes options: * :jssh_ip => the ip to connect to, default 127.0.0.1 * :jssh_port => the port to connect to, default 9997 * :send_prototype => true|false, whether to load and send the Prototype library (the functional programming part of it anyway, and JSON bits).
- #inspect ⇒ Object
- #instanceof(js_expression, js_interface) ⇒ Object
- #object(ref) ⇒ Object
-
#parse_json(json) ⇒ Object
parses the given JSON string using ActiveSupport::JSON.decode Raises ActiveSupport::JSON::ParseError if given a blank string, something that is not a string, or a string that contains invalid JSON.
- #send_and_read(js_expr, options = {}) ⇒ Object
- #temp_object ⇒ Object
-
#typeof(expression) ⇒ Object
returns the type of the given expression using javascript typeof operator, with the exception that if the expression is null, returns ‘null’ - whereas typeof(null) in javascript returns ‘object’.
-
#value(js) ⇒ Object
returns the value of the given javascript expression, as reported by JSSH.
-
#value_json(js, options = {}) ⇒ Object
returns the value of the given javascript expression.
Constructor Details
#initialize(options = {}) ⇒ JsshSocket
Connects a new socket to jssh Takes options:
-
:jssh_ip => the ip to connect to, default 127.0.0.1
-
:jssh_port => the port to connect to, default 9997
-
:send_prototype => true|false, whether to load and send the Prototype library (the functional programming part of it anyway, and JSON bits)
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 91 def initialize(={}) @ip=[:jssh_ip] || @@default_jssh_ip @port=[:jssh_port] || @@default_jssh_port @prototype=.key?(:send_prototype) ? [:send_prototype] : true begin @socket = TCPSocket::new(@ip, @port) @socket.sync = true @expecting_prompt=false # initially, the welcome message comes before the prompt, so this so this is false to start with @expecting_extra_maybe=false welcome="Welcome to the Mozilla JavaScript Shell!\n" read=read_value if !read @expecting_extra_maybe=true raise JsshUnableToStart, "Something went wrong initializing - no response" elsif read != welcome @expecting_extra_maybe=true raise JsshUnableToStart, "Something went wrong initializing - message #{read.inspect} != #{welcome.inspect}" end rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE err=JsshUnableToStart.new("Could not connect to JSSH sever #{@ip}:#{@port}. Ensure that Firefox is running and has JSSH configured, or try restarting firefox.\nMessage from TCPSocket:\n#{$!.}") err.set_backtrace($!.backtrace) raise err end if @prototype ret=send_and_read(File.read(PrototypeFile)) if ret != "done!" @expecting_extra_maybe=true raise JsshError, "Something went wrong loading Prototype - message #{ret.inspect}" end end ret=send_and_read("(function() { nativeJSON=Components.classes['@mozilla.org/dom/json;1'].createInstance(Components.interfaces.nsIJSON); nativeJSON_encode_length=function(object) { var encoded=nativeJSON.encode(object); return encoded.length.toString()+\"\\n\"+encoded; } return 'done!'; })()") if ret != "done!" @expecting_extra_maybe=true raise JsshError, "Something went wrong initializing native JSON - message #{ret.inspect}" end temp_object.assign({}) end |
Instance Attribute Details
#ip ⇒ Object (readonly)
Returns the value of attribute ip.
84 85 86 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 84 def ip @ip end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
84 85 86 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 84 def port @port end |
#prototype ⇒ Object (readonly)
Returns the value of attribute prototype.
84 85 86 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 84 def prototype @prototype end |
Instance Method Details
#assert_socket ⇒ Object
raises an informative error if the socket is down for some reason
519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 519 def assert_socket begin actual, expected=if prototype [value_json('["foo"]'), ["foo"]] else [value('"foo"'), "foo"] end rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE raise(JsshConnectionError, "Encountered a socket error while checking the socket.\n#{$!.class}\n#{$!.}", $!.backtrace) end unless expected==actual raise JsshError, "The socket seems to have a problem: sent #{expected.inspect} but got back #{actual.inspect}" end end |
#assign(js_left, js_right) ⇒ Object
assigns to the javascript reference on the left the javascript expression on the right. returns the value of the expression as reported by JSSH, which will be a string, the expression’s toString. Uses #value; see its documentation.
313 314 315 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 313 def assign(js_left, js_right) value("#{js_left}= #{js_right}") end |
#assign_json(js_left, rb_right) ⇒ Object
assigns to the javascript reference on the left the object on the right. Assuming the right object can be converted to JSON, the javascript value will be the equivalent javascript data type to the ruby object. Will return the assigned value, converted from its javascript value back to ruby. So, the return value won’t be exactly equivalent if you use symbols for example.
>> jssh_socket.assign_json(‘bar’, => [:baz, ‘qux’])
> “qux”]
Uses #value_json; see its documentation.
409 410 411 412 413 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 409 def assign_json(js_left, rb_right) ensure_prototype js_right=rb_right.to_jssh value_json("#{js_left}=#{js_right}") end |
#call(js_function, *js_args) ⇒ Object
calls to the given function (javascript reference to a function) passing it the given arguments (javascript expressions). returns the return value of the function, a string, the toString of the javascript value. Uses #value; see its documentation.
320 321 322 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 320 def call(js_function, *js_args) value("#{js_function}(#{js_args.join(', ')})") end |
#call_json(js_function, *rb_args) ⇒ Object
calls to the given function (javascript reference to a function) passing it the given arguments, each argument being converted from a ruby object to a javascript object via JSON. returns the return value of the function, of equivalent type to the javascript return value, converted from javascript to ruby via JSON. Uses #value_json; see its documentation.
420 421 422 423 424 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 420 def call_json(js_function, *rb_args) ensure_prototype js_args=rb_args.map{|arg| arg.to_jssh} value_json("#{js_function}(#{js_args.join(', ')})") end |
#Components ⇒ Object
511 512 513 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 511 def Components @components ||= object('Components') end |
#ensure_prototype ⇒ Object
raises error if the prototype library (needed for JSON stuff in javascript) has not been loaded
458 459 460 461 462 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 458 def ensure_prototype unless prototype raise JsshError, "Cannot invoke JSON on a Jssh session that does not have the Prototype library" end end |
#error_or_val_json(val, js) ⇒ Object
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 371 def error_or_val_json(val, js) if !val || val=='' @expecting_extra_maybe=true raise JsshError, "received no value! may have timed out waiting for a value that was not coming." end if val=="SyntaxError: syntax error" raise JsshSyntaxError, val end errord_and_val=parse_json(val) unless errord_and_val.is_a?(Hash) && errord_and_val.keys.sort == ['errored', 'value'].sort raise RuntimeError, "unexpected result: \n\t#{errord_and_val.inspect} \nencountered parsing value: \n\t#{val.inspect} \nreturned from expression: \n\t#{js.inspect}" end errord=errord_and_val['errored'] val= errord_and_val['value'] if errord case val when Hash js_error(val['name'],val['message'],js,val) when String js_error(nil, val, js) else js_error(nil, val.inspect, js) end else val end end |
#getWindows ⇒ Object
514 515 516 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 514 def getWindows @getwindows ||= object('getWindows()') end |
#handle(js_expr, *args) ⇒ Object
if the given javascript expression ends with an = symbol, #handle calls to #assign assuming it is given one argument; if the expression refers to a function, calls that function with the given arguments using #call; if the expression is some other value, returns that value (its javascript toString), calling #value, assuming given no arguments. Uses #value; see its documentation.
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 329 def handle(js_expr, *args) if js_expr=~/=\z/ # doing assignment js_left=$` if args.size != 1 raise ArgumentError, "Assignment (#{js_expr}) must take one argument" end assign(js_left, *args) else type=typeof(js_expr) case type when "function" call(js_expr, *args) when "undefined" raise JsshUndefinedValueError, "undefined expression #{js_expr.inspect}" else if !args.empty? raise ArgumentError, "Cannot pass arguments to expression #{js_expr.inspect} of type #{type}" end value(js_expr) end end end |
#handle_json(js_expr, *args) ⇒ Object
does the same thing as #handle, but with json, calling #assign_json, #value_json, or #call_json. if the given javascript expression ends with an = symbol, #handle_json calls to #assign_json assuming it is given one argument; if the expression refers to a function, calls that function with the given arguments using #call_json; if the expression is some other value, returns that value, converted to ruby via JSON, assuming given no arguments. Uses #value_json; see its documentation.
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 433 def handle_json(js_expr, *args) ensure_prototype if js_expr=~/=\z/ # doing assignment js_left=$` if args.size != 1 raise ArgumentError, "Assignment (#{js_expr}) must take one argument" end assign_json(js_left, *args) else type=typeof(js_expr) case type when "function" call_json(js_expr, *args) when "undefined" raise JsshUndefinedValueError, "undefined expression #{js_expr}" else if !args.empty? raise ArgumentError, "Cannot pass arguments to expression #{js_expr.inspect} of type #{type}" end value_json(js_expr) end end end |
#inspect ⇒ Object
534 535 536 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 534 def inspect "\#<#{self.class.name}:0x#{"%.8x"%(self.hash*2)} #{[:ip, :port, :prototype].map{|attr| aa="@#{attr}";aa+'='+instance_variable_get(aa).inspect}.join(', ')}>" end |
#instanceof(js_expression, js_interface) ⇒ Object
481 482 483 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 481 def instanceof(js_expression, js_interface) value_json "(#{js_expression}) instanceof (#{js_interface})" end |
#object(ref) ⇒ Object
504 505 506 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 504 def object(ref) JsshObject.new(ref, self, :debug_name => ref) end |
#parse_json(json) ⇒ Object
parses the given JSON string using ActiveSupport::JSON.decode Raises ActiveSupport::JSON::ParseError if given a blank string, something that is not a string, or a string that contains invalid JSON
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 488 def parse_json(json) err_class=JSON::ParserError decoder=JSON.method(:parse) # err_class=ActiveSupport::JSON::ParseError # decoder=ActiveSupport::JSON.method(:decode) raise err_class, "Not a string! got: #{json.inspect}" unless json.is_a?(String) raise err_class, "Blank string!" if json=='' begin return decoder.call(json) rescue err_class err=$!.class.new($!.+"\nParsing: #{json.inspect}") err.set_backtrace($!.backtrace) raise err end end |
#send_and_read(js_expr, options = {}) ⇒ Object
273 274 275 276 277 278 279 280 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 273 def send_and_read(js_expr, ={}) # logger.add(-1) { "SEND_AND_READ is starting. options=#{options.inspect}" } @last_expression=js_expr js_expr=js_expr+"\n" unless js_expr =~ /\n\z/ # logger.debug { "SEND_AND_READ sending #{js_expr.inspect}" } @socket.send(js_expr, 0) return read_value() end |
#temp_object ⇒ Object
508 509 510 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 508 def temp_object @temp_object ||= object('JsshTemp') end |
#typeof(expression) ⇒ Object
returns the type of the given expression using javascript typeof operator, with the exception that if the expression is null, returns ‘null’ - whereas typeof(null) in javascript returns ‘object’
466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 466 def typeof(expression) ensure_prototype js="try { nativeJSON_encode_length({errored: false, value: (function(object){ return (object===null) ? 'null' : (typeof object); })(#{expression})}); } catch(e) { if(e.name=='ReferenceError') { nativeJSON_encode_length({errored: false, value: 'undefined'}); } else { nativeJSON_encode_length({errored: true, value: Object.extend({}, e)}); } }" error_or_val_json(send_and_read(js, :length_before_value => true),js) end |
#value(js) ⇒ Object
returns the value of the given javascript expression, as reported by JSSH. This will be a string, the given expression’s toString.
304 305 306 307 308 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 304 def value(js) # this is wrapped in a function so that ... # dang, now I can't remember. I'm sure I had a good reason at the time. send_and_read("(function(){return #{js}})()") end |
#value_json(js, options = {}) ⇒ Object
returns the value of the given javascript expression. Assuming that it can be converted to JSON, will return the equivalent ruby data type to the javascript value. Will raise an error if the javascript errors.
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 355 def value_json(js, ={}) ={:error_on_undefined => true}.merge() raise ArgumentError, "Expected a string containing a javascript expression! received #{js.inspect} (#{js.class})" unless js.is_a?(String) ensure_prototype ref_error=[:error_on_undefined] ? "typeof(result)=='undefined' ? {errored: true, value: {'name': 'ReferenceError', 'message': 'undefined expression in: '+result_f.toString()}} : " : "" wrapped_js= "try { var result_f=(function(){return #{js}}); var result=result_f(); nativeJSON_encode_length(#{ref_error} {errored: false, value: result}); }catch(e) { nativeJSON_encode_length({errored: true, value: Object.extend({}, e)}); }" val=send_and_read(wrapped_js, .merge(:length_before_value => true)) error_or_val_json(val, js) end |