- Move Elixir code to server/ subdirectory for monorepo structure - Update flake.nix to provide packages and apps outputs for nix run support - Update nix/package.nix to accept src parameter instead of fetchgit - Add NixOS module export for easy consumption Now supports: nix run, nix build, and nix develop from git repo 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
69 lines
2.0 KiB
Elixir
69 lines
2.0 KiB
Elixir
defmodule Tortoise.Package.Suback do
|
|
@moduledoc false
|
|
|
|
@opcode 9
|
|
|
|
alias Tortoise.Package
|
|
|
|
@type qos :: 0 | 1 | 2
|
|
@type ack_result :: {:ok, qos} | {:error, :access_denied}
|
|
|
|
@opaque t :: %__MODULE__{
|
|
__META__: Package.Meta.t(),
|
|
identifier: Tortoise.package_identifier(),
|
|
acks: [ack_result]
|
|
}
|
|
@enforce_keys [:identifier]
|
|
defstruct __META__: %Package.Meta{opcode: @opcode, flags: 0},
|
|
identifier: nil,
|
|
acks: []
|
|
|
|
@spec decode(binary()) :: t
|
|
def decode(<<@opcode::4, 0::4, payload::binary>>) do
|
|
with payload <- drop_length(payload),
|
|
<<identifier::big-integer-size(16), acks::binary>> <- payload do
|
|
case return_codes_to_list(acks) do
|
|
[] ->
|
|
{:error, {:protocol_violation, :empty_subscription_ack}}
|
|
|
|
sub_acks ->
|
|
%__MODULE__{identifier: identifier, acks: sub_acks}
|
|
end
|
|
end
|
|
end
|
|
|
|
defp drop_length(payload) do
|
|
case payload do
|
|
<<0::1, _::7, r::binary>> -> r
|
|
<<1::1, _::7, 0::1, _::7, r::binary>> -> r
|
|
<<1::1, _::7, 1::1, _::7, 0::1, _::7, r::binary>> -> r
|
|
<<1::1, _::7, 1::1, _::7, 1::1, _::7, 0::1, _::7, r::binary>> -> r
|
|
end
|
|
end
|
|
|
|
defp return_codes_to_list(<<>>), do: []
|
|
|
|
defp return_codes_to_list(<<0x80::integer, acks::binary>>),
|
|
do: [{:error, :access_denied}] ++ return_codes_to_list(acks)
|
|
|
|
defp return_codes_to_list(<<ack::integer, acks::binary>>) when ack in 0x00..0x02,
|
|
do: [{:ok, ack}] ++ return_codes_to_list(acks)
|
|
|
|
# Protocols ----------------------------------------------------------
|
|
defimpl Tortoise.Encodable do
|
|
def encode(%Package.Suback{identifier: identifier} = t)
|
|
when identifier in 0x0001..0xFFFF do
|
|
[
|
|
Package.Meta.encode(t.__META__),
|
|
Package.variable_length_encode([
|
|
<<identifier::big-integer-size(16)>>,
|
|
Enum.map(t.acks, &encode_ack/1)
|
|
])
|
|
]
|
|
end
|
|
|
|
defp encode_ack({:ok, qos}) when qos in 0x00..0x02, do: qos
|
|
defp encode_ack({:error, _}), do: 0x80
|
|
end
|
|
end
|