bidi2pdf 0.1.2 → 0.1.4

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +29 -1
  3. data/CHANGELOG.md +36 -0
  4. data/cliff.toml +50 -26
  5. data/docker/Dockerfile.chromedriver +5 -0
  6. data/docker/entrypoint.sh +11 -1
  7. data/docker/nginx/default.conf +6 -0
  8. data/lib/bidi2pdf/bidi/add_headers_interceptor.rb +18 -21
  9. data/lib/bidi2pdf/bidi/auth_interceptor.rb +31 -38
  10. data/lib/bidi2pdf/bidi/browser_tab.rb +32 -52
  11. data/lib/bidi2pdf/bidi/client.rb +30 -57
  12. data/lib/bidi2pdf/bidi/command_manager.rb +50 -28
  13. data/lib/bidi2pdf/bidi/commands/add_intercept.rb +41 -0
  14. data/lib/bidi2pdf/bidi/commands/base.rb +73 -0
  15. data/lib/bidi2pdf/bidi/commands/browser_close.rb +15 -0
  16. data/lib/bidi2pdf/bidi/commands/browser_create_user_context.rb +15 -0
  17. data/lib/bidi2pdf/bidi/commands/browsing_context_close.rb +25 -0
  18. data/lib/bidi2pdf/bidi/commands/browsing_context_navigate.rb +31 -0
  19. data/lib/bidi2pdf/bidi/commands/browsing_context_print.rb +28 -0
  20. data/lib/bidi2pdf/bidi/commands/cancel_auth.rb +26 -0
  21. data/lib/bidi2pdf/bidi/commands/create_tab.rb +11 -0
  22. data/lib/bidi2pdf/bidi/commands/create_window.rb +32 -0
  23. data/lib/bidi2pdf/bidi/commands/get_user_contexts.rb +15 -0
  24. data/lib/bidi2pdf/bidi/commands/network_continue.rb +29 -0
  25. data/lib/bidi2pdf/bidi/commands/print_parameters_validator.rb +116 -0
  26. data/lib/bidi2pdf/bidi/commands/provide_credentials.rb +33 -0
  27. data/lib/bidi2pdf/bidi/commands/script_evaluate.rb +33 -0
  28. data/lib/bidi2pdf/bidi/commands/session_end.rb +15 -0
  29. data/lib/bidi2pdf/bidi/commands/session_status.rb +15 -0
  30. data/lib/bidi2pdf/bidi/commands/session_subscribe.rb +25 -0
  31. data/lib/bidi2pdf/bidi/commands/set_tab_cookie.rb +63 -0
  32. data/lib/bidi2pdf/bidi/commands/set_usercontext_cookie.rb +67 -0
  33. data/lib/bidi2pdf/bidi/commands.rb +27 -0
  34. data/lib/bidi2pdf/bidi/connection_manager.rb +16 -13
  35. data/lib/bidi2pdf/bidi/event_manager.rb +2 -0
  36. data/lib/bidi2pdf/bidi/interceptor.rb +75 -0
  37. data/lib/bidi2pdf/bidi/network_events.rb +0 -1
  38. data/lib/bidi2pdf/bidi/session.rb +141 -76
  39. data/lib/bidi2pdf/bidi/user_context.rb +25 -31
  40. data/lib/bidi2pdf/bidi/web_socket_dispatcher.rb +2 -0
  41. data/lib/bidi2pdf/chromedriver_manager.rb +23 -13
  42. data/lib/bidi2pdf/cli.rb +1 -3
  43. data/lib/bidi2pdf/launcher.rb +3 -1
  44. data/lib/bidi2pdf/version.rb +1 -1
  45. data/lib/bidi2pdf.rb +12 -0
  46. data/sig/bidi2pdf/bidi/command_manager.rbs +41 -0
  47. data/sig/bidi2pdf/bidi/commands/add_intercept.rbs +21 -0
  48. data/sig/bidi2pdf/bidi/commands/base.rbs +27 -0
  49. data/sig/bidi2pdf/bidi/commands/browser_close.rbs +9 -0
  50. data/sig/bidi2pdf/bidi/commands/browser_create_user_context.rbs +9 -0
  51. data/sig/bidi2pdf/bidi/commands/browsing_context_close.rbs +11 -0
  52. data/sig/bidi2pdf/bidi/commands/browsing_context_navigate.rbs +15 -0
  53. data/sig/bidi2pdf/bidi/commands/browsing_context_print.rbs +14 -0
  54. data/sig/bidi2pdf/bidi/commands/cancel_auth.rbs +11 -0
  55. data/sig/bidi2pdf/bidi/commands/create_tab.rbs +9 -0
  56. data/sig/bidi2pdf/bidi/commands/create_window.rbs +19 -0
  57. data/sig/bidi2pdf/bidi/commands/get_user_contexts.rbs +9 -0
  58. data/sig/bidi2pdf/bidi/commands/network_continue.rbs +19 -0
  59. data/sig/bidi2pdf/bidi/commands/print_parameters_validator.rbs +53 -0
  60. data/sig/bidi2pdf/bidi/commands/provide_credentials.rbs +15 -0
  61. data/sig/bidi2pdf/bidi/commands/script_evaluate.rbs +17 -0
  62. data/sig/bidi2pdf/bidi/commands/session_end.rbs +9 -0
  63. data/sig/bidi2pdf/bidi/commands/session_status.rbs +9 -0
  64. data/sig/bidi2pdf/bidi/commands/session_subscribe.rbs +15 -0
  65. data/sig/bidi2pdf/bidi/commands/set_tab_cookie.rbs +31 -0
  66. data/sig/bidi2pdf/bidi/commands/set_usercontext_cookie.rbs +27 -0
  67. data/sig/bidi2pdf/bidi/commands.rbs +6 -0
  68. data/sig/bidi2pdf/bidi/connection_manager.rbs +17 -0
  69. data/sig/bidi2pdf/bidi/interceptor.rbs +31 -0
  70. data/tasks/coverage.rake +16 -0
  71. metadata +65 -11
  72. data/lib/bidi2pdf/bidi/print_parameters_validator.rb +0 -114
  73. data/sig/bidi2pdf/bidi/print_parameters_validator.rbs +0 -44
  74. data/sig/bidi2pdf/chrome/chromedriver_downloader.rbs +0 -11
  75. data/sig/bidi2pdf/chrome/downloader_helper.rbs +0 -9
  76. data/sig/bidi2pdf/chrome/finder.rbs +0 -27
  77. data/sig/bidi2pdf/chrome/platform.rbs +0 -13
  78. data/sig/bidi2pdf/chrome/version_resolver.rbs +0 -19
@@ -10,143 +10,208 @@ require_relative "user_context"
10
10
  module Bidi2pdf
11
11
  module Bidi
12
12
  class Session
13
- SUBSCRIBE_EVENTS = [
14
- "browsingContext",
15
- "network",
16
- "log",
17
- "script",
18
- "goog:cdp.Debugger.scriptParsed",
19
- "goog:cdp.CSS.styleSheetAdded",
20
- "goog:cdp.Runtime.executionContextsCleared",
21
- # Tracing
22
- "goog:cdp.Tracing.tracingComplete",
23
- "goog:cdp.Network.requestWillBeSent",
24
- "goog:cdp.Debugger.scriptParsed",
25
- "goog:cdp.Page.screencastFrame"
26
- ].freeze
27
-
28
- attr_reader :session_uri, :started
29
-
30
- def initialize(session_url:, headless: true)
13
+ SUBSCRIBE_EVENTS = %w[log script].freeze
14
+ DEFAULT_CHROME_ARGS = %w[--disable-gpu --disable-popup-blocking --disable-hang-monitor].freeze
15
+
16
+ attr_reader :session_uri, :started, :chrome_args
17
+
18
+ def initialize(session_url:, headless: true, chrome_args: DEFAULT_CHROME_ARGS)
31
19
  @session_uri = URI(session_url)
32
20
  @headless = headless
33
- @client = nil
34
- @browser = nil
35
- @websocket_url = nil
36
21
  @started = false
22
+ @chrome_args = chrome_args.dup
37
23
  end
38
24
 
39
25
  def start
26
+ return if started?
27
+
40
28
  @started = true
41
29
  client
30
+ rescue StandardError => e
31
+ @started = false
32
+ raise e
42
33
  end
43
34
 
44
35
  def client
45
- @client ||= @started ? create_client : nil
46
- end
47
-
48
- def close
49
- client&.send_cmd_and_wait("session.end", {}) do |response|
50
- Bidi2pdf.logger.debug "Session ended: #{response}"
51
- @client = nil
52
- @websocket_url = nil
53
- @browser = nil
54
- end
36
+ @client ||= started? ? create_client : nil
55
37
  end
56
38
 
57
39
  def browser
58
40
  @browser ||= create_browser
59
41
  end
60
42
 
61
- def user_contexts
62
- client&.send_cmd_and_wait("browser.getUserContexts", {}) do |response|
63
- Bidi2pdf.logger.debug "User contexts: #{response}"
43
+ def close
44
+ return unless started?
45
+
46
+ 2.times do |attempt|
47
+ client&.send_cmd_and_wait(Bidi2pdf::Bidi::Commands::SessionEnd.new, timeout: 1) do |response|
48
+ Bidi2pdf.logger.info "Session ended: #{response}"
49
+
50
+ cleanup
51
+ end
52
+ break
53
+ rescue CmdTimeoutError
54
+ Bidi2pdf.logger.error "Session end command timed out. Retrying... (#{attempt + 1})"
64
55
  end
65
56
  end
66
57
 
58
+ def user_contexts
59
+ send_cmd(Bidi2pdf::Bidi::Commands::GetUserContexts.new) { |resp| Bidi2pdf.logger.debug "User contexts: #{resp}" }
60
+ end
61
+
67
62
  def status
68
- client&.send_cmd_and_wait("session.status", {}) do |response|
69
- Bidi2pdf.logger.info "Session status: #{response.inspect}"
70
- end
63
+ send_cmd(Bidi2pdf::Bidi::Commands::SessionStatus.new) { |resp| Bidi2pdf.logger.info "Session status: #{resp.inspect}" }
64
+ end
65
+
66
+ def started?
67
+ @started
68
+ end
69
+
70
+ def websocket_url
71
+ return @websocket_url if @websocket_url
72
+
73
+ @websocket_url = if %w[ws wss].include?(session_uri.scheme)
74
+ session_uri.to_s
75
+ else
76
+ create_new_session
77
+ end
71
78
  end
72
79
 
73
80
  private
74
81
 
82
+ def send_cmd(command, &block)
83
+ client&.send_cmd_and_wait(command, &block)
84
+ end
85
+
86
+ # rubocop: disable Metrics/AbcSize
75
87
  def create_browser
76
88
  start
77
-
78
- @client.start
79
- @client.wait_until_open
89
+ client.start
90
+ client.wait_until_open
80
91
 
81
92
  Bidi2pdf.logger.info "Subscribing to events"
82
93
 
83
- event_client = Bidi::Client.new(websocket_url).tap(&:start)
84
- event_client.wait_until_open
94
+ Bidi::Client.new(websocket_url).tap do |event_client|
95
+ event_client.start
96
+ event_client.wait_until_open
85
97
 
86
- event_client.on_event(*SUBSCRIBE_EVENTS) do |data|
87
- Bidi2pdf.logger.debug "Received event: #{data["method"]}, params: #{data["params"]}"
98
+ event_client.on_event(*SUBSCRIBE_EVENTS) do |data|
99
+ Bidi2pdf.logger.debug "Received event: #{data["method"]}, params: #{data["params"]}"
100
+ end
88
101
  end
89
102
 
90
- Bidi::Browser.new(@client)
103
+ Bidi::Browser.new(client)
91
104
  end
92
105
 
106
+ # rubocop: enable Metrics/AbcSize
107
+
93
108
  def create_client
94
109
  Bidi::Client.new(websocket_url).tap(&:start)
95
110
  end
96
111
 
97
- # rubocop:disable Metrics/AbcSize
98
- def websocket_url
99
- return @websocket_url if @websocket_url
112
+ def create_new_session
113
+ session_data = exec_api_call(session_request)
114
+ Bidi2pdf.logger.debug "Session data: #{session_data}"
100
115
 
101
- if %w[ws wss].include?(session_uri.scheme)
102
- @websocket_url = session_uri.to_s
103
- return @websocket_url
104
- end
116
+ value = session_data["value"]
117
+ handle_error(value) if value.nil? || value["error"]
105
118
 
106
- args = %w[
107
- --disable-gpu
108
- --disable-popup-blocking
109
- --disable-hang-monitor
110
- ]
119
+ session_id = value["sessionId"]
120
+ ws_url = value["capabilities"]["webSocketUrl"]
111
121
 
112
- args << "--headless" if @headless
122
+ Bidi2pdf.logger.info "Created session with ID: #{session_id}"
123
+ Bidi2pdf.logger.info "WebSocket URL: #{ws_url}"
124
+ ws_url
125
+ end
113
126
 
114
- session_request = {
127
+ def session_request
128
+ session_chrome_args = chrome_args.dup
129
+ session_chrome_args << "--headless" if @headless
130
+
131
+ {
115
132
  "capabilities" => {
116
133
  "alwaysMatch" => {
117
134
  "browserName" => "chrome",
118
- "goog:chromeOptions" => {
119
- "args" => args
120
- },
135
+ "goog:chromeOptions" => { "args" => session_chrome_args },
121
136
  "goog:prerenderingDisabled" => true,
122
- "unhandledPromptBehavior" => {
123
- default: "ignore"
124
- },
137
+ "unhandledPromptBehavior" => { default: "ignore" },
125
138
  "acceptInsecureCerts" => true,
126
139
  "webSocketUrl" => true
127
140
  }
128
141
  }
129
142
  }
143
+ end
130
144
 
131
- response = Net::HTTP.post(session_uri, session_request.to_json, "Content-Type" => "application/json")
145
+ def exec_api_call(payload)
146
+ response = Net::HTTP.post(session_uri, payload.to_json, "Content-Type" => "application/json")
147
+ body = response.body
148
+ code = response.code.to_i
132
149
 
133
- Bidi2pdf.logger.debug "Response code: #{response.code}"
134
- Bidi2pdf.logger.debug "Response body: #{response.body}"
150
+ if code != 200
151
+ log_api_error("Failed to create session", code, body)
152
+ return build_error("Session creation failed", "Response code: #{code}")
153
+ end
135
154
 
136
- session_data = JSON.parse(response.body)
155
+ JSON.parse(body)
156
+ rescue StandardError => e
157
+ error_type = error_category(e)
158
+ build_error(error_type, "#{error_description(error_type)} #{e.message}", e.backtrace)
159
+ end
137
160
 
138
- Bidi2pdf.logger.debug "Session data: #{session_data}"
161
+ def log_api_error(message, code, body)
162
+ Bidi2pdf.logger.error "#{message}. Response code: #{code}"
163
+ Bidi2pdf.logger.error "Response body: #{body}"
164
+ end
139
165
 
140
- session_id = session_data["value"]["sessionId"]
141
- @websocket_url = session_data["value"]["capabilities"]["webSocketUrl"]
166
+ def error_category(exception)
167
+ case exception
168
+ when Errno::ECONNREFUSED then "Connection refused"
169
+ when JSON::ParserError then "Invalid JSON response"
170
+ else "Unknown error"
171
+ end
172
+ end
142
173
 
143
- Bidi2pdf.logger.info "Created session with ID: #{session_id}"
144
- Bidi2pdf.logger.info "WebSocket URL: #{@websocket_url}"
174
+ def error_description(type)
175
+ {
176
+ "Connection refused" => "Could not connect to the session URL:",
177
+ "Invalid JSON response" => "Could not parse the response:",
178
+ "Unknown error" => "An unknown error occurred:"
179
+ }[type]
180
+ end
145
181
 
146
- @websocket_url
182
+ def build_error(error, message, backtrace = nil)
183
+ {
184
+ "value" => {
185
+ "error" => error,
186
+ "message" => message,
187
+ "stacktrace" => backtrace&.join("\n")
188
+ }.compact
189
+ }
147
190
  end
148
191
 
149
- # rubocop:enable Metrics/AbcSize
192
+ def handle_error(value)
193
+ error = value["error"]
194
+ return unless error
195
+
196
+ msg = value["message"]
197
+ trace = value["stacktrace"]
198
+
199
+ Bidi2pdf.logger.error "Error: #{error} message: #{msg}"
200
+ Bidi2pdf.logger.error "Stacktrace: #{trace}" if trace
201
+
202
+ if msg =~ /probably user data directory is already in use/
203
+ Bidi2pdf.logger.info "Container detected with headless-only support, ensure xvfb is started" unless @headless
204
+ Bidi2pdf.logger.info "Check chromedriver permissions and --user-data-dir"
205
+ end
206
+
207
+ raise SessionNotStartedError,
208
+ "Session not started. Check logs for more details. Error: #{error} message: #{msg}"
209
+ end
210
+
211
+ def cleanup
212
+ @client&.close
213
+ @client = @websocket_url = @browser = nil
214
+ end
150
215
  end
151
216
  end
152
217
  end
@@ -14,14 +14,16 @@ module Bidi2pdf
14
14
 
15
15
  def context_id
16
16
  @context_id ||= begin
17
- res = client.send_cmd_and_wait("browser.createUserContext", {}) do |response|
18
- response["result"]["userContext"]
19
- end
17
+ res = client.send_cmd_and_wait(Bidi2pdf::Bidi::Commands::BrowserCreateUserContext.new) do |response|
18
+ raise "Error creating user context: #{response.inspect}" if response["error"]
20
19
 
21
- Bidi2pdf.logger.debug "User context created: #{res.inspect}"
20
+ response["result"]["userContext"]
21
+ end
22
22
 
23
- res
24
- end
23
+ Bidi2pdf.logger.debug "User context created: #{res.inspect}"
24
+
25
+ res
26
+ end
25
27
  end
26
28
 
27
29
  def set_cookie(
@@ -35,36 +37,28 @@ module Bidi2pdf
35
37
  same_site: "strict",
36
38
  ttl: 30
37
39
  )
38
- expiry = Time.now.to_i + ttl
39
- client.send_cmd_and_wait("storage.setCookie", {
40
- cookie: {
41
- name: name,
42
- value: {
43
- type: "string",
44
- value: value
45
- },
46
- domain: domain,
47
- path: path,
48
- secure: secure,
49
- httpOnly: http_only,
50
- sameSite: same_site,
51
- expiry: expiry
52
- },
53
- partition: {
54
- type: "storageKey",
55
- userContext: context_id,
56
- sourceOrigin: source_origin
57
- }
58
- }) do |response|
40
+ cmd = Bidi2pdf::Bidi::Commands::SetUsercontextCookie.new(
41
+ user_context_id: context_id,
42
+ source_origin: source_origin,
43
+ name: name,
44
+ value: value,
45
+ domain: domain,
46
+ path: path,
47
+ secure: secure,
48
+ http_only: http_only,
49
+ same_site: same_site,
50
+ ttl: ttl
51
+ )
52
+
53
+ client.send_cmd_and_wait(cmd) do |response|
59
54
  Bidi2pdf.logger.debug "Cookie set: #{response.inspect}"
60
55
  end
61
56
  end
62
57
 
63
58
  def create_browser_window
64
- client.send_cmd_and_wait("browsingContext.create", {
65
- type: "window",
66
- userContext: context_id
67
- }) do |response|
59
+ cmd = Bidi2pdf::Bidi::Commands::CreateWindow.new(user_context_id: context_id)
60
+
61
+ client.send_cmd_and_wait(cmd) do |response|
68
62
  browsing_context_id = response["result"]["context"]
69
63
 
70
64
  BrowserTab.new(client, browsing_context_id, context_id)
@@ -42,6 +42,8 @@ module Bidi2pdf
42
42
 
43
43
  def remove_error_listener(block) = socket_events.off(:error, block)
44
44
 
45
+ private
46
+
45
47
  def setup_message_handler
46
48
  that = self
47
49
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "chromedriver/binary"
4
+ require "securerandom"
4
5
 
5
6
  module Bidi2pdf
6
7
  class ChromedriverManager
@@ -55,9 +56,11 @@ module Bidi2pdf
55
56
 
56
57
  close_session
57
58
 
58
- term_chromedriver
59
+ debug_show_all_children
60
+
61
+ old_childprocesses = term_chromedriver
59
62
 
60
- detect_zombie_processes
63
+ detect_zombie_processes old_childprocesses
61
64
 
62
65
  return unless process_alive?
63
66
 
@@ -68,14 +71,10 @@ module Bidi2pdf
68
71
 
69
72
  private
70
73
 
71
- # rubocop:disable Metrics/AbcSize
72
- def detect_zombie_processes
73
- debug_show_all_children
74
+ def detect_zombie_processes(old_childprocesses)
75
+ Bidi2pdf.logger.debug "Old child processes for #{@pid}: #{old_childprocesses.map(&:pid).join(", ")}"
74
76
 
75
- child_processes = Bidi2pdf::ProcessTree.new(@pid).children(@pid)
76
- Bidi2pdf.logger.debug "Found child processes: #{child_processes.map(&:pid).join(", ")}"
77
-
78
- zombie_processes = child_processes.select { |child| process_alive? child.pid }
77
+ zombie_processes = old_childprocesses.select { |child| process_alive? child.pid }
79
78
 
80
79
  return if zombie_processes.empty?
81
80
 
@@ -83,9 +82,18 @@ module Bidi2pdf
83
82
  printable_zombie_processes_str = printable_zombie_processes.join(", ")
84
83
 
85
84
  Bidi2pdf.logger.error "Zombie Processes detected #{printable_zombie_processes_str}"
85
+
86
+ term_zombie_processes zombie_processes
86
87
  end
87
88
 
88
- # rubocop:enable Metrics/AbcSize
89
+ def term_zombie_processes(zombie_processes)
90
+ Bidi2pdf.logger.info "Terminating zombie processes: #{zombie_processes.map(&:pid).join(", ")}"
91
+
92
+ zombie_processes.each do |child|
93
+ Bidi2pdf.logger.debug "Terminating PID #{child.pid} (#{child.name})"
94
+ Process.kill("TERM", child.pid)
95
+ end
96
+ end
89
97
 
90
98
  def debug_show_all_children
91
99
  Bidi2pdf::ProcessTree.new(@pid).traverse do |process, level|
@@ -103,9 +111,11 @@ module Bidi2pdf
103
111
  end
104
112
 
105
113
  def term_chromedriver
106
- Bidi2pdf.logger.info "Stopping Chromedriver (PID #{@pid})"
114
+ Bidi2pdf::ProcessTree.new(@pid).children(@pid).tap do |_child_processes|
115
+ Bidi2pdf.logger.info "Stopping Chromedriver (PID #{@pid})"
107
116
 
108
- Process.kill("TERM", @pid)
117
+ Process.kill("TERM", @pid)
118
+ end
109
119
  rescue Errno::ESRCH
110
120
  Bidi2pdf.logger.debug "Process already gone"
111
121
  @pid = nil
@@ -131,7 +141,7 @@ module Bidi2pdf
131
141
 
132
142
  def build_cmd
133
143
  bin = Chromedriver::Binary::ChromedriverDownloader.driver_path
134
- user_data_dir = File.join(Dir.tmpdir, "bidi2pdf", "user_data")
144
+ user_data_dir = File.join(Dir.tmpdir, "bidi2pdf", "user_data", SecureRandom.hex(8))
135
145
 
136
146
  cmd = [bin]
137
147
  cmd << "--port=#{@port}" unless @port.zero?
data/lib/bidi2pdf/cli.rb CHANGED
@@ -122,7 +122,7 @@ module Bidi2pdf
122
122
  end
123
123
 
124
124
  def validate_print_options(opts)
125
- Bidi2pdf::Bidi::PrintParametersValidator.validate!(opts)
125
+ Bidi2pdf::Bidi::Commands::PrintParametersValidator.validate!(opts)
126
126
  rescue ArgumentError => e
127
127
  raise Thor::Error, "Invalid print option: #{e.message}"
128
128
  end
@@ -177,7 +177,6 @@ module Bidi2pdf
177
177
  end
178
178
 
179
179
  def launcher
180
- # rubocop:disable Layout/BeginEndAlignment
181
180
  @launcher ||= begin
182
181
  username, password = parse_auth(merged_options[:auth]) if merged_options[:auth]
183
182
 
@@ -195,7 +194,6 @@ module Bidi2pdf
195
194
  print_options: print_options
196
195
  )
197
196
  end
198
- # rubocop:enable Layout/BeginEndAlignment
199
197
  end
200
198
 
201
199
  # rubocop:enable Metrics/AbcSize
@@ -21,6 +21,7 @@ module Bidi2pdf
21
21
  @wait_network_idle = wait_network_idle
22
22
  @print_options = print_options || {}
23
23
  @remote_browser_url = remote_browser_url
24
+ @custom_session = nil
24
25
  end
25
26
 
26
27
  # rubocop:enable Metrics/ParameterLists
@@ -42,13 +43,14 @@ module Bidi2pdf
42
43
 
43
44
  def stop
44
45
  @manager&.stop
46
+ @custom_session&.close
45
47
  end
46
48
 
47
49
  private
48
50
 
49
51
  def session
50
52
  if @remote_browser_url
51
- Bidi::Session.new(session_url: @remote_browser_url, headless: @headless)
53
+ @custom_session = Bidi::Session.new(session_url: @remote_browser_url, headless: @headless)
52
54
  else
53
55
  @manager = ChromedriverManager.new(port: @port, headless: @headless)
54
56
  @manager.start
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bidi2pdf
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
data/lib/bidi2pdf.rb CHANGED
@@ -10,6 +10,18 @@ require "logger"
10
10
  module Bidi2pdf
11
11
  class Error < StandardError; end
12
12
 
13
+ class SessionNotStartedError < Error; end
14
+
15
+ class WebsocketError < Error; end
16
+
17
+ class ClientError < WebsocketError; end
18
+
19
+ class CmdError < ClientError; end
20
+
21
+ class CmdResponseNotStoredError < ClientError; end
22
+
23
+ class CmdTimeoutError < ClientError; end
24
+
13
25
  @logger = Logger.new($stdout)
14
26
  @logger.level = Logger::DEBUG
15
27
 
@@ -0,0 +1,41 @@
1
+ module Bidi2pdf
2
+ module Bidi
3
+ class CommandManager
4
+ self.@id: untyped
5
+
6
+ self.@id_mutex: untyped
7
+
8
+ @socket: untyped
9
+
10
+ @logger: untyped
11
+
12
+ @pending_responses: untyped
13
+
14
+ @initiated_cmds: untyped
15
+
16
+ def self.initialize_counter: () -> untyped
17
+
18
+ def self.next_id: () -> untyped
19
+
20
+ def initialize: (untyped socket, logger: untyped) -> void
21
+
22
+ def send_cmd: (untyped cmd, ?store_response: bool) -> untyped
23
+
24
+ def send_cmd_and_wait: (untyped cmd, ?timeout: untyped) ?{ (untyped) -> untyped } -> untyped
25
+
26
+ def pop_response: (untyped id, timeout: untyped) -> untyped
27
+
28
+ def handle_response: (untyped data) -> (true | untyped | false)
29
+
30
+ private
31
+
32
+ def init_queue_for: (untyped id) -> untyped
33
+
34
+ def next_id: () -> untyped
35
+
36
+ def redact_sensitive_fields: (untyped obj, ?::Array[untyped] sensitive_keys) -> untyped
37
+
38
+ def raise_timeout_error: (untyped id, untyped cmd) -> untyped
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ module Bidi2pdf
2
+ module Bidi
3
+ module Commands
4
+ class AddIntercept
5
+ include Base
6
+
7
+ BEFORE_REQUEST: String
8
+ RESPONSE_STARTED: String
9
+ AUTH_REQUIRED: String
10
+
11
+ @context: String
12
+ @phases: Array[String]
13
+ @url_patterns: Array[String]
14
+
15
+ def initialize: (context: String, phases: Array[String], url_patterns: Array[String]) -> void
16
+
17
+ def validate_phases!: () -> void
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ module Bidi2pdf
2
+ module Bidi
3
+ module Commands
4
+ module Base
5
+ def method_name: () -> String
6
+
7
+ def params: () -> Hash[Symbol, untyped]
8
+
9
+ def as_payload: (untyped id) -> Hash[Symbol, untyped]
10
+
11
+ def ==: (untyped other) -> bool
12
+
13
+ def eql?: (untyped other) -> bool
14
+
15
+ def hash: () -> Integer
16
+
17
+ def inspect: () -> String
18
+
19
+ private
20
+
21
+ def redact_sensitive_fields: (untyped obj, Array[String] sensitive_keys) -> untyped
22
+
23
+ def raise_timeout_error: (untyped id, String method, Hash[Symbol, untyped] params) -> void
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ module Bidi2pdf
2
+ module Bidi
3
+ module Commands
4
+ class BrowserClose
5
+ include Commands::Base
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Bidi2pdf
2
+ module Bidi
3
+ module Commands
4
+ class BrowserCreateUserContext
5
+ include Base
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Bidi2pdf
2
+ module Bidi
3
+ module Commands
4
+ class BrowsingContextClose
5
+ include Commands::Base
6
+
7
+ def initialize: (context: String) -> void
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Bidi2pdf
2
+ module Bidi
3
+ module Commands
4
+ class BrowsingContextNavigate
5
+ include Commands::Base
6
+
7
+ def initialize: (
8
+ url: String,
9
+ context: String,
10
+ ?wait: String
11
+ ) -> void
12
+ end
13
+ end
14
+ end
15
+ end