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
- #object_in_temp(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
533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 533 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.
324 325 326 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 324 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.
420 421 422 423 424 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 420 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.
331 332 333 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 331 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.
431 432 433 434 435 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 431 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
525 526 527 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 525 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
469 470 471 472 473 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 469 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
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 382 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
528 529 530 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 528 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.
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 340 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.
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 444 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
548 549 550 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 548 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
492 493 494 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 492 def instanceof(js_expression, js_interface) value_json "(#{js_expression}) instanceof (#{js_interface})" end |
#object(ref) ⇒ Object
515 516 517 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 515 def object(ref) JsshObject.new(ref, self, :debug_name => ref) end |
#object_in_temp(ref) ⇒ Object
518 519 520 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 518 def object_in_temp(ref) object(ref).store_rand_temp 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
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 499 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
283 284 285 286 287 288 289 290 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 283 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
522 523 524 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 522 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’
477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 477 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.
315 316 317 318 319 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 315 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.
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/vapir-firefox/jssh_socket.rb', line 366 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 |