ExWapp.Chat (ExWapp v0.1.2)

Copy Markdown View Source

Chat and conversation management.

This module handles:

  • Storing and retrieving conversations
  • Managing chat history
  • Tracking message state (read, delivered, etc.)

Storage

Chats are persisted via the session's store adapter. The chat data is stored under the :chats key in the store.

Usage

# Get all chats from session
chats = ExWapp.Chat.list(session)

# Get a specific chat
{:ok, chat} = ExWapp.Chat.get(session, "1234567890@s.whatsapp.net")

# Get messages for a chat
messages = ExWapp.Chat.messages(session, "1234567890@s.whatsapp.net")

Summary

Functions

Adds a message to a chat.

Returns a lazy stream over every locally retained message, oldest first.

Archives a chat.

Deletes a chat.

Deletes selected local messages after they have been persisted elsewhere.

Finds one locally stored message in a chat.

Finds one locally stored message by ID across all chats.

Gets a specific chat by JID.

Gets or creates a chat for a JID.

Lists all chats for a session.

Lists only group chats for a session.

Marks all messages in a chat as read.

Mark chat as read/unread from app state sync dispatch.

Merges a batch of messages into a chat, deduplicating by message ID.

Upserts metadata fields for a chat from sync/notification payloads.

Gets a materialized page of locally retained messages, newest first.

Creates a new chat struct.

Parses a received message node into a message struct.

Pins a chat.

Builds a lazy stream over locally retained messages.

Unarchives a chat.

Unpins a chat.

Update archived state from app state sync dispatch.

Updates a message status by message ID across all chats.

Update muted state from app state sync dispatch.

Updates the chat name (for contacts that send push names).

Update pinned state from app state sync dispatch.

Types

chat()

@type chat() :: %ExWapp.Chat{
  archived: boolean(),
  is_group: boolean(),
  jid: String.t(),
  last_message_timestamp: integer() | nil,
  muted_until: integer() | nil,
  name: String.t() | nil,
  pinned: boolean(),
  unread_count: non_neg_integer()
}

message()

@type message() :: %{
  :id => String.t(),
  :from_me => boolean(),
  :timestamp => integer(),
  :text => String.t() | nil,
  :status => message_status(),
  :participant => String.t() | ExWapp.JID.t() | nil,
  :raw => map() | nil,
  optional(:content) => term(),
  optional(:media) => term(),
  optional(:location) => term(),
  optional(:contact) => term(),
  optional(:event) => term()
}

message_status()

@type message_status() :: :pending | :sent | :received | :delivered | :read | :failed

target()

@type target() :: pid() | struct()

Functions

add_message(target, jid, message)

@spec add_message(target(), String.t() | ExWapp.JID.t(), message()) ::
  :ok | {:error, term()}

Adds a message to a chat.

all_messages(target, jid, opts \\ [])

@spec all_messages(target(), String.t() | ExWapp.JID.t(), keyword()) :: Enumerable.t()

Returns a lazy stream over every locally retained message, oldest first.

archive(target, jid)

@spec archive(target(), String.t()) :: :ok

Archives a chat.

delete(target, jid)

@spec delete(target(), String.t()) :: :ok | {:error, term()}

Deletes a chat.

delete_messages(target, jid, message_ids)

@spec delete_messages(target(), String.t() | ExWapp.JID.t(), [String.t()]) ::
  :ok | {:error, term()}

Deletes selected local messages after they have been persisted elsewhere.

find_message(target, jid, message_id)

@spec find_message(target(), String.t() | ExWapp.JID.t(), String.t()) ::
  message() | nil

Finds one locally stored message in a chat.

find_message_by_id(target, message_id)

@spec find_message_by_id(target(), String.t()) :: {String.t(), message()} | nil

Finds one locally stored message by ID across all chats.

get(target, jid)

@spec get(target(), String.t() | ExWapp.JID.t()) ::
  {:ok, chat()} | {:error, :not_found}

Gets a specific chat by JID.

get_or_create(target, jid, opts \\ [])

@spec get_or_create(target(), String.t() | ExWapp.JID.t(), keyword()) :: chat()

Gets or creates a chat for a JID.

list(target)

@spec list(target()) :: [chat()]

Lists all chats for a session.

Returns a list of chat structs sorted by last message timestamp (most recent first).

list_groups(target)

@spec list_groups(target()) :: [chat()]

Lists only group chats for a session.

mark_read(target, jid)

@spec mark_read(target(), String.t() | ExWapp.JID.t()) :: :ok

Marks all messages in a chat as read.

mark_read_from_sync(target, jid, action_value)

@spec mark_read_from_sync(target(), String.t(), map()) :: :ok

Mark chat as read/unread from app state sync dispatch.

merge_messages(target, jid, messages)

@spec merge_messages(target(), String.t() | ExWapp.JID.t(), [message()]) ::
  :ok | {:error, term()}

Merges a batch of messages into a chat, deduplicating by message ID.

merge_metadata(target, jid, metadata)

@spec merge_metadata(target(), String.t() | ExWapp.JID.t(), map() | keyword()) :: :ok

Upserts metadata fields for a chat from sync/notification payloads.

Supported keys:

  • :name
  • :unread_count
  • :last_message_timestamp
  • :pinned
  • :muted_until
  • :archived
  • :is_group

messages(target, jid, opts \\ [])

@spec messages(target(), String.t() | ExWapp.JID.t(), keyword()) :: [message()]

Gets a materialized page of locally retained messages, newest first.

Message payloads live in the configured message store rather than in the chat struct. Use stream_messages/3 for an unbounded, lazy traversal.

new_chat(jid, opts \\ [])

@spec new_chat(
  String.t(),
  keyword()
) :: chat()

Creates a new chat struct.

parse_message_node(arg1)

@spec parse_message_node(ExWapp.Binary.Node.t()) ::
  {:ok, String.t(), message()} | {:error, term()}

Parses a received message node into a message struct.

pin(target, jid)

@spec pin(target(), String.t()) :: :ok

Pins a chat.

stream_messages(target, jid, opts \\ [])

@spec stream_messages(target(), String.t() | ExWapp.JID.t(), keyword()) ::
  Enumerable.t()

Builds a lazy stream over locally retained messages.

The default order is oldest first so a wrapper can persist history in chronological order. The stream reads one indexed record at a time and does not first load the complete chat history.

This is local history only; it does not request older messages from WhatsApp.

unarchive(target, jid)

@spec unarchive(target(), String.t()) :: :ok

Unarchives a chat.

unpin(target, jid)

@spec unpin(target(), String.t()) :: :ok

Unpins a chat.

update_archived(target, jid, archived)

@spec update_archived(target(), String.t(), boolean()) :: :ok

Update archived state from app state sync dispatch.

update_message_status(target, jid, message_id, status)

@spec update_message_status(
  target(),
  String.t() | ExWapp.JID.t(),
  String.t(),
  message_status()
) ::
  :ok | {:error, term()}

Updates a message status.

update_message_status_by_id(target, message_id, status)

@spec update_message_status_by_id(target(), String.t(), message_status()) ::
  :ok | {:error, term()}

Updates a message status by message ID across all chats.

Useful for ACK nodes that do not provide a chat JID we can trust.

update_muted(target, jid, mute_action)

@spec update_muted(target(), String.t(), map()) :: :ok

Update muted state from app state sync dispatch.

update_name(target, jid, name)

@spec update_name(target(), String.t(), String.t()) :: :ok

Updates the chat name (for contacts that send push names).

update_pinned(target, jid, pinned)

@spec update_pinned(target(), String.t(), boolean()) :: :ok

Update pinned state from app state sync dispatch.