Class: Palapala::Renderer
- Inherits:
-
Object
- Object
- Palapala::Renderer
- Defined in:
- lib/palapala/renderer.rb
Overview
Render HTML content to PDF using Chrome in headless mode with minimal dependencies
Class Method Summary collapse
- .html_to_pdf(html, params: {}) ⇒ Object
-
.reset ⇒ Object
Reset the thread-local instance of the renderer.
-
.thread_local_instance ⇒ Object
Create a thread-local instance of the renderer.
-
.websocket_url ⇒ Object
Open a new tab in the remote chrome and return the WebSocket URL.
Instance Method Summary collapse
- #close ⇒ Object
-
#current_id ⇒ Object
Get the current ID.
-
#html_to_pdf(html, params: {}) ⇒ Object
Convert HTML content to PDF See chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF.
-
#initialize ⇒ Renderer
constructor
A new instance of Renderer.
-
#next_id ⇒ Object
Update the current ID to the next ID (increment by 1).
-
#on_message(e) ⇒ Object
Callback to handle the incomming WebSocket messages.
-
#process_until(&block) ⇒ Object
Process the WebSocket messages until some state is true.
-
#send_and_wait(message) ⇒ Object
Method to send a message (text) and wait for a response.
-
#send_command(method, params: {}, &block) ⇒ Object
Method to send a CDP command and wait for some state to be true.
-
#send_command_and_wait_for_event(method, event_name:, params: {}) ⇒ Object
Method to send a CDP command and wait for a specific method to be called.
-
#send_command_and_wait_for_result(method, params: {}) ⇒ Hash
Method to send a CDP command and wait for the matching event to get the result.
- #websocket_url ⇒ Object
Constructor Details
#initialize ⇒ Renderer
Returns a new instance of Renderer.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/palapala/renderer.rb', line 10 def initialize puts "Initializing a renderer" if Palapala.debug # Create an instance of WebSocketClient with the WebSocket URL @client = Palapala::WebSocketClient.new(websocket_url) # Create the WebSocket driver @driver = WebSocket::Driver.client(@client) # Register the on_message callback @driver.on(:message, &method(:on_message)) @driver.on(:close) { Thread.current[:renderer] = nil } # Reset the renderer on close # Start the WebSocket handshake @driver.start # Initialize the protocol to get the page events send_command_and_wait_for_result("Page.enable") end |
Class Method Details
.html_to_pdf(html, params: {}) ⇒ Object
103 104 105 |
# File 'lib/palapala/renderer.rb', line 103 def self.html_to_pdf(html, params: {}) thread_local_instance.html_to_pdf(html, params: params) end |
.reset ⇒ Object
Reset the thread-local instance of the renderer
38 39 40 41 |
# File 'lib/palapala/renderer.rb', line 38 def self.reset puts "Clearing the thread local renderer" if Palapala.debug Thread.current[:renderer] = nil end |
.thread_local_instance ⇒ Object
Create a thread-local instance of the renderer
33 34 35 |
# File 'lib/palapala/renderer.rb', line 33 def self.thread_local_instance Thread.current[:renderer] ||= Renderer.new end |
.websocket_url ⇒ Object
Open a new tab in the remote chrome and return the WebSocket URL
113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/palapala/renderer.rb', line 113 def self.websocket_url uri = URI("#{Palapala.headless_chrome_url}/json/new") http = Net::HTTP.new(uri.host, uri.port) request = Net::HTTP::Put.new(uri) request["Content-Type"] = "application/json" response = http.request(request) tab_info = JSON.parse(response.body) websocket_url = tab_info["webSocketDebuggerUrl"] puts "WebSocket URL: #{websocket_url}" if Palapala.debug websocket_url end |
Instance Method Details
#close ⇒ Object
107 108 109 110 |
# File 'lib/palapala/renderer.rb', line 107 def close @driver.close @client.close end |
#current_id ⇒ Object
Get the current ID
53 |
# File 'lib/palapala/renderer.rb', line 53 def current_id = @id |
#html_to_pdf(html, params: {}) ⇒ Object
Convert HTML content to PDF See chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
96 97 98 99 100 101 |
# File 'lib/palapala/renderer.rb', line 96 def html_to_pdf(html, params: {}) send_command_and_wait_for_event("Page.navigate", params: { url: data_url_for_html(html) }, event_name: "Page.frameStoppedLoading") result = send_command_and_wait_for_result("Page.printToPDF", params:) Base64.decode64(result["data"]) end |
#next_id ⇒ Object
Update the current ID to the next ID (increment by 1)
50 |
# File 'lib/palapala/renderer.rb', line 50 def next_id = @id = (@id || 0) + 1 |
#on_message(e) ⇒ Object
Callback to handle the incomming WebSocket messages
44 45 46 47 |
# File 'lib/palapala/renderer.rb', line 44 def (e) puts "Received: #{e.data[0..64]}" if Palapala.debug @response = JSON.parse(e.data) # Parse the JSON response end |
#process_until(&block) ⇒ Object
Process the WebSocket messages until some state is true
56 57 58 59 60 61 62 |
# File 'lib/palapala/renderer.rb', line 56 def process_until(&block) loop do @driver.parse(@client.read) return if block.call return if @driver.state == :closed end end |
#send_and_wait(message) ⇒ Object
Method to send a message (text) and wait for a response
65 66 67 68 69 |
# File 'lib/palapala/renderer.rb', line 65 def send_and_wait(, &) puts "\nSending: #{}" if Palapala.debug @driver.text() process_until(&) end |
#send_command(method, params: {}, &block) ⇒ Object
Method to send a CDP command and wait for some state to be true
72 73 74 |
# File 'lib/palapala/renderer.rb', line 72 def send_command(method, params: {}, &block) send_and_wait(JSON.generate({ id: next_id, method:, params: }), &block) end |
#send_command_and_wait_for_event(method, event_name:, params: {}) ⇒ Object
Method to send a CDP command and wait for a specific method to be called
86 87 88 89 90 |
# File 'lib/palapala/renderer.rb', line 86 def send_command_and_wait_for_event(method, event_name:, params: {}) send_command(method, params:) do @response && @response["method"] == event_name end end |
#send_command_and_wait_for_result(method, params: {}) ⇒ Hash
Method to send a CDP command and wait for the matching event to get the result
78 79 80 81 82 83 |
# File 'lib/palapala/renderer.rb', line 78 def send_command_and_wait_for_result(method, params: {}) send_command(method, params:) do @response && @response["id"] == current_id end @response["result"] end |
#websocket_url ⇒ Object
25 26 27 28 29 30 |
# File 'lib/palapala/renderer.rb', line 25 def websocket_url self.class.websocket_url rescue Errno::ECONNREFUSED ChromeProcess.spawn_chrome # Spawn a new Chrome process self.class.websocket_url # Retry (once) end |