bidi2pdf 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +61 -1
- data/README.md +47 -10
- data/docker/Dockerfile +11 -3
- data/docker/Dockerfile.chromedriver +4 -2
- data/docker/Dockerfile.slim +75 -0
- data/lib/bidi2pdf/bidi/browser_console_logger.rb +92 -0
- data/lib/bidi2pdf/bidi/browser_tab.rb +415 -39
- data/lib/bidi2pdf/bidi/client.rb +85 -23
- data/lib/bidi2pdf/bidi/command_manager.rb +46 -48
- data/lib/bidi2pdf/bidi/commands/base.rb +39 -1
- data/lib/bidi2pdf/bidi/commands/browser_remove_user_context.rb +27 -0
- data/lib/bidi2pdf/bidi/commands/browsing_context_print.rb +4 -0
- data/lib/bidi2pdf/bidi/commands/print_parameters_validator.rb +5 -0
- data/lib/bidi2pdf/bidi/commands.rb +1 -0
- data/lib/bidi2pdf/bidi/event_manager.rb +1 -1
- data/lib/bidi2pdf/bidi/interceptor.rb +1 -1
- data/lib/bidi2pdf/bidi/js_logger_helper.rb +16 -0
- data/lib/bidi2pdf/bidi/logger_events.rb +66 -0
- data/lib/bidi2pdf/bidi/network_event.rb +40 -7
- data/lib/bidi2pdf/bidi/network_event_formatters/network_event_console_formatter.rb +110 -0
- data/lib/bidi2pdf/bidi/network_event_formatters/network_event_formatter_utils.rb +53 -0
- data/lib/bidi2pdf/bidi/network_event_formatters/network_event_html_formatter.rb +125 -0
- data/lib/bidi2pdf/bidi/network_event_formatters.rb +11 -0
- data/lib/bidi2pdf/bidi/network_events.rb +46 -17
- data/lib/bidi2pdf/bidi/session.rb +120 -13
- data/lib/bidi2pdf/bidi/user_context.rb +62 -0
- data/lib/bidi2pdf/bidi/web_socket_dispatcher.rb +7 -7
- data/lib/bidi2pdf/chromedriver_manager.rb +48 -21
- data/lib/bidi2pdf/cli.rb +27 -3
- data/lib/bidi2pdf/dsl.rb +33 -0
- data/lib/bidi2pdf/launcher.rb +34 -2
- data/lib/bidi2pdf/notifications/event.rb +52 -0
- data/lib/bidi2pdf/notifications/instrumenter.rb +65 -0
- data/lib/bidi2pdf/notifications/logging_subscriber.rb +136 -0
- data/lib/bidi2pdf/notifications.rb +78 -0
- data/lib/bidi2pdf/session_runner.rb +49 -7
- data/lib/bidi2pdf/verbose_logger.rb +79 -0
- data/lib/bidi2pdf/version.rb +1 -1
- data/lib/bidi2pdf.rb +99 -5
- data/sig/bidi2pdf/bidi/client.rbs +1 -1
- metadata +45 -4
- data/lib/bidi2pdf/utils.rb +0 -15
@@ -4,14 +4,41 @@ require_relative "browser_tab"
|
|
4
4
|
|
5
5
|
module Bidi2pdf
|
6
6
|
module Bidi
|
7
|
+
# Represents a user context for managing browser interactions and cookies
|
8
|
+
# using the Bidi2pdf library. This class provides methods for creating
|
9
|
+
# user contexts, setting cookies, and creating browser windows.
|
10
|
+
#
|
11
|
+
# @example Creating a user context
|
12
|
+
# user_context = Bidi2pdf::Bidi::UserContext.new(client)
|
13
|
+
#
|
14
|
+
# @example Setting a cookie
|
15
|
+
# user_context.set_cookie(
|
16
|
+
# name: "session",
|
17
|
+
# value: "abc123",
|
18
|
+
# domain: "example.com",
|
19
|
+
# source_origin: "http://example.com"
|
20
|
+
# )
|
21
|
+
#
|
22
|
+
# @example Creating a browser window
|
23
|
+
# browser_window = user_context.create_browser_window
|
24
|
+
#
|
25
|
+
# @param [Object] client The WebSocket client for communication.
|
7
26
|
class UserContext
|
27
|
+
# @return [Object] The WebSocket client.
|
8
28
|
attr_reader :client
|
9
29
|
|
30
|
+
# Initializes a new user context.
|
31
|
+
#
|
32
|
+
# @param [Object] client The WebSocket client for communication.
|
10
33
|
def initialize(client)
|
11
34
|
@client = client
|
12
35
|
@context_id = nil
|
13
36
|
end
|
14
37
|
|
38
|
+
# Retrieves the user context ID, creating it if it does not exist.
|
39
|
+
#
|
40
|
+
# @return [String] The user context ID.
|
41
|
+
# @raise [RuntimeError] If an error occurs while creating the user context.
|
15
42
|
def context_id
|
16
43
|
@context_id ||= begin
|
17
44
|
res = client.send_cmd_and_wait(Bidi2pdf::Bidi::Commands::BrowserCreateUserContext.new) do |response|
|
@@ -26,6 +53,17 @@ module Bidi2pdf
|
|
26
53
|
end
|
27
54
|
end
|
28
55
|
|
56
|
+
# Sets a cookie in the user context.
|
57
|
+
#
|
58
|
+
# @param [String] name The name of the cookie.
|
59
|
+
# @param [String] value The value of the cookie.
|
60
|
+
# @param [String] domain The domain for the cookie.
|
61
|
+
# @param [String] source_origin The source origin for the cookie.
|
62
|
+
# @param [String] path The path for the cookie. Defaults to "/".
|
63
|
+
# @param [Boolean] secure Whether the cookie is secure. Defaults to true.
|
64
|
+
# @param [Boolean] http_only Whether the cookie is HTTP-only. Defaults to false.
|
65
|
+
# @param [String] same_site The SameSite attribute for the cookie. Defaults to "strict".
|
66
|
+
# @param [Integer] ttl The time-to-live for the cookie in seconds. Defaults to 30.
|
29
67
|
def set_cookie(
|
30
68
|
name:,
|
31
69
|
value:,
|
@@ -55,6 +93,9 @@ module Bidi2pdf
|
|
55
93
|
end
|
56
94
|
end
|
57
95
|
|
96
|
+
# Creates a new browser window in the user context.
|
97
|
+
#
|
98
|
+
# @return [BrowserTab] The newly created browser tab.
|
58
99
|
def create_browser_window
|
59
100
|
cmd = Bidi2pdf::Bidi::Commands::CreateWindow.new(user_context_id: context_id)
|
60
101
|
|
@@ -64,6 +105,27 @@ module Bidi2pdf
|
|
64
105
|
BrowserTab.new(client, browsing_context_id, context_id)
|
65
106
|
end
|
66
107
|
end
|
108
|
+
|
109
|
+
# Closes the user context.
|
110
|
+
#
|
111
|
+
# This method removes the user context from the browser, effectively cleaning up
|
112
|
+
# any associated resources. If the user context does not exist, the method does nothing.
|
113
|
+
#
|
114
|
+
# @return [nil]
|
115
|
+
# @raise [RuntimeError] If an error occurs while removing the user context.
|
116
|
+
def close
|
117
|
+
return unless context_id
|
118
|
+
|
119
|
+
res = client.send_cmd_and_wait(Bidi2pdf::Bidi::Commands::BrowserRemoveUserContext.new(user_context_id: context_id)) do |response|
|
120
|
+
raise "Error removing user context: #{response.inspect}" if response["error"]
|
121
|
+
|
122
|
+
response["result"]
|
123
|
+
end
|
124
|
+
|
125
|
+
Bidi2pdf.logger.debug "User context deleted: #{res.inspect}"
|
126
|
+
|
127
|
+
@context_id = nil
|
128
|
+
end
|
67
129
|
end
|
68
130
|
end
|
69
131
|
end
|
@@ -22,15 +22,15 @@ module Bidi2pdf
|
|
22
22
|
|
23
23
|
# Add listeners
|
24
24
|
|
25
|
-
def on_message(&
|
25
|
+
def on_message(&) = socket_events.on(:message, &)
|
26
26
|
|
27
|
-
def on_event(name, &
|
27
|
+
def on_event(name, &) = session_events.on(name, &)
|
28
28
|
|
29
|
-
def on_open(&
|
29
|
+
def on_open(&) = socket_events.on(:open, &)
|
30
30
|
|
31
|
-
def on_close(&
|
31
|
+
def on_close(&) = socket_events.on(:close, &)
|
32
32
|
|
33
|
-
def on_error(&
|
33
|
+
def on_error(&) = socket_events.on(:error, &)
|
34
34
|
|
35
35
|
def remove_message_listener(block) = socket_events.off(:message, block)
|
36
36
|
|
@@ -52,10 +52,10 @@ module Bidi2pdf
|
|
52
52
|
method = data["method"]
|
53
53
|
|
54
54
|
if method
|
55
|
-
Bidi2pdf.logger.
|
55
|
+
Bidi2pdf.logger.debug3 "Dispatching session event: #{method}"
|
56
56
|
that.session_events.dispatch(method, data)
|
57
57
|
else
|
58
|
-
Bidi2pdf.logger.
|
58
|
+
Bidi2pdf.logger.debug3 "Dispatching socket message"
|
59
59
|
that.socket_events.dispatch(:message, data)
|
60
60
|
end
|
61
61
|
end
|
@@ -5,13 +5,17 @@ require "securerandom"
|
|
5
5
|
|
6
6
|
module Bidi2pdf
|
7
7
|
class ChromedriverManager
|
8
|
-
|
8
|
+
include Chromedriver::Binary::Platform
|
9
9
|
|
10
|
-
|
10
|
+
attr_reader :port, :pid, :started, :headless, :chrome_args, :shutdown_mutex
|
11
|
+
|
12
|
+
def initialize(port: 0, headless: true, chrome_args: Bidi::Session::DEFAULT_CHROME_ARGS)
|
11
13
|
@port = port
|
12
14
|
@headless = headless
|
13
15
|
@session = nil
|
14
16
|
@started = false
|
17
|
+
@chrome_args = chrome_args
|
18
|
+
@shutdown_mutex ||= Mutex.new
|
15
19
|
end
|
16
20
|
|
17
21
|
def start
|
@@ -23,11 +27,7 @@ module Bidi2pdf
|
|
23
27
|
cmd = build_cmd
|
24
28
|
Bidi2pdf.logger.info "Starting Chromedriver with command: #{cmd}"
|
25
29
|
|
26
|
-
|
27
|
-
@pid = Process.spawn(cmd, out: w, err: w)
|
28
|
-
w.close # close writer in parent
|
29
|
-
|
30
|
-
parse_port_from_output(r)
|
30
|
+
spawn_process(cmd)
|
31
31
|
|
32
32
|
Bidi2pdf.logger.info "Started Chromedriver on port #{@port}, PID #{@pid}"
|
33
33
|
wait_until_chromedriver_ready
|
@@ -40,7 +40,7 @@ module Bidi2pdf
|
|
40
40
|
def session
|
41
41
|
return unless @started
|
42
42
|
|
43
|
-
@session ||= Bidi::Session.new(session_url: session_url, headless: @headless)
|
43
|
+
@session ||= Bidi::Session.new(session_url: session_url, headless: @headless, chrome_args: @chrome_args)
|
44
44
|
end
|
45
45
|
|
46
46
|
def session_url
|
@@ -50,27 +50,54 @@ module Bidi2pdf
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def stop(timeout: 5)
|
53
|
-
|
53
|
+
shutdown_mutex.synchronize do
|
54
|
+
return unless @pid
|
54
55
|
|
55
|
-
|
56
|
+
@started = false
|
56
57
|
|
57
|
-
|
58
|
+
close_session
|
58
59
|
|
59
|
-
|
60
|
+
debug_show_all_children
|
60
61
|
|
61
|
-
|
62
|
+
old_childprocesses = term_chromedriver
|
62
63
|
|
63
|
-
|
64
|
+
detect_zombie_processes old_childprocesses
|
64
65
|
|
65
|
-
|
66
|
+
return unless process_alive?
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
kill_chromedriver timeout: timeout
|
69
|
+
ensure
|
70
|
+
@pid = nil
|
71
|
+
@started = false
|
72
|
+
end
|
70
73
|
end
|
71
74
|
|
72
75
|
private
|
73
76
|
|
77
|
+
def spawn_process(cmd)
|
78
|
+
r, w = IO.pipe
|
79
|
+
|
80
|
+
options = {
|
81
|
+
out: w,
|
82
|
+
err: w,
|
83
|
+
close_others: true,
|
84
|
+
chdir: Dir.tmpdir
|
85
|
+
}
|
86
|
+
|
87
|
+
if platform == "win"
|
88
|
+
options[:new_pgroup] = true
|
89
|
+
else
|
90
|
+
options[:pgroup] = true
|
91
|
+
end
|
92
|
+
|
93
|
+
env = {}
|
94
|
+
|
95
|
+
@pid = Process.spawn(env, cmd, **options)
|
96
|
+
w.close # close writer in parent
|
97
|
+
|
98
|
+
parse_port_from_output(r)
|
99
|
+
end
|
100
|
+
|
74
101
|
def detect_zombie_processes(old_childprocesses)
|
75
102
|
Bidi2pdf.logger.debug "Old child processes for #{@pid}: #{old_childprocesses.map(&:pid).join(", ")}"
|
76
103
|
|
@@ -99,7 +126,7 @@ module Bidi2pdf
|
|
99
126
|
Bidi2pdf::ProcessTree.new(@pid).traverse do |process, level|
|
100
127
|
indent = " " * level
|
101
128
|
prefix = level.zero? ? "" : "└─ "
|
102
|
-
Bidi2pdf.logger.
|
129
|
+
Bidi2pdf.logger.debug2 "#{indent}#{prefix}PID #{process.pid} (#{process.name})"
|
103
130
|
end
|
104
131
|
end
|
105
132
|
|
@@ -114,7 +141,7 @@ module Bidi2pdf
|
|
114
141
|
Bidi2pdf::ProcessTree.new(@pid).children(@pid).tap do |_child_processes|
|
115
142
|
Bidi2pdf.logger.info "Stopping Chromedriver (PID #{@pid})"
|
116
143
|
|
117
|
-
Process.kill("TERM",
|
144
|
+
Process.kill("TERM", -@pid) # - meanskill linux pgroup
|
118
145
|
end
|
119
146
|
rescue Errno::ESRCH
|
120
147
|
Bidi2pdf.logger.debug "Process already gone"
|
@@ -159,7 +186,7 @@ module Bidi2pdf
|
|
159
186
|
def parse_port_from_output(io, timeout: 5)
|
160
187
|
Thread.new do
|
161
188
|
io.each_line do |line|
|
162
|
-
Bidi2pdf.logger.
|
189
|
+
Bidi2pdf.logger.debug1 line.chomp
|
163
190
|
|
164
191
|
next unless line =~ /ChromeDriver was started successfully on port (\d+)/
|
165
192
|
|
data/lib/bidi2pdf/cli.rb
CHANGED
@@ -51,6 +51,17 @@ module Bidi2pdf
|
|
51
51
|
option :log_level,
|
52
52
|
type: :string,
|
53
53
|
default: "info", enum: %w[debug info warn error fatal unknown], desc: "Set log level"
|
54
|
+
verbosity_levels = Bidi2pdf::VerboseLogger::VERBOSITY_LEVELS.keys.sort_by { |k| Bidi2pdf::VerboseLogger::VERBOSITY_LEVELS[k] }
|
55
|
+
option :verbosity,
|
56
|
+
type: :string,
|
57
|
+
default: verbosity_levels.first, enum: Bidi2pdf::VerboseLogger::VERBOSITY_LEVELS.keys.sort_by { |k| Bidi2pdf::VerboseLogger::VERBOSITY_LEVELS[k] }.map(&:to_s),
|
58
|
+
desc: "Set debug verbosity level", aliases: "-v"
|
59
|
+
option :log_network_traffic, type: :boolean, default: false, desc: "Log network traffic", aliases: "-n"
|
60
|
+
option :network_log_format,
|
61
|
+
type: :string,
|
62
|
+
default: "console",
|
63
|
+
enum: %w[console pdf],
|
64
|
+
desc: "Choose network log format: console or pdf", aliases: "-f"
|
54
65
|
|
55
66
|
option :background, type: :boolean, default: true, desc: "Print background graphics"
|
56
67
|
option :margin_top, type: :numeric, default: 1.0, desc: "Top margin in inches"
|
@@ -64,6 +75,12 @@ module Bidi2pdf
|
|
64
75
|
option :scale, type: :numeric, default: 1.0, desc: "Scale between 0.1 and 2.0"
|
65
76
|
option :shrink_to_fit, type: :boolean, default: true, desc: "Shrink content to fit page"
|
66
77
|
|
78
|
+
class << self
|
79
|
+
def exit_on_failure?
|
80
|
+
true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
67
84
|
def render
|
68
85
|
load_config
|
69
86
|
|
@@ -198,16 +215,20 @@ module Bidi2pdf
|
|
198
215
|
headless: merged_options[:headless],
|
199
216
|
wait_window_loaded: merged_options[:wait_window_loaded],
|
200
217
|
wait_network_idle: merged_options[:wait_network_idle],
|
201
|
-
print_options: print_options
|
218
|
+
print_options: print_options,
|
219
|
+
network_log_format: merged_options[:network_log_format]
|
202
220
|
)
|
203
221
|
end
|
204
222
|
end
|
205
223
|
|
206
|
-
# rubocop:enable Metrics/AbcSize
|
207
|
-
|
208
224
|
def configure
|
209
225
|
Bidi2pdf.configure do |config|
|
210
226
|
config.logger.level = log_level
|
227
|
+
|
228
|
+
config.logger.verbosity = merged_options[:verbosity]
|
229
|
+
|
230
|
+
config.network_events_logger.level = Logger::INFO if merged_options[:log_network_traffic]
|
231
|
+
|
211
232
|
config.default_timeout = merged_options[:default_timeout]
|
212
233
|
|
213
234
|
Chromedriver::Binary.configure do |c|
|
@@ -216,6 +237,8 @@ module Bidi2pdf
|
|
216
237
|
end
|
217
238
|
end
|
218
239
|
|
240
|
+
# rubocop: enable Metrics/MethodLength
|
241
|
+
|
219
242
|
def log_level
|
220
243
|
case merged_options[:log_level]
|
221
244
|
when "debug" then Logger::DEBUG
|
@@ -250,3 +273,4 @@ module Bidi2pdf
|
|
250
273
|
end
|
251
274
|
end
|
252
275
|
end
|
276
|
+
# rubocop:enable Metrics/AbcSize
|
data/lib/bidi2pdf/dsl.rb
CHANGED
@@ -4,7 +4,39 @@ require "bidi2pdf"
|
|
4
4
|
|
5
5
|
module Bidi2pdf
|
6
6
|
module DSL
|
7
|
+
# Provides a DSL for managing browser sessions and tabs
|
8
|
+
# using the Bidi2pdf library. This module includes a method to create and manage
|
9
|
+
# browser tabs within a controlled session.
|
10
|
+
|
7
11
|
# rubocop: disable Metrics/AbcSize
|
12
|
+
#
|
13
|
+
# Executes a block of code within the context of a browser tab.
|
14
|
+
#
|
15
|
+
# This method handles the setup and teardown of a browser session, user context,
|
16
|
+
# browser window, and tab. It ensures that resources are properly cleaned up
|
17
|
+
# after the block is executed.
|
18
|
+
#
|
19
|
+
# @param [String, nil] remote_browser_url The URL of a remote browser to connect to.
|
20
|
+
# If provided, the session will connect to this browser in headless mode.
|
21
|
+
# @param [Integer] port The port to use for the local browser session. Defaults to 0 (chooses a random port).
|
22
|
+
# @param [Boolean] headless Whether to run the browser in headless mode. Defaults to true.
|
23
|
+
# @param [Array<String>] chrome_args Additional arguments to pass to the Chrome browser.
|
24
|
+
# Defaults to the `DEFAULT_CHROME_ARGS` from the `Bidi2pdf::Bidi::Session` class.
|
25
|
+
#
|
26
|
+
# @yield [tab] The browser tab created within the session.
|
27
|
+
# @yieldparam [Object] tab The browser tab object.
|
28
|
+
#
|
29
|
+
# @example Using a local browser session
|
30
|
+
# Bidi2pdf::DSL.with_tab(port: 9222, headless: false) do |tab|
|
31
|
+
# # Perform actions with the tab
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @example Using a remote browser session
|
35
|
+
# Bidi2pdf::DSL.with_tab(remote_browser_url: "http://remote-browser:9222/session") do |tab|
|
36
|
+
# # Perform actions with the tab
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# @return [void]
|
8
40
|
def self.with_tab(remote_browser_url: nil, port: 0, headless: true, chrome_args: Bidi2pdf::Bidi::Session::DEFAULT_CHROME_ARGS.dup)
|
9
41
|
manager = nil
|
10
42
|
session = nil
|
@@ -35,6 +67,7 @@ module Bidi2pdf
|
|
35
67
|
ensure
|
36
68
|
tab&.close
|
37
69
|
window&.close
|
70
|
+
context&.close
|
38
71
|
session&.close
|
39
72
|
manager&.stop
|
40
73
|
end
|
data/lib/bidi2pdf/launcher.rb
CHANGED
@@ -5,10 +5,40 @@ require_relative "session_runner"
|
|
5
5
|
require_relative "bidi/session"
|
6
6
|
|
7
7
|
module Bidi2pdf
|
8
|
+
# Represents a launcher for managing browser sessions and executing tasks
|
9
|
+
# using the Bidi2pdf library. This class handles the setup and teardown
|
10
|
+
# of browser sessions, as well as the execution of tasks within those sessions.
|
11
|
+
#
|
12
|
+
# @example Launching a session
|
13
|
+
# launcher = Bidi2pdf::Launcher.new(
|
14
|
+
# url: "http://example.com",
|
15
|
+
# inputfile: "input.pdf",
|
16
|
+
# output: "output.pdf",
|
17
|
+
# cookies: [],
|
18
|
+
# headers: {},
|
19
|
+
# auth: nil,
|
20
|
+
# headless: true
|
21
|
+
# )
|
22
|
+
# launcher.launch
|
23
|
+
# launcher.stop
|
24
|
+
#
|
25
|
+
# @param [String] url The URL to navigate to in the browser session.
|
26
|
+
# @param [String] inputfile The path to the input file to be processed.
|
27
|
+
# @param [String] output The path to the output file to be generated.
|
28
|
+
# @param [Array<Hash>] cookies An array of cookies to set in the browser session.
|
29
|
+
# @param [Hash] headers A hash of HTTP headers to include in the browser session.
|
30
|
+
# @param [Hash, nil] auth Authentication credentials (e.g., username and password).
|
31
|
+
# @param [Boolean] headless Whether to run the browser in headless mode. Defaults to true.
|
32
|
+
# @param [Integer] port The port to use for the browser session. Defaults to 0.
|
33
|
+
# @param [Boolean] wait_window_loaded Whether to wait for the window to fully load. Defaults to false.
|
34
|
+
# @param [Boolean] wait_network_idle Whether to wait for the network to become idle. Defaults to false.
|
35
|
+
# @param [Hash] print_options Options for printing the page. Defaults to an empty hash.
|
36
|
+
# @param [String, nil] remote_browser_url The URL of a remote browser to connect to. Defaults to nil.
|
37
|
+
# @param [Symbol] network_log_format The format for network logs. Defaults to :console.
|
8
38
|
class Launcher
|
9
39
|
# rubocop:disable Metrics/ParameterLists
|
10
40
|
def initialize(url:, inputfile:, output:, cookies:, headers:, auth:, headless: true, port: 0, wait_window_loaded: false,
|
11
|
-
wait_network_idle: false, print_options: {}, remote_browser_url: nil)
|
41
|
+
wait_network_idle: false, print_options: {}, remote_browser_url: nil, network_log_format: :console)
|
12
42
|
@url = url
|
13
43
|
@inputfile = inputfile
|
14
44
|
@port = port
|
@@ -23,6 +53,7 @@ module Bidi2pdf
|
|
23
53
|
@print_options = print_options || {}
|
24
54
|
@remote_browser_url = remote_browser_url
|
25
55
|
@custom_session = nil
|
56
|
+
@network_log_format = network_log_format
|
26
57
|
end
|
27
58
|
|
28
59
|
# rubocop:enable Metrics/ParameterLists
|
@@ -38,7 +69,8 @@ module Bidi2pdf
|
|
38
69
|
auth: @auth,
|
39
70
|
wait_window_loaded: @wait_window_loaded,
|
40
71
|
wait_network_idle: @wait_network_idle,
|
41
|
-
print_options: @print_options
|
72
|
+
print_options: @print_options,
|
73
|
+
network_log_format: @network_log_format
|
42
74
|
)
|
43
75
|
runner.run
|
44
76
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdf
|
4
|
+
# rubocop: disable Lint/RescueException
|
5
|
+
module Notifications
|
6
|
+
class Event
|
7
|
+
attr_reader :name, :transaction_id
|
8
|
+
attr_accessor :payload
|
9
|
+
|
10
|
+
def initialize(name, start, ending, transaction_id, payload)
|
11
|
+
@name = name
|
12
|
+
@payload = payload
|
13
|
+
@time = start ? start.to_f * 1_000.0 : start
|
14
|
+
@transaction_id = transaction_id
|
15
|
+
@end = ending ? ending.to_f * 1_000.0 : ending
|
16
|
+
end
|
17
|
+
|
18
|
+
def record # :nodoc:
|
19
|
+
start!
|
20
|
+
begin
|
21
|
+
yield payload if block_given?
|
22
|
+
rescue Exception => e
|
23
|
+
payload[:exception] = [e.class.name, e.message]
|
24
|
+
payload[:exception_object] = e
|
25
|
+
raise e
|
26
|
+
ensure
|
27
|
+
finish!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def start! = @time = now
|
32
|
+
|
33
|
+
def finish! = @end = now
|
34
|
+
|
35
|
+
def duration = @end - @time
|
36
|
+
|
37
|
+
def time
|
38
|
+
@time / 1000.0 if @time
|
39
|
+
end
|
40
|
+
|
41
|
+
def end
|
42
|
+
@end / 1000.0 if @end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# rubocop: enable Lint/RescueException
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
|
5
|
+
module Bidi2pdf
|
6
|
+
# This module provides a way to instrument events in the Bidi2pdf library.
|
7
|
+
# It it's heavyly inspired by ActiveSupport::Notifications.
|
8
|
+
# and thought to be used in a similar way.
|
9
|
+
# In Rails environment, ActiveSupport::Notifications should be use instead.
|
10
|
+
# via configuration: Bidi2pdf.notification_service = ActiveSupport::Notifications
|
11
|
+
|
12
|
+
# rubocop: disable Lint/RescueException, Lint/SuppressedException
|
13
|
+
module Notifications
|
14
|
+
class Instrumenter
|
15
|
+
attr_reader :id
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@id = SecureRandom.uuid
|
19
|
+
end
|
20
|
+
|
21
|
+
def notify(name, payload, &)
|
22
|
+
event = create_event(name, payload)
|
23
|
+
result = nil
|
24
|
+
begin
|
25
|
+
result = event.record(&)
|
26
|
+
rescue Exception => e
|
27
|
+
end
|
28
|
+
|
29
|
+
subscriber_exceptions = notify_subscribers(name, event)
|
30
|
+
|
31
|
+
raise Bidi2pdf::NotificationsError.new(subscriber_exceptions), cause: subscriber_exceptions.first if subscriber_exceptions.any?
|
32
|
+
raise e if e
|
33
|
+
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def create_event(name, payload)
|
40
|
+
Event.new(name, nil, nil, @id, payload)
|
41
|
+
end
|
42
|
+
|
43
|
+
# rubocop:disable Style/CaseEquality
|
44
|
+
def notify_subscribers(name, event)
|
45
|
+
exceptions = []
|
46
|
+
|
47
|
+
Notifications.subscribers.each do |pattern, blocks|
|
48
|
+
next unless pattern === name
|
49
|
+
|
50
|
+
blocks.each do |subscriber|
|
51
|
+
subscriber.call(event)
|
52
|
+
rescue Exception => e
|
53
|
+
exceptions << e
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
exceptions
|
58
|
+
end
|
59
|
+
|
60
|
+
# rubocop:enable Style/CaseEquality
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# rubocop: enable Lint/RescueException, Lint/SuppressedException
|