Class: Unmagic::Browser::Driver::Cloudflare::Transport

Inherits:
Puppeteer::WebSocketTransport
  • Object
show all
Defined in:
lib/unmagic/browser/driver/cloudflare/transport.rb

Overview

The one seam between puppeteer-ruby and Cloudflare.

puppeteer-ruby opens the CDP websocket with no custom headers, and Cloudflare's remote devtools endpoint authenticates on the handshake with Authorization: Bearer. This subclass injects it; everything else about driving the browser is unchanged.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url, token) ⇒ Transport

Returns a new instance of Transport.

Parameters:

  • url (String)

    the wss:// devtools endpoint

  • token (String)

    a Cloudflare API token with Browser Rendering access



35
36
37
38
# File 'lib/unmagic/browser/driver/cloudflare/transport.rb', line 35

def initialize(url, token)
  super(url)
  @headers = [["authorization", "Bearer #{token}"]]
end

Class Method Details

.create(url, token) ⇒ Transport

Connect to Cloudflare's devtools endpoint.

Must be called from inside a running Async reactor. Outside one, connect's Async do ... end becomes the reactor itself and blocks until the read loop ends — that is, until Cloudflare drops the idle socket — handing back a transport that's already dead.

Parameters:

  • url (String)

    the wss:// devtools endpoint

  • token (String)

    a Cloudflare API token with Browser Rendering access

Returns:



28
29
30
# File 'lib/unmagic/browser/driver/cloudflare/transport.rb', line 28

def create(url, token)
  new(url, token).tap { |transport| transport.connect.wait }
end

Instance Method Details

#connectAsync::Promise

Returns resolved once the socket is open.

Returns:

  • (Async::Promise)

    resolved once the socket is open



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/unmagic/browser/driver/cloudflare/transport.rb', line 41

def connect
  return @connect_promise if @connect_promise

  @connect_promise = Async::Promise.new
  @task = Async do
    Async::WebSocket::Client.connect(@endpoint, headers: @headers) do |connection|
      @connection = connection
      @connected = true
      @connect_promise.resolve(true) unless @connect_promise.resolved?
      send(:receive_loop, connection)
    end
  rescue Async::Stop
    nil # Task stopped on the way out; nothing to clean up here.
  rescue StandardError => error
    @connect_promise.reject(error) unless @connect_promise.resolved?
    close
  ensure
    @connected = false
  end

  @connect_promise
end