Class: MisarReach::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/misar_reach/client.rb

Overview

── Main Client ──────────────────────────────────────────────────────────────

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key:, base_url: BASE_URL, timeout: 30, max_retries: 3) ⇒ Client

Returns a new instance of Client.

Parameters:

  • api_key (String)

    a reach developer key (mrk_...)

Raises:

  • (ArgumentError)


513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/misar_reach/client.rb', line 513

def initialize(api_key:, base_url: BASE_URL, timeout: 30, max_retries: 3)
  raise ArgumentError, "api_key is required" if api_key.nil? || api_key.empty?

  @api_key     = api_key
  @base_url    = base_url.chomp("/")
  @timeout     = timeout
  @max_retries = max_retries

  @leads         = LeadsResource.new(self)
  @deals         = DealsResource.new(self)
  @pipeline      = PipelineResource.new(self)
  @channels      = ChannelsResource.new(self)
  @autopilot     = AutopilotResource.new(self)
  @sales_agent   = SalesAgentResource.new(self)
  @campaigns     = CampaignsResource.new(self)
  @contacts      = ContactsResource.new(self)
  @conversations = ConversationsResource.new(self)
  @workspaces    = WorkspacesResource.new(self)
  @settings      = SettingsResource.new(self)
  @plan          = PlanResource.new(self)
  @ads           = AdsResource.new(self)
  @campaign_templates = CampaignTemplatesResource.new(self)
  @deliverability     = DeliverabilityResource.new(self)
  @notifications      = NotificationsResource.new(self)
  @webhooks           = WebhooksResource.new(self)
end

Instance Attribute Details

#adsObject (readonly)

Returns the value of attribute ads.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def ads
  @ads
end

#autopilotObject (readonly)

Returns the value of attribute autopilot.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def autopilot
  @autopilot
end

#campaign_templatesObject (readonly)

Returns the value of attribute campaign_templates.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def campaign_templates
  @campaign_templates
end

#campaignsObject (readonly)

Returns the value of attribute campaigns.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def campaigns
  @campaigns
end

#channelsObject (readonly)

Returns the value of attribute channels.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def channels
  @channels
end

#contactsObject (readonly)

Returns the value of attribute contacts.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def contacts
  @contacts
end

#conversationsObject (readonly)

Returns the value of attribute conversations.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def conversations
  @conversations
end

#dealsObject (readonly)

Returns the value of attribute deals.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def deals
  @deals
end

#deliverabilityObject (readonly)

Returns the value of attribute deliverability.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def deliverability
  @deliverability
end

#leadsObject (readonly)

Returns the value of attribute leads.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def leads
  @leads
end

#notificationsObject (readonly)

Returns the value of attribute notifications.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def notifications
  @notifications
end

#pipelineObject (readonly)

Returns the value of attribute pipeline.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def pipeline
  @pipeline
end

#planObject (readonly)

Returns the value of attribute plan.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def plan
  @plan
end

#sales_agentObject (readonly)

Returns the value of attribute sales_agent.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def sales_agent
  @sales_agent
end

#settingsObject (readonly)

Returns the value of attribute settings.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def settings
  @settings
end

#webhooksObject (readonly)

Returns the value of attribute webhooks.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def webhooks
  @webhooks
end

#workspacesObject (readonly)

Returns the value of attribute workspaces.



507
508
509
# File 'lib/misar_reach/client.rb', line 507

def workspaces
  @workspaces
end

Instance Method Details

#request(method, path, data = {}) ⇒ Hash

Parameters:

  • method (Symbol)

    :get, :post, :patch, :put, :delete

  • path (String)

    e.g. "/deals"

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

    request body (post/put/patch only)

Returns:

  • (Hash)

Raises:



545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
# File 'lib/misar_reach/client.rb', line 545

def request(method, path, data = {})
  url       = URI.parse(@base_url + "/" + path.delete_prefix("/"))
  has_body  = !data.nil? && !data.empty? && %i[post put patch].include?(method)
  json_body = has_body ? JSON.generate(data) : nil

  last_status = 0

  @max_retries.times do |attempt|
    begin
      http = build_http(url)
      req  = build_request(method, url, json_body)
      resp = http.request(req)
      last_status = resp.code.to_i

      if RETRYABLE.include?(last_status) && attempt < @max_retries - 1
        sleep(backoff_seconds(resp, attempt))
        next
      end

      return parse_response(resp, last_status)
    rescue Net::OpenTimeout, Net::ReadTimeout,
           Errno::ECONNREFUSED, Errno::ECONNRESET, SocketError => e
      if attempt < @max_retries - 1
        sleep(RETRY_BASE_S * (2**attempt))
        next
      end
      raise NetworkError.new(e.message, e)
    end
  end

  raise ApiError.new(last_status, "Max retries exceeded")
end

#stream(method, path, &block) ⇒ Object

Streaming request for Server-Sent Events. Yields { event:, data: } hashes.



579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
# File 'lib/misar_reach/client.rb', line 579

def stream(method, path, &block)
  url = URI.parse(@base_url + "/" + path.delete_prefix("/"))
  http = build_http(url)
  req  = build_request(method, url, nil)
  req["Accept"] = "text/event-stream"

  http.request(req) do |resp|
    status = resp.code.to_i
    raise_for_status(status, resp.body) if status >= 400

    # The route does not always stream. A job that has already finished is
    # answered with a JSON snapshot, because there is nothing left to
    # stream. Parsing that as SSE finds no frames and returns silently, so
    # the caller would see nothing rather than the outcome. Synthesise the
    # terminal event the SSE path would have sent.
    unless resp["content-type"].to_s.include?("text/event-stream")
      body = +""
      resp.read_body { |chunk| body << chunk }
      snapshot = begin
        JSON.parse(body)
      rescue JSON::ParserError
        body
      end
      name = snapshot.is_a?(Hash) && snapshot["status"] == "failed" ? "error" : "complete"
      block.call({ event: name, data: snapshot })
      return nil
    end

    buffer = +""
    resp.read_body do |chunk|
      buffer << chunk
      while (idx = buffer.index("\n\n"))
        raw   = buffer.slice!(0..idx + 1)
        event = parse_sse_block(raw)
        block.call(event) if event
      end
    end
  end
  nil
end