Packages

Elixir client library for cryptocurrency exchanges — generated from CCXT specs via compile-time macros.

Current section

Files

Jump to
ccxt_client lib ccxt ws subscription method_params.ex
Raw

lib/ccxt/ws/subscription/method_params.ex

defmodule CCXT.WS.Subscription.MethodParams do
@moduledoc """
Kraken v2 / Crypto.com-style subscribe frame.
Accepts two caller conventions per channel list:
1. **Plain strings** — channels are grouped under
`params.<channel_key>` (default key `"channel"`).
MethodParams.subscribe(["ticker", "book"], %{})
# => %{"method" => "subscribe", "params" => %{"channel" => ["ticker", "book"]}}
2. **Single pre-shaped map** — the caller supplies the `params` object
directly (Kraken v2 expects `{"channel": "ticker", "symbol": [...]}`).
MethodParams.subscribe([%{"channel" => "ticker", "symbol" => ["BTC/USD"]}], %{})
# => %{"method" => "subscribe",
# "params" => %{"channel" => "ticker", "symbol" => ["BTC/USD"]}}
Multiple maps per call return `{:error, :multiple_maps_not_supported}`;
lists that mix maps and strings return `{:error, :mixed_channel_types}`.
Both errors propagate verbatim through `CCXT.WS.Subscription.build_subscribe/3`.
Config keys:
- `:op_field` — default `"method"`
- `:args_field` — default `"params"`
- `:channel_key` — default `"channel"` (string-channel branch only)
"""
@behaviour CCXT.WS.Subscription.Behaviour
@impl true
def subscribe(channels, config) when is_list(channels) do
build(channels, config, "subscribe")
end
@impl true
def unsubscribe(channels, config) when is_list(channels) do
build(channels, config, "unsubscribe")
end
defp build([%{} = params_map], config, action) do
method = Map.get(config, :op_field, "method")
params = Map.get(config, :args_field, "params")
%{method => action, params => params_map}
end
defp build(channels, config, action) when is_list(channels) do
case classify_channels(channels) do
:strings -> build_string_frame(channels, config, action)
:all_maps -> {:error, :multiple_maps_not_supported}
:mixed -> {:error, :mixed_channel_types}
end
end
defp build_string_frame(channels, config, action) do
method = Map.get(config, :op_field, "method")
params = Map.get(config, :args_field, "params")
channel_key = Map.get(config, :channel_key, "channel")
%{method => action, params => %{channel_key => channels}}
end
# Empty list classifies as `:strings` so the existing default-frame
# behavior (empty channel array under params) is preserved.
defp classify_channels(channels) do
cond do
Enum.all?(channels, &is_binary/1) -> :strings
Enum.all?(channels, &is_map/1) -> :all_maps
true -> :mixed
end
end
end