neo4j-ruby-driver 6.0.3.alpha.0 → 6.2.1.beta.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.
Files changed (348) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +113 -411
  3. data/{ruby → lib}/neo4j/driver/access_mode.rb +2 -1
  4. data/lib/neo4j/driver/auth_token_managers.rb +31 -0
  5. data/lib/neo4j/driver/auth_tokens.rb +41 -0
  6. data/lib/neo4j/driver/auto_commit_retries_mode.rb +18 -0
  7. data/lib/neo4j/driver/bolt/bolt_version.rb +67 -0
  8. data/lib/neo4j/driver/bolt/connection.rb +1091 -0
  9. data/lib/neo4j/driver/bolt/handshake.rb +236 -0
  10. data/lib/neo4j/driver/bolt/message/failure.rb +139 -0
  11. data/lib/neo4j/driver/bolt/message/ignored.rb +27 -0
  12. data/lib/neo4j/driver/bolt/message/record.rb +30 -0
  13. data/lib/neo4j/driver/bolt/message/success.rb +34 -0
  14. data/lib/neo4j/driver/bolt/message.rb +112 -0
  15. data/lib/neo4j/driver/bolt/pool.rb +255 -0
  16. data/lib/neo4j/driver/bolt/protocol/base.rb +146 -0
  17. data/lib/neo4j/driver/bolt/protocol/v3.rb +43 -0
  18. data/lib/neo4j/driver/bolt/protocol/v4.rb +24 -0
  19. data/lib/neo4j/driver/bolt/protocol/v43.rb +28 -0
  20. data/lib/neo4j/driver/bolt/protocol/v44.rb +23 -0
  21. data/lib/neo4j/driver/bolt/protocol/v5.rb +27 -0
  22. data/lib/neo4j/driver/bolt/protocol/v51.rb +24 -0
  23. data/lib/neo4j/driver/bolt/protocol/v52.rb +28 -0
  24. data/lib/neo4j/driver/bolt/protocol/v53.rb +27 -0
  25. data/lib/neo4j/driver/bolt/protocol/v54.rb +14 -0
  26. data/lib/neo4j/driver/bolt/protocol/v55.rb +17 -0
  27. data/lib/neo4j/driver/bolt/protocol/v56.rb +14 -0
  28. data/lib/neo4j/driver/bolt/protocol/v57.rb +31 -0
  29. data/lib/neo4j/driver/bolt/protocol/v58.rb +15 -0
  30. data/lib/neo4j/driver/bolt/protocol/v6.rb +43 -0
  31. data/lib/neo4j/driver/bolt/protocol/v61.rb +21 -0
  32. data/lib/neo4j/driver/bolt/protocol_version_handler.rb +39 -0
  33. data/lib/neo4j/driver/bolt/record_buffer.rb +143 -0
  34. data/lib/neo4j/driver/bolt/stream_handler.rb +53 -0
  35. data/lib/neo4j/driver/bolt/tls_config.rb +129 -0
  36. data/lib/neo4j/driver/bolt/wire.rb +321 -0
  37. data/lib/neo4j/driver/bookmark.rb +15 -0
  38. data/lib/neo4j/driver/bookmark_managers.rb +39 -0
  39. data/lib/neo4j/driver/client_certificate.rb +19 -0
  40. data/lib/neo4j/driver/client_certificate_manager.rb +37 -0
  41. data/lib/neo4j/driver/client_certificate_managers.rb +15 -0
  42. data/lib/neo4j/driver/client_certificates.rb +14 -0
  43. data/lib/neo4j/driver/direct/connection_provider.rb +262 -0
  44. data/lib/neo4j/driver/driver.rb +268 -0
  45. data/lib/neo4j/driver/eager_result.rb +10 -0
  46. data/lib/neo4j/driver/exceptions/neo4j_exception.rb +16 -7
  47. data/lib/neo4j/driver/exceptions/no_such_record_exception.rb +1 -1
  48. data/lib/neo4j/driver/exceptions/protocol_exception.rb +0 -5
  49. data/lib/neo4j/driver/exceptions/security_retryable_exception.rb +14 -0
  50. data/lib/neo4j/driver/exceptions/transaction_terminated_exception.rb +13 -0
  51. data/lib/neo4j/driver/graph_database.rb +29 -0
  52. data/lib/neo4j/driver/internal/clock.rb +20 -0
  53. data/lib/neo4j/driver/internal/clock_adapter.rb +21 -0
  54. data/lib/neo4j/driver/internal/default_bookmark_manager.rb +54 -0
  55. data/lib/neo4j/driver/internal/deprecator.rb +9 -5
  56. data/lib/neo4j/driver/internal/driver_factory.rb +128 -0
  57. data/lib/neo4j/driver/internal/duration_normalizer.rb +14 -39
  58. data/lib/neo4j/driver/internal/extras.rb +23 -0
  59. data/lib/neo4j/driver/internal/home_db_cache.rb +57 -0
  60. data/lib/neo4j/driver/internal/internal_auth_token_manager.rb +37 -0
  61. data/lib/neo4j/driver/internal/metrics.rb +31 -0
  62. data/lib/neo4j/driver/internal/security/static_auth_token_manager.rb +25 -0
  63. data/lib/neo4j/driver/internal/validator.rb +16 -2
  64. data/lib/neo4j/driver/net.rb +29 -0
  65. data/lib/neo4j/driver/packstream/markers.rb +49 -0
  66. data/lib/neo4j/driver/packstream/packer.rb +335 -0
  67. data/lib/neo4j/driver/packstream/structure.rb +27 -0
  68. data/lib/neo4j/driver/packstream/unpacker.rb +170 -0
  69. data/lib/neo4j/driver/record.rb +43 -0
  70. data/lib/neo4j/driver/result.rb +282 -0
  71. data/lib/neo4j/driver/routing/load_balancer.rb +706 -0
  72. data/lib/neo4j/driver/routing/routed_connection.rb +132 -0
  73. data/lib/neo4j/driver/routing/routing_table.rb +127 -0
  74. data/lib/neo4j/driver/routing/server_address.rb +25 -0
  75. data/lib/neo4j/driver/routing_control.rb +13 -0
  76. data/lib/neo4j/driver/session.rb +577 -0
  77. data/lib/neo4j/driver/summary/database_info.rb +25 -0
  78. data/lib/neo4j/driver/summary/gql_notification.rb +38 -0
  79. data/lib/neo4j/driver/summary/gql_status_object.rb +35 -0
  80. data/lib/neo4j/driver/summary/notification.rb +46 -0
  81. data/lib/neo4j/driver/summary/plan.rb +23 -0
  82. data/lib/neo4j/driver/summary/profile.rb +28 -0
  83. data/lib/neo4j/driver/summary/query.rb +19 -0
  84. data/lib/neo4j/driver/summary/query_type.rb +5 -1
  85. data/lib/neo4j/driver/summary/result_summary.rb +215 -0
  86. data/lib/neo4j/driver/summary/server_info.rb +33 -0
  87. data/lib/neo4j/driver/summary/summary_counters.rb +72 -0
  88. data/lib/neo4j/driver/transaction.rb +344 -0
  89. data/lib/neo4j/driver/types/duration.rb +76 -0
  90. data/lib/neo4j/driver/types/entity.rb +40 -0
  91. data/lib/neo4j/driver/types/local_date_time.rb +77 -8
  92. data/lib/neo4j/driver/types/local_time.rb +50 -7
  93. data/lib/neo4j/driver/types/node.rb +18 -0
  94. data/lib/neo4j/driver/types/offset_time.rb +78 -7
  95. data/lib/neo4j/driver/types/path.rb +68 -0
  96. data/lib/neo4j/driver/types/point.rb +38 -18
  97. data/lib/neo4j/driver/types/relationship.rb +32 -0
  98. data/lib/neo4j/driver/types/temporal_value.rb +44 -0
  99. data/lib/neo4j/driver/types/unbound_relationship.rb +24 -0
  100. data/lib/neo4j/driver/types/unresolvable_zoned_date_time.rb +38 -0
  101. data/lib/neo4j/driver/types/unsupported_type.rb +25 -0
  102. data/lib/neo4j/driver/types/uuid.rb +29 -0
  103. data/{ruby → lib}/neo4j/driver/version.rb +1 -1
  104. data/lib/neo4j/driver.rb +15 -0
  105. data/lib/neo4j-ruby-driver_loader.rb +34 -20
  106. metadata +115 -441
  107. data/lib/neo4j/driver/internal/bolt_server_address.rb +0 -97
  108. data/lib/neo4j/driver/synchronizable.rb +0 -23
  109. data/lib/neo4j/driver/types/time.rb +0 -45
  110. data/ruby/neo4j/driver/auth_tokens.rb +0 -34
  111. data/ruby/neo4j/driver/bookmark.rb +0 -21
  112. data/ruby/neo4j/driver/config.rb +0 -89
  113. data/ruby/neo4j/driver/graph_database.rb +0 -78
  114. data/ruby/neo4j/driver/internal/async/connection/bolt_protocol_util.rb +0 -51
  115. data/ruby/neo4j/driver/internal/async/connection/bootstrap_factory.rb +0 -22
  116. data/ruby/neo4j/driver/internal/async/connection/channel_attributes.rb +0 -31
  117. data/ruby/neo4j/driver/internal/async/connection/channel_connected_listener.rb +0 -32
  118. data/ruby/neo4j/driver/internal/async/connection/channel_connector_impl.rb +0 -83
  119. data/ruby/neo4j/driver/internal/async/connection/channel_pipeline_builder_impl.rb +0 -22
  120. data/ruby/neo4j/driver/internal/async/connection/direct_connection.rb +0 -30
  121. data/ruby/neo4j/driver/internal/async/connection/event_loop_group_factory.rb +0 -83
  122. data/ruby/neo4j/driver/internal/async/connection/handshake_completed_listener.rb +0 -27
  123. data/ruby/neo4j/driver/internal/async/connection/handshake_handler.rb +0 -113
  124. data/ruby/neo4j/driver/internal/async/connection/netty_channel_initializer.rb +0 -57
  125. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver.rb +0 -26
  126. data/ruby/neo4j/driver/internal/async/connection/netty_domain_name_resolver_group.rb +0 -19
  127. data/ruby/neo4j/driver/internal/async/connection/routing_connection.rb +0 -36
  128. data/ruby/neo4j/driver/internal/async/connection/stream.rb +0 -12
  129. data/ruby/neo4j/driver/internal/async/connection/stream_reader.rb +0 -16
  130. data/ruby/neo4j/driver/internal/async/connection_context.rb +0 -10
  131. data/ruby/neo4j/driver/internal/async/immutable_connection_context.rb +0 -24
  132. data/ruby/neo4j/driver/internal/async/inbound/byte_buf_input.rb +0 -30
  133. data/ruby/neo4j/driver/internal/async/inbound/channel_error_handler.rb +0 -77
  134. data/ruby/neo4j/driver/internal/async/inbound/chunk_decoder.rb +0 -41
  135. data/ruby/neo4j/driver/internal/async/inbound/connect_timeout_handler.rb +0 -32
  136. data/ruby/neo4j/driver/internal/async/inbound/connection_read_timeout_handler.rb +0 -17
  137. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_dispatcher.rb +0 -171
  138. data/ruby/neo4j/driver/internal/async/inbound/inbound_message_handler.rb +0 -42
  139. data/ruby/neo4j/driver/internal/async/inbound/message_decoder.rb +0 -51
  140. data/ruby/neo4j/driver/internal/async/internal_async_session.rb +0 -92
  141. data/ruby/neo4j/driver/internal/async/internal_async_transaction.rb +0 -13
  142. data/ruby/neo4j/driver/internal/async/leak_logging_network_session.rb +0 -34
  143. data/ruby/neo4j/driver/internal/async/network_connection.rb +0 -194
  144. data/ruby/neo4j/driver/internal/async/network_session.rb +0 -150
  145. data/ruby/neo4j/driver/internal/async/outbound/chunk_aware_byte_buf_output.rb +0 -110
  146. data/ruby/neo4j/driver/internal/async/outbound/outbound_message_handler.rb +0 -39
  147. data/ruby/neo4j/driver/internal/async/pool/channel.rb +0 -66
  148. data/ruby/neo4j/driver/internal/async/pool/channel_pool.rb +0 -31
  149. data/ruby/neo4j/driver/internal/async/pool/channel_tracker.rb +0 -135
  150. data/ruby/neo4j/driver/internal/async/pool/connection_pool_impl.rb +0 -156
  151. data/ruby/neo4j/driver/internal/async/pool/netty_channel_health_checker.rb +0 -87
  152. data/ruby/neo4j/driver/internal/async/pool/netty_channel_pool.rb +0 -52
  153. data/ruby/neo4j/driver/internal/async/pool/network_connection_factory.rb +0 -21
  154. data/ruby/neo4j/driver/internal/async/pool/pool_settings.rb +0 -34
  155. data/ruby/neo4j/driver/internal/async/pool/timed_stack.rb +0 -15
  156. data/ruby/neo4j/driver/internal/async/result_cursors_holder.rb +0 -17
  157. data/ruby/neo4j/driver/internal/async/unmanaged_transaction.rb +0 -212
  158. data/ruby/neo4j/driver/internal/bookmark_holder.rb +0 -9
  159. data/ruby/neo4j/driver/internal/cluster/cluster_composition.rb +0 -48
  160. data/ruby/neo4j/driver/internal/cluster/cluster_composition_lookup_result.rb +0 -14
  161. data/ruby/neo4j/driver/internal/cluster/cluster_routing_table.rb +0 -122
  162. data/ruby/neo4j/driver/internal/cluster/identity_resolver.rb +0 -10
  163. data/ruby/neo4j/driver/internal/cluster/loadbalancing/least_connected_load_balancing_strategy.rb +0 -68
  164. data/ruby/neo4j/driver/internal/cluster/loadbalancing/load_balancer.rb +0 -125
  165. data/ruby/neo4j/driver/internal/cluster/loadbalancing/round_robin_array_index.rb +0 -13
  166. data/ruby/neo4j/driver/internal/cluster/multi_databases_routing_procedure_runner.rb +0 -31
  167. data/ruby/neo4j/driver/internal/cluster/rediscovery_impl.rb +0 -147
  168. data/ruby/neo4j/driver/internal/cluster/route_message_routing_procedure_runner.rb +0 -43
  169. data/ruby/neo4j/driver/internal/cluster/routing_context.rb +0 -77
  170. data/ruby/neo4j/driver/internal/cluster/routing_procedure_cluster_composition_provider.rb +0 -60
  171. data/ruby/neo4j/driver/internal/cluster/routing_procedure_response.rb +0 -35
  172. data/ruby/neo4j/driver/internal/cluster/routing_settings.rb +0 -24
  173. data/ruby/neo4j/driver/internal/cluster/routing_table_handler_impl.rb +0 -95
  174. data/ruby/neo4j/driver/internal/cluster/routing_table_registry_impl.rb +0 -121
  175. data/ruby/neo4j/driver/internal/cluster/single_database_routing_procedure_runner.rb +0 -73
  176. data/ruby/neo4j/driver/internal/connection_settings.rb +0 -16
  177. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_impl.rb +0 -55
  178. data/ruby/neo4j/driver/internal/cursor/async_result_cursor_only_factory.rb +0 -24
  179. data/ruby/neo4j/driver/internal/cursor/disposable_async_result_cursor.rb +0 -61
  180. data/ruby/neo4j/driver/internal/cursor/result_cursor_factory_impl.rb +0 -24
  181. data/ruby/neo4j/driver/internal/cursor/rx_result_cursor_impl.rb +0 -110
  182. data/ruby/neo4j/driver/internal/database_name_util.rb +0 -37
  183. data/ruby/neo4j/driver/internal/default_bookmark_holder.rb +0 -9
  184. data/ruby/neo4j/driver/internal/default_domain_name_resolver.rb +0 -11
  185. data/ruby/neo4j/driver/internal/direct_connection_provider.rb +0 -40
  186. data/ruby/neo4j/driver/internal/driver_factory.rb +0 -126
  187. data/ruby/neo4j/driver/internal/eager_result_value.rb +0 -5
  188. data/ruby/neo4j/driver/internal/handlers/begin_tx_response_handler.rb +0 -20
  189. data/ruby/neo4j/driver/internal/handlers/channel_releasing_reset_response_handler.rb +0 -30
  190. data/ruby/neo4j/driver/internal/handlers/commit_tx_response_handler.rb +0 -23
  191. data/ruby/neo4j/driver/internal/handlers/hello_response_handler.rb +0 -65
  192. data/ruby/neo4j/driver/internal/handlers/init_response_handler.rb +0 -34
  193. data/ruby/neo4j/driver/internal/handlers/legacy_pull_all_response_handler.rb +0 -199
  194. data/ruby/neo4j/driver/internal/handlers/no_op_response_handler.rb +0 -16
  195. data/ruby/neo4j/driver/internal/handlers/ping_response_handler.rb +0 -29
  196. data/ruby/neo4j/driver/internal/handlers/pull_handlers.rb +0 -32
  197. data/ruby/neo4j/driver/internal/handlers/pulln/auto_pull_response_handler.rb +0 -169
  198. data/ruby/neo4j/driver/internal/handlers/pulln/basic_pull_response_handler.rb +0 -298
  199. data/ruby/neo4j/driver/internal/handlers/pulln/fetch_size_util.rb +0 -20
  200. data/ruby/neo4j/driver/internal/handlers/reset_response_handler.rb +0 -34
  201. data/ruby/neo4j/driver/internal/handlers/rollback_tx_response_handler.rb +0 -25
  202. data/ruby/neo4j/driver/internal/handlers/route_message_response_handler.rb +0 -21
  203. data/ruby/neo4j/driver/internal/handlers/routing_response_handler.rb +0 -79
  204. data/ruby/neo4j/driver/internal/handlers/run_response_handler.rb +0 -38
  205. data/ruby/neo4j/driver/internal/handlers/session_pull_response_completion_listener.rb +0 -34
  206. data/ruby/neo4j/driver/internal/handlers/transaction_pull_response_completion_listener.rb +0 -20
  207. data/ruby/neo4j/driver/internal/impersonation_util.rb +0 -22
  208. data/ruby/neo4j/driver/internal/internal_bookmark.rb +0 -9
  209. data/ruby/neo4j/driver/internal/internal_database_name.rb +0 -9
  210. data/ruby/neo4j/driver/internal/internal_driver.rb +0 -83
  211. data/ruby/neo4j/driver/internal/internal_entity.rb +0 -21
  212. data/ruby/neo4j/driver/internal/internal_node.rb +0 -21
  213. data/ruby/neo4j/driver/internal/internal_pair.rb +0 -9
  214. data/ruby/neo4j/driver/internal/internal_path.rb +0 -35
  215. data/ruby/neo4j/driver/internal/internal_point2_d.rb +0 -9
  216. data/ruby/neo4j/driver/internal/internal_point3_d.rb +0 -6
  217. data/ruby/neo4j/driver/internal/internal_record.rb +0 -27
  218. data/ruby/neo4j/driver/internal/internal_relationship.rb +0 -27
  219. data/ruby/neo4j/driver/internal/internal_result.rb +0 -49
  220. data/ruby/neo4j/driver/internal/internal_session.rb +0 -91
  221. data/ruby/neo4j/driver/internal/internal_transaction.rb +0 -48
  222. data/ruby/neo4j/driver/internal/logging/channel_activity_logger.rb +0 -29
  223. data/ruby/neo4j/driver/internal/logging/channel_error_logger.rb +0 -17
  224. data/ruby/neo4j/driver/internal/logging/prefixed_logger.rb +0 -19
  225. data/ruby/neo4j/driver/internal/logging/reformatted_logger.rb +0 -17
  226. data/ruby/neo4j/driver/internal/messaging/abstract_message_writer.rb +0 -23
  227. data/ruby/neo4j/driver/internal/messaging/bolt_protocol.rb +0 -32
  228. data/ruby/neo4j/driver/internal/messaging/bolt_protocol_version.rb +0 -48
  229. data/ruby/neo4j/driver/internal/messaging/common/common_message_reader.rb +0 -51
  230. data/ruby/neo4j/driver/internal/messaging/common/common_value.rb +0 -33
  231. data/ruby/neo4j/driver/internal/messaging/common/common_value_packer.rb +0 -104
  232. data/ruby/neo4j/driver/internal/messaging/common/common_value_unpacker.rb +0 -256
  233. data/ruby/neo4j/driver/internal/messaging/encode/begin_message_encoder.rb +0 -15
  234. data/ruby/neo4j/driver/internal/messaging/encode/commit_message_encoder.rb +0 -14
  235. data/ruby/neo4j/driver/internal/messaging/encode/discard_all_message_encoder.rb +0 -14
  236. data/ruby/neo4j/driver/internal/messaging/encode/discard_message_encoder.rb +0 -15
  237. data/ruby/neo4j/driver/internal/messaging/encode/goodbye_message_encoder.rb +0 -14
  238. data/ruby/neo4j/driver/internal/messaging/encode/hello_message_encoder.rb +0 -15
  239. data/ruby/neo4j/driver/internal/messaging/encode/init_message_encoder.rb +0 -16
  240. data/ruby/neo4j/driver/internal/messaging/encode/logoff_message_encoder.rb +0 -14
  241. data/ruby/neo4j/driver/internal/messaging/encode/logon_message_encoder.rb +0 -15
  242. data/ruby/neo4j/driver/internal/messaging/encode/pull_all_message_encoder.rb +0 -14
  243. data/ruby/neo4j/driver/internal/messaging/encode/pull_message_encoder.rb +0 -15
  244. data/ruby/neo4j/driver/internal/messaging/encode/reset_message_encoder.rb +0 -14
  245. data/ruby/neo4j/driver/internal/messaging/encode/rollback_message_encoder.rb +0 -14
  246. data/ruby/neo4j/driver/internal/messaging/encode/route_message_encoder.rb +0 -24
  247. data/ruby/neo4j/driver/internal/messaging/encode/route_v44_message_encoder.rb +0 -22
  248. data/ruby/neo4j/driver/internal/messaging/encode/run_message_encoder.rb +0 -16
  249. data/ruby/neo4j/driver/internal/messaging/encode/run_with_metadata_message_encoder.rb +0 -17
  250. data/ruby/neo4j/driver/internal/messaging/request/abstract_streaming_message.rb +0 -25
  251. data/ruby/neo4j/driver/internal/messaging/request/begin_message.rb +0 -25
  252. data/ruby/neo4j/driver/internal/messaging/request/commit_message.rb +0 -20
  253. data/ruby/neo4j/driver/internal/messaging/request/discard_all_message.rb +0 -20
  254. data/ruby/neo4j/driver/internal/messaging/request/discard_message.rb +0 -23
  255. data/ruby/neo4j/driver/internal/messaging/request/goodbye_message.rb +0 -20
  256. data/ruby/neo4j/driver/internal/messaging/request/hello_message.rb +0 -30
  257. data/ruby/neo4j/driver/internal/messaging/request/init_message.rb +0 -19
  258. data/ruby/neo4j/driver/internal/messaging/request/logoff_message.rb +0 -13
  259. data/ruby/neo4j/driver/internal/messaging/request/logon_message.rb +0 -13
  260. data/ruby/neo4j/driver/internal/messaging/request/message_with_metadata.rb +0 -17
  261. data/ruby/neo4j/driver/internal/messaging/request/multi_database_util.rb +0 -26
  262. data/ruby/neo4j/driver/internal/messaging/request/pull_all_message.rb +0 -23
  263. data/ruby/neo4j/driver/internal/messaging/request/pull_message.rb +0 -22
  264. data/ruby/neo4j/driver/internal/messaging/request/reset_message.rb +0 -32
  265. data/ruby/neo4j/driver/internal/messaging/request/rollback_message.rb +0 -20
  266. data/ruby/neo4j/driver/internal/messaging/request/route_message.rb +0 -28
  267. data/ruby/neo4j/driver/internal/messaging/request/run_message.rb +0 -23
  268. data/ruby/neo4j/driver/internal/messaging/request/run_with_metadata_message.rb +0 -49
  269. data/ruby/neo4j/driver/internal/messaging/request/transaction_metadata_builder.rb +0 -24
  270. data/ruby/neo4j/driver/internal/messaging/response/failure_message.rb +0 -40
  271. data/ruby/neo4j/driver/internal/messaging/response/ignored_message.rb +0 -29
  272. data/ruby/neo4j/driver/internal/messaging/response/record_message.rb +0 -33
  273. data/ruby/neo4j/driver/internal/messaging/response/success_message.rb +0 -34
  274. data/ruby/neo4j/driver/internal/messaging/v3/bolt_protocol_v3.rb +0 -82
  275. data/ruby/neo4j/driver/internal/messaging/v3/message_format_v3.rb +0 -17
  276. data/ruby/neo4j/driver/internal/messaging/v3/message_writer_v3.rb +0 -27
  277. data/ruby/neo4j/driver/internal/messaging/v4/bolt_protocol_v4.rb +0 -29
  278. data/ruby/neo4j/driver/internal/messaging/v4/message_format_v4.rb +0 -13
  279. data/ruby/neo4j/driver/internal/messaging/v4/message_writer_v4.rb +0 -17
  280. data/ruby/neo4j/driver/internal/messaging/v41/bolt_protocol_v41.rb +0 -25
  281. data/ruby/neo4j/driver/internal/messaging/v42/bolt_protocol_v42.rb +0 -13
  282. data/ruby/neo4j/driver/internal/messaging/v43/bolt_protocol_v43.rb +0 -19
  283. data/ruby/neo4j/driver/internal/messaging/v43/message_format_v43.rb +0 -14
  284. data/ruby/neo4j/driver/internal/messaging/v43/message_writer_v43.rb +0 -20
  285. data/ruby/neo4j/driver/internal/messaging/v44/bolt_protocol_v44.rb +0 -17
  286. data/ruby/neo4j/driver/internal/messaging/v44/message_format_v44.rb +0 -14
  287. data/ruby/neo4j/driver/internal/messaging/v44/message_writer_v44.rb +0 -15
  288. data/ruby/neo4j/driver/internal/messaging/v5/bolt_protocol_v5.rb +0 -21
  289. data/ruby/neo4j/driver/internal/messaging/v5/message_format_v5.rb +0 -18
  290. data/ruby/neo4j/driver/internal/messaging/v5/value_unpacker_v5.rb +0 -17
  291. data/ruby/neo4j/driver/internal/messaging/v51/bolt_protocol_v51.rb +0 -40
  292. data/ruby/neo4j/driver/internal/messaging/v51/message_format_v51.rb +0 -14
  293. data/ruby/neo4j/driver/internal/messaging/v51/message_writer_v51.rb +0 -17
  294. data/ruby/neo4j/driver/internal/metrics/connection_pool_metrics_listener.rb +0 -34
  295. data/ruby/neo4j/driver/internal/metrics/internal_abstract_metrics.rb +0 -46
  296. data/ruby/neo4j/driver/internal/metrics/internal_connection_pool_metrics.rb +0 -105
  297. data/ruby/neo4j/driver/internal/metrics/internal_metrics.rb +0 -82
  298. data/ruby/neo4j/driver/internal/metrics/internal_metrics_provider.rb +0 -18
  299. data/ruby/neo4j/driver/internal/metrics/listener_event.rb +0 -17
  300. data/ruby/neo4j/driver/internal/metrics/metrics_provider.rb +0 -24
  301. data/ruby/neo4j/driver/internal/metrics/time_recorder_listener_event.rb +0 -15
  302. data/ruby/neo4j/driver/internal/packstream/byte_array_incompatible_packer.rb +0 -12
  303. data/ruby/neo4j/driver/internal/packstream/pack_input.rb +0 -47
  304. data/ruby/neo4j/driver/internal/packstream/pack_output.rb +0 -39
  305. data/ruby/neo4j/driver/internal/packstream/pack_stream.rb +0 -324
  306. data/ruby/neo4j/driver/internal/packstream/pack_type.rb +0 -17
  307. data/ruby/neo4j/driver/internal/read_only_bookmark_holder.rb +0 -13
  308. data/ruby/neo4j/driver/internal/resolved_bolt_server_address.rb +0 -35
  309. data/ruby/neo4j/driver/internal/retry/exponential_backoff_retry_logic.rb +0 -150
  310. data/ruby/neo4j/driver/internal/revocation_strategy.rb +0 -19
  311. data/ruby/neo4j/driver/internal/scheme.rb +0 -32
  312. data/ruby/neo4j/driver/internal/security/internal_auth_token.rb +0 -15
  313. data/ruby/neo4j/driver/internal/security/security_plan_impl.rb +0 -48
  314. data/ruby/neo4j/driver/internal/security_setting.rb +0 -66
  315. data/ruby/neo4j/driver/internal/session_factory_impl.rb +0 -32
  316. data/ruby/neo4j/driver/internal/spi/connection.rb +0 -19
  317. data/ruby/neo4j/driver/internal/spi/connection_pool.rb +0 -9
  318. data/ruby/neo4j/driver/internal/spi/response_handler.rb +0 -23
  319. data/ruby/neo4j/driver/internal/summary/internal_database_info.rb +0 -7
  320. data/ruby/neo4j/driver/internal/summary/internal_input_position.rb +0 -11
  321. data/ruby/neo4j/driver/internal/summary/internal_notification.rb +0 -16
  322. data/ruby/neo4j/driver/internal/summary/internal_plan.rb +0 -41
  323. data/ruby/neo4j/driver/internal/summary/internal_profiled_plan.rb +0 -32
  324. data/ruby/neo4j/driver/internal/summary/internal_result_summary.rb +0 -33
  325. data/ruby/neo4j/driver/internal/summary/internal_server_info.rb +0 -6
  326. data/ruby/neo4j/driver/internal/summary/internal_summary_counters.rb +0 -18
  327. data/ruby/neo4j/driver/internal/svm/netty_substitutions.rb +0 -196
  328. data/ruby/neo4j/driver/internal/svm/z_lib_substitutions.rb +0 -21
  329. data/ruby/neo4j/driver/internal/util/certificate_tool.rb +0 -65
  330. data/ruby/neo4j/driver/internal/util/clock.rb +0 -29
  331. data/ruby/neo4j/driver/internal/util/error_util.rb +0 -104
  332. data/ruby/neo4j/driver/internal/util/extract.rb +0 -123
  333. data/ruby/neo4j/driver/internal/util/format.rb +0 -39
  334. data/ruby/neo4j/driver/internal/util/futures.rb +0 -99
  335. data/ruby/neo4j/driver/internal/util/iterables.rb +0 -35
  336. data/ruby/neo4j/driver/internal/util/lock_util.rb +0 -23
  337. data/ruby/neo4j/driver/internal/util/metadata_extractor.rb +0 -101
  338. data/ruby/neo4j/driver/internal/util/mutex.rb +0 -9
  339. data/ruby/neo4j/driver/internal/util/preconditions.rb +0 -16
  340. data/ruby/neo4j/driver/internal/util/result_holder.rb +0 -72
  341. data/ruby/neo4j/driver/internal/util/server_version.rb +0 -60
  342. data/ruby/neo4j/driver/logging1.rb +0 -51
  343. data/ruby/neo4j/driver/net/server_address.rb +0 -9
  344. data/ruby/neo4j/driver/query.rb +0 -48
  345. data/ruby/neo4j/driver/records.rb +0 -13
  346. data/ruby/neo4j/driver/transaction_config.rb +0 -50
  347. data/ruby/neo4j/driver/values.rb +0 -26
  348. data/ruby/neo4j/driver.rb +0 -30
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ module Protocol
7
+ # Bolt 5.7. FAILURE switches to a GQL-flavoured map: the legacy
8
+ # `code` key is renamed to `neo4j_code` (optional, defaults to
9
+ # "N/A"), and new keys appear (`gql_status`, `description`,
10
+ # `diagnostic_record`, recursive `cause`). The driver's
11
+ # exception classifier keys off `:code`, so we alias
12
+ # `neo4j_code → code` here. The other GQL fields ride along in
13
+ # the metadata for any caller that wants them.
14
+ #
15
+ # 5.7+ is also where HandshakeManifestV1 negotiation becomes
16
+ # mandatory on the server side; that's handled in Bolt::Handshake,
17
+ # not here.
18
+ class V57 < V56
19
+ def customize_hydration(unpacker)
20
+ super
21
+ unpacker.register_hydration_handler(Message::FAILURE) do |fields|
22
+ meta = fields[0] || {}
23
+ meta = meta.merge(code: meta[:neo4j_code]) if meta[:neo4j_code]
24
+ Message::Failure.new(meta)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ module Protocol
7
+ # Bolt 5.8. Wire-identical to 5.7 from the client's perspective;
8
+ # the version bump only flags additional server capabilities
9
+ # negotiated through the manifest's capabilities bitmask.
10
+ class V58 < V57
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ module Protocol
7
+ # Bolt 6.0. HELLO / LOGON / TELEMETRY shapes are unchanged vs
8
+ # 5.8; the major bump exists to (a) gate the manifest as the
9
+ # only supported negotiation path and (b) introduce two new
10
+ # server-pushed struct types in result records:
11
+ # - VECTOR 0x56 — packed numeric array; 2 fields
12
+ # (element-type byte, raw bytes).
13
+ # - UNSUPPORTED 0x3F — forward-compat marker; 4 fields
14
+ # (name, min_major, min_minor, extra-map whose
15
+ # optional `message` key carries a server note).
16
+ #
17
+ # UNSUPPORTED hydrates to Types::UnsupportedType (Feature:API:Type.
18
+ # UnsupportedType). VECTOR stays a plain hash — Feature:API:Type.Vector
19
+ # is unimplemented, so the goal there is still just "don't crash at
20
+ # hydration" until there's a public API to wire it to.
21
+ class V6 < V58
22
+ VECTOR_SIGNATURE = 0x56
23
+ UNSUPPORTED_SIGNATURE = 0x3F
24
+
25
+ def customize_hydration(unpacker)
26
+ super
27
+ unpacker.register_hydration_handler(VECTOR_SIGNATURE) do |fields|
28
+ { element_type: fields[0], bytes: fields[1] }
29
+ end
30
+ unpacker.register_hydration_handler(UNSUPPORTED_SIGNATURE) do |fields|
31
+ # fields[3] is an extra map (symbol keys) whose :message is the
32
+ # optional server note. Guard the type so a malformed/absent
33
+ # 4th field can't crash hydration — the whole point of a
34
+ # forward-compat marker is to survive the unexpected.
35
+ extra = fields[3].is_a?(Hash) ? fields[3] : {}
36
+ Types::UnsupportedType.new(fields[0], fields[1], fields[2], extra[:message])
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ module Protocol
7
+ # Bolt 6.1. HELLO / LOGON shapes are unchanged vs 6.0; the minor bump
8
+ # introduces PackStream V2, whose only new type is UUID — a top-level
9
+ # value (marker 0xE0 + 16 raw bytes), not a struct. This is the one
10
+ # protocol version that supports it: pack/unpack the UUID codec here
11
+ # instead of raising like Protocol::Base (Feature:API:Type.UUID,
12
+ # Feature:Bolt:6.1).
13
+ class V61 < V6
14
+ def pack_uuid(packer, value) = packer.pack_uuid_value(value)
15
+
16
+ def unpack_uuid(unpacker) = unpacker.unpack_uuid_value
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ # Factory for the per-minor protocol handler matching the
7
+ # negotiated wire version. Lookup is exact (`major.minor`)
8
+ # because the Bolt handshake only ever returns a version the
9
+ # server actually supports — so we don't need fuzzy matching.
10
+ class ProtocolVersionHandler
11
+ HANDLERS = {
12
+ BoltVersion::V6_1.to_i => Protocol::V61,
13
+ BoltVersion::V6_0.to_i => Protocol::V6,
14
+ BoltVersion::V5_8.to_i => Protocol::V58,
15
+ BoltVersion::V5_7.to_i => Protocol::V57,
16
+ BoltVersion::V5_6.to_i => Protocol::V56,
17
+ BoltVersion::V5_5.to_i => Protocol::V55,
18
+ BoltVersion::V5_4.to_i => Protocol::V54,
19
+ BoltVersion::V5_3.to_i => Protocol::V53,
20
+ BoltVersion::V5_2.to_i => Protocol::V52,
21
+ BoltVersion::V5_1.to_i => Protocol::V51,
22
+ BoltVersion::V5_0.to_i => Protocol::V5,
23
+ BoltVersion::V4_4.to_i => Protocol::V44,
24
+ BoltVersion::V4_3.to_i => Protocol::V43,
25
+ BoltVersion::V4_2.to_i => Protocol::V4,
26
+ BoltVersion::V3_0.to_i => Protocol::V3
27
+ }.freeze
28
+
29
+ def self.for_version(connection, version_int)
30
+ version = BoltVersion.from_int(version_int)
31
+ klass = HANDLERS[version.to_i] ||
32
+ raise(Exceptions::ServiceUnavailableException,
33
+ "Unsupported Bolt protocol version: #{version}")
34
+ klass.new(connection, version)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ # Record buffer for one streaming result, with a high/low watermark autopull
7
+ # policy. Sits between the connection's reader (producer) and the cursor
8
+ # (consumer), and unifies two things under one mutex + condition variable:
9
+ # the record queue *and* the batch's "has_more promise".
10
+ #
11
+ # Records are delivered incrementally — pushed the instant the reader decodes
12
+ # them — so the cursor sees record 1 without waiting for the whole batch. The
13
+ # batch's terminating SUCCESS resolves the promise (`batch_complete`), which
14
+ # says whether the server has more. The cursor drives flow control:
15
+ #
16
+ # * after each record, once drained to/below the low watermark, it checks
17
+ # the promise (`pull_ready?`, non-blocking) and, if fulfilled with
18
+ # has_more, issues the next `PULL {n: fetch_size}` — prefetch overlap;
19
+ # * when it drains the buffer empty mid-stream, it `await`s — one wait that
20
+ # wakes on *either* the next record *or* the promise resolving. That
21
+ # shared wait is the crux: mid-batch it wakes on a record (incremental
22
+ # delivery preserved), at batch-end it wakes on the promise (so it PULLs
23
+ # the next batch instead of blocking forever on a record that, the SUCCESS
24
+ # having no payload, will never come).
25
+ #
26
+ # The cursor is the sole writer (issues every PULL/DISCARD); the reader only
27
+ # ever fills. All sync primitives are stdlib + scheduler-aware, so a cursor
28
+ # running as a fiber under a host reactor yields rather than blocking the
29
+ # thread. See docs/unified-pipeline.md.
30
+ class RecordBuffer
31
+ attr_reader :fetch_size, :high_watermark, :low_watermark
32
+
33
+ def initialize(fetch_size:, high_watermark: nil, low_watermark: nil)
34
+ @fetch_size = fetch_size
35
+ # Defaults: refill under half of ~2 batches held. fetch_size -1 ("pull
36
+ # all in one batch") never paginates, so just size the watermarks for a
37
+ # steady single-batch handoff.
38
+ @high_watermark = high_watermark || (fetch_size.positive? ? fetch_size * 2 : 1000)
39
+ @low_watermark = low_watermark || [@high_watermark / 2, 1].max
40
+ @mutex = Mutex.new
41
+ @cv = ConditionVariable.new
42
+ @records = [] # incrementally filled by the reader, drained by the cursor
43
+ @has_more = true # server may have more records for this stream
44
+ @pull_in_flight = true # the first PULL is pipelined with RUN — promise unfulfilled
45
+ @ended = false # terminal SUCCESS/IGNORED seen → no more records
46
+ @error = nil # stream failed; re-raised to the cursor after buffered records
47
+ @summary = nil # terminating SUCCESS metadata
48
+ end
49
+
50
+ # --- Producer (reader) side -----------------------------------------
51
+
52
+ # Append a decoded record and wake a cursor parked in #await. Never blocks
53
+ # (unbounded); the cursor's watermark bounds how much the server ships.
54
+ def push_record(record)
55
+ @mutex.synchronize do
56
+ @records.push(record)
57
+ @cv.broadcast
58
+ end
59
+ end
60
+
61
+ # The current batch's terminal SUCCESS arrived — resolve the promise.
62
+ # `has_more` says whether to keep paging; either way no PULL is in flight,
63
+ # so the cursor may issue the next once it drains past the low watermark.
64
+ # Wake a cursor parked in #await waiting for exactly this.
65
+ def batch_complete(has_more:)
66
+ @mutex.synchronize do
67
+ @has_more = has_more
68
+ @pull_in_flight = false
69
+ @cv.broadcast
70
+ end
71
+ end
72
+
73
+ # Final batch (terminating SUCCESS without has_more, or IGNORED): stash the
74
+ # summary, mark ended, and wake the cursor.
75
+ def finish(summary = nil)
76
+ @mutex.synchronize do
77
+ @summary = summary
78
+ @ended = true
79
+ @has_more = false
80
+ @pull_in_flight = false
81
+ @cv.broadcast
82
+ end
83
+ end
84
+
85
+ # The stream failed: arm the error the cursor re-raises *after* it drains
86
+ # the records already delivered (records that preceded the failure are
87
+ # valid), and wake it.
88
+ def fail(error)
89
+ @mutex.synchronize do
90
+ @error ||= error
91
+ @ended = true
92
+ @has_more = false
93
+ @pull_in_flight = false
94
+ @cv.broadcast
95
+ end
96
+ end
97
+
98
+ # The terminating SUCCESS's metadata (nil until finished / on failure).
99
+ def summary = @mutex.synchronize { @summary }
100
+
101
+ # --- Consumer (cursor) side -----------------------------------------
102
+
103
+ # Non-blocking: the next buffered record, or :empty when none is buffered
104
+ # yet, or :ended once the stream is drained and terminal. Buffered records
105
+ # are handed out before a stream failure is raised (they preceded it).
106
+ def try_shift
107
+ @mutex.synchronize do
108
+ return @records.shift unless @records.empty?
109
+ raise @error if @error
110
+
111
+ @ended ? :ended : :empty
112
+ end
113
+ end
114
+
115
+ # Block (colorlessly) until there's something to re-evaluate: a record was
116
+ # delivered, the batch completed (promise resolved), or the stream
117
+ # ended/failed. Called only when the cursor has drained the buffer empty
118
+ # and a PULL is still outstanding (records coming, or its SUCCESS pending).
119
+ def await
120
+ @mutex.synchronize do
121
+ @cv.wait(@mutex) while @records.empty? && !@ended && @error.nil? && @pull_in_flight
122
+ end
123
+ end
124
+
125
+ def empty? = @mutex.synchronize { @records.empty? }
126
+ def size = @mutex.synchronize { @records.size }
127
+ def ended? = @mutex.synchronize { @ended }
128
+ def has_more? = @mutex.synchronize { @has_more }
129
+
130
+ # --- Autopull policy (cursor side) ----------------------------------
131
+
132
+ # True when the cursor should issue the next PULL: the batch promise is
133
+ # fulfilled (none in flight) with has_more, and the buffer has drained
134
+ # to/below the low watermark.
135
+ def pull_ready? = @mutex.synchronize { @has_more && !@pull_in_flight && @records.size <= @low_watermark }
136
+
137
+ # The cursor issued the next PULL — the promise is unfulfilled again; don't
138
+ # issue another until this batch completes.
139
+ def note_pull_issued = @mutex.synchronize { @pull_in_flight = true }
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ # The wire handler for a streaming PULL/DISCARD: the dedicated reader routes
7
+ # the result's replies here, and it fills the result's RecordBuffer.
8
+ #
9
+ # Records are forwarded to the buffer incrementally — the instant each is
10
+ # decoded — so the cursor can read record 1 without waiting for the whole
11
+ # batch. The batch's terminating SUCCESS resolves the buffer's has_more
12
+ # promise (batch_complete) or ends the stream (finish); a FAILURE/IGNORED
13
+ # ends it too. The cursor consumes the buffer and drives follow-up PULLs —
14
+ # this side only fills.
15
+ #
16
+ # Runs in the reader thread; same visitor interface as @collector, so the
17
+ # wire dispatches to it identically.
18
+ class StreamHandler
19
+ def initialize(buffer)
20
+ @buffer = buffer
21
+ end
22
+
23
+ def on_record(message)
24
+ @buffer.push_record(message)
25
+ end
26
+
27
+ def on_success(message)
28
+ if message.metadata[:has_more]
29
+ @buffer.batch_complete(has_more: true)
30
+ else
31
+ @buffer.finish(message.metadata)
32
+ end
33
+ end
34
+
35
+ def on_failure(message)
36
+ # Records already delivered stay readable; the cursor hits this error
37
+ # once it drains them (records that preceded the failure are valid).
38
+ @buffer.fail(message.to_exception)
39
+ end
40
+
41
+ def on_ignored(_message)
42
+ @buffer.finish
43
+ end
44
+
45
+ # Connection failure fan-out (see Connection#fan_out / Wire#fail_pending):
46
+ # surface the error to a cursor parked in the buffer.
47
+ def fail(error)
48
+ @buffer.fail(error)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Neo4j
4
+ module Driver
5
+ module Bolt
6
+ # Resolves the driver's URI scheme + user options into an
7
+ # OpenSSL::SSL::SSLContext, or nil for plaintext. Mirrors Java's
8
+ # TrustStrategy modes:
9
+ #
10
+ # :system_certificates — verify cert chain against system roots
11
+ # + verify hostname. Default for +s schemes.
12
+ # :all_certificates — encrypted but skip both checks. Default
13
+ # for +ssc schemes. Useful for self-signed
14
+ # dev servers; not for production.
15
+ # :custom_certificates — verify against an explicit CA bundle.
16
+ #
17
+ # Hostname verification rides along with peer verification — turning
18
+ # peer verification off (:all_certificates) implicitly turns off
19
+ # hostname check too, which is why +ssc exists.
20
+ class TlsConfig
21
+ # +s / +ssc are scheme-level encryption opt-in (mirrors
22
+ # Driver::ENCRYPTED_SCHEMES). +ssc additionally implies
23
+ # trust-all — the whole point of the "self-signed" suffix.
24
+ ENCRYPTED_SCHEMES = Driver::ENCRYPTED_SCHEMES
25
+ TRUST_ALL_SCHEMES = %w[bolt+ssc neo4j+ssc].freeze
26
+
27
+ def initialize(uri:, options:)
28
+ @uri = uri
29
+ @options = options
30
+ end
31
+
32
+ # nil ⇒ plaintext socket; SSLContext ⇒ wrap.
33
+ def ssl_context
34
+ return nil unless encrypted?
35
+
36
+ ctx = OpenSSL::SSL::SSLContext.new
37
+ ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
38
+ apply_trust(ctx)
39
+ apply_client_certificate(ctx)
40
+ ctx
41
+ end
42
+
43
+ def encrypted?
44
+ ENCRYPTED_SCHEMES.include?(@uri.scheme) || @options[:encryption] == true
45
+ end
46
+
47
+ # Whether the SSLSocket should verify the server hostname after
48
+ # the TLS handshake. False for the trust-all path; true otherwise.
49
+ def verify_hostname?
50
+ encrypted? && resolved_strategy != :all_certificates
51
+ end
52
+
53
+ private
54
+
55
+ # Mutual TLS (Feature:API:SSLClientCertificate): present the client
56
+ # certificate the manager currently holds. Polled per connection so a
57
+ # rotated certificate takes effect on the next connect; nil manager or
58
+ # nil certificate leaves the context client-cert-free.
59
+ def apply_client_certificate(ctx)
60
+ certificate = @options[:client_certificate_manager]&.get_client_certificate
61
+ return unless certificate
62
+
63
+ ctx.cert = OpenSSL::X509::Certificate.new(File.read(certificate.certfile))
64
+ # PKey.read handles both encrypted (password used) and unencrypted
65
+ # (password ignored) PEM keys. Pass "" rather than nil for a missing
66
+ # password so an encrypted key raises PKeyError instead of blocking
67
+ # the thread on OpenSSL's interactive stdin passphrase prompt.
68
+ ctx.key = OpenSSL::PKey.read(File.read(certificate.keyfile), certificate.password || '')
69
+ end
70
+
71
+ def apply_trust(ctx)
72
+ case resolved_strategy
73
+ when :all_certificates
74
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
75
+ when :custom_certificates
76
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
77
+ ctx.cert_store = custom_cert_store
78
+ else # :system_certificates
79
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
80
+ ctx.cert_store = OpenSSL::X509::Store.new.tap(&:set_default_paths)
81
+ end
82
+ end
83
+
84
+ # Custom-trust mode without any `cert_files` paths would produce
85
+ # a VERIFY_PEER context with an empty store — every connection
86
+ # would fail with an opaque OpenSSL error. Catch this at config
87
+ # time with a clear message instead.
88
+ def custom_cert_store
89
+ paths = cert_files
90
+ if paths.empty?
91
+ raise ArgumentError,
92
+ 'trust_strategy :trust_custom_certificates requires at least one path in :cert_files'
93
+ end
94
+
95
+ paths.each_with_object(OpenSSL::X509::Store.new) do |path, store|
96
+ store.add_file(path)
97
+ end
98
+ end
99
+
100
+ # Resolves trust-strategy option → internal symbol. Falls back
101
+ # to the URI-implied default (+ssc → all-certs, anything else
102
+ # → system-certs) when no explicit option was given.
103
+ def resolved_strategy
104
+ return uri_default unless explicit_strategy
105
+
106
+ case explicit_strategy
107
+ when :trust_system_certificates then :system_certificates
108
+ when :trust_all_certificates then :all_certificates
109
+ when :trust_custom_certificates then :custom_certificates
110
+ else
111
+ raise ArgumentError, "Unknown trust_strategy: #{explicit_strategy.inspect}"
112
+ end
113
+ end
114
+
115
+ def uri_default
116
+ TRUST_ALL_SCHEMES.include?(@uri.scheme) ? :all_certificates : :system_certificates
117
+ end
118
+
119
+ def explicit_strategy
120
+ @options.dig(:trust_strategy, :strategy)
121
+ end
122
+
123
+ def cert_files
124
+ Array(@options.dig(:trust_strategy, :cert_files))
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end