Current section
Files
Jump to
Current section
Files
lib/conduit/message.ex
defmodule Conduit.Message do
@moduledoc """
The Conduit message.
This module defines a `Conduit.Message` struct and the main functions
for working with Conduit messages.
Note this struct is used for sending and receiving messages from a
message queue.
## Public fields
These fields are for you to use in your application. The values in
`meta`, `headers`, and `status` may have special meaning based on
the adapter you use. See your adapters documention to understand
how to use them correctly.
* `meta` - Information applicable to every message stored as a map.
* `headers` - Information applicable to a specific message stored as a keyword list.
* `body` - The contents of the message.
* `status` - The operation to perform on the message. This only applies to messages
that are being received.
## Private fields
These fields are reserved for library/framework usage.
* `private` - shared library data as a map
"""
@type source :: binary
@type destination :: binary
@type meta :: %{atom => any}
@type headers :: Keyword.t
@type body :: any
@type status :: :ack | :nack
@type assigns :: %{atom => any}
@type private :: %{atom => any}
@type t :: %__MODULE__{
source: source,
destination: destination,
meta: meta,
headers: headers,
body: body,
status: status,
assigns: assigns,
private: private
}
defstruct source: nil,
destination: nil,
meta: %{},
headers: [],
body: nil,
status: :ack,
assigns: %{},
private: %{}
alias Conduit.Message
@doc """
Assigns the source of the message.
## Examples
iex> import Conduit.Message
iex> message = put_source(%Conduit.Message{}, "my.queue")
iex> message.source
"my.queue"
"""
@spec put_source(Conduit.Message.t, source) :: Conduit.Message.t
def put_source(%Message{} = message, source) do
%{message | source: source}
end
@doc """
Assigns the destination of the message.
## Examples
iex> import Conduit.Message
iex> message = put_destination(%Conduit.Message{}, "my.queue")
iex> message.destination
"my.queue"
"""
@spec put_destination(Conduit.Message.t, destination) :: Conduit.Message.t
def put_destination(%Message{} = message, destination) do
%{message | destination: destination}
end
@doc """
Gets a meta property from the message.
## Examples
iex> import Conduit.Message
iex> message = put_meta(%Conduit.Message{}, :content_type, "application/json")
iex> get_meta(message, :content_type)
"application/json"
"""
@spec get_meta(Conduit.Message.t, term) :: any
def get_meta(%Message{meta: meta}, key) do
get_in(meta, [key])
end
@doc """
Assigns a meta property to the message.
## Examples
iex> import Conduit.Message
iex> message = put_meta(%Conduit.Message{}, :content_type, "application/json")
iex> get_meta(message, :content_type)
"application/json"
"""
@spec put_meta(Conduit.Message.t, atom, any) :: Conduit.Message.t
def put_meta(%Message{meta: meta} = message, key, value) when is_atom(key) do
%{message | meta: Map.put(meta, key, value)}
end
@doc """
Assigns a meta property to the message if not already set.
## Examples
iex> import Conduit.Message
iex> message =
iex> %Conduit.Message{}
iex> |> put_new_meta(:content_type, "application/json")
iex> |> put_new_meta(:content_type, "application/xml")
iex> get_meta(message, :content_type)
"application/json"
"""
@spec put_new_meta(Conduit.Message.t, atom, any) :: Conduit.Message.t
def put_new_meta(%Message{meta: meta} = message, key, value) when is_atom(key) do
%{message | meta: Map.put_new(meta, key, value)}
end
@doc """
Returns a header from the message specified by `key`.
## Examples
iex> import Conduit.Message
iex> message = put_header(%Conduit.Message{}, :retries, 1)
iex> get_header(message, :retries)
1
"""
@spec get_header(Conduit.Message.t, atom | binary) :: any
def get_header(%Message{headers: headers}, key) when is_atom(key) or is_binary(key) do
Enum.find_value(headers, nil, fn
{^key, value} -> value
_ -> nil
end)
end
@doc """
Assigns a header for the message specified by `key`.
## Examples
iex> import Conduit.Message
iex> message = put_header(%Conduit.Message{}, :retries, 1)
iex> get_header(message, :retries)
1
"""
@spec put_header(Conduit.Message.t, atom, any) :: Conduit.Message.t
def put_header(%Message{headers: headers} = message, key, value) when is_atom(key) do
%{message | headers: Keyword.put(headers, key, value)}
end
@doc """
Assigns the content of the message.
## Examples
iex> import Conduit.Message
iex> message = put_body(%Conduit.Message{}, "hi")
iex> message.body
"hi"
"""
@spec put_body(Conduit.Message.t, body) :: Conduit.Message.t
def put_body(%Message{} = message, body) do
%{message | body: body}
end
@doc """
Assigs the status of the message as acknowledged. This will be used
to signal to the message queue that processing the message was successful
and can be discarded.
## Examples
iex> import Conduit.Message
iex> message = ack(%Conduit.Message{})
iex> message.status
:ack
"""
@spec ack(Conduit.Message.t) :: Conduit.Message.t
def ack(message) do
%{message | status: :ack}
end
@doc """
Assigs the status of the message to a negative acknowledged. This will be used
to signal to the message queue that processing the message was not successful.
## Examples
iex> import Conduit.Message
iex> message = nack(%Conduit.Message{})
iex> message.status
:nack
"""
@spec nack(Conduit.Message.t) :: Conduit.Message.t
def nack(message) do
%{message | status: :nack}
end
@doc """
Retrieves a named value from the message.
## Examples
iex> import Conduit.Message
iex> message = assign(%Conduit.Message{}, :user_id, 1)
iex> assigns(message, :user_id)
1
"""
@spec assigns(Conduit.Message.t, term) :: Conduit.Message.t
def assigns(%Message{assigns: assigns}, key) do
get_in(assigns, [key])
end
@doc """
Assigns a named value to the message.
## Examples
iex> import Conduit.Message
iex> message = assign(%Conduit.Message{}, :user_id, 1)
iex> assigns(message, :user_id)
1
"""
@spec assign(Conduit.Message.t, atom, any) :: Conduit.Message.t
def assign(%Message{assigns: assigns} = message, key, value) when is_atom(key) do
%{message | assigns: Map.put(assigns, key, value)}
end
@doc """
Retrieves a named value from the message. This is intended for libraries and framework use.
## Examples
iex> import Conduit.Message
iex> message = put_private(%Conduit.Message{}, :message_id, 1)
iex> get_private(message, :message_id)
1
"""
@spec get_private(Conduit.Message.t, term) :: Conduit.Message.t
def get_private(%Message{private: private}, key) do
get_in(private, [key])
end
@doc """
Assigns a named value to the message. This is intended for libraries and framework use.
## Examples
iex> import Conduit.Message
iex> message = put_private(%Conduit.Message{}, :message_id, 1)
iex> get_private(message, :message_id)
1
"""
@spec put_private(Conduit.Message.t, atom, any) :: Conduit.Message.t
def put_private(%Message{private: private} = message, key, value) when is_atom(key) do
%{message | private: Map.put(private, key, value)}
end
end