onebusaway-sdk 0.1.0.pre.alpha.205 → 0.1.0.pre.alpha.206

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: 429ccc3f00c50a5b1de30b48e7f6b1b050bd1b17c397a6a752c8e9e46d469184
4
- data.tar.gz: fa2d71c19e522f6baa5d9b11afdd5876707e2197791d3dff8c3e1d79c82029c2
3
+ metadata.gz: 75896ea053e81f2065eafd3e5dca608343251ec36a36f651f784fee694daf5a8
4
+ data.tar.gz: 548e74e04af38ba29427750afe087efe67582b4f25af60493a331abb656c74ac
5
5
  SHA512:
6
- metadata.gz: e86dc1479c36ee96fc7ac234fbd5df45f67590f5f3854a2bf20532e6624b8e423b56ae34002f7bdfa105dddbfab46c8df07b3ab2743ecdd442518fde9d2cd422
7
- data.tar.gz: a13e694db85c0bae734ca456560d1c16e107bb92caadc322154c69e14a1a8d9a8456e76ea6f1060c93192c5d2c4179ffcde3b862e047844c424b4c92dd804a2d
6
+ metadata.gz: 63c34916992cb26b12ec8d3ad2a067608d5d2fd912e916cc6db8f340ba89a11f5ae3d03dfa2de2dee6bb2bf8f855f6313cda9a7c7aa7a1d76351d8200609ddc6
7
+ data.tar.gz: 33b8ddc65ca3dd17ba252facdb4515c8f41508b9ad1f0ecbee755957bb2dd42b25d108e795ecfc098339b22ea61c47174532679545971c88787e3153dc4ab6ab
@@ -28,7 +28,7 @@ module OnebusawaySDK
28
28
  # @raise [ArgumentError]
29
29
  #
30
30
  def validate!(req)
31
- keys = [:method, :path, :query, :headers, :body, :unwrap, :page, :model, :options]
31
+ keys = [:method, :path, :query, :headers, :body, :unwrap, :page, :stream, :model, :options]
32
32
  case req
33
33
  in Hash
34
34
  req.each_key do |k|
@@ -201,6 +201,8 @@ module OnebusawaySDK
201
201
  #
202
202
  # @option req [Class, nil] :page
203
203
  #
204
+ # @option req [Class, nil] :stream
205
+ #
204
206
  # @option req [OnebusawaySDK::Converter, Class, nil] :model
205
207
  #
206
208
  # @param opts [Hash{Symbol=>Object}] .
@@ -318,7 +320,7 @@ module OnebusawaySDK
318
320
  # @param send_retry_header [Boolean]
319
321
  #
320
322
  # @raise [OnebusawaySDK::APIError]
321
- # @return [Array(Net::HTTPResponse, Enumerable)]
323
+ # @return [Array(Integer, Net::HTTPResponse, Enumerable)]
322
324
  #
323
325
  private def send_request(request, redirect_count:, retry_count:, send_retry_header:)
324
326
  url, headers, max_retries, timeout = request.fetch_values(:url, :headers, :max_retries, :timeout)
@@ -341,7 +343,7 @@ module OnebusawaySDK
341
343
 
342
344
  case status
343
345
  in ..299
344
- [response, stream]
346
+ [status, response, stream]
345
347
  in 300..399 if redirect_count >= self.class::MAX_REDIRECTS
346
348
  message = "Failed to complete the request within #{self.class::MAX_REDIRECTS} redirects."
347
349
 
@@ -359,13 +361,15 @@ module OnebusawaySDK
359
361
  )
360
362
  in OnebusawaySDK::APIConnectionError if retry_count >= max_retries
361
363
  raise status
362
- in (400..) if retry_count >= max_retries || (response && !self.class.should_retry?(
363
- status,
364
- headers: response
365
- ))
364
+ in (400..) if retry_count >= max_retries || !self.class.should_retry?(status, headers: response)
366
365
  decoded = OnebusawaySDK::Util.decode_content(response, stream: stream, suppress_error: true)
367
366
 
368
- stream.each { srv_fault ? break : next }
367
+ if srv_fault
368
+ OnebusawaySDK::Util.close_fused!(stream)
369
+ else
370
+ stream.each { next }
371
+ end
372
+
369
373
  raise OnebusawaySDK::APIStatusError.for(
370
374
  url: url,
371
375
  status: status,
@@ -376,7 +380,11 @@ module OnebusawaySDK
376
380
  in (400..) | OnebusawaySDK::APIConnectionError
377
381
  delay = retry_delay(response, retry_count: retry_count)
378
382
 
379
- stream&.each { srv_fault ? break : next }
383
+ if srv_fault
384
+ OnebusawaySDK::Util.close_fused!(stream)
385
+ else
386
+ stream&.each { next }
387
+ end
380
388
  sleep(delay)
381
389
 
382
390
  send_request(
@@ -388,48 +396,6 @@ module OnebusawaySDK
388
396
  end
389
397
  end
390
398
 
391
- # @private
392
- #
393
- # @param req [Hash{Symbol=>Object}] .
394
- #
395
- # @option req [Symbol] :method
396
- #
397
- # @option req [String, Array<String>] :path
398
- #
399
- # @option req [Hash{String=>Array<String>, String, nil}, nil] :query
400
- #
401
- # @option req [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}, nil] :headers
402
- #
403
- # @option req [Object, nil] :body
404
- #
405
- # @option req [Symbol, nil] :unwrap
406
- #
407
- # @option req [Class, nil] :page
408
- #
409
- # @option req [OnebusawaySDK::Converter, Class, nil] :model
410
- #
411
- # @option req [OnebusawaySDK::RequestOptions, Hash{Symbol=>Object}, nil] :options
412
- #
413
- # @param headers [Hash{String=>String}, Net::HTTPHeader]
414
- #
415
- # @param stream [Enumerable]
416
- #
417
- # @return [Object]
418
- #
419
- private def parse_response(req, headers:, stream:)
420
- decoded = OnebusawaySDK::Util.decode_content(headers, stream: stream)
421
- unwrapped = OnebusawaySDK::Util.dig(decoded, req[:unwrap])
422
-
423
- case [req[:page], req.fetch(:model, OnebusawaySDK::Unknown)]
424
- in [Class => page, _]
425
- page.new(client: self, req: req, headers: headers, unwrapped: unwrapped)
426
- in [nil, Class | OnebusawaySDK::Converter => model]
427
- OnebusawaySDK::Converter.coerce(model, unwrapped)
428
- in [nil, nil]
429
- unwrapped
430
- end
431
- end
432
-
433
399
  # Execute the request specified by `req`. This is the method that all resource
434
400
  # methods call into.
435
401
  #
@@ -449,6 +415,8 @@ module OnebusawaySDK
449
415
  #
450
416
  # @option req [Class, nil] :page
451
417
  #
418
+ # @option req [Class, nil] :stream
419
+ #
452
420
  # @option req [OnebusawaySDK::Converter, Class, nil] :model
453
421
  #
454
422
  # @option req [OnebusawaySDK::RequestOptions, Hash{Symbol=>Object}, nil] :options
@@ -458,19 +426,31 @@ module OnebusawaySDK
458
426
  #
459
427
  def request(req)
460
428
  self.class.validate!(req)
429
+ model = req.fetch(:model) { OnebusawaySDK::Unknown }
461
430
  opts = req[:options].to_h
462
431
  OnebusawaySDK::RequestOptions.validate!(opts)
463
432
  request = build_request(req.except(:options), opts)
433
+ url = request.fetch(:url)
464
434
 
465
435
  # Don't send the current retry count in the headers if the caller modified the header defaults.
466
436
  send_retry_header = request.fetch(:headers)["x-stainless-retry-count"] == "0"
467
- response, stream = send_request(
437
+ status, response, stream = send_request(
468
438
  request,
469
439
  redirect_count: 0,
470
440
  retry_count: 0,
471
441
  send_retry_header: send_retry_header
472
442
  )
473
- parse_response(req, headers: response, stream: stream)
443
+
444
+ decoded = OnebusawaySDK::Util.decode_content(response, stream: stream)
445
+ case req
446
+ in { stream: Class => st }
447
+ st.new(model: model, url: url, status: status, response: response, messages: decoded)
448
+ in { page: Class => page }
449
+ page.new(client: self, req: req, headers: response, unwrapped: decoded)
450
+ else
451
+ unwrapped = OnebusawaySDK::Util.dig(decoded, req[:unwrap])
452
+ OnebusawaySDK::Converter.coerce(model, unwrapped)
453
+ end
474
454
  end
475
455
 
476
456
  # @return [String]
@@ -99,11 +99,12 @@ module OnebusawaySDK
99
99
  # @param body [Object, nil]
100
100
  # @param request [nil]
101
101
  # @param response [nil]
102
+ # @param message [String, nil]
102
103
  #
103
104
  # @return [OnebusawaySDK::APIStatusError]
104
105
  #
105
- def self.for(url:, status:, body:, request:, response:)
106
- kwargs = {url: url, status: status, body: body, request: request, response: response}
106
+ def self.for(url:, status:, body:, request:, response:, message: nil)
107
+ kwargs = {url: url, status: status, body: body, request: request, response: response, message: message}
107
108
 
108
109
  case status
109
110
  in 400
@@ -131,16 +131,23 @@ module OnebusawaySDK
131
131
  req = self.class.build_request(request)
132
132
 
133
133
  eof = false
134
+ finished = false
134
135
  enum = Enumerator.new do |y|
135
136
  with_pool(url) do |conn|
137
+ next if finished
138
+
136
139
  self.class.calibrate_socket_timeout(conn, deadline)
137
140
  conn.start unless conn.started?
138
141
 
139
142
  self.class.calibrate_socket_timeout(conn, deadline)
140
143
  conn.request(req) do |rsp|
141
144
  y << [conn, rsp]
145
+ break if finished
146
+
142
147
  rsp.read_body do |bytes|
143
148
  y << bytes
149
+ break if finished
150
+
144
151
  self.class.calibrate_socket_timeout(conn, deadline)
145
152
  end
146
153
  eof = true
@@ -148,16 +155,14 @@ module OnebusawaySDK
148
155
  end
149
156
  end
150
157
 
151
- # need to protect the `Enumerator` against `#.rewind`
152
- fused = false
153
158
  conn, response = enum.next
154
- body = Enumerator.new do |y|
155
- next if fused
156
-
157
- fused = true
158
- loop { y << enum.next }
159
- ensure
160
- conn.finish if !eof && conn.started?
159
+ body = OnebusawaySDK::Util.fused_enum(enum) do
160
+ finished = true
161
+ tap do
162
+ enum.next
163
+ rescue StopIteration
164
+ end
165
+ conn.finish if !eof && conn&.started?
161
166
  end
162
167
  [response, (response.body = body)]
163
168
  end
@@ -496,6 +496,9 @@ module OnebusawaySDK
496
496
  #
497
497
  def decode_content(headers, stream:, suppress_error: false)
498
498
  case headers["content-type"]
499
+ in %r{^text/event-stream}
500
+ lines = enum_lines(stream)
501
+ parse_sse(lines)
499
502
  in %r{^application/json}
500
503
  json = stream.to_a.join
501
504
  begin
@@ -512,6 +515,121 @@ module OnebusawaySDK
512
515
  end
513
516
  end
514
517
  end
518
+
519
+ class << self
520
+ # @private
521
+ #
522
+ # https://doc.rust-lang.org/std/iter/trait.FusedIterator.html
523
+ #
524
+ # @param enum [Enumerable]
525
+ # @param close [Proc]
526
+ #
527
+ # @return [Enumerable]
528
+ #
529
+ def fused_enum(enum, &close)
530
+ fused = false
531
+ iter = Enumerator.new do |y|
532
+ next if fused
533
+
534
+ fused = true
535
+ loop { y << enum.next }
536
+ ensure
537
+ close&.call
538
+ close = nil
539
+ end
540
+
541
+ iter.define_singleton_method(:rewind) do
542
+ fused = true
543
+ self
544
+ end
545
+ iter
546
+ end
547
+
548
+ # @private
549
+ #
550
+ # @param enum [Enumerable, nil]
551
+ #
552
+ def close_fused!(enum)
553
+ return unless enum.is_a?(Enumerator)
554
+
555
+ # rubocop:disable Lint/UnreachableLoop
556
+ enum.rewind.each { break }
557
+ # rubocop:enable Lint/UnreachableLoop
558
+ end
559
+
560
+ # @private
561
+ #
562
+ # @param enum [Enumerable, nil]
563
+ # @param blk [Proc]
564
+ #
565
+ def chain_fused(enum, &blk)
566
+ iter = Enumerator.new { blk.call(_1) }
567
+ fused_enum(iter) { close_fused!(enum) }
568
+ end
569
+ end
570
+
571
+ class << self
572
+ # @private
573
+ #
574
+ # @param enum [Enumerable]
575
+ #
576
+ # @return [Enumerable]
577
+ #
578
+ def enum_lines(enum)
579
+ chain_fused(enum) do |y|
580
+ buffer = String.new
581
+ enum.each do |row|
582
+ buffer << row
583
+ while (idx = buffer.index("\n"))
584
+ y << buffer.slice!(..idx)
585
+ end
586
+ end
587
+ y << buffer unless buffer.empty?
588
+ end
589
+ end
590
+
591
+ # @private
592
+ #
593
+ # https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream
594
+ #
595
+ # @param lines [Enumerable]
596
+ #
597
+ # @return [Hash{Symbol=>Object}]
598
+ #
599
+ def parse_sse(lines)
600
+ chain_fused(lines) do |y|
601
+ blank = {event: nil, data: nil, id: nil, retry: nil}
602
+ current = {}
603
+
604
+ lines.each do |line|
605
+ case line.strip
606
+ in ""
607
+ next if current.empty?
608
+ y << {**blank, **current}
609
+ current = {}
610
+ in /^:/
611
+ next
612
+ in /^([^:]+):\s?(.*)$/
613
+ _, field, value = Regexp.last_match.to_a
614
+ case field
615
+ in "event"
616
+ current.merge!(event: value)
617
+ in "data"
618
+ (current[:data] ||= String.new) << value << "\n"
619
+ in "id" unless value.include?("\0")
620
+ current.merge!(id: value)
621
+ in "retry" if /^\d+$/ =~ value
622
+ current.merge!(retry: Integer(value))
623
+ else
624
+ end
625
+ else
626
+ end
627
+ end
628
+
629
+ y << {**blank, **current} unless current.empty?
630
+ end
631
+ end
632
+ end
515
633
  end
516
634
 
517
635
  # rubocop:enable Metrics/ModuleLength
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OnebusawaySDK
4
- VERSION = "0.1.0-alpha.205"
4
+ VERSION = "0.1.0-alpha.206"
5
5
  end
@@ -21,7 +21,8 @@ module OnebusawaySDK
21
21
  ),
22
22
  body: T.nilable(T.anything),
23
23
  unwrap: T.nilable(Symbol),
24
- page: T.nilable(T::Class[OnebusawaySDK::BaseModel]),
24
+ page: T.nilable(T::Class[OnebusawaySDK::BasePage[OnebusawaySDK::BaseModel]]),
25
+ stream: T.nilable(T::Class[T.anything]),
25
26
  model: T.nilable(OnebusawaySDK::Converter::Input),
26
27
  options: T.nilable(T.any(OnebusawaySDK::RequestOptions, T::Hash[Symbol, T.anything]))
27
28
  }
@@ -122,22 +123,11 @@ module OnebusawaySDK
122
123
  retry_count: Integer,
123
124
  send_retry_header: T::Boolean
124
125
  )
125
- .returns([Net::HTTPResponse, T::Enumerable[String]])
126
+ .returns([Integer, Net::HTTPResponse, T::Enumerable[String]])
126
127
  end
127
128
  private def send_request(request, redirect_count:, retry_count:, send_retry_header:)
128
129
  end
129
130
 
130
- sig do
131
- params(
132
- req: OnebusawaySDK::BaseClient::RequestComponentsShape,
133
- headers: T.any(T::Hash[String, String], Net::HTTPHeader),
134
- stream: T::Enumerable[String]
135
- )
136
- .returns(T.anything)
137
- end
138
- private def parse_response(req, headers:, stream:)
139
- end
140
-
141
131
  sig do
142
132
  params(
143
133
  method: Symbol,
@@ -155,7 +145,8 @@ module OnebusawaySDK
155
145
  ),
156
146
  body: T.nilable(T.anything),
157
147
  unwrap: T.nilable(Symbol),
158
- page: T.nilable(T::Class[OnebusawaySDK::BaseModel]),
148
+ page: T.nilable(T::Class[OnebusawaySDK::BasePage[OnebusawaySDK::BaseModel]]),
149
+ stream: T.nilable(T::Class[T.anything]),
159
150
  model: T.nilable(OnebusawaySDK::Converter::Input),
160
151
  options: T.nilable(T.any(OnebusawaySDK::RequestOptions, T::Hash[Symbol, T.anything]))
161
152
  )
@@ -169,6 +160,7 @@ module OnebusawaySDK
169
160
  body: nil,
170
161
  unwrap: nil,
171
162
  page: nil,
163
+ stream: nil,
172
164
  model: OnebusawaySDK::Unknown,
173
165
  options: {}
174
166
  )
@@ -85,11 +85,12 @@ module OnebusawaySDK
85
85
  status: Integer,
86
86
  body: T.nilable(Object),
87
87
  request: NilClass,
88
- response: NilClass
88
+ response: NilClass,
89
+ message: T.nilable(String)
89
90
  )
90
91
  .returns(T.attached_class)
91
92
  end
92
- def self.for(url:, status:, body:, request:, response:)
93
+ def self.for(url:, status:, body:, request:, response:, message: nil)
93
94
  end
94
95
 
95
96
  sig { returns(Integer) }
@@ -135,5 +135,34 @@ module OnebusawaySDK
135
135
  end
136
136
  def self.decode_content(headers, stream:, suppress_error: false)
137
137
  end
138
+
139
+ sig { params(enum: T::Enumerable[T.anything], close: T.proc.void).returns(T::Enumerable[T.anything]) }
140
+ def self.fused_enum(enum, &close)
141
+ end
142
+
143
+ sig { params(enum: T.nilable(T::Enumerable[T.anything])).void }
144
+ def self.close_fused!(enum)
145
+ end
146
+
147
+ sig do
148
+ params(
149
+ enum: T.nilable(T::Enumerable[T.anything]),
150
+ blk: T.proc.params(arg0: Enumerator::Yielder).void
151
+ ).void
152
+ end
153
+ def self.chain_fused(enum, &blk)
154
+ end
155
+
156
+ SSEMessage = T.type_alias do
157
+ {event: T.nilable(String), data: T.nilable(String), id: T.nilable(String), retry: T.nilable(Integer)}
158
+ end
159
+
160
+ sig { params(enum: T::Enumerable[String]).returns(T::Enumerable[String]) }
161
+ def self.enum_lines(enum)
162
+ end
163
+
164
+ sig { params(lines: T::Enumerable[String]).returns(OnebusawaySDK::Util::SSEMessage) }
165
+ def self.parse_sse(lines)
166
+ end
138
167
  end
139
168
  end
@@ -1,5 +1,5 @@
1
1
  # typed: strong
2
2
 
3
3
  module OnebusawaySDK
4
- VERSION = "0.1.0-alpha.205"
4
+ VERSION = "0.1.0-alpha.206"
5
5
  end
@@ -11,6 +11,7 @@ module OnebusawaySDK
11
11
  body: top?,
12
12
  unwrap: Symbol?,
13
13
  page: Class?,
14
+ stream: Class?,
14
15
  model: OnebusawaySDK::Converter::input?,
15
16
  options: OnebusawaySDK::request_opts?
16
17
  }
@@ -78,13 +79,7 @@ module OnebusawaySDK
78
79
  redirect_count: Integer,
79
80
  retry_count: Integer,
80
81
  send_retry_header: bool
81
- ) -> [top, Enumerable[String]]
82
-
83
- private def parse_response: (
84
- OnebusawaySDK::BaseClient::request_components req,
85
- headers: ::Hash[String, String],
86
- stream: Enumerable[String]
87
- ) -> top
82
+ ) -> [Integer, top, Enumerable[String]]
88
83
 
89
84
  def request:
90
85
  (
@@ -97,6 +92,7 @@ module OnebusawaySDK
97
92
  body: top?,
98
93
  unwrap: Symbol?,
99
94
  page: Class?,
95
+ stream: Class?,
100
96
  model: OnebusawaySDK::Converter::input?,
101
97
  options: OnebusawaySDK::request_opts?
102
98
  ) -> top
@@ -51,7 +51,8 @@ module OnebusawaySDK
51
51
  status: Integer,
52
52
  body: Object?,
53
53
  request: nil,
54
- response: nil
54
+ response: nil,
55
+ message: String?
55
56
  ) -> instance
56
57
 
57
58
  def initialize: (
@@ -88,5 +88,24 @@ module OnebusawaySDK
88
88
  stream: Enumerable[String],
89
89
  suppress_error: bool
90
90
  ) -> top
91
+
92
+ def self?.fused_enum: (Enumerable[top] enum) { -> void } -> Enumerable[top]
93
+
94
+ def self?.close_fused!: (Enumerable[top]? enum) -> void
95
+
96
+ def self?.chain_fused: (
97
+ Enumerable[top]? enum
98
+ ) {
99
+ (Enumerator::Yielder arg0) -> void
100
+ } -> void
101
+
102
+ type sse_message =
103
+ { event: String?, data: String?, id: String?, retry: Integer? }
104
+
105
+ def self?.enum_lines: (Enumerable[String] enum) -> Enumerable[String]
106
+
107
+ def self?.parse_sse: (
108
+ Enumerable[String] lines
109
+ ) -> OnebusawaySDK::Util::sse_message
91
110
  end
92
111
  end
@@ -1,3 +1,3 @@
1
1
  module OnebusawaySDK
2
- VERSION: "0.1.0-alpha.204"
2
+ VERSION: "0.1.0-alpha.205"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onebusaway-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.alpha.205
4
+ version: 0.1.0.pre.alpha.206
5
5
  platform: ruby
6
6
  authors:
7
7
  - Onebusaway SDK
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-05 00:00:00.000000000 Z
11
+ date: 2025-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool