Go SDK conversations
A conversation is the message stream between two users (one-to-one) or in a group (group chat). This page covers fetching conversations and reading them locally, unread counts, read receipts, and pinning, drafts, marking unread, deleting and clearing. For messages in a conversation, see Messages; for event subscriptions and how the Store works, see Events and errors.
| You want to | See |
|---|---|
| Show the conversation list | Read the conversation list from the Store, Fetch recent conversations |
| Unread counts, mark unread, mark all read | Unread counts |
| Show "Read" and report group read receipts | Read receipts |
| Pin conversations and save drafts | Pinning and drafts |
| Delete a conversation or clear its history | Delete and clear |
| Open a one-to-one chat from a contact | Find a one-to-one conversation |
Below, c is the client from Initialization, sign-in and connection:
import im "github.com/DeepRespond-AI/deeprespond-im-go-sdk"
c, _ := im.New(im.Config{
AppKey: "1575529652#demo", // 组织#应用
APIURL: "https://im.example.com", // IM 服务端 REST 地址
})
_, _ = c.Login(ctx, im.LoginPassword, "alice", "pass-123")Where conversations come from
You never "create" a conversation. The server creates it when the first message is sent to a user or in a group, whoever sends first. After that, every conversation operation uses the conversation ID the server assigned. The server maintains conversation state, and the SDK keeps it in the in-memory Store through post-sign-in sync and connection events, so you don't merge anything yourself.
Identifying conversations
In the SDK a conversation is a ConversationState, with ConversationType telling one-to-one and group apart:
- One-to-one (
single):ConversationIDis an ID the server generates, and the other user's username is inPeer.PeerReadSeqis how far the other person has read. - Group (
group):ConversationIDis the group ID, also inGroupID. Whether the user is still in the group is inMembership(member,left,removed,dismissed).
Because a group conversation's ID is the group ID, you can send from a group page straight away with im.ToGroup(groupID); for one-to-one chats use im.ToUser(peer). See Messages.
Methods
Conversation methods are on Client. They all use REST, take a context.Context first, and return *im.APIError on failure:
| Method | Use | Key parameters |
|---|---|---|
RecentConversations | Fetch recent conversations, paged by cursor | cursor: "" for the first page, then the previous page's NextCursor; limit: items per page, 100 when ≤0 |
Conversation | Get one conversation's state | id: conversation ID; the result is also written to the Store |
SingleConversation | Get the one-to-one conversation with a user | peer: the other username; not_found if they have no conversation yet |
DeleteConversation | Delete a conversation | id; the server hides it and the local cache is cleared |
ClearConversation | Clear a conversation's history | id; the server advances ClearedSeq |
SetConversationPinned | Pin or unpin | id; pinned |
MarkConversationUnread | Mark or unmark as unread | id; marked |
SetConversationDraft | Save a draft | id; draft: the draft text, an empty string clears it |
ReadAllConversations | Mark all conversations read | None |
UnreadCount | Total unread across all conversations | None |
GroupReceipts | Report group read receipts | conversationID; seqs: the seqs read |
ReactionUsers | Who reacted with a key on a message | conversationID, seq, key: the reaction key |
Read, which marks one conversation read, is covered in Messages.
Fetch recent conversations
RecentConversations returns a Page[ConversationState]: Items are this page's conversations, and a non-empty NextCursor means there's another page:
cursor := ""
for {
page, err := c.RecentConversations(ctx, cursor, 100)
if err != nil {
log.Fatal(err)
}
for _, st := range page.Items {
fmt.Printf("%s %s 未读 %d\n", st.ConversationID, st.ConversationType, st.UnreadCount)
}
if page.NextCursor == "" {
break
}
cursor = page.NextCursor
}Read the conversation list from the Store
Rather than fetching from the server, it's more common to read the in-memory Store. Once the connection is open, the Store is maintained from events (new messages, reads, pins, deletes on other devices all update it), so just rebuild the UI from it:
store := c.Store()
for _, st := range store.Conversations() { // 按最近消息时间倒序
title := st.GroupID
if st.ConversationType == "single" {
title = st.Peer
}
// 未读数为 0 但被标记为未读时,显示一个小圆点
dot := st.UnreadCount == 0 && st.MarkedUnread
// 有 @ 本人还没读到的消息时,可以显示“[有人@我]”
mentioned := st.MentionSeq > 0
fmt.Println(title, st.UnreadCount, dot, mentioned)
}- The Store is an in-process memory cache and is empty after a restart. Fill it with
SyncAll(or wait for the SDK's sync) first; see the Store section of Events and errors. store.Conversation(id)reads one conversation, ornilif it isn't there. State from REST calls such asConversationandSingleConversationcan also be written withstore.PutConversation.store.Typing(conversationID)returns typing indicators from the last 10 seconds; see Messages.- Events drive when to refresh the UI (
message.received,message.conversation_changedand so on): re-read the Store in yourOnEventcallback.
Unread counts
- A conversation's unread count is
ConversationState.UnreadCount. The Store increments it when messages from others arrive; the user's own messages andexclude_from_unreadmessages don't count. - Total unread across all conversations:
total, err := c.UnreadCount(ctx)- To deal with a conversation later, the user can mark it unread without changing the read position:
_ = c.MarkConversationUnread(ctx, convID, true)
_ = c.MarkConversationUnread(ctx, convID, false)- Mark everything read:
_ = c.ReadAllConversations(ctx)While the user is looking at a conversation, call Read to mark it read; see "Read status and typing" in Messages.
Read receipts
- One-to-one: no separate query is needed.
ConversationState.PeerReadSeqis how far the other person has read; messages the user sent withSequp to it can show "Read". When the other person marks read, the server pushes amessage.peer_readevent and the conversation state in the Store updates. - Group: after reading messages that ask for receipts, members report the
seqs they've read withGroupReceipts(there's no such call for one-to-one chats). The sender learns who read which messages throughmessage.read_byevents; for the payload, see Events and errors.
// 用户把群会话看到第 120 条时
_ = c.GroupReceipts(ctx, groupConvID, []int64{120})Pinning and drafts
// 置顶、取消置顶
_ = c.SetConversationPinned(ctx, convID, true)
_ = c.SetConversationPinned(ctx, convID, false)
// 离开会话时保存草稿,发出后清除
_ = c.SetConversationDraft(ctx, convID, "明天上午十点")
_ = c.SetConversationDraft(ctx, convID, "")- Once pinned,
ConversationState.PinnedAtis the pin time, so the list can put pinned conversations first. - A draft is any text; the server stores it as is and it's shared across the user's signed-in devices. The Go SDK's
ConversationStatehas no draft field, so to restore drafts, keep track of which draft belongs to which conversation in your app.
Delete and clear
// 从会话列表中删除:服务端隐藏会话,Store 中的本地缓存一并清空
_ = c.DeleteConversation(ctx, convID)
// 只清空聊天记录,会话仍在列表中:服务端推进 ClearedSeq,
// Store 中不大于它的消息随后被自动清除
_ = c.ClearConversation(ctx, convID)- Both only affect the user; the other person and other group members aren't affected.
- A deleted conversation comes back through events when the other person sends a new message.
- After clearing, the user can't see earlier messages, and
StartSeq(the start of the visible range) grows.
Reaction users
To get every user who reacted with a key on a message, page through ReactionUsers (adding and removing reactions with AddReaction / RemoveReaction is in Messages):
users, err := c.ReactionUsers(ctx, convID, 120, "thumbs_up")
if err != nil {
log.Fatal(err)
}
for _, u := range users.Items { // 用户名列表
fmt.Println(u)
}
if users.NextCursor != "" {
// 下一页
}Find a one-to-one conversation
When entering a chat from somewhere like a contacts page, get the one-to-one conversation by the other username:
st, err := c.SingleConversation(ctx, "bob")
if im.IsCode(err, im.CodeNotFound) {
// 两人还没有会话:直接发第一条消息即可,服务端会自动建立
}If the conversation exists, you get its state. Conversation(ctx, id) gets one by conversation ID and also writes it to the Store.
Types
ConversationState
The user's state in a conversation; REST and the Store use the same structure.
| Field | Type | Description |
|---|---|---|
ConversationID | string | Conversation ID; for groups, the group ID |
ConversationType | string | single or group |
Peer | string | The other username in a one-to-one chat; empty for groups |
GroupID | string | Group ID for group chats; empty for one-to-one |
Membership | *string | The user's membership in a group: member, left, removed, dismissed; nil for one-to-one |
StartSeq | int64 | seq of the first message the user can see (joining a group and clearing both raise it) |
MaxSeq | int64 | seq of the last message the user can see |
ReadSeq | int64 | The user's read position |
UnreadCount | int64 | Number of unread messages |
MarkedUnread | bool | Whether it's marked unread |
PeerReadSeq | int64 | How far the other person has read, in one-to-one chats |
MentionSeq | int64 | seq of an unread message that mentions the user or everyone; 0 if none |
ClearedSeq | int64 | Position the history was cleared at; 0 if never cleared |
HiddenSeq | int64 | Position when the conversation was deleted; 0 if never deleted |
Hidden | bool | Whether the conversation is deleted (hidden) |
PinnedAt | string | When it was pinned; empty if not pinned |
JoinedAt / LeftAt | string | When the user joined or left the group this time |
LastMessageAt | string | Time of the last message |
MessageVersion | int64 | Change version of the conversation's messages |
Version | int64 | State version, for sync and de-duplication |
Page[T]
Generic page result, returned by RecentConversations and ReactionUsers.
| Field | Type | Description |
|---|---|---|
Items | []T | This page's items |
NextCursor | string | Cursor for the next page; empty when there isn't one |
Total | int64 | Total count (only when the API gives it) |
See also
- Messages: send and receive messages in a conversation, mark read, react.
- Events and errors: event subscriptions, how the Store is maintained, and error codes.
