Module: Vapir::Firefox::FirefoxClassAndInstanceMethods

Included in:
Vapir::Firefox, Vapir::Firefox
Defined in:
lib/vapir-firefox/browser.rb

Instance Method Summary collapse

Instance Method Details

#current_osObject

returns a symbol representing the platform we’re currently running on - currently implemented platforms are :windows, :macosx, and :linux. raises NotImplementedError if the current platform isn’t one of those.



554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
# File 'lib/vapir-firefox/browser.rb', line 554

def current_os
  @current_os ||= begin
    platform= if RUBY_PLATFORM =~ /java/
      require 'java'
      java.lang.System.getProperty("os.name")
    else
      RUBY_PLATFORM
    end
    case platform
    when /mswin|windows|mingw32/i
      :windows
    when /darwin|mac os/i
      :macosx
    when /linux/i
      :linux
    else
      raise NotImplementedError, "Unidentified platform #{platform}"
    end
  end
end

#pidObject

returns the pid of the currently-attached Firefox process.

This only works on Firefox >= 3.6, on platforms supported (see #current_os), and raises NotImplementedError if it can’t get the pid.



481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/vapir-firefox/browser.rb', line 481

def pid
  begin
    begin
      ctypes = jssh_socket.Components.utils.import("resource://gre/modules/ctypes.jsm").ctypes
    rescue JsshJavascriptError
      raise NotImplementedError, "Firefox 3.6 or greater is required for this method.\n\nOriginal error from firefox: #{$!.class}: #{$!.message}", $!.backtrace
    end
    lib, pidfunction, abi = *case current_os
    when :macosx
      ["libc.dylib", 'getpid', ctypes.default_abi]
    when :linux
      ["libc.so.6", 'getpid', ctypes.default_abi]
    when :windows
      ['kernel32', 'GetCurrentProcessId', ctypes.stdcall_abi]
    else
      raise NotImplementedError, "don't know how to get pid for #{current_os}"
    end
    getpid = ctypes.open(lib).declare(pidfunction, abi, ctypes.int32_t)
    getpid.call()
  end
end

#process_running?(pid) ⇒ Boolean

attempts to determine whether the given process is still running. will raise NotImplementedError if it can’t determine this.

Returns:

  • (Boolean)


505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/vapir-firefox/browser.rb', line 505

def process_running?(pid)
  case current_os
  when :windows
    kernel32 = Vapir::Firefox.instance_eval do # define this on the class for reuse 
      @kernel32 ||= begin
        require 'ffi'
        kernel32 = Module.new
        kernel32.send :extend, FFI::Library
        kernel32.ffi_lib 'kernel32'
        kernel32.ffi_convention :stdcall
        kernel32.attach_function :OpenProcess, [:ulong, :char, :ulong], :pointer
        kernel32.attach_function :GetExitCodeProcess, [:pointer, :pointer], :char
        kernel32.const_set('PROCESS_QUERY_INFORMATION', 0x0400)
        kernel32.const_set('STILL_ACTIVE', 259)
        kernel32
      end
    end
    process_handle = kernel32.OpenProcess(kernel32::PROCESS_QUERY_INFORMATION, 0, pid)
    exit_code=FFI::MemoryPointer.new(:ulong)
    result = kernel32.GetExitCodeProcess(process_handle, exit_code)
    if result == 0
      raise "GetExitCodeProcess failed"
    end
    return exit_code.get_ulong(0)==kernel32::STILL_ACTIVE
  when :linux, :macosx
    `ps -p #{pid}`
    $? == 0
  else
    raise NotImplementedError
  end
end

#quit_browser(options = {}) ⇒ Object

quits the browser.

quit_browser(:force => true) will force the browser to quit.

if there is no existing connection to JSSH, this will attempt to create one. If that fails, JsshUnableToStart will be raised.



448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/vapir-firefox/browser.rb', line 448

def quit_browser(options={})
  jssh_socket(:reset_if_dead => true).assert_socket
  options=handle_options(options, :force => false)
  
  pid = @pid || begin
    self.pid
  rescue NotImplementedError
    nil
  end
  
  # from https://developer.mozilla.org/en/How_to_Quit_a_XUL_Application
  appStartup= jssh_socket.Components.classes['@mozilla.org/toolkit/app-startup;1'].getService(jssh_socket.Components.interfaces.nsIAppStartup)
  quitSeverity = options[:force] ? jssh_socket.Components.interfaces.nsIAppStartup.eForceQuit : jssh_socket.Components.interfaces.nsIAppStartup.eAttemptQuit
  begin
    appStartup.quit(quitSeverity)
    ::Waiter.try_for(8, :exception => Exception::WindowFailedToCloseException.new("The browser did not quit")) do
      jssh_socket.assert_socket # this should error, going up past the waiter to the rescue block above 
      false
    end
  rescue JsshConnectionError
    Vapir::Firefox.uninitialize_jssh_socket
  end
  
  wait_for_process_exit(pid)
  
  @browser_window_object=@browser_object=@document_object=@content_window_object=@body_object=nil
  nil
end

#wait_for_process_exit(pid) ⇒ Object

waits until the Firefox process with the given pid has exited.

if no pid is given, waits the configured amount of time until it is safe to assume the pfirefox process has exited.



541
542
543
544
545
546
547
548
549
# File 'lib/vapir-firefox/browser.rb', line 541

def wait_for_process_exit(pid)
  if pid
    ::Waiter.try_for(16, :exception => Exception::WindowFailedToCloseException.new("The browser did not quit")) do
      !process_running?(pid)
    end
  else
    sleep config.firefox_quit_sleep_time
  end
end