Class: Takagi::ClientBase

Inherits:
Object
  • Object
show all
Defined in:
lib/takagi/client_base.rb,
sig/takagi/client_base.rbs

Overview

Base class for Takagi clients, providing common functionality for both UDP (CoAP) and TCP (CoAP over TCP) clients.

This class defines the common interface and lifecycle management that all Takagi clients should follow.

Direct Known Subclasses

Client, TcpClient, UdpClient

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server_uri, timeout: 5) ⇒ ClientBase

Initializes the base client

Parameters:

  • URL of the Takagi server

  • (defaults to: 5)

    Maximum time to wait for a response

  • (defaults to: 5)


18
19
20
21
22
23
# File 'lib/takagi/client_base.rb', line 18

def initialize(server_uri, timeout: 5)
  @server_uri = URI(server_uri)
  @timeout = timeout
  @callbacks = {}
  @closed = false
end

Instance Attribute Details

#callbacksObject (readonly)

Returns the value of attribute callbacks.

Returns:



13
14
15
# File 'lib/takagi/client_base.rb', line 13

def callbacks
  @callbacks
end

#server_uriObject (readonly)

Returns the value of attribute server_uri.

Returns:



13
14
15
# File 'lib/takagi/client_base.rb', line 13

def server_uri
  @server_uri
end

#timeoutObject (readonly)

Returns the value of attribute timeout.

Returns:



13
14
15
# File 'lib/takagi/client_base.rb', line 13

def timeout
  @timeout
end

Class Method Details

.open(server_uri, timeout: 5, **options) {|client| ... } ⇒ Object

Creates a new client and yields it to the block, ensuring it's closed afterward. This is the recommended way to use clients to prevent resource leaks.

Examples:

Takagi::Client.open('coap://localhost:5683') do |client|
  client.get('/temperature')
end

Parameters:

  • URL of the Takagi server

  • (defaults to: 5)

    Maximum time to wait for a response

  • Additional options passed to the subclass constructor

  • (defaults to: 5)

Yields:

  • (client)

    Gives the client to the block

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:

  • The return value of the block



146
147
148
149
150
151
# File 'lib/takagi/client_base.rb', line 146

def self.open(server_uri, timeout: 5, **options, &block)
  client = new(server_uri, timeout: timeout, **options)
  block.call(client)
ensure
  client&.close
end

Instance Method Details

#cleanup_resourcesnil

Subclasses can override this to perform specific cleanup Called by #close before marking the client as closed

Returns:



168
169
170
# File 'lib/takagi/client_base.rb', line 168

def cleanup_resources
  # Default: no-op
end

#closenil, untyped

Closes the client and releases any resources. This should be called when the client is no longer needed to prevent resource leaks in long-running processes.

Subclasses should override this method to perform specific cleanup and then call super.

Returns:



120
121
122
123
124
125
# File 'lib/takagi/client_base.rb', line 120

def close
  return if @closed

  cleanup_resources
  @closed = true
end

#closed?Boolean

Check if the client has been closed

Returns:

  • true if the client is closed



129
130
131
# File 'lib/takagi/client_base.rb', line 129

def closed?
  @closed
end

#delete(path, options: {}, type: nil) {|arg0| ... } ⇒ Object

Sends a DELETE request

Parameters:

  • Resource path

  • (optional) Callback function for processing the response

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



66
67
68
# File 'lib/takagi/client_base.rb', line 66

def delete(path, options: {}, type: nil, &block)
  request(:delete, path, nil, options: options, type: type, &block)
end

#deliver_response(response_data, &callback) ⇒ void

This method returns an undefined value.

Delivers a response using the callback or registered callback Wraps raw response data in a Response object for convenience

Parameters:

  • The response data to deliver

  • Optional callback for this specific request



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/takagi/client_base.rb', line 176

def deliver_response(response_data, &callback)
  # Wrap response in Response object for better DX
  require_relative 'client/response'
  response = Client::Response.new(response_data)

  return callback.call(response) if callback
  return @callbacks[:response].call(response) if @callbacks[:response]

  # Default: print response details
  if response.success?
    puts "[#{response.code_name}] #{response.payload}"
  else
    puts "[ERROR #{response.code_name}] #{response.payload}"
  end
end

#get(path, options: {}, type: nil) {|arg0| ... } ⇒ Object

Sends a GET request

Parameters:

  • Resource path

  • (optional) Callback function for processing the response

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



37
38
39
# File 'lib/takagi/client_base.rb', line 37

def get(path, options: {}, type: nil, &block)
  request(:get, path, nil, options: options, type: type, &block)
end

#get_json(path, options: {}) {|data| ... } ⇒ Hash, ...

Sends a GET request and automatically parses JSON response (convenience method)

Examples:

With block

client.get_json('/sensors') do |data|
  puts data['temperature']
end

Without block

data = client.get_json('/sensors')

Parameters:

  • Resource path

Yields:

  • (data)

    Yields the parsed JSON data

Returns:

  • Parsed JSON data if no block given



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/takagi/client_base.rb', line 99

def get_json(path, options: {}, &block)
  cf = Takagi::CoAP::Registries::ContentFormat::JSON
  merged = { Takagi::CoAP::Registries::Option::ACCEPT => cf }.merge(options)
  if block_given?
    get(path, options: merged) do |response|
      data = response.is_a?(String) ? parse_json_response(response) : response.json
      block.call(data)
    end
  else
    result = nil
    get(path, options: merged) { |response| result = response.is_a?(String) ? parse_json_response(response) : response.json }
    result
  end
end

#observe(path, options: {}, &block) ⇒ Object

Sends an OBSERVE request (RFC 7641). The Observe option is added automatically; additional CoAP options can be supplied via options:.

Parameters:

  • Resource path

  • (defaults to: {})

    CoAP options (Observe is injected automatically)

  • (optional) Callback function for processing notifications



75
76
77
78
# File 'lib/takagi/client_base.rb', line 75

def observe(path, options: {}, &block)
  merged = { Takagi::CoAP::Registries::Option::OBSERVE => 0 }.merge(options)
  request(:get, path, nil, options: merged, &block)
end

#on(event, &callback) {|arg0| ... } ⇒ Object

Registers a callback for a given event

Parameters:

  • Event name (e.g., :response)

  • Callback function to handle the event

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



28
29
30
# File 'lib/takagi/client_base.rb', line 28

def on(event, &callback)
  @callbacks[event] = callback
end

#parse_json_response(response_data) ⇒ Hash, ...

Helper to parse JSON response from raw data

Parameters:

  • Raw response data

Returns:

  • Parsed JSON or nil



195
196
197
198
199
200
201
202
# File 'lib/takagi/client_base.rb', line 195

def parse_json_response(response_data)
  inbound = Takagi::Message::Inbound.new(response_data)
  return nil unless inbound.payload

  JSON.parse(inbound.payload)
rescue JSON::ParserError
  nil
end

#post(path, payload = nil, options: {}, type: nil) {|arg0| ... } ⇒ Object

Sends a POST request

Parameters:

  • Resource path

  • (defaults to: nil)

    Data to send

  • (optional) Callback function for processing the response

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



47
48
49
# File 'lib/takagi/client_base.rb', line 47

def post(path, payload = nil, options: {}, type: nil, &block)
  request(:post, path, payload, options: options, type: type, &block)
end

#post_json(path, data, options: {}) {|arg0| ... } ⇒ Object

Sends a POST request with JSON payload (convenience method)

Examples:

client.post_json('/sensors', {temperature: 25, humidity: 60})

Parameters:

  • Resource path

  • Data to encode as JSON

  • (optional) Callback function for processing the response

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



85
86
87
88
89
# File 'lib/takagi/client_base.rb', line 85

def post_json(path, data, options: {}, &block)
  cf = Takagi::CoAP::Registries::ContentFormat::JSON
  merged = { Takagi::CoAP::Registries::Option::CONTENT_FORMAT => cf }.merge(options)
  request(:post, path, JSON.generate(data), options: merged, &block)
end

#put(path, payload = nil, options: {}, type: nil) {|arg0| ... } ⇒ Object

Sends a PUT request

Parameters:

  • Resource path

  • (defaults to: nil)

    Data to send

  • (optional) Callback function for processing the response

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



57
58
59
# File 'lib/takagi/client_base.rb', line 57

def put(path, payload = nil, options: {}, type: nil, &block)
  request(:put, path, payload, options: options, type: type, &block)
end

#put_json(path, data, options: {}) {|arg0| ... } ⇒ Object

Sends a PUT request with JSON payload (convenience method)

Examples:

client.put_json('/config', {enabled: true})

Parameters:

  • Resource path

  • Data to encode as JSON

  • (optional) Callback function for processing the response

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



92
93
94
95
96
# File 'lib/takagi/client_base.rb', line 92

def put_json(path, data, options: {}, &block)
  cf = Takagi::CoAP::Registries::ContentFormat::JSON
  merged = { Takagi::CoAP::Registries::Option::CONTENT_FORMAT => cf }.merge(options)
  request(:put, path, JSON.generate(data), options: merged, &block)
end

#request(_method, _path, _payload = nil, options: {}, type: nil) {|arg0| ... } ⇒ Object

Subclasses must implement this method to perform the actual request

Parameters:

  • HTTP method (:get, :post, :put, :delete)

  • Resource path

  • (optional) Data for POST/PUT requests

  • (optional) Callback function for processing the response

  • (defaults to: nil)

Yields:

Yield Parameters:

  • arg0

Yield Returns:

  • (Object)

Returns:



162
163
164
# File 'lib/takagi/client_base.rb', line 162

def request(_method, _path, _payload = nil, options: {}, type: nil, &_callback)
  raise NotImplementedError, "#{self.class} must implement #request"
end