Class: Superbot::Web

Inherits:
Object
  • Object
show all
Defined in:
lib/superbot/web.rb

Instance Method Summary collapse

Constructor Details

#initialize(webdriver_type: 'cloud', region: nil) ⇒ Web



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/superbot/web.rb', line 12

def initialize(webdriver_type: 'cloud', region: nil)
  @sinatra = Sinatra.new
  @sinatra.set :bind, ENV.fetch('SUPERBOT_TELEPORT_BIND_ADDRESS', '127.0.0.1')
  @sinatra.set :silent_sinatra, true
  @sinatra.set :silent_webrick, true
  @sinatra.set :silent_access_log, false
  @sinatra.server_settings[:Silent] = true
  instance = self

  @sinatra.before do
    headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Headers'] = 'accept, authorization, origin'
  end

  @sinatra.options '*' do
    response.headers['Allow'] = 'HEAD,GET,PUT,DELETE,OPTIONS,POST'
    response.headers['Access-Control-Allow-Headers'] = 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept'
  end

  @sinatra.get "/__superbot/v1/ping" do
    "PONG"
  end

  @sinatra.post "/__superbot/v1/convert" do
    begin
      converted_script = Superbot::Capybara::Convert.call(request.body.read)
      instance.capybara_runner.run(converted_script)
      halt 200
    rescue SystemExit => e
      e.message
    end
  end

  @webdriver_type = webdriver_type
  webdriver_uri = URI.parse(Superbot.webdriver_endpoint(@webdriver_type))
  @request_settings = {
    scheme:   webdriver_uri.scheme,
    host:     webdriver_uri.host,
    port:     webdriver_uri.port,
    path:     webdriver_uri.path
  }
  @region = region

  %w(get post put patch delete).each do |verb|
    @sinatra.send(verb, "/wd/hub/*") do
      begin
        request_path = request.path_info.gsub('/wd/hub', '')
        content_type 'application/json'
        response = instance.remote_webdriver_request(
          verb.capitalize,
          request_path,
          request.query_string,
          request.body,
          instance.incomming_headers(request)
        )
        status response.code
        headers instance.all_headers(response)
        response.body
      rescue StandardError => e
        error_message = "Remote webdriver doesn't respond"
        puts error_message, e
        halt 500, { message: error_message }.to_json
      end
    end
  end
end

Instance Method Details

#all_headers(response) ⇒ Object



123
124
125
126
127
128
129
# File 'lib/superbot/web.rb', line 123

def all_headers(response)
  header_list = {}
  response.header.each_capitalized do |k, v|
    header_list[k] = v unless k == "Transfer-Encoding"
  end
  header_list
end

#capybara_runnerObject



80
81
82
# File 'lib/superbot/web.rb', line 80

def capybara_runner
  @capybara_runner ||= Superbot::Capybara::Runner.new
end

#cloud_teleport?Boolean



115
116
117
# File 'lib/superbot/web.rb', line 115

def cloud_teleport?
  %w(cloud local_cloud).include?(@webdriver_type)
end

#creating_session?(method, path) ⇒ Boolean



119
120
121
# File 'lib/superbot/web.rb', line 119

def creating_session?(method, path)
  method.casecmp?('post') && path == '/session'
end

#incomming_headers(request) ⇒ Object



131
132
133
# File 'lib/superbot/web.rb', line 131

def incomming_headers(request)
  request.env.map { |header, value| [header[5..-1].split("_").map(&:capitalize).join('-'), value] if header.start_with?("HTTP_") }.compact.to_h
end

#output_response_errors(response) ⇒ Object



135
136
137
138
139
140
141
142
# File 'lib/superbot/web.rb', line 135

def output_response_errors(response)
  return unless response.is_a?(Net::HTTPClientError) || response.is_a?(Net::HTTPServerError)

  parsed_body = JSON.parse(response.body, symbolize_names: true)
  puts "Error: #{parsed_body[:error]}"
rescue JSON::ParserError
  puts "Request to webdriver failed with status: #{response.code}"
end

#quit!Object



160
161
162
# File 'lib/superbot/web.rb', line 160

def quit!
  @sinatra&.quit!
end

#remote_webdriver_request(type, path, query_string, body, new_headers) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/superbot/web.rb', line 84

def remote_webdriver_request(type, path, query_string, body, new_headers)
  uri = URI.const_get(@request_settings[:scheme].upcase).build(
    @request_settings.merge(
      path: @request_settings[:path] + path,
      query: query_string.empty? ? nil : query_string
    )
  )
  req = Net::HTTP.const_get(type).new(uri, new_headers.merge('Content-Type' => 'application/json'))

  request_body = body.read
  if cloud_teleport?
    user_auth_creds = Superbot::Cloud.credentials&.slice(:username, :token)
    req.basic_auth(*user_auth_creds.values) if user_auth_creds

    if @region && creating_session?(type, path)
      parsed_body = JSON.parse(request_body)
      parsed_body['desiredCapabilities']['superOptions'] = { 'region': @region }
      request_body = parsed_body.to_json
    end
  end
  req.body = request_body

  Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
    http.verify_mode = OpenSSL::SSL::VERIFY_PEER
    http.read_timeout = Superbot.cloud_timeout
    http.request(req)
  end.tap do |response|
    output_response_errors(response)
  end
end

#run!Object



144
145
146
# File 'lib/superbot/web.rb', line 144

def run!
  @sinatra.run_async!
end

#run_async_after_running!Object



148
149
150
151
152
153
154
155
156
157
158
# File 'lib/superbot/web.rb', line 148

def run_async_after_running!
  Thread.new do
    @sinatra.run!
  end

  loop do
    break if @sinatra.running?

    sleep 0.001
  end
end