bidi2pdf 0.1.1 → 0.1.2
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 +3 -0
- data/CHANGELOG.md +29 -3
- data/README.md +10 -0
- data/Rakefile +2 -0
- data/cliff.toml +114 -0
- data/docker/Dockerfile.chromedriver +33 -0
- data/docker/docker-compose.yml +7 -0
- data/docker/entrypoint.sh +3 -0
- data/lib/bidi2pdf/bidi/add_headers_interceptor.rb +1 -1
- data/lib/bidi2pdf/bidi/auth_interceptor.rb +1 -1
- data/lib/bidi2pdf/bidi/client.rb +55 -140
- data/lib/bidi2pdf/bidi/command_manager.rb +82 -0
- data/lib/bidi2pdf/bidi/connection_manager.rb +34 -0
- data/lib/bidi2pdf/bidi/session.rb +26 -9
- data/lib/bidi2pdf/chromedriver_manager.rb +19 -4
- data/lib/bidi2pdf/cli.rb +147 -18
- data/lib/bidi2pdf/launcher.rb +19 -6
- data/lib/bidi2pdf/version.rb +1 -1
- data/sig/bidi2pdf/bidi/add_headers_interceptor.rbs +20 -0
- data/sig/bidi2pdf/bidi/auth_interceptor.rbs +17 -0
- data/sig/bidi2pdf/bidi/browser.rbs +38 -0
- data/sig/bidi2pdf/bidi/browser_tab.rbs +42 -0
- data/sig/bidi2pdf/bidi/client.rbs +72 -0
- data/sig/bidi2pdf/bidi/event_manager.rbs +29 -0
- data/sig/bidi2pdf/bidi/network_event.rbs +51 -0
- data/sig/bidi2pdf/bidi/network_events.rbs +55 -0
- data/sig/bidi2pdf/bidi/print_parameters_validator.rbs +44 -0
- data/sig/bidi2pdf/bidi/session.rbs +52 -0
- data/sig/bidi2pdf/bidi/user_context.rbs +50 -0
- data/sig/bidi2pdf/bidi/web_socket_dispatcher.rbs +53 -0
- data/sig/bidi2pdf/chromedriver_manager.rbs +42 -0
- data/sig/bidi2pdf/cli.rbs +21 -0
- data/sig/bidi2pdf/launcher.rbs +38 -0
- data/sig/bidi2pdf/process_tree.rbs +27 -0
- data/sig/bidi2pdf/session_runner.rbs +51 -0
- data/sig/bidi2pdf/utils.rbs +5 -0
- data/sig/vendor/thor.rbs +13 -0
- data/tasks/changelog.rake +29 -0
- data/tasks/generate_rbs.rake +64 -0
- metadata +48 -8
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdf
|
4
|
+
module Bidi
|
5
|
+
class ConnectionManager
|
6
|
+
def initialize(logger:)
|
7
|
+
@logger = logger
|
8
|
+
@connected = false
|
9
|
+
@mutex = Mutex.new
|
10
|
+
@cv = ConditionVariable.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def mark_connected
|
14
|
+
@mutex.synchronize do
|
15
|
+
@connected = true
|
16
|
+
@cv.broadcast
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def wait_until_open(timeout:)
|
21
|
+
@mutex.synchronize do
|
22
|
+
unless @connected
|
23
|
+
@logger.debug "Waiting for WebSocket connection to open"
|
24
|
+
@cv.wait(@mutex, timeout)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
raise "WebSocket connection did not open in time" unless @connected
|
29
|
+
|
30
|
+
@logger.debug "WebSocket connection is open"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -25,22 +25,24 @@ module Bidi2pdf
|
|
25
25
|
"goog:cdp.Page.screencastFrame"
|
26
26
|
].freeze
|
27
27
|
|
28
|
-
attr_reader :
|
28
|
+
attr_reader :session_uri, :started
|
29
29
|
|
30
|
-
def initialize(
|
31
|
-
@
|
30
|
+
def initialize(session_url:, headless: true)
|
31
|
+
@session_uri = URI(session_url)
|
32
32
|
@headless = headless
|
33
33
|
@client = nil
|
34
34
|
@browser = nil
|
35
35
|
@websocket_url = nil
|
36
|
+
@started = false
|
36
37
|
end
|
37
38
|
|
38
39
|
def start
|
40
|
+
@started = true
|
39
41
|
client
|
40
42
|
end
|
41
43
|
|
42
44
|
def client
|
43
|
-
@client ||= create_client
|
45
|
+
@client ||= @started ? create_client : nil
|
44
46
|
end
|
45
47
|
|
46
48
|
def close
|
@@ -88,9 +90,19 @@ module Bidi2pdf
|
|
88
90
|
Bidi::Browser.new(@client)
|
89
91
|
end
|
90
92
|
|
91
|
-
# rubocop: disable Metrics/AbcSize
|
92
93
|
def create_client
|
93
|
-
|
94
|
+
Bidi::Client.new(websocket_url).tap(&:start)
|
95
|
+
end
|
96
|
+
|
97
|
+
# rubocop:disable Metrics/AbcSize
|
98
|
+
def websocket_url
|
99
|
+
return @websocket_url if @websocket_url
|
100
|
+
|
101
|
+
if %w[ws wss].include?(session_uri.scheme)
|
102
|
+
@websocket_url = session_uri.to_s
|
103
|
+
return @websocket_url
|
104
|
+
end
|
105
|
+
|
94
106
|
args = %w[
|
95
107
|
--disable-gpu
|
96
108
|
--disable-popup-blocking
|
@@ -115,7 +127,12 @@ module Bidi2pdf
|
|
115
127
|
}
|
116
128
|
}
|
117
129
|
}
|
118
|
-
|
130
|
+
|
131
|
+
response = Net::HTTP.post(session_uri, session_request.to_json, "Content-Type" => "application/json")
|
132
|
+
|
133
|
+
Bidi2pdf.logger.debug "Response code: #{response.code}"
|
134
|
+
Bidi2pdf.logger.debug "Response body: #{response.body}"
|
135
|
+
|
119
136
|
session_data = JSON.parse(response.body)
|
120
137
|
|
121
138
|
Bidi2pdf.logger.debug "Session data: #{session_data}"
|
@@ -126,10 +143,10 @@ module Bidi2pdf
|
|
126
143
|
Bidi2pdf.logger.info "Created session with ID: #{session_id}"
|
127
144
|
Bidi2pdf.logger.info "WebSocket URL: #{@websocket_url}"
|
128
145
|
|
129
|
-
|
146
|
+
@websocket_url
|
130
147
|
end
|
131
148
|
|
132
|
-
# rubocop:
|
149
|
+
# rubocop:enable Metrics/AbcSize
|
133
150
|
end
|
134
151
|
end
|
135
152
|
end
|
@@ -4,17 +4,20 @@ require "chromedriver/binary"
|
|
4
4
|
|
5
5
|
module Bidi2pdf
|
6
6
|
class ChromedriverManager
|
7
|
-
attr_reader :port, :pid, :
|
7
|
+
attr_reader :port, :pid, :started
|
8
8
|
|
9
9
|
def initialize(port: 0, headless: true)
|
10
10
|
@port = port
|
11
11
|
@headless = headless
|
12
12
|
@session = nil
|
13
|
+
@started = false
|
13
14
|
end
|
14
15
|
|
15
16
|
def start
|
16
17
|
return @pid if @pid
|
17
18
|
|
19
|
+
@started = true
|
20
|
+
|
18
21
|
update_chromedriver
|
19
22
|
cmd = build_cmd
|
20
23
|
Bidi2pdf.logger.info "Starting Chromedriver with command: #{cmd}"
|
@@ -30,14 +33,26 @@ module Bidi2pdf
|
|
30
33
|
|
31
34
|
at_exit { stop }
|
32
35
|
|
33
|
-
@session = Bidi::Session.new(@port, headless: @headless)
|
34
|
-
|
35
36
|
@pid
|
36
37
|
end
|
37
38
|
|
39
|
+
def session
|
40
|
+
return unless @started
|
41
|
+
|
42
|
+
@session ||= Bidi::Session.new(session_url: session_url, headless: @headless)
|
43
|
+
end
|
44
|
+
|
45
|
+
def session_url
|
46
|
+
return unless @started
|
47
|
+
|
48
|
+
"http://localhost:#{@port}/session"
|
49
|
+
end
|
50
|
+
|
38
51
|
def stop(timeout: 5)
|
39
52
|
return unless @pid
|
40
53
|
|
54
|
+
@started = false
|
55
|
+
|
41
56
|
close_session
|
42
57
|
|
43
58
|
term_chromedriver
|
@@ -83,7 +98,7 @@ module Bidi2pdf
|
|
83
98
|
def close_session
|
84
99
|
Bidi2pdf.logger.info "Closing session"
|
85
100
|
|
86
|
-
@session
|
101
|
+
@session&.close
|
87
102
|
@session = nil
|
88
103
|
end
|
89
104
|
|
data/lib/bidi2pdf/cli.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "thor"
|
4
|
+
require "yaml"
|
4
5
|
|
5
6
|
module Bidi2pdf
|
7
|
+
# rubocop:disable Metrics/AbcSize
|
6
8
|
class CLI < Thor
|
9
|
+
class_option :config, type: :string, desc: "Load configuration from YAML file"
|
10
|
+
|
7
11
|
desc "render", "Render a URL to PDF using Chrome BiDi"
|
8
12
|
long_desc <<~USAGE, wrap: false
|
9
13
|
Example:
|
@@ -26,11 +30,11 @@ module Bidi2pdf
|
|
26
30
|
Set --port to 0 for a random ChromeDriver port.
|
27
31
|
USAGE
|
28
32
|
|
29
|
-
option :url,
|
30
|
-
option :output, default: "output.pdf", desc: "Filename for the output PDF"
|
31
|
-
option :cookie, type: :array, default: [], banner: "name=value", desc: "One or more cookies"
|
32
|
-
option :header, type: :array, default: [], banner: "name=value", desc: "One or more custom headers"
|
33
|
-
option :auth, type: :string, banner: "user:pass", desc: "Basic auth credentials"
|
33
|
+
option :url, desc: "The URL to render"
|
34
|
+
option :output, default: "output.pdf", desc: "Filename for the output PDF", aliases: "-o"
|
35
|
+
option :cookie, type: :array, default: [], banner: "name=value", desc: "One or more cookies", aliases: "-C"
|
36
|
+
option :header, type: :array, default: [], banner: "name=value", desc: "One or more custom headers", aliases: "-H"
|
37
|
+
option :auth, type: :string, banner: "user:pass", desc: "Basic auth credentials", aliases: "-a"
|
34
38
|
option :headless, type: :boolean, default: true, desc: "Run Chrome in headless mode"
|
35
39
|
option :port, type: :numeric, default: 0, desc: "Port to run ChromeDriver on (0 = auto)"
|
36
40
|
option :wait_window_loaded,
|
@@ -39,36 +43,156 @@ module Bidi2pdf
|
|
39
43
|
desc: "Wait for the window to be fully loaded (windoow.loaded set by your script)"
|
40
44
|
option :wait_network_idle, type: :boolean, default: false, desc: "Wait for network to be idle"
|
41
45
|
option :default_timeout, type: :numeric, default: 60, desc: "Default timeout for commands"
|
46
|
+
option :remote_browser_url, type: :string, desc: "Remote browser URL for ChromeDriver"
|
42
47
|
option :log_level,
|
43
48
|
type: :string,
|
44
49
|
default: "info", enum: %w[debug info warn error fatal unknown], desc: "Set log level"
|
45
50
|
|
51
|
+
option :background, type: :boolean, default: true, desc: "Print background graphics"
|
52
|
+
option :margin_top, type: :numeric, default: 1.0, desc: "Top margin in inches"
|
53
|
+
option :margin_bottom, type: :numeric, default: 1.0, desc: "Bottom margin in inches"
|
54
|
+
option :margin_left, type: :numeric, default: 1.0, desc: "Left margin in inches"
|
55
|
+
option :margin_right, type: :numeric, default: 1.0, desc: "Right margin in inches"
|
56
|
+
option :orientation, type: :string, default: "portrait", enum: %w[portrait landscape], desc: "Page orientation"
|
57
|
+
option :page_width, type: :numeric, default: 21.59, desc: "Page width in cm (min 0.0352)"
|
58
|
+
option :page_height, type: :numeric, default: 27.94, desc: "Page height in cm (min 0.0352)"
|
59
|
+
option :page_ranges, type: :array, desc: "Page ranges to print (e.g., 1-2 4 6)"
|
60
|
+
option :scale, type: :numeric, default: 1.0, desc: "Scale between 0.1 and 2.0"
|
61
|
+
option :shrink_to_fit, type: :boolean, default: true, desc: "Shrink content to fit page"
|
62
|
+
|
46
63
|
def render
|
64
|
+
load_config
|
65
|
+
|
66
|
+
validate_required_options! :url
|
67
|
+
|
47
68
|
configure
|
48
69
|
|
49
|
-
Bidi2pdf.logger.info "Rendering: #{
|
70
|
+
Bidi2pdf.logger.info "Rendering: #{merged_options[:url]} -> #{merged_options[:output]}"
|
71
|
+
Bidi2pdf.logger.info "Print options: #{print_options.inspect}" if print_options
|
72
|
+
|
73
|
+
validate_print_options(print_options) if print_options
|
50
74
|
|
51
75
|
launcher.launch
|
76
|
+
ensure
|
77
|
+
launcher.stop if defined?(@launcher) && @launcher
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "version", "Show bidi2pdf version"
|
81
|
+
|
82
|
+
def version
|
83
|
+
puts "bidi2pdf #{Bidi2pdf::VERSION}"
|
84
|
+
end
|
85
|
+
|
86
|
+
desc "template", "Generate a config file template"
|
87
|
+
option :output, default: "bidi2pdf.yml", desc: "Output configuration filename"
|
88
|
+
|
89
|
+
def template
|
90
|
+
config = {
|
91
|
+
"url" => "https://example.com",
|
92
|
+
"output" => "output.pdf",
|
93
|
+
"headless" => true,
|
94
|
+
"print_options" => {
|
95
|
+
"background" => true,
|
96
|
+
"orientation" => "portrait",
|
97
|
+
"margin" => {
|
98
|
+
"top" => 1.0,
|
99
|
+
"bottom" => 1.0,
|
100
|
+
"left" => 1.0,
|
101
|
+
"right" => 1.0
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
File.write(merged_options[:output], config.to_yaml)
|
107
|
+
puts "Config template written to #{merged_options[:output]}"
|
52
108
|
end
|
53
109
|
|
54
110
|
private
|
55
111
|
|
56
|
-
|
112
|
+
def load_config
|
113
|
+
return unless options[:config] && File.exist?(options[:config])
|
114
|
+
|
115
|
+
YAML.load_file(options[:config]).transform_keys(&:to_sym)
|
116
|
+
end
|
117
|
+
|
118
|
+
def validate_required_options!(*keys)
|
119
|
+
keys.each do |key|
|
120
|
+
raise Thor::Error, "Missing required option: --#{key.to_s.tr("_", "-")}" unless merged_options[key]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def validate_print_options(opts)
|
125
|
+
Bidi2pdf::Bidi::PrintParametersValidator.validate!(opts)
|
126
|
+
rescue ArgumentError => e
|
127
|
+
raise Thor::Error, "Invalid print option: #{e.message}"
|
128
|
+
end
|
129
|
+
|
130
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
131
|
+
def print_options
|
132
|
+
opts = {}
|
133
|
+
|
134
|
+
assign_if_provided(opts, :background)
|
135
|
+
assign_if_provided(opts, :orientation)
|
136
|
+
opts[:pageRanges] = merged_options[:page_ranges] if merged_options[:page_ranges]
|
137
|
+
|
138
|
+
if option_provided?(:scale)
|
139
|
+
scale = merged_options[:scale]
|
140
|
+
raise ArgumentError, "Scale must be between 0.1 and 2.0" unless (0.1..2.0).include?(scale)
|
141
|
+
|
142
|
+
opts[:scale] = scale
|
143
|
+
end
|
144
|
+
|
145
|
+
assign_if_provided(opts, :shrinkToFit, :shrink_to_fit)
|
146
|
+
|
147
|
+
# Margins
|
148
|
+
margin_keys = {
|
149
|
+
top: :margin_top,
|
150
|
+
bottom: :margin_bottom,
|
151
|
+
left: :margin_left,
|
152
|
+
right: :margin_right
|
153
|
+
}
|
154
|
+
margins = {}
|
155
|
+
margin_keys.each do |short, full|
|
156
|
+
assign_if_provided(margins, short, full)
|
157
|
+
end
|
158
|
+
opts[:margin] = margins unless margins.empty?
|
159
|
+
|
160
|
+
# Page size
|
161
|
+
page = {}
|
162
|
+
assign_if_provided(page, :width, :page_width)
|
163
|
+
assign_if_provided(page, :height, :page_height)
|
164
|
+
opts[:page] = page unless page.empty?
|
165
|
+
|
166
|
+
opts.empty? ? nil : opts
|
167
|
+
end
|
168
|
+
|
169
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
170
|
+
|
171
|
+
def option_provided?(key)
|
172
|
+
ARGV.include?("--#{key.to_s.tr("_", "-")}") || ARGV.include?("--#{key}")
|
173
|
+
end
|
174
|
+
|
175
|
+
def assign_if_provided(hash, key, option_key = key)
|
176
|
+
hash[key] = merged_options[option_key] if option_provided?(option_key)
|
177
|
+
end
|
178
|
+
|
57
179
|
def launcher
|
58
180
|
# rubocop:disable Layout/BeginEndAlignment
|
59
181
|
@launcher ||= begin
|
60
|
-
username, password = parse_auth(
|
182
|
+
username, password = parse_auth(merged_options[:auth]) if merged_options[:auth]
|
61
183
|
|
62
184
|
Bidi2pdf::Launcher.new(
|
63
|
-
url:
|
64
|
-
output:
|
65
|
-
cookies: parse_key_values(
|
66
|
-
headers: parse_key_values(
|
185
|
+
url: merged_options[:url],
|
186
|
+
output: merged_options[:output],
|
187
|
+
cookies: parse_key_values(merged_options[:cookie]),
|
188
|
+
headers: parse_key_values(merged_options[:header]),
|
67
189
|
auth: { username: username, password: password },
|
68
|
-
port:
|
69
|
-
|
70
|
-
|
71
|
-
|
190
|
+
port: merged_options[:port],
|
191
|
+
remote_browser_url: merged_options[:remote_browser_url],
|
192
|
+
headless: merged_options[:headless],
|
193
|
+
wait_window_loaded: merged_options[:wait_window_loaded],
|
194
|
+
wait_network_idle: merged_options[:wait_network_idle],
|
195
|
+
print_options: print_options
|
72
196
|
)
|
73
197
|
end
|
74
198
|
# rubocop:enable Layout/BeginEndAlignment
|
@@ -79,7 +203,7 @@ module Bidi2pdf
|
|
79
203
|
def configure
|
80
204
|
Bidi2pdf.configure do |config|
|
81
205
|
config.logger.level = log_level
|
82
|
-
config.default_timeout =
|
206
|
+
config.default_timeout = merged_options[:default_timeout]
|
83
207
|
|
84
208
|
Chromedriver::Binary.configure do |c|
|
85
209
|
c.logger.level = log_level
|
@@ -88,7 +212,7 @@ module Bidi2pdf
|
|
88
212
|
end
|
89
213
|
|
90
214
|
def log_level
|
91
|
-
case
|
215
|
+
case merged_options[:log_level]
|
92
216
|
when "debug" then Logger::DEBUG
|
93
217
|
when "warn" then Logger::WARN
|
94
218
|
when "error" then Logger::ERROR
|
@@ -114,5 +238,10 @@ module Bidi2pdf
|
|
114
238
|
|
115
239
|
[user, pass]
|
116
240
|
end
|
241
|
+
|
242
|
+
def merged_options
|
243
|
+
defaults = load_config || {}
|
244
|
+
Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(options))
|
245
|
+
end
|
117
246
|
end
|
118
247
|
end
|
data/lib/bidi2pdf/launcher.rb
CHANGED
@@ -6,8 +6,9 @@ require_relative "bidi/session"
|
|
6
6
|
|
7
7
|
module Bidi2pdf
|
8
8
|
class Launcher
|
9
|
+
# rubocop:disable Metrics/ParameterLists
|
9
10
|
def initialize(url:, output:, cookies:, headers:, auth:, headless: true, port: 0, wait_window_loaded: false,
|
10
|
-
wait_network_idle: false, print_options: {})
|
11
|
+
wait_network_idle: false, print_options: {}, remote_browser_url: nil)
|
11
12
|
@url = url
|
12
13
|
@port = port
|
13
14
|
@headless = headless
|
@@ -19,14 +20,14 @@ module Bidi2pdf
|
|
19
20
|
@wait_window_loaded = wait_window_loaded
|
20
21
|
@wait_network_idle = wait_network_idle
|
21
22
|
@print_options = print_options || {}
|
23
|
+
@remote_browser_url = remote_browser_url
|
22
24
|
end
|
23
25
|
|
24
|
-
|
25
|
-
@manager = ChromedriverManager.new(port: @port, headless: @headless)
|
26
|
-
@manager.start
|
26
|
+
# rubocop:enable Metrics/ParameterLists
|
27
27
|
|
28
|
+
def launch
|
28
29
|
runner = SessionRunner.new(
|
29
|
-
session:
|
30
|
+
session: session,
|
30
31
|
url: @url,
|
31
32
|
output: @output,
|
32
33
|
cookies: @cookies,
|
@@ -40,7 +41,19 @@ module Bidi2pdf
|
|
40
41
|
end
|
41
42
|
|
42
43
|
def stop
|
43
|
-
@manager
|
44
|
+
@manager&.stop
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def session
|
50
|
+
if @remote_browser_url
|
51
|
+
Bidi::Session.new(session_url: @remote_browser_url, headless: @headless)
|
52
|
+
else
|
53
|
+
@manager = ChromedriverManager.new(port: @port, headless: @headless)
|
54
|
+
@manager.start
|
55
|
+
@manager.session
|
56
|
+
end
|
44
57
|
end
|
45
58
|
end
|
46
59
|
end
|
data/lib/bidi2pdf/version.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Bidi2pdf
|
2
|
+
module Bidi
|
3
|
+
class AddHeadersInterceptor
|
4
|
+
@id: String
|
5
|
+
@client: untyped
|
6
|
+
@headers: Hash[String, String]
|
7
|
+
|
8
|
+
attr_reader id: String
|
9
|
+
attr_reader headers: Hash[String, String]
|
10
|
+
|
11
|
+
def initialize: (String id, Hash[String, String] headers, untyped client) -> void
|
12
|
+
|
13
|
+
def handle_event: (Hash[String, untyped] response) -> (nil | untyped)
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader client: untyped
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Bidi2pdf
|
2
|
+
module Bidi
|
3
|
+
class AuthInterceptor
|
4
|
+
@credentials: Hash[Symbol, String]?
|
5
|
+
|
6
|
+
def initialize: (?credentials: Hash[Symbol, String]?) -> void
|
7
|
+
|
8
|
+
def intercept: (untyped request) -> untyped
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def add_auth_header: (untyped request) -> void
|
13
|
+
|
14
|
+
def auth_header_value: () -> String?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Bidi2pdf
|
2
|
+
module Bidi
|
3
|
+
class Browser
|
4
|
+
@url: String
|
5
|
+
@chromedriver_manager: Bidi2pdf::ChromedriverManager
|
6
|
+
@browser: untyped
|
7
|
+
@timeout: Integer
|
8
|
+
@debug: bool
|
9
|
+
|
10
|
+
attr_reader browser: untyped
|
11
|
+
attr_reader timeout: Integer
|
12
|
+
|
13
|
+
def initialize: (
|
14
|
+
url: String,
|
15
|
+
chromedriver_manager: Bidi2pdf::ChromedriverManager,
|
16
|
+
?timeout: Integer,
|
17
|
+
?debug: bool
|
18
|
+
) -> void
|
19
|
+
|
20
|
+
def navigate: (?reload: bool) -> void
|
21
|
+
|
22
|
+
def current_url: -> String
|
23
|
+
|
24
|
+
def wait_until: [T] (
|
25
|
+
?timeout: Integer,
|
26
|
+
?message: String
|
27
|
+
) { () -> T? } -> T
|
28
|
+
|
29
|
+
def close: () -> void
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def connect: () -> untyped
|
34
|
+
|
35
|
+
def setup_browser: () -> untyped
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Bidi2pdf
|
2
|
+
module Bidi
|
3
|
+
class BrowserTab
|
4
|
+
@browser: Bidi2pdf::Bidi::Browser
|
5
|
+
@tab_id: String?
|
6
|
+
@session_id: String?
|
7
|
+
@timeout: Integer
|
8
|
+
|
9
|
+
attr_reader browser: Bidi2pdf::Bidi::Browser
|
10
|
+
attr_reader tab_id: String?
|
11
|
+
attr_reader session_id: String?
|
12
|
+
|
13
|
+
def initialize: (
|
14
|
+
browser: Bidi2pdf::Bidi::Browser,
|
15
|
+
?tab_id: String?,
|
16
|
+
?timeout: Integer
|
17
|
+
) -> void
|
18
|
+
|
19
|
+
def navigate_to: (String url) -> void
|
20
|
+
|
21
|
+
def execute_script: [T] (String script, *untyped args) -> T
|
22
|
+
|
23
|
+
def wait_for_navigation: (?timeout: Integer) -> void
|
24
|
+
|
25
|
+
def wait_for_element: (
|
26
|
+
selector: String,
|
27
|
+
?visible: bool,
|
28
|
+
?timeout: Integer
|
29
|
+
) -> untyped
|
30
|
+
|
31
|
+
def capture_screenshot: (?path: String?) -> String
|
32
|
+
|
33
|
+
def close: () -> void
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def ensure_tab_active: () -> void
|
38
|
+
|
39
|
+
def connect_to_tab: () -> String?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Bidi2pdf
|
2
|
+
module Bidi
|
3
|
+
class Client
|
4
|
+
@next_id_mutex: Mutex
|
5
|
+
@ws_url: untyped
|
6
|
+
|
7
|
+
@id: untyped
|
8
|
+
|
9
|
+
@pending_responses: Hash[String, Thread::Queue]
|
10
|
+
|
11
|
+
@connected: untyped
|
12
|
+
|
13
|
+
@connection_mutex: Mutex
|
14
|
+
|
15
|
+
@send_cmd_mutex: Mutex
|
16
|
+
|
17
|
+
@connection_cv: untyped
|
18
|
+
|
19
|
+
@started: untyped
|
20
|
+
|
21
|
+
@socket: untyped
|
22
|
+
|
23
|
+
@dispatcher: untyped
|
24
|
+
|
25
|
+
include Bidi2pdf::Utils
|
26
|
+
|
27
|
+
attr_reader ws_url: untyped
|
28
|
+
|
29
|
+
def initialize: (untyped ws_url) -> void
|
30
|
+
|
31
|
+
def start: () -> untyped
|
32
|
+
|
33
|
+
def started?: () -> untyped
|
34
|
+
|
35
|
+
def wait_until_open: (?timeout: untyped) -> untyped
|
36
|
+
|
37
|
+
def send_cmd: (untyped method, ?::Hash[untyped, untyped] params) -> untyped
|
38
|
+
|
39
|
+
# rubocop:disable Metrics/AbcSize
|
40
|
+
def send_cmd_and_wait: (untyped method, ?::Hash[untyped, untyped] params, ?timeout: untyped) ?{ (untyped) -> untyped } -> untyped
|
41
|
+
|
42
|
+
# Event API for external consumers
|
43
|
+
def on_message: () { () -> untyped } -> untyped
|
44
|
+
|
45
|
+
def on_open: () { () -> untyped } -> untyped
|
46
|
+
|
47
|
+
def on_close: () { () -> untyped } -> untyped
|
48
|
+
|
49
|
+
def on_error: () { () -> untyped } -> untyped
|
50
|
+
|
51
|
+
def on_event: (*untyped names) { () -> untyped } -> untyped
|
52
|
+
|
53
|
+
def remove_message_listener: (untyped block) -> untyped
|
54
|
+
|
55
|
+
def remove_event_listener: (*untyped names) { () -> untyped } -> untyped
|
56
|
+
|
57
|
+
def add_headers_interceptor: (context: untyped, url_patterns: untyped, headers: untyped) -> untyped
|
58
|
+
|
59
|
+
def add_auth_interceptor: (context: untyped, url_patterns: untyped, username: untyped, password: untyped) -> untyped
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def next_id: () -> untyped
|
64
|
+
|
65
|
+
def handle_open: () -> untyped
|
66
|
+
|
67
|
+
def handle_response_to_cmd: (untyped data) -> untyped
|
68
|
+
|
69
|
+
def redact_sensitive_fields: (untyped obj, ?::Array[untyped] sensitive_keys) -> untyped
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bidi2pdf
|
2
|
+
module Bidi
|
3
|
+
class EventManager
|
4
|
+
@browser: Bidi2pdf::Bidi::Browser
|
5
|
+
@listeners: Hash[String, Array[Proc]]
|
6
|
+
@active: bool
|
7
|
+
|
8
|
+
def initialize: (browser: Bidi2pdf::Bidi::Browser) -> void
|
9
|
+
|
10
|
+
def on: (String event_name) { (Hash[String, untyped]) -> void } -> void
|
11
|
+
|
12
|
+
def off: (String event_name) -> void
|
13
|
+
|
14
|
+
def emit: (String event_name, Hash[String, untyped] params) -> void
|
15
|
+
|
16
|
+
def start_listening: () -> void
|
17
|
+
|
18
|
+
def stop_listening: () -> void
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def register_browser_events: () -> void
|
23
|
+
|
24
|
+
def handle_event: (String event_name, Hash[String, untyped] params) -> void
|
25
|
+
|
26
|
+
def process_event: (String event_name, Hash[String, untyped] params) -> void
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|