Class: BSV::Network::Protocol
- Inherits:
-
Object
- Object
- BSV::Network::Protocol
- Defined in:
- lib/bsv/network/protocol.rb
Overview
Protocol is the base class for all BSV network protocol definitions.
Subclasses declare their commands via the endpoint DSL macro. Each endpoint maps a command name (Symbol) to an HTTP method, a path template, and a response handler. The subscription macro is a placeholder for future WebSocket support.
Subclass isolation is enforced via an inherited hook — each subclass receives its own empty @endpoints and @subscriptions hashes. Adding endpoints to a subclass never affects the parent.
HTTP dispatch routes through call: if a call_<name> escape hatch method exists on the instance, it is called; otherwise default_call interpolates the URL template, makes the HTTP request, and maps the response to a Result.
Example
class MyProtocol < BSV::Network::Protocol
endpoint :get_tx, :get, '/v1/tx/{txid}'
endpoint :broadcast, :post, '/v1/tx', response: :json
end
p = MyProtocol.new(base_url: 'https://api.example.com', network: 'main')
MyProtocol.commands #=> #<Set: {:get_tx, :broadcast}>
Direct Known Subclasses
BSV::Network::Protocols::ARC, BSV::Network::Protocols::Chaintracks, BSV::Network::Protocols::Ordinals, BSV::Network::Protocols::TAALBinary, BSV::Network::Protocols::WoCREST
Instance Attribute Summary collapse
-
#api_key ⇒ Object
readonly
Returns the value of attribute api_key.
-
#base_url ⇒ Object
readonly
Returns the value of attribute base_url.
-
#http_client ⇒ Object
readonly
Returns the value of attribute http_client.
-
#network ⇒ Object
readonly
Returns the value of attribute network.
Class Method Summary collapse
-
.commands ⇒ Set<Symbol>
Returns a
Setof command names declared on this protocol class. -
.endpoint(command_name, http_method, path_template, response: :raw) ⇒ Object
Registers an endpoint definition for this protocol class.
-
.endpoints ⇒ Hash
Returns a frozen copy of the endpoints hash for introspection.
-
.inherited(subclass) ⇒ Object
Give each subclass its own isolated @endpoints and @subscriptions hashes.
-
.subscription(event_name, path, **opts) ⇒ Object
Registers a subscription definition.
-
.subscriptions ⇒ Hash
Returns a frozen copy of the subscriptions hash for introspection.
Instance Method Summary collapse
-
#call(command_name, *args, **kwargs) ⇒ Result::Success, ...
Dispatches a command by name.
-
#default_call(command_name, *args, **kwargs) ⇒ Result::Success, ...
Dispatches a command directly via HTTP, bypassing any escape hatch.
-
#initialize(base_url:, api_key: nil, network: nil, http_client: nil) ⇒ Protocol
constructor
A new instance of Protocol.
Constructor Details
#initialize(base_url:, api_key: nil, network: nil, http_client: nil) ⇒ Protocol
Returns a new instance of Protocol.
112 113 114 115 116 117 |
# File 'lib/bsv/network/protocol.rb', line 112 def initialize(base_url:, api_key: nil, network: nil, http_client: nil) @api_key = api_key @network = network @http_client = http_client @base_url = build_base_url(base_url, network) end |
Instance Attribute Details
#api_key ⇒ Object (readonly)
Returns the value of attribute api_key.
106 107 108 |
# File 'lib/bsv/network/protocol.rb', line 106 def api_key @api_key end |
#base_url ⇒ Object (readonly)
Returns the value of attribute base_url.
106 107 108 |
# File 'lib/bsv/network/protocol.rb', line 106 def base_url @base_url end |
#http_client ⇒ Object (readonly)
Returns the value of attribute http_client.
106 107 108 |
# File 'lib/bsv/network/protocol.rb', line 106 def http_client @http_client end |
#network ⇒ Object (readonly)
Returns the value of attribute network.
106 107 108 |
# File 'lib/bsv/network/protocol.rb', line 106 def network @network end |
Class Method Details
.commands ⇒ Set<Symbol>
Returns a Set of command names declared on this protocol class.
65 66 67 |
# File 'lib/bsv/network/protocol.rb', line 65 def commands Set.new(@endpoints.keys) end |
.endpoint(command_name, http_method, path_template, response: :raw) ⇒ Object
Registers an endpoint definition for this protocol class.
44 45 46 47 48 49 50 |
# File 'lib/bsv/network/protocol.rb', line 44 def endpoint(command_name, http_method, path_template, response: :raw) @endpoints[command_name] = { method: http_method, path: path_template, response: response } end |
.endpoints ⇒ Hash
Returns a frozen copy of the endpoints hash for introspection.
72 73 74 |
# File 'lib/bsv/network/protocol.rb', line 72 def endpoints @endpoints.dup.freeze end |
.inherited(subclass) ⇒ Object
Give each subclass its own isolated @endpoints and @subscriptions hashes. Deep-copies the parent’s endpoints so that existing declarations are inherited but mutations on the subclass do not affect the parent.
86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/bsv/network/protocol.rb', line 86 def inherited(subclass) super # Deep copy: each endpoint value is a plain hash of scalar values, # so a one-level transform_values dup is sufficient. parent_endpoints = @endpoints.each_with_object({}) do |(k, v), h| h[k] = v.dup end parent_subscriptions = @subscriptions.each_with_object({}) do |(k, v), h| h[k] = v.dup end subclass.instance_variable_set(:@endpoints, parent_endpoints) subclass.instance_variable_set(:@subscriptions, parent_subscriptions) end |
.subscription(event_name, path, **opts) ⇒ Object
Registers a subscription definition. Placeholder for Phase C WebSocket support. Stored but not callable at runtime.
58 59 60 |
# File 'lib/bsv/network/protocol.rb', line 58 def subscription(event_name, path, **opts) @subscriptions[event_name] = { path: path }.merge(opts) end |
.subscriptions ⇒ Hash
Returns a frozen copy of the subscriptions hash for introspection.
79 80 81 |
# File 'lib/bsv/network/protocol.rb', line 79 def subscriptions @subscriptions.dup.freeze end |
Instance Method Details
#call(command_name, *args, **kwargs) ⇒ Result::Success, ...
Dispatches a command by name.
If a method named call_<command_name> exists on the instance it is used as an escape hatch — that method receives args and kwargs and MUST return a Result. Otherwise default_call is invoked.
Subscriptions are not callable; calling one raises NotImplementedError.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/bsv/network/protocol.rb', line 132 def call(command_name, *args, **kwargs) name = command_name.to_sym if self.class.subscriptions.key?(name) raise NotImplementedError, "#{name} is a subscription — WebSocket dispatch is not yet implemented" end escape = :"call_#{name}" if respond_to?(escape, true) return kwargs.empty? ? send(escape, *args) : send(escape, *args, **kwargs) end default_call(name, *args, **kwargs) end |
#default_call(command_name, *args, **kwargs) ⇒ Result::Success, ...
Dispatches a command directly via HTTP, bypassing any escape hatch.
Path placeholders (+param+) are filled from kwargs first; any remaining placeholders are filled positionally from args. Named kwargs take precedence over positional args for the same placeholder.
POST body is taken from kwargs.delete(:body) (removed before path interpolation).
163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/bsv/network/protocol.rb', line 163 def default_call(command_name, *args, **kwargs) name = command_name.to_sym defn = self.class.endpoints[name] raise ArgumentError, "unknown command: #{name}" unless defn body = kwargs.delete(:body) path = interpolate_path(defn[:path], args, kwargs) uri = URI("#{@base_url}#{path}") request = build_request(defn[:method], uri, body) response = execute(uri, request) map_response(response, defn[:response]) end |