ld-eventsource 2.2.6 → 2.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1011203906e4edf8d237499d75edc29f0c4eb4917189941fd02e9953492e5f77
4
- data.tar.gz: e2f0bfa715c896259f51c70f84f8bd3640959f7821228813c304222292a50445
3
+ metadata.gz: 56eca88c610f3aa1f572426034422f66f343ce30553c9d2e281462c4f3efe831
4
+ data.tar.gz: a9719f1e29695c0468c8b745239feb71041d5735e32f071fd77873866518bad5
5
5
  SHA512:
6
- metadata.gz: 985d8ed3a900de96dfb99bc582227903f727a097dc53826f23062f4b8585f3b76e1300381eb43703eb15f33256e26433ffb884d036c09af0e667780e7040767a
7
- data.tar.gz: 5dd455b911c275cdc98db3dbff4fd70dce1b7b6ccada654053e79639aa8351552e466b8574ce6de97cab875f5f8c7448c957ce1a33af3822f86e89ce836ba43b
6
+ metadata.gz: 2daad080ae032ab394dd4700e6bc22d20d167aca0e0a7ba9f74b41544ff0c5232cb0d34b6803fdc09342d95608732bea6c9ee7cef87bc912fef9a8ab10ccfb26
7
+ data.tar.gz: 520224cf097791d2942ed0662dc29d94bff02c979fdebde479186efb21dbfa052aa80eee62779be723db2c918a9dd34a19ab4eea343453b7e114524a3dc23eb5
@@ -49,6 +49,9 @@ module SSE
49
49
  # The default value for `reconnect_reset_interval` in {#initialize}.
50
50
  DEFAULT_RECONNECT_RESET_INTERVAL = 60
51
51
 
52
+ # The default HTTP method for requests.
53
+ DEFAULT_HTTP_METHOD = "GET"
54
+
52
55
  #
53
56
  # Creates a new SSE client.
54
57
  #
@@ -84,6 +87,16 @@ module SSE
84
87
  # @param socket_factory [#open] (nil) an optional factory object for creating sockets,
85
88
  # if you want to use something other than the default `TCPSocket`; it must implement
86
89
  # `open(uri, timeout)` to return a connected `Socket`
90
+ # @param method [String] ("GET") the HTTP method to use for requests
91
+ # @param payload [String, Hash, Array, #call] (nil) optional request payload. If payload is a Hash or
92
+ # an Array, it will be converted to JSON and sent as the request body. A string will be sent as a non-JSON
93
+ # request body. If payload responds to #call, it will be invoked on each
94
+ # request to generate the payload dynamically.
95
+ # @param retry_enabled [Boolean] (true) whether to retry connections after failures. If false, the client
96
+ # will exit after the first connection failure instead of attempting to reconnect.
97
+ # @param http_client_options [Hash] (nil) additional options to pass to
98
+ # the HTTP client, such as `socket_factory` or `proxy`. These settings will override
99
+ # the socket factory and proxy settings.
87
100
  # @yieldparam [Client] client the new client instance, before opening the connection
88
101
  #
89
102
  def initialize(uri,
@@ -95,17 +108,25 @@ module SSE
95
108
  last_event_id: nil,
96
109
  proxy: nil,
97
110
  logger: nil,
98
- socket_factory: nil)
111
+ socket_factory: nil,
112
+ method: DEFAULT_HTTP_METHOD,
113
+ payload: nil,
114
+ retry_enabled: true,
115
+ http_client_options: nil)
99
116
  @uri = URI(uri)
100
117
  @stopped = Concurrent::AtomicBoolean.new(false)
118
+ @retry_enabled = retry_enabled
101
119
 
102
120
  @headers = headers.clone
103
121
  @connect_timeout = connect_timeout
104
122
  @read_timeout = read_timeout
123
+ @method = method.to_s.upcase
124
+ @payload = payload
105
125
  @logger = logger || default_logger
106
- http_client_options = {}
126
+
127
+ base_http_client_options = {}
107
128
  if socket_factory
108
- http_client_options["socket_class"] = socket_factory
129
+ base_http_client_options["socket_class"] = socket_factory
109
130
  end
110
131
 
111
132
  if proxy
@@ -118,13 +139,18 @@ module SSE
118
139
  end
119
140
 
120
141
  if @proxy
121
- http_client_options["proxy"] = {
142
+ base_http_client_options["proxy"] = {
122
143
  :proxy_address => @proxy.host,
123
144
  :proxy_port => @proxy.port,
124
145
  }
146
+ base_http_client_options["proxy"][:proxy_username] = @proxy.user unless @proxy.user.nil?
147
+ base_http_client_options["proxy"][:proxy_password] = @proxy.password unless @proxy.password.nil?
125
148
  end
126
149
 
127
- @http_client = HTTP::Client.new(http_client_options)
150
+ options = http_client_options.is_a?(Hash) ? base_http_client_options.merge(http_client_options) : base_http_client_options
151
+
152
+ @http_client = HTTP::Client.new(options)
153
+ .follow
128
154
  .timeout({
129
155
  read: read_timeout,
130
156
  connect: connect_timeout,
@@ -246,6 +272,8 @@ module SSE
246
272
  rescue StandardError => e
247
273
  log_and_dispatch_error(e, "Unexpected error while closing stream")
248
274
  end
275
+
276
+ return close unless @retry_enabled
249
277
  end
250
278
  end
251
279
 
@@ -262,9 +290,7 @@ module SSE
262
290
  cxn = nil
263
291
  begin
264
292
  @logger.info { "Connecting to event stream at #{@uri}" }
265
- cxn = @http_client.request("GET", @uri, {
266
- headers: build_headers,
267
- })
293
+ cxn = @http_client.request(@method, @uri, build_opts)
268
294
  if cxn.status.code == 200
269
295
  content_type = cxn.content_type.mime_type
270
296
  if content_type && content_type.start_with?("text/event-stream")
@@ -358,5 +384,18 @@ module SSE
358
384
  h['Last-Event-Id'] = @last_id if !@last_id.nil? && @last_id != ""
359
385
  h.merge(@headers)
360
386
  end
387
+
388
+ def build_opts
389
+ return {headers: build_headers} if @payload.nil?
390
+
391
+ # Resolve payload if it's callable
392
+ resolved_payload = @payload.respond_to?(:call) ? @payload.call : @payload
393
+
394
+ if resolved_payload.is_a?(Hash) || resolved_payload.is_a?(Array)
395
+ {headers: build_headers, json: resolved_payload}
396
+ else
397
+ {headers: build_headers, body: resolved_payload.to_s}
398
+ end
399
+ end
361
400
  end
362
401
  end
@@ -42,9 +42,14 @@ module SSE
42
42
 
43
43
  pos += 1 # skip colon
44
44
  pos += 1 if pos < line.length && line[pos] == ' ' # skip optional single space, per SSE spec
45
- line = line.slice(pos..-1)
45
+ value = line.slice(pos..-1)
46
46
 
47
- item = process_field(name, line)
47
+ item = process_field(name, value)
48
+ gen.yield item unless item.nil?
49
+ else
50
+ # Handle field with no colon - treat as having empty value
51
+ # According to SSE spec, a line like "data" should be treated as "data:"
52
+ item = process_field(line, "")
48
53
  gen.yield item unless item.nil?
49
54
  end
50
55
  end
@@ -1,3 +1,3 @@
1
1
  module SSE
2
- VERSION = "2.2.6" # x-release-please-version
2
+ VERSION = "2.3.0" # x-release-please-version
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ld-eventsource
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.6
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-15 00:00:00.000000000 Z
11
+ date: 2025-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger