ChatEngine

class ChatEngine(api: WidgetApi, connector: SocketConnector, store: SessionStore, appInfo: HatangAppInfo, logger: HatangLogger = HatangLogger.SILENT, preferredLocale: String? = null, backoff: Backoff = Backoff(), val backgroundCloseDelay: Duration = 10.seconds, val typingIdle: Duration = 3.seconds, val bootstrapRetry: Duration = 5.seconds, val openOnProactiveMessage: Boolean = true, clock: HatangClock = HatangClock.SYSTEM, scope: CoroutineScope? = null, dispatcher: CoroutineDispatcher = Dispatchers.Default)

The chat state machine: bootstrap → connect → ready → frames, plus every host-facing action. Pure Kotlin/JVM; the Android module wires storage, lifecycle and UI around it.

All work runs on one confined coroutine (a single-parallelism view of dispatcher) inside scope's lifecycle, so the engine needs no locks. Observe state and events; call actions from any thread. Suspending actions finish when the work is done (a send, once acknowledged or failed); the non-suspending ones are queued in call order.

Constructors

Link copied to clipboard
constructor(api: WidgetApi, connector: SocketConnector, store: SessionStore, appInfo: HatangAppInfo, logger: HatangLogger = HatangLogger.SILENT, preferredLocale: String? = null, backoff: Backoff = Backoff(), backgroundCloseDelay: Duration = 10.seconds, typingIdle: Duration = 3.seconds, bootstrapRetry: Duration = 5.seconds, openOnProactiveMessage: Boolean = true, clock: HatangClock = HatangClock.SYSTEM, scope: CoroutineScope? = null, dispatcher: CoroutineDispatcher = Dispatchers.Default)

Properties

Link copied to clipboard

How long after going to the background the socket is closed.

Link copied to clipboard

Delay before a failed bootstrap is retried (transient errors only).

Link copied to clipboard
val events: SharedFlow<HatangEvent>

Host-facing events (not replayed: subscribe before start).

Link copied to clipboard

The install id (after start).

Link copied to clipboard

start was called and stop was not.

Link copied to clipboard

Open the chat when the team starts a conversation with open: true (see openRequests).

Link copied to clipboard
val openRequests: SharedFlow<String>

Conversation ids the team opened proactively with open: true; the UI layer opens the screen.

Link copied to clipboard
val state: StateFlow<ChatState>

Every snapshot the UI renders.

Link copied to clipboard

The current visitor token (after bootstrap).

Link copied to clipboard

Idle time after the last keystroke before typing off.

Functions

Link copied to clipboard
suspend fun attach(source: UploadSource, caption: String = "")

Sends a file, optionally with a caption. It shows at once as a pending bubble with upload progress; when the bytes are on the server the message goes out like text (same retry by client id). Files over 10 MB or of a type the gateway refuses fail immediately with a transient error.

Link copied to clipboard

Dismisses the pre-chat form without sending.

Link copied to clipboard
suspend fun clearPushToken()

Unregisters the push token (DELETE devices), e.g. on sign-out.

Link copied to clipboard

Clears the error banner.

Link copied to clipboard
suspend fun connect()

Opens the socket again after stop or a background close (bootstraps first when it never ran).

Link copied to clipboard
fun dispose()

Releases every resource; the engine cannot be used afterwards.

Link copied to clipboard
suspend fun identify(user: HatangUser)

Attaches an identity. Returns once the gateway acknowledged it (or, on a merge, once the new session started). Throws HatangException (closed, timeout, or the gateway's code).

Link copied to clipboard
suspend fun listConversations(status: String = "all", after: String? = null, limit: Int = 20): ConversationPage

The visitor's conversations, newest activity first, resolved ones included (an in-app inbox). status is all, open or resolved; pass the last id of a page as after for the next one.

Link copied to clipboard
suspend fun loadEarlier()

Loads the page before the oldest loaded item.

Link copied to clipboard

The composer text changed: sends one typing on, then off after typingIdle without keystrokes.

Link copied to clipboard
suspend fun openActive()

Back to the visitor's current conversation (the newest open one), or an empty chat when there is none, so the next message starts a new one.

Link copied to clipboard
suspend fun openConversation(id: String, summary: VisitorConversationDto? = null)

Shows conversation id: its latest 50 items, live updates while it is on screen, earlier ones through loadEarlier. Writing into a resolved conversation reopens it; a closed one is read-only. summary (from listConversations) avoids a flash of the wrong status. Before the session is ready the request is remembered and honoured on ready (a notification tap on a cold start).

Link copied to clipboard
fun pushEvent(name: String, data: Map<String, Any?>? = null)

Records a custom event on the active conversation.

Link copied to clipboard
fun rate(score: Int, comment: String? = null)

Rates the conversation (CSAT, score 1–5).

Link copied to clipboard
suspend fun refreshAttachments(message: MessageDto)

Signed attachment links expire after a day. When one fails to load, fetch that message again for fresh links (once per message per session).

Link copied to clipboard
suspend fun reportPurchase(storeProductId: String, transactionId: String? = null, amount: Double? = null, currency: String? = null, platform: String = "android", purchaseToken: String? = null, productType: String? = null, kind: String? = null): Boolean

Reports a finished store purchase: with the Play purchaseToken Hatang verifies it with Google and records it for this person; the team also gets an internal note in the conversation. False without a session, on an older gateway, or when the store refuses it.

Link copied to clipboard
suspend fun reset()

Forgets this visitor: the old token stops working, a fresh visitor is bootstrapped and the push token (if any) is re-registered for it. Before start the stored visitor is forgotten all the same, and the new one connects on the next start.

Link copied to clipboard
suspend fun restoreSession(linkToken: String)

Swaps a magic-link token (…/c/<token> from a "we replied" email) for that session.

Link copied to clipboard
suspend fun retry(clientId: String)

Re-sends a failed message with the same client id (re-uploading its file first if it never finished).

Link copied to clipboard
suspend fun send(text: String)

Sends text (trimmed; blank text is ignored). Shows the pre-chat form instead when the team is away and the site wants an email. Returns once the message is acknowledged or marked failed.

Link copied to clipboard
suspend fun setData(data: Map<String, Any?>)

Attaches custom data (shown to agents).

Link copied to clipboard
fun setForeground(foreground: Boolean)

The app moved to the foreground or background. In the background the gateway is told at once (app.state) and the socket closes after backgroundCloseDelay; back in the foreground it reconnects.

Link copied to clipboard
suspend fun setLocale(locale: HatangLocale)

Switches the UI language; the socket re-authenticates so the gateway learns it too.

Link copied to clipboard
suspend fun setPushToken(token: String, provider: PushProvider)

Remembers the push token and registers it (PUT devices) once a visitor token exists.

Link copied to clipboard
fun setScreen(name: String, params: Map<String, String>? = null)

Reports the screen the app shows (sent now when connected, and on every auth).

Link copied to clipboard
fun setVisible(visible: Boolean)

The conversation is (not) on screen. Visible clears unread and sends a read receipt for everything loaded.

Link copied to clipboard
fun showLocalMessage(text: String, senderName: String? = null)

Inserts a local-only bot bubble (never sent, never persisted).

Link copied to clipboard
suspend fun skipEmail()

The visitor declined the optional email; the held-back draft is sent.

Link copied to clipboard
suspend fun start()

Loads the stored session, bootstraps and connects.

Link copied to clipboard
suspend fun stop()

Closes the socket and stops retrying; start may be called again.

Link copied to clipboard
suspend fun submitEmail(email: String)

Inline email request answered: identifies the visitor by email, then sends the held-back draft.

Link copied to clipboard
suspend fun submitOfflineForm(name: String? = null, email: String? = null, message: String? = null)

Offline pre-chat form: posts the first message (or the held-back draft) with name and email.