Skip to content

Commit

Permalink
Encapsulate configuration and node script invocation in separate classes
Browse files Browse the repository at this point in the history
  • Loading branch information
NielsSteensma committed Mar 26, 2024
1 parent b447376 commit 8c3d143
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 105 deletions.
3 changes: 2 additions & 1 deletion lib/Dhalang.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module Dhalang
require_relative 'Dhalang/url_utils'
require_relative 'Dhalang/file_utils'
require_relative 'Dhalang/error'
require_relative 'Dhalang/puppeteer'
require_relative 'Dhalang/configuration'
require_relative 'Dhalang/node_script_invoker'
require 'uri'
require 'tempfile'
require 'shellwords'
Expand Down
87 changes: 87 additions & 0 deletions lib/Dhalang/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
module Dhalang
# Groups Puppeteer and Dhalang configuration.
class Configuration
NODE_MODULES_PATH = Dir.pwd + '/node_modules/'.freeze
USER_OPTIONS = {
navigationTimeout: 10000,
printToPDFTimeout: 0, # unlimited
navigationWaitUntil: 'load',
navigationWaitForSelector: '',
navigationWaitForXPath: '',
userAgent: '',
isHeadless: true,
viewPort: '',
httpAuthenticationCredentials: '',
isAutoHeight: false,
chromeOptions: []
}.freeze
DEFAULT_PDF_OPTIONS = {
scale: 1,
displayHeaderFooter: false,
headerTemplate: '',
footerTemplate: '',
headerTemplateFile: '',
footerTemplateFile: '',
printBackground: true,
landscape: false,
pageRanges: '',
format: 'A4',
width: '',
height: '',
margin: { top: 36, right: 36, bottom: 20, left: 36 },
preferCSSPageSize: true,
omitBackground: false
}.freeze
DEFAULT_SCREENSHOT_OPTIONS = {
fullPage: true,
clip: nil,
omitBackground: false
}.freeze
DEFAULT_JPEG_OPTIONS = {
quality: 100
}.freeze

private_constant :NODE_MODULES_PATH
private_constant :USER_OPTIONS
private_constant :DEFAULT_PDF_OPTIONS
private_constant :DEFAULT_SCREENSHOT_OPTIONS
private_constant :DEFAULT_JPEG_OPTIONS

private attr_accessor :page_url
private attr_accessor :temp_file_path
private attr_accessor :temp_file_extension
private attr_accessor :user_options
private attr_accessor :pdf_options
private attr_accessor :screenshot_options
private attr_accessor :jpeg_options

# @param [Hash] custom_options Changes that should override default.
# @param [String] page_url Url for Puppeteer to visit.
# @param [String] temp_file_path Absolute path of temp file to write results of scripts towards.
# Can be nil for scripts using stdout.
# @param [String] temp_file_extension Extension of temp file. Can be nil for scripts using stdout.
def initialize(custom_options, page_url, temp_file_path = nil, temp_file_extension = nil)
self.page_url = page_url
self.temp_file_path = temp_file_path
self.temp_file_extension = temp_file_extension
self.user_options = USER_OPTIONS.map { |key, default_value| [key, custom_options.fetch(key, default_value)] }
self.pdf_options = DEFAULT_PDF_OPTIONS.map { |key, default_value| [key, custom_options.fetch(key, default_value)] }
self.screenshot_options = DEFAULT_SCREENSHOT_OPTIONS.map { |key, default_value| [key, custom_options.fetch(key, default_value)] }
self.jpeg_options = DEFAULT_JPEG_OPTIONS.map { |key, default_value| [key, custom_options.fetch(key, default_value)] }
end

# Returns configuration as JSON string.
def json
return {
webPageUrl: page_url,
tempFilePath: temp_file_path,
puppeteerPath: NODE_MODULES_PATH,
imageType: temp_file_extension,
userOptions: user_options.to_h,
pdfOptions: pdf_options.to_h,
screenshotOptions: screenshot_options.to_h,
jpegOptions: jpeg_options.to_h
}.to_json
end
end
end
28 changes: 28 additions & 0 deletions lib/Dhalang/node_script_invoker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Dhalang
class NodeScriptInvoker

# Executes JS script under given script_path by launching a new Node process.
#
# @param [String] script_path Absolute path of the JS script to execute.
# @param [Configuration] configuration Configuration to use by j.
def self.execute_script(script_path, configuration)
command = create_node_command(script_path, configuration)
Open3.popen2e(command) do |_stdin, stdouterr, wait|
return nil if wait.value.success?

output = stdouterr.read.strip
output = nil if output == ''
message = output || "Exited with status #{wait.value.exitstatus}"
raise DhalangError, message
end
end

# Returns a [String] with the node command to invoke the provided script with the configuration.
#
# @param [String] script_path Absolute path of JS script to invoke.
# @param [Object] configuration JSON with options to use for Puppeteer.
private_class_method def self.create_node_command(script_path, configuration)
"node #{script_path} #{Shellwords.escape(configuration.json)}"
end
end
end
97 changes: 0 additions & 97 deletions lib/Dhalang/puppeteer.rb

This file was deleted.

7 changes: 4 additions & 3 deletions lib/PDF.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Dhalang
# Allows consumers of this library to create PDFs with Puppeteer.
class PDF
PUPPETEER_SCRIPT_PATH = File.expand_path('../js/pdf-generator.js', __FILE__).freeze
private_constant :PUPPETEER_SCRIPT_PATH
SCRIPT_PATH = File.expand_path('../js/pdf-generator.js', __FILE__).freeze
private_constant :SCRIPT_PATH

# Captures the full webpage under the given url as PDF.
#
Expand Down Expand Up @@ -43,7 +43,8 @@ def self.get_from_html(html, options = {})
private_class_method def self.get(url, options)
temp_file = FileUtils.create_temp_file("pdf")
begin
Puppeteer.visit(url, PUPPETEER_SCRIPT_PATH, temp_file.path, "pdf", options)
configuration = Configuration.new(options, url, temp_file.path, "pdf")
NodeScriptInvoker.execute_script(SCRIPT_PATH, configuration)
binary_pdf_content = FileUtils.read_binary(temp_file.path)
ensure
FileUtils.delete(temp_file)
Expand Down
7 changes: 4 additions & 3 deletions lib/Screenshot.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module Dhalang
# Allows consumers of this library to take screenshots with Puppeteer.
class Screenshot
PUPPETEER_SCRIPT_PATH = File.expand_path('../js/screenshot-generator.js', __FILE__).freeze
SCRIPT_PATH = File.expand_path('../js/screenshot-generator.js', __FILE__).freeze
IMAGE_TYPES = [:jpeg, :png, :webp].freeze
private_constant :PUPPETEER_SCRIPT_PATH
private_constant :SCRIPT_PATH
private_constant :IMAGE_TYPES

# <b>DEPRECATED:</b> Please use `get_from_url(url, :jpeg)` instead.
Expand Down Expand Up @@ -44,7 +44,8 @@ def self.get_from_url(url, image_type, options = {})

temp_file = FileUtils.create_temp_file(image_type)
begin
Puppeteer.visit(url, PUPPETEER_SCRIPT_PATH, temp_file.path, image_type, options)
configuration = Configuration.new(options, url, temp_file.path, image_type)
NodeScriptInvoker.execute_script(SCRIPT_PATH, configuration)
binary_image_content = FileUtils.read_binary(temp_file.path)
ensure
FileUtils.delete(temp_file)
Expand Down
1 change: 0 additions & 1 deletion lib/js/screenshot-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const createScreenshot = async () => {
...configuration.screenshotOptions
});
} catch (error) {
console.error(error.message);
process.exit(1);
} finally {
if (browser) {
Expand Down

0 comments on commit 8c3d143

Please sign in to comment.