Class: Clacky::PlatformHttpClient

Inherits:
Object
  • Object
show all
Defined in:
lib/clacky/platform_http_client.rb

Overview

PlatformHttpClient provides a resilient HTTP client for all calls to the OpenClacky platform API (www.openclacky.com and its fallback domain).

Features:

- Primary domain:  https://www.openclacky.com  (EdgeOne CDN-accelerated)
- Fallback domain: https://openclacky-platform.clackyai.app  (direct, no CDN)
- Automatic retry with exponential back-off on transient failures
- Transparent domain failover: if the primary domain times out or returns a
  5xx error, the request is automatically retried against the fallback domain
- Override via CLACKY_LICENSE_SERVER env var (used in development)

Usage:

client = Clacky::PlatformHttpClient.new
result = client.post("/api/v1/licenses/activate", payload)
# result => { success: true, data: {...} }
#        or { success: false, error: "...", data: {} }

Defined Under Namespace

Classes: RetryableNetworkError

Constant Summary collapse

PRIMARY_HOST =

Primary CDN-accelerated endpoint

"https://www.openclacky.com"
FALLBACK_HOST =

Direct fallback — bypasses EdgeOne, used when the primary times out

"https://openclacky-platform.clackyai.app"
ATTEMPTS_PER_HOST =

Number of attempts per domain (1 = no retry within the same domain)

2
INITIAL_BACKOFF =

Initial back-off between retries within the same domain (seconds)

0.5
OPEN_TIMEOUT =

Connection / read timeouts (seconds)

8
READ_TIMEOUT =
15
API_ERROR_MESSAGES =

API error code → human-readable message table (shared across all callers)

{
  "invalid_proof"        => "Invalid license key — please check and try again.",
  "invalid_signature"    => "Invalid request signature.",
  "nonce_replayed"       => "Duplicate request detected. Please try again.",
  "timestamp_expired"    => "System clock is out of sync. Please adjust your time settings.",
  "license_revoked"      => "This license has been revoked. Please contact support.",
  "license_expired"      => "This license has expired. Please renew to continue.",
  "device_limit_reached" => "Device limit reached for this license.",
  "device_revoked"       => "This device has been revoked from the license.",
  "invalid_license"      => "License key not found. Please verify the key.",
  "device_not_found"     => "Device not registered. Please re-activate."
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(base_url: nil) ⇒ PlatformHttpClient

Returns a new instance of PlatformHttpClient.

Parameters:

  • base_url (String, nil) (defaults to: nil)

    Override the primary host (e.g. for local dev). When set, the fallback domain is disabled — only the override URL is used.



54
55
56
57
58
59
60
61
# File 'lib/clacky/platform_http_client.rb', line 54

def initialize(base_url: nil)
  if base_url
    # Developer / test override: single host, no failover
    @hosts   = [base_url]
  else
    @hosts = [PRIMARY_HOST, FALLBACK_HOST]
  end
end

Instance Method Details

#delete(path, headers: {}) ⇒ Object

Send a DELETE request (no body).



89
90
91
# File 'lib/clacky/platform_http_client.rb', line 89

def delete(path, headers: {})
  request_with_failover(:delete, path, nil, headers)
end

#get(path, headers: {}) ⇒ Hash

Send a GET request and return a normalised result hash. Query string parameters should be appended to path by the caller.

Parameters:

  • path (String)

    API path with optional query string

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

    Additional HTTP headers (optional)

Returns:

  • (Hash)

    { success: Boolean, data: Hash, error: String }



79
80
81
# File 'lib/clacky/platform_http_client.rb', line 79

def get(path, headers: {})
  request_with_failover(:get, path, nil, headers)
end

#multipart_patch(path, body_bytes, boundary, read_timeout: READ_TIMEOUT) ⇒ Object

Send a multipart/form-data PATCH. Same contract as #multipart_post.



107
108
109
110
111
# File 'lib/clacky/platform_http_client.rb', line 107

def multipart_patch(path, body_bytes, boundary, read_timeout: READ_TIMEOUT)
  headers = { "Content-Type" => "multipart/form-data; boundary=#{boundary}" }
  request_with_failover(:multipart_patch, path, body_bytes, headers,
                        read_timeout_override: read_timeout)
end

#multipart_post(path, body_bytes, boundary, read_timeout: READ_TIMEOUT) ⇒ Hash

Send a multipart/form-data POST.

Parameters:

  • path (String)

    API path

  • body_bytes (String)

    Pre-built binary multipart body

  • boundary (String)

    Multipart boundary string (without leading –)

  • read_timeout (Integer) (defaults to: READ_TIMEOUT)

    Override read timeout (uploads may be slow)

Returns:

  • (Hash)

    { success: Boolean, data: Hash, error: String }



100
101
102
103
104
# File 'lib/clacky/platform_http_client.rb', line 100

def multipart_post(path, body_bytes, boundary, read_timeout: READ_TIMEOUT)
  headers = { "Content-Type" => "multipart/form-data; boundary=#{boundary}" }
  request_with_failover(:multipart_post, path, body_bytes, headers,
                        read_timeout_override: read_timeout)
end

#patch(path, payload, headers: {}) ⇒ Object

Send a PATCH request. Same contract as #post.



84
85
86
# File 'lib/clacky/platform_http_client.rb', line 84

def patch(path, payload, headers: {})
  request_with_failover(:patch, path, payload, headers)
end

#post(path, payload, headers: {}) ⇒ Hash

Send a POST request with a JSON body and return a normalised result hash.

Parameters:

  • path (String)

    API path, e.g. “/api/v1/licenses/activate”

  • payload (Hash)

    Request body (will be JSON-encoded)

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

    Additional HTTP headers (optional)

Returns:

  • (Hash)

    { success: Boolean, data: Hash, error: String }



69
70
71
# File 'lib/clacky/platform_http_client.rb', line 69

def post(path, payload, headers: {})
  request_with_failover(:post, path, payload, headers)
end