bidi2pdf 0.1.3 → 0.1.5
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 +19 -1
- data/CHANGELOG.md +40 -3
- data/README.md +145 -55
- data/docker/Dockerfile.chromedriver +5 -0
- data/docker/entrypoint.sh +11 -1
- data/lib/bidi2pdf/bidi/add_headers_interceptor.rb +18 -21
- data/lib/bidi2pdf/bidi/auth_interceptor.rb +31 -38
- data/lib/bidi2pdf/bidi/browser_tab.rb +47 -53
- data/lib/bidi2pdf/bidi/client.rb +24 -52
- data/lib/bidi2pdf/bidi/command_manager.rb +50 -28
- data/lib/bidi2pdf/bidi/commands/add_intercept.rb +41 -0
- data/lib/bidi2pdf/bidi/commands/base.rb +73 -0
- data/lib/bidi2pdf/bidi/commands/browser_close.rb +15 -0
- data/lib/bidi2pdf/bidi/commands/browser_create_user_context.rb +15 -0
- data/lib/bidi2pdf/bidi/commands/browsing_context_close.rb +25 -0
- data/lib/bidi2pdf/bidi/commands/browsing_context_navigate.rb +31 -0
- data/lib/bidi2pdf/bidi/commands/browsing_context_print.rb +28 -0
- data/lib/bidi2pdf/bidi/commands/cancel_auth.rb +26 -0
- data/lib/bidi2pdf/bidi/commands/create_tab.rb +11 -0
- data/lib/bidi2pdf/bidi/commands/create_window.rb +32 -0
- data/lib/bidi2pdf/bidi/commands/get_user_contexts.rb +15 -0
- data/lib/bidi2pdf/bidi/commands/network_continue.rb +29 -0
- data/lib/bidi2pdf/bidi/commands/print_parameters_validator.rb +116 -0
- data/lib/bidi2pdf/bidi/commands/provide_credentials.rb +33 -0
- data/lib/bidi2pdf/bidi/commands/script_evaluate.rb +33 -0
- data/lib/bidi2pdf/bidi/commands/session_end.rb +15 -0
- data/lib/bidi2pdf/bidi/commands/session_status.rb +15 -0
- data/lib/bidi2pdf/bidi/commands/session_subscribe.rb +25 -0
- data/lib/bidi2pdf/bidi/commands/set_tab_cookie.rb +71 -0
- data/lib/bidi2pdf/bidi/commands/set_usercontext_cookie.rb +67 -0
- data/lib/bidi2pdf/bidi/commands.rb +27 -0
- data/lib/bidi2pdf/bidi/connection_manager.rb +16 -13
- data/lib/bidi2pdf/bidi/event_manager.rb +2 -0
- data/lib/bidi2pdf/bidi/interceptor.rb +75 -0
- data/lib/bidi2pdf/bidi/network_events.rb +0 -1
- data/lib/bidi2pdf/bidi/session.rb +139 -65
- data/lib/bidi2pdf/bidi/user_context.rb +25 -31
- data/lib/bidi2pdf/bidi/web_socket_dispatcher.rb +2 -0
- data/lib/bidi2pdf/chromedriver_manager.rb +2 -1
- data/lib/bidi2pdf/cli.rb +12 -7
- data/lib/bidi2pdf/dsl.rb +45 -0
- data/lib/bidi2pdf/launcher.rb +6 -2
- data/lib/bidi2pdf/session_runner.rb +9 -2
- data/lib/bidi2pdf/version.rb +1 -1
- data/lib/bidi2pdf.rb +16 -1
- data/sig/bidi2pdf/bidi/command_manager.rbs +41 -0
- data/sig/bidi2pdf/bidi/commands/add_intercept.rbs +21 -0
- data/sig/bidi2pdf/bidi/commands/base.rbs +27 -0
- data/sig/bidi2pdf/bidi/commands/browser_close.rbs +9 -0
- data/sig/bidi2pdf/bidi/commands/browser_create_user_context.rbs +9 -0
- data/sig/bidi2pdf/bidi/commands/browsing_context_close.rbs +11 -0
- data/sig/bidi2pdf/bidi/commands/browsing_context_navigate.rbs +15 -0
- data/sig/bidi2pdf/bidi/commands/browsing_context_print.rbs +14 -0
- data/sig/bidi2pdf/bidi/commands/cancel_auth.rbs +11 -0
- data/sig/bidi2pdf/bidi/commands/create_tab.rbs +9 -0
- data/sig/bidi2pdf/bidi/commands/create_window.rbs +19 -0
- data/sig/bidi2pdf/bidi/commands/get_user_contexts.rbs +9 -0
- data/sig/bidi2pdf/bidi/commands/network_continue.rbs +19 -0
- data/sig/bidi2pdf/bidi/commands/print_parameters_validator.rbs +53 -0
- data/sig/bidi2pdf/bidi/commands/provide_credentials.rbs +15 -0
- data/sig/bidi2pdf/bidi/commands/script_evaluate.rbs +17 -0
- data/sig/bidi2pdf/bidi/commands/session_end.rbs +9 -0
- data/sig/bidi2pdf/bidi/commands/session_status.rbs +9 -0
- data/sig/bidi2pdf/bidi/commands/session_subscribe.rbs +15 -0
- data/sig/bidi2pdf/bidi/commands/set_tab_cookie.rbs +31 -0
- data/sig/bidi2pdf/bidi/commands/set_usercontext_cookie.rbs +27 -0
- data/sig/bidi2pdf/bidi/commands.rbs +6 -0
- data/sig/bidi2pdf/bidi/connection_manager.rbs +17 -0
- data/sig/bidi2pdf/bidi/interceptor.rbs +31 -0
- data/tasks/coverage.rake +16 -0
- metadata +66 -11
- data/lib/bidi2pdf/bidi/print_parameters_validator.rb +0 -114
- data/sig/bidi2pdf/bidi/print_parameters_validator.rbs +0 -44
- data/sig/bidi2pdf/chrome/chromedriver_downloader.rbs +0 -11
- data/sig/bidi2pdf/chrome/downloader_helper.rbs +0 -9
- data/sig/bidi2pdf/chrome/finder.rbs +0 -27
- data/sig/bidi2pdf/chrome/platform.rbs +0 -13
- data/sig/bidi2pdf/chrome/version_resolver.rbs +0 -19
@@ -3,7 +3,8 @@
|
|
3
3
|
require "base64"
|
4
4
|
|
5
5
|
require_relative "network_events"
|
6
|
-
require_relative "
|
6
|
+
require_relative "auth_interceptor"
|
7
|
+
require_relative "add_headers_interceptor"
|
7
8
|
|
8
9
|
module Bidi2pdf
|
9
10
|
module Bidi
|
@@ -20,10 +21,8 @@ module Bidi2pdf
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def create_browser_tab
|
23
|
-
|
24
|
-
|
25
|
-
userContext: @user_context_id
|
26
|
-
}) do |response|
|
24
|
+
cmd = Bidi2pdf::Bidi::Commands::CreateTab.new(user_context_id: user_context_id)
|
25
|
+
client.send_cmd_and_wait(cmd) do |response|
|
27
26
|
tab_browsing_context_id = response["result"]["context"]
|
28
27
|
|
29
28
|
BrowserTab.new(client, tab_browsing_context_id, user_context_id).tap do |tab|
|
@@ -43,26 +42,18 @@ module Bidi2pdf
|
|
43
42
|
same_site: "strict",
|
44
43
|
ttl: 30
|
45
44
|
)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
sameSite: same_site,
|
59
|
-
expiry: expiry
|
60
|
-
},
|
61
|
-
partition: {
|
62
|
-
type: "context",
|
63
|
-
context: browsing_context_id
|
64
|
-
}
|
65
|
-
}) do |response|
|
45
|
+
cmd = Bidi2pdf::Bidi::Commands::SetTabCookie.new(
|
46
|
+
browsing_context_id: browsing_context_id,
|
47
|
+
name: name,
|
48
|
+
value: value,
|
49
|
+
domain: domain,
|
50
|
+
path: path,
|
51
|
+
secure: secure,
|
52
|
+
http_only: http_only,
|
53
|
+
same_site: same_site,
|
54
|
+
ttl: ttl
|
55
|
+
)
|
56
|
+
client.send_cmd_and_wait(cmd) do |response|
|
66
57
|
Bidi2pdf.logger.debug "Cookie set: #{response.inspect}"
|
67
58
|
end
|
68
59
|
end
|
@@ -71,43 +62,42 @@ module Bidi2pdf
|
|
71
62
|
headers:,
|
72
63
|
url_patterns:
|
73
64
|
)
|
74
|
-
|
65
|
+
AddHeadersInterceptor.new(
|
75
66
|
context: browsing_context_id,
|
76
67
|
url_patterns: url_patterns,
|
77
68
|
headers: headers
|
78
|
-
)
|
69
|
+
).tap { |interceptor| interceptor.register_with_client(client: client) }
|
79
70
|
end
|
80
71
|
|
81
72
|
def basic_auth(username:, password:, url_patterns:)
|
82
|
-
|
73
|
+
AuthInterceptor.new(
|
83
74
|
context: browsing_context_id,
|
84
75
|
url_patterns: url_patterns,
|
85
|
-
username: username,
|
86
|
-
|
87
|
-
)
|
76
|
+
username: username, password: password
|
77
|
+
).tap { |interceptor| interceptor.register_with_client(client: client) }
|
88
78
|
end
|
89
79
|
|
90
80
|
def open_page(url)
|
91
81
|
client.on_event("network.responseStarted", "network.responseCompleted", "network.fetchError",
|
92
82
|
&network_events.method(:handle_event))
|
93
83
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
wait: "complete"
|
98
|
-
}) do |response|
|
84
|
+
cmd = Bidi2pdf::Bidi::Commands::BrowsingContextNavigate.new url: url, context: browsing_context_id
|
85
|
+
|
86
|
+
client.send_cmd_and_wait(cmd) do |response|
|
99
87
|
Bidi2pdf.logger.debug "Navigated to page url: #{url} response: #{response}"
|
100
88
|
end
|
101
89
|
end
|
102
90
|
|
91
|
+
def view_html_page(html_content)
|
92
|
+
base64_encoded = Base64.strict_encode64(html_content)
|
93
|
+
data_url = "data:text/html;charset=utf-8;base64,#{base64_encoded}"
|
94
|
+
|
95
|
+
open_page(data_url)
|
96
|
+
end
|
97
|
+
|
103
98
|
def execute_script(script)
|
104
|
-
|
105
|
-
|
106
|
-
target: {
|
107
|
-
context: browsing_context_id
|
108
|
-
},
|
109
|
-
awaitPromise: true
|
110
|
-
}) do |response|
|
99
|
+
cmd = Bidi2pdf::Bidi::Commands::ScriptEvaluate.new context: browsing_context_id, expression: script
|
100
|
+
client.send_cmd_and_wait(cmd) do |response|
|
111
101
|
Bidi2pdf.logger.debug "Script Result: #{response.inspect}"
|
112
102
|
|
113
103
|
response["result"]
|
@@ -128,37 +118,41 @@ module Bidi2pdf
|
|
128
118
|
@open = false
|
129
119
|
end
|
130
120
|
|
131
|
-
# rubocop:disable Metrics/AbcSize
|
132
|
-
def print(outputfile, print_options: { background: true })
|
133
|
-
|
134
|
-
|
135
|
-
cmd_params = (print_options || {}).merge(context: browsing_context_id)
|
121
|
+
# rubocop: disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
122
|
+
def print(outputfile = nil, print_options: { background: true }, &block)
|
123
|
+
cmd = Bidi2pdf::Bidi::Commands::BrowsingContextPrint.new context: browsing_context_id, print_options: print_options
|
136
124
|
|
137
|
-
client.send_cmd_and_wait(
|
125
|
+
client.send_cmd_and_wait(cmd) do |response|
|
138
126
|
if response["result"]
|
139
127
|
pdf_base64 = response["result"]["data"]
|
140
128
|
|
141
129
|
if outputfile
|
130
|
+
raise PrintError, "Folder does not exist: #{File.dirname(outputfile)}" unless File.directory?(File.dirname(outputfile))
|
131
|
+
|
142
132
|
File.binwrite(outputfile, Base64.decode64(pdf_base64))
|
143
133
|
Bidi2pdf.logger.info "PDF saved as '#{outputfile}'."
|
144
134
|
else
|
145
135
|
Bidi2pdf.logger.info "PDF generated successfully."
|
146
136
|
end
|
147
137
|
|
148
|
-
|
138
|
+
block.call(pdf_base64) if block_given?
|
139
|
+
|
140
|
+
return pdf_base64 unless outputfile || block_given?
|
149
141
|
else
|
150
142
|
Bidi2pdf.logger.error "Error printing: #{response}"
|
151
143
|
end
|
152
144
|
end
|
153
145
|
end
|
154
146
|
|
155
|
-
# rubocop:enable Metrics/AbcSize
|
147
|
+
# rubocop: enable Metrics/AbcSize, Metrics/PerceivedComplexity
|
156
148
|
|
157
149
|
private
|
158
150
|
|
159
151
|
def close_context
|
160
|
-
|
161
|
-
|
152
|
+
that = self
|
153
|
+
cmd = Bidi2pdf::Bidi::Commands::BrowsingContextClose.new context: browsing_context_id
|
154
|
+
client.send_cmd_and_wait(cmd) do |response|
|
155
|
+
Bidi2pdf.logger.info "Browsing context closed: #{that.browsing_context_id} #{response}"
|
162
156
|
end
|
163
157
|
end
|
164
158
|
|
data/lib/bidi2pdf/bidi/client.rb
CHANGED
@@ -4,10 +4,9 @@ require "json"
|
|
4
4
|
require "websocket-client-simple"
|
5
5
|
|
6
6
|
require_relative "web_socket_dispatcher"
|
7
|
-
require_relative "add_headers_interceptor"
|
8
|
-
require_relative "auth_interceptor"
|
9
7
|
require_relative "command_manager"
|
10
8
|
require_relative "connection_manager"
|
9
|
+
require_relative "commands"
|
11
10
|
|
12
11
|
module Bidi2pdf
|
13
12
|
module Bidi
|
@@ -19,20 +18,21 @@ module Bidi2pdf
|
|
19
18
|
def initialize(ws_url)
|
20
19
|
@ws_url = ws_url
|
21
20
|
@started = false
|
21
|
+
@connection_manager = ConnectionManager.new(logger: Bidi2pdf.logger)
|
22
22
|
end
|
23
23
|
|
24
24
|
def start
|
25
25
|
return @socket if started?
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@command_manager = CommandManager.new(@socket, logger: Bidi2pdf.logger)
|
27
|
+
WebSocket::Client::Simple.connect(ws_url) do |socket|
|
28
|
+
@socket = socket
|
29
|
+
@command_manager = CommandManager.new(@socket, logger: Bidi2pdf.logger)
|
31
30
|
|
32
|
-
|
33
|
-
|
31
|
+
dispatcher.on_open { @connection_manager.mark_connected }
|
32
|
+
dispatcher.on_message { |data| handle_response_to_cmd(data) }
|
33
|
+
dispatcher.start_listening
|
34
|
+
end
|
34
35
|
|
35
|
-
dispatcher.start_listening
|
36
36
|
@started = true
|
37
37
|
|
38
38
|
@socket
|
@@ -42,15 +42,23 @@ module Bidi2pdf
|
|
42
42
|
|
43
43
|
def wait_until_open(timeout: Bidi2pdf.default_timeout)
|
44
44
|
@connection_manager.wait_until_open(timeout: timeout)
|
45
|
+
rescue Bidi2pdf::WebsocketError => e
|
46
|
+
raise Bidi2pdf::WebsocketError, "Client#start must be called within #{timeout} sec." unless started?
|
47
|
+
|
48
|
+
raise e
|
45
49
|
end
|
46
50
|
|
47
|
-
def send_cmd(
|
48
|
-
|
51
|
+
def send_cmd(cmd)
|
52
|
+
raise Bidi2pdf::ClientError, "Client#start must be called before" unless started?
|
53
|
+
|
54
|
+
@command_manager.send_cmd(cmd)
|
49
55
|
end
|
50
56
|
|
51
|
-
def send_cmd_and_wait(
|
52
|
-
|
53
|
-
|
57
|
+
def send_cmd_and_wait(cmd, timeout: Bidi2pdf.default_timeout, &block)
|
58
|
+
raise Bidi2pdf::ClientError, "Client#start must be called before" unless started?
|
59
|
+
|
60
|
+
timed("Command #{cmd.inspect}") do
|
61
|
+
@command_manager.send_cmd_and_wait(cmd, timeout: timeout, &block)
|
54
62
|
end
|
55
63
|
end
|
56
64
|
|
@@ -64,7 +72,8 @@ module Bidi2pdf
|
|
64
72
|
|
65
73
|
def on_event(*names, &block)
|
66
74
|
names.each { |name| dispatcher.on_event(name, &block) }
|
67
|
-
|
75
|
+
cmd = Bidi2pdf::Bidi::Commands::SessionSubscribe.new(events: names)
|
76
|
+
send_cmd(cmd) if names.any?
|
68
77
|
end
|
69
78
|
|
70
79
|
def remove_message_listener(block) = dispatcher.remove_message_listener(block)
|
@@ -73,28 +82,6 @@ module Bidi2pdf
|
|
73
82
|
names.each { |event_name| dispatcher.remove_event_listener(event_name, block) }
|
74
83
|
end
|
75
84
|
|
76
|
-
def add_headers_interceptor(context:, url_patterns:, headers:)
|
77
|
-
add_interceptor(
|
78
|
-
context: context,
|
79
|
-
url_patterns: url_patterns,
|
80
|
-
phase: "beforeRequestSent",
|
81
|
-
event: "network.beforeRequestSent",
|
82
|
-
interceptor_class: AddHeadersInterceptor,
|
83
|
-
extra_args: { headers: headers }
|
84
|
-
)
|
85
|
-
end
|
86
|
-
|
87
|
-
def add_auth_interceptor(context:, url_patterns:, username:, password:)
|
88
|
-
add_interceptor(
|
89
|
-
context: context,
|
90
|
-
url_patterns: url_patterns,
|
91
|
-
phase: "authRequired",
|
92
|
-
event: "network.authRequired",
|
93
|
-
interceptor_class: AuthInterceptor,
|
94
|
-
extra_args: { username: username, password: password }
|
95
|
-
)
|
96
|
-
end
|
97
|
-
|
98
85
|
def close
|
99
86
|
return unless @socket
|
100
87
|
|
@@ -120,21 +107,6 @@ module Bidi2pdf
|
|
120
107
|
Bidi2pdf.logger.warn "Unknown response: #{data.inspect}"
|
121
108
|
end
|
122
109
|
end
|
123
|
-
|
124
|
-
def add_interceptor(context:, url_patterns:, phase:, event:, interceptor_class:, extra_args: {})
|
125
|
-
send_cmd_and_wait("network.addIntercept", {
|
126
|
-
context: context,
|
127
|
-
phases: [phase],
|
128
|
-
urlPatterns: url_patterns
|
129
|
-
}) do |response|
|
130
|
-
id = response["result"]["intercept"]
|
131
|
-
Bidi2pdf.logger.debug "Interceptor added: #{id}"
|
132
|
-
|
133
|
-
interceptor_class.new(id, **extra_args, client: self).tap do |interceptor|
|
134
|
-
on_event(event, &interceptor.method(:handle_event))
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
110
|
end
|
139
111
|
end
|
140
112
|
end
|
@@ -3,18 +3,35 @@
|
|
3
3
|
module Bidi2pdf
|
4
4
|
module Bidi
|
5
5
|
class CommandManager
|
6
|
+
class << self
|
7
|
+
def initialize_counter
|
8
|
+
@id = 0
|
9
|
+
@id_mutex = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def next_id = @id_mutex.synchronize { @id += 1 }
|
13
|
+
end
|
14
|
+
|
15
|
+
initialize_counter
|
16
|
+
|
6
17
|
def initialize(socket, logger:)
|
7
18
|
@socket = socket
|
8
19
|
@logger = logger
|
9
20
|
|
10
|
-
@id = 0
|
11
|
-
@next_id_mutex = Mutex.new
|
12
21
|
@pending_responses = {}
|
22
|
+
@initiated_cmds = {}
|
13
23
|
end
|
14
24
|
|
15
|
-
def send_cmd(
|
25
|
+
def send_cmd(cmd, store_response: false)
|
16
26
|
id = next_id
|
17
|
-
|
27
|
+
|
28
|
+
if store_response
|
29
|
+
init_queue_for id
|
30
|
+
else
|
31
|
+
@initiated_cmds[id] = true
|
32
|
+
end
|
33
|
+
|
34
|
+
payload = cmd.as_payload(id)
|
18
35
|
|
19
36
|
@logger.debug "Sending command: #{redact_sensitive_fields(payload).inspect}"
|
20
37
|
@socket.send(payload.to_json)
|
@@ -22,40 +39,46 @@ module Bidi2pdf
|
|
22
39
|
id
|
23
40
|
end
|
24
41
|
|
25
|
-
def send_cmd_and_wait(
|
26
|
-
id = send_cmd(
|
27
|
-
|
42
|
+
def send_cmd_and_wait(cmd, timeout: Bidi2pdf.default_timeout)
|
43
|
+
id = send_cmd(cmd, store_response: true)
|
44
|
+
response = pop_response id, timeout: timeout
|
28
45
|
|
29
|
-
|
30
|
-
|
31
|
-
raise "Error response: #{response["error"]}" if response["error"]
|
46
|
+
raise_timeout_error(id, cmd) if response.nil?
|
47
|
+
raise CmdError, "Error response: #{response["error"]} #{cmd.inspect}" if response["error"]
|
32
48
|
|
33
49
|
block_given? ? yield(response) : response
|
34
50
|
ensure
|
35
51
|
@pending_responses.delete(id)
|
36
52
|
end
|
37
53
|
|
38
|
-
def
|
39
|
-
@pending_responses
|
54
|
+
def pop_response(id, timeout:)
|
55
|
+
raise CmdResponseNotStoredError, "No response stored for command ID #{id} or already popped or this command was not send" unless @pending_responses.key?(id)
|
56
|
+
|
57
|
+
@pending_responses[id].pop(timeout: timeout)
|
58
|
+
ensure
|
59
|
+
@pending_responses.delete(id)
|
40
60
|
end
|
41
61
|
|
42
62
|
def handle_response(data)
|
43
|
-
if (id = data["id"])
|
44
|
-
@pending_responses
|
45
|
-
|
46
|
-
|
63
|
+
if (id = data["id"])
|
64
|
+
if @pending_responses.key?(id)
|
65
|
+
@pending_responses[id]&.push(data)
|
66
|
+
return true
|
67
|
+
elsif @initiated_cmds.key?(id)
|
68
|
+
@logger.error "Received error: #{data["error"]} for cmd: #{id}" if data["error"]
|
69
|
+
|
70
|
+
return @initiated_cmds.delete(id)
|
71
|
+
end
|
47
72
|
end
|
73
|
+
|
74
|
+
false
|
48
75
|
end
|
49
76
|
|
50
77
|
private
|
51
78
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
@pending_responses[@id] = Thread::Queue.new
|
56
|
-
@id
|
57
|
-
end
|
58
|
-
end
|
79
|
+
def init_queue_for(id) = @pending_responses[id] = Thread::Queue.new
|
80
|
+
|
81
|
+
def next_id = self.class.next_id
|
59
82
|
|
60
83
|
def redact_sensitive_fields(obj, sensitive_keys = %w[value token password authorization username])
|
61
84
|
case obj
|
@@ -71,11 +94,10 @@ module Bidi2pdf
|
|
71
94
|
end
|
72
95
|
end
|
73
96
|
|
74
|
-
def raise_timeout_error(id,
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
raise "Timeout waiting for response to command ID #{id}"
|
97
|
+
def raise_timeout_error(id, cmd)
|
98
|
+
@logger.error "Timeout waiting for response to command #{id}, cmd: #{cmd.inspect}"
|
99
|
+
|
100
|
+
raise CmdTimeoutError, "Timeout waiting for response to command ID #{id}"
|
79
101
|
end
|
80
102
|
end
|
81
103
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdf
|
4
|
+
module Bidi
|
5
|
+
module Commands
|
6
|
+
class AddIntercept
|
7
|
+
include Base
|
8
|
+
|
9
|
+
BEFORE_REQUEST = "beforeRequestSent"
|
10
|
+
RESPONSE_STARTED = "responseStarted"
|
11
|
+
AUTH_REQUIRED = "authRequired"
|
12
|
+
|
13
|
+
def initialize(context:, phases:, url_patterns:)
|
14
|
+
@context = context
|
15
|
+
@phases = phases
|
16
|
+
@url_patterns = url_patterns
|
17
|
+
|
18
|
+
validate_phases!
|
19
|
+
end
|
20
|
+
|
21
|
+
def method_name
|
22
|
+
"network.addIntercept"
|
23
|
+
end
|
24
|
+
|
25
|
+
def params
|
26
|
+
{
|
27
|
+
context: @context,
|
28
|
+
phases: @phases,
|
29
|
+
urlPatterns: @url_patterns
|
30
|
+
}.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_phases!
|
34
|
+
valid_phases = [BEFORE_REQUEST, RESPONSE_STARTED, AUTH_REQUIRED]
|
35
|
+
|
36
|
+
raise ArgumentError, "Unsupported phase(s): #{@phases}" unless @phases.all? { |phase| valid_phases.include?(phase) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdf
|
4
|
+
module Bidi
|
5
|
+
module Commands
|
6
|
+
module Base
|
7
|
+
def method_name = raise(NotImplementedError, "method_name must be implemented in subclass")
|
8
|
+
|
9
|
+
def params = {}
|
10
|
+
|
11
|
+
def as_payload(id)
|
12
|
+
{
|
13
|
+
id: id,
|
14
|
+
method: method_name,
|
15
|
+
params: params
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# rubocop: disable Metrics/AbcSize
|
20
|
+
def ==(other)
|
21
|
+
return false unless other.respond_to?(:method_name) && other.respond_to?(:params)
|
22
|
+
|
23
|
+
return false unless method_name == other.method_name
|
24
|
+
|
25
|
+
return false unless params.keys.sort == other.params.keys.sort
|
26
|
+
|
27
|
+
params.all? { |key, value| other.params.key?(key) && value == other.params[key] }
|
28
|
+
end
|
29
|
+
|
30
|
+
# rubocop: enable Metrics/AbcSize
|
31
|
+
|
32
|
+
# Hash equality comparison
|
33
|
+
def eql?(other)
|
34
|
+
return false unless other.is_a?(Bidi2pdf::Bidi::Commands::Base)
|
35
|
+
|
36
|
+
self == other
|
37
|
+
end
|
38
|
+
|
39
|
+
def hash
|
40
|
+
[method_name, params].hash
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
attributes = redact_sensitive_fields({ method_name: method_name, params: params })
|
45
|
+
|
46
|
+
"#<#{self.class}:#{object_id} #{attributes}>"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def redact_sensitive_fields(obj, sensitive_keys = %w[value token password authorization username])
|
52
|
+
case obj
|
53
|
+
when Hash
|
54
|
+
obj.transform_values.with_index do |v, idx|
|
55
|
+
k = obj.keys[idx]
|
56
|
+
sensitive_keys.include?(k.to_s.downcase) ? "[REDACTED]" : redact_sensitive_fields(v, sensitive_keys)
|
57
|
+
end
|
58
|
+
when Array
|
59
|
+
obj.map { |item| redact_sensitive_fields(item, sensitive_keys) }
|
60
|
+
else
|
61
|
+
obj
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def raise_timeout_error(id, method, params)
|
66
|
+
@logger.error "Timeout waiting for response to command #{id}, cmd: #{method}, params: #{redact_sensitive_fields(params).inspect}"
|
67
|
+
|
68
|
+
raise CmdTimeoutError, "Timeout waiting for response to command ID #{id}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdf
|
4
|
+
module Bidi
|
5
|
+
module Commands
|
6
|
+
class BrowsingContextClose
|
7
|
+
include Base
|
8
|
+
|
9
|
+
def initialize(context:)
|
10
|
+
@context = context
|
11
|
+
end
|
12
|
+
|
13
|
+
def params
|
14
|
+
{
|
15
|
+
context: @context
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_name
|
20
|
+
"browsingContext.close"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdf
|
4
|
+
module Bidi
|
5
|
+
module Commands
|
6
|
+
class BrowsingContextNavigate
|
7
|
+
include Base
|
8
|
+
|
9
|
+
def initialize(url:,
|
10
|
+
context:,
|
11
|
+
wait: "complete")
|
12
|
+
@url = url
|
13
|
+
@context = context
|
14
|
+
@wait = wait
|
15
|
+
end
|
16
|
+
|
17
|
+
def params
|
18
|
+
{
|
19
|
+
url: @url,
|
20
|
+
context: @context,
|
21
|
+
wait: @wait
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_name
|
26
|
+
"browsingContext.navigate"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "print_parameters_validator"
|
4
|
+
|
5
|
+
module Bidi2pdf
|
6
|
+
module Bidi
|
7
|
+
module Commands
|
8
|
+
class BrowsingContextPrint
|
9
|
+
include Base
|
10
|
+
|
11
|
+
def initialize(context:, print_options:)
|
12
|
+
@context = context
|
13
|
+
@print_options = print_options || { background: true }
|
14
|
+
|
15
|
+
PrintParametersValidator.validate!(@print_options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def params
|
19
|
+
@print_options.merge(context: @context)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_name
|
23
|
+
"browsingContext.print"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bidi2pdf
|
4
|
+
module Bidi
|
5
|
+
module Commands
|
6
|
+
class CancelAuth
|
7
|
+
include Base
|
8
|
+
|
9
|
+
def initialize(request:)
|
10
|
+
@request = request
|
11
|
+
end
|
12
|
+
|
13
|
+
def params
|
14
|
+
{
|
15
|
+
request: @request,
|
16
|
+
action: "cancel"
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_name
|
21
|
+
"network.continueWithAuth"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|