Class: GetStreamRuby::Client

Inherits:
Object
  • Object
show all
Includes:
RequestLogging
Defined in:
lib/getstream_ruby/client.rb

Constant Summary collapse

AUTH_IAT_LEEWAY_SECONDS =

Backdate the JWT iat claim by this many seconds.

JWT timestamps are whole-second (RFC 7519 NumericDate), so Time.now.to_i truncates to the second. The server applies minimal forward leeway on iat, so stamping iat = now lets a small fraction of requests be rejected ("token used before issue at (iat)") whenever the caller's clock is even marginally ahead of the server and the truncation lands on a second boundary. Backdating absorbs that sub-second skew.

5

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = nil, api_key: nil, api_secret: nil, **options) ⇒ Client

Returns a new instance of Client.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/getstream_ruby/client.rb', line 43

def initialize(config = nil, api_key: nil, api_secret: nil, **options)
  # Overrides win over an explicit config, matching prior behavior. Only
  # fall back to GetStreamRuby.configuration when neither is given, so
  # that path (currently unimplemented) isn't evaluated needlessly.
  @configuration = if api_key || api_secret || !options.empty?
                     Configuration.with_overrides(
                       api_key: api_key,
                       api_secret: api_secret,
                       **options,
                     )
                   else
                     config || GetStreamRuby.configuration
                   end

  @configuration.validate!
  @connection = build_connection
  @configuration.log_pool_config_to(@configuration.logger)
  warn_log_bodies_enabled
end

Instance Attribute Details

#configurationObject (readonly)

Returns the value of attribute configuration.



41
42
43
# File 'lib/getstream_ruby/client.rb', line 41

def configuration
  @configuration
end

Instance Method Details

#chatGetStream::Generated::ChatClient

Returns The chat API client.

Returns:



85
86
87
# File 'lib/getstream_ruby/client.rb', line 85

def chat
  @chat ||= GetStream::Generated::ChatClient.new(self)
end

#commonGetStream::Generated::CommonClient

Returns The common API client.

Returns:



70
71
72
# File 'lib/getstream_ruby/client.rb', line 70

def common
  @common ||= GetStream::Generated::CommonClient.new(self)
end

#feed(feed_group_id, feed_id) ⇒ GetStream::Generated::Feed

Create an individual feed instance

Parameters:

  • feed_group_id (String)

    The feed group ID

  • feed_id (String)

    The feed ID

Returns:



98
99
100
# File 'lib/getstream_ruby/client.rb', line 98

def feed(feed_group_id, feed_id)
  GetStream::Generated::Feed.new(self, feed_group_id, feed_id)
end

#feed_resourceObject



63
64
65
# File 'lib/getstream_ruby/client.rb', line 63

def feed_resource
  @feed_resource ||= Resources::Feed.new(self)
end

#feedsGetStream::Generated::FeedsClient

Returns The feeds API client.

Returns:



75
76
77
# File 'lib/getstream_ruby/client.rb', line 75

def feeds
  @feeds ||= GetStream::Generated::FeedsClient.new(self)
end

#make_request(method, path, query_params: nil, body: nil, request_timeout: nil) ⇒ Object



198
199
200
201
202
203
204
205
206
207
# File 'lib/getstream_ruby/client.rb', line 198

def make_request(method, path, query_params: nil, body: nil, request_timeout: nil)
  # Handle query parameters
  if query_params && !query_params.empty?
    query_string = query_params.map { |k, v| "#{k}=#{v}" }.join('&')
    path = "#{path}?#{query_string}"
  end

  # Make the request
  request(method, path, body, request_timeout: request_timeout)
end

#moderationGetStream::Generated::ModerationClient

Returns The moderation API client.

Returns:



80
81
82
# File 'lib/getstream_ruby/client.rb', line 80

def moderation
  @moderation ||= GetStream::Generated::ModerationClient.new(self)
end

#parse_sns(notification_body) ⇒ Object

Decode + parse a Stream-delivered SNS notification body.

Accepts either the raw SNS HTTP envelope JSON or the pre-extracted Message string. Convenience wrapper around StreamChat::Webhook.parse_sns. No signature is required; SNS deliveries are authenticated via AWS IAM.



144
145
146
# File 'lib/getstream_ruby/client.rb', line 144

def parse_sns(notification_body)
  StreamChat::Webhook.parse_sns(notification_body)
end

#parse_sqs(message_body) ⇒ Object

Decode + parse a Stream-delivered SQS message body.

Convenience wrapper around StreamChat::Webhook.parse_sqs. No signature is required; SQS deliveries are authenticated via AWS IAM.



135
136
137
# File 'lib/getstream_ruby/client.rb', line 135

def parse_sqs(message_body)
  StreamChat::Webhook.parse_sqs(message_body)
end

#post(path, body = {}) ⇒ GetStreamRuby::StreamResponse

Returns The API response.

Parameters:

  • path (String)

    The API path

  • body (Hash) (defaults to: {})

    The request body

Returns:



151
152
153
# File 'lib/getstream_ruby/client.rb', line 151

def post(path, body = {})
  request(:post, path, body)
end

#verify_and_parse_webhook(body, signature) ⇒ Object

Verify and parse a webhook payload in one call, using this client's API secret (CHA-2961).

Handles gzip-compressed bodies transparently. Raises StreamChat::Webhook::InvalidWebhookError on signature mismatch or parse failures; distinguish failure modes via the message substring.

Parameters:

  • body (String)

    raw request body (possibly gzip-compressed)

  • signature (String)

    X-Signature header value

Returns:

  • (Object)

    the typed event class instance or StreamChat::Webhook::UnknownEvent

Raises:



127
128
129
# File 'lib/getstream_ruby/client.rb', line 127

def verify_and_parse_webhook(body, signature)
  StreamChat::Webhook.verify_and_parse_webhook(body, signature, @configuration.api_secret)
end

#verify_signature(body, signature) ⇒ Boolean

Verify a webhook signature using this client's API secret (CHA-2961).

Convenience wrapper around StreamChat::Webhook.verify_signature that supplies the secret automatically. The module-level method is still available for callers that need to verify with an arbitrary secret.

Parameters:

  • body (String)

    The raw request body (already-decompressed)

  • signature (String)

    The signature from the X-Signature header

Returns:

  • (Boolean)

    true if the signature is valid, false otherwise



111
112
113
# File 'lib/getstream_ruby/client.rb', line 111

def verify_signature(body, signature)
  StreamChat::Webhook.verify_signature(body, signature, @configuration.api_secret)
end

#videoGetStream::Generated::VideoClient

Returns The video API client.

Returns:



90
91
92
# File 'lib/getstream_ruby/client.rb', line 90

def video
  @video ||= GetStream::Generated::VideoClient.new(self)
end

#wait_for_task(task_id, poll_interval: 1, timeout: 60) ⇒ Object

Polls the task-status endpoint until the task reaches a terminal state.

Behaviour:

- status="completed": returns the task `result` payload.
- status="failed":    raises `TaskError` populated from the task's
                    `ErrorResult` (`type`, `description`, `stacktrace`,
                    `version`).
- timeout elapsed:    raises `TransportError` with `error_type:
                    "timeout"`.

Parameters:

  • task_id (String)
  • poll_interval (Numeric) (defaults to: 1)

    seconds between polls (default 1)

  • timeout (Numeric) (defaults to: 60)

    max seconds to wait (default 60)

Returns:

  • (Object)

    the task result payload on success

Raises:

  • (TaskError)

    when the task reports status="failed"

  • (TransportError)

    when the timeout elapses (error_type="timeout")



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/getstream_ruby/client.rb', line 171

def wait_for_task(task_id, poll_interval: 1, timeout: 60)
  start_time = monotonic_now

  loop do

    response = common.get_task(task_id)
    status = response.status

    case status
    when 'completed'
      return response.result
    when 'failed'
      raise ErrorMapping.build_task_error(task_id, response.error)
    end

    if monotonic_now - start_time >= timeout
      raise TransportError.new(
        "wait_for_task timed out after #{timeout}s for task_id=#{task_id}",
        error_type: 'timeout',
      )
    end

    sleep(poll_interval)

  end
end