Go SDK users, friends and presence
This page covers everything about people: the user's own profile, other users' profiles, friends and friend requests, the blocklist, presence, and the user's signed-in devices. In the Go SDK these are all methods on im.Client; the method names, parameters and return values below match the source.
Call these methods after signing in (see Initialization and sign-in). Changes arrive as events (see Events, sync and Store). The SDK's in-memory Store only caches conversations and messages, so keep friends, groups and presence yourself.
| You want to | See |
|---|---|
| Read or edit the user's own profile | Own profile |
| Look up other users' nicknames and avatars | Other users' profiles |
| Show presence | Presence |
| List or kick the user's signed-in devices | Signed-in devices |
| Friends, friend requests, how people can add the user | Friends, Friend requests, Friend settings |
| Block someone | Blocklist |
Own profile
| Method | Use | Key parameters |
|---|---|---|
c.Me(ctx) | Get the user's own profile | Returns *im.SelfProfile (including HasPassword) |
c.UpdateProfile(ctx, nickname, avatarURL, attributes) | Edit the user's own profile | An empty nickname or avatar leaves it unchanged; nil attributes leaves them unchanged |
c.SetPassword(ctx, oldPassword, newPassword) | Set or change the password | An empty oldPassword means setting it for the first time |
c.ClientConfig(ctx) | App-level config | Returns map[string]any |
c.Report(ctx, reason, attributes) | Report crashes, logs, stats and so on | reason up to 256 characters |
ctx := context.Background()
me, err := c.Me(ctx)
if err != nil {
log.Fatal(err)
}
_, err = c.UpdateProfile(ctx, "张三", "", map[string]any{"sign": "今天也要加油"})
if err != nil {
log.Print(err)
}
// 首次设置密码时第一个参数传空字符串
err = c.SetPassword(ctx, "", "new-pass-123")Other users' profiles
| Method | Use | Key parameters |
|---|---|---|
c.GetUser(ctx, username) | Get a user's public profile | Returns *im.UserProfile |
c.LookupUsers(ctx, usernames) | Look up users in a batch | Up to 100 at a time; returns []im.UserProfile |
p, err := c.GetUser(ctx, "bob")
if err == nil {
fmt.Println(p.Username, p.Nickname)
}
profiles, err := c.LookupUsers(ctx, []string{"bob", "lisi"})When the user changes their own profile you get im.EventUserProfileChanged (user.profile_changed, about the user only). Other users' profile changes aren't pushed; look them up again when you need the latest.
Presence
| Method | Use | Key parameters |
|---|---|---|
c.QueryPresence(ctx, usernames) | Query presence once | Returns []im.PresenceItem |
c.SubscribePresence(ctx, usernames) | Subscribe to presence | Goes over the connection (presence.subscribe); ConnectWait must have succeeded |
c.UnsubscribePresence(ctx, usernames) | Unsubscribe | An empty slice unsubscribes from everyone |
It works by subscription and events, not polling: SubscribePresence registers the people to follow, and their changes then arrive as im.EventPresenceChanged (presence.changed) events, each with one person's latest state. The payload is a presence JSON with the same fields as the PresenceItem returned by QueryPresence (username, online, platforms, last_seen_at, version), so parse it straight into im.PresenceItem:
c.OnEvent(func(e im.Event) {
switch e.Name {
case im.EventPresenceChanged:
var p im.PresenceItem
if json.Unmarshal(e.Data, &p) == nil {
fmt.Println(p.Username, p.Online, p.Platforms)
}
case im.EventPresenceReset:
// 订阅被服务端取消(如应用的在线状态设置变化)
// 清空本地保存的状态后重新订阅
}
})
if err := c.SubscribePresence(ctx, []string{"bob"}); err != nil {
log.Print(err)
}Only subscribe to people on screen
Subscriptions belong to one connection, so subscribe again after reconnecting. Each connection can subscribe to a limited number of people, and a user may have tens of thousands of friends. Only subscribe to people whose presence is on screen right now (such as friends in the conversation list, or the other person in an open one-to-one chat), and unsubscribe with UnsubscribePresence when leaving that screen. The SDK doesn't keep this subscription list for you.
The app must turn on presence
Your app turns presence on on the server. When it's off, SubscribePresence and QueryPresence are refused with permission_denied. You can read the app config with c.ClientConfig(ctx) first to decide whether to show presence.
Signed-in devices
| Method | Use | Key parameters |
|---|---|---|
c.Sessions(ctx) | All the user's active sign-ins (devices) | Returns []im.LoginSession; the one with Current true is this device |
c.RevokeSession(ctx, sessionID) | Kick a sign-in | The kicked device's connection closes immediately and it must sign in again |
LoginSession has SessionID, Platform, DeviceName, DeviceID, CreatedAt, LastActiveAt and Current. You can also get this sign-in's server session ID with c.SessionID() to mark "this device" in the list:
sessions, err := c.Sessions(ctx)
if err != nil {
log.Print(err)
}
for _, s := range sessions {
mark := ""
if s.SessionID == c.SessionID() || s.Current {
mark = "(本机)"
}
fmt.Println(s.DeviceName, s.Platform, mark)
}
// 吊销其他设备:跳过本机
for _, s := range sessions {
if s.SessionID != c.SessionID() {
_ = c.RevokeSession(ctx, s.SessionID)
}
}When one of the user's devices is revoked from another device, or must sign in again, you get im.EventUserSessionsRevoked or im.EventUserReloginRequired; changes to the device list arrive as im.EventDevicesChanged.
Friends
| Method | Use | Key parameters |
|---|---|---|
c.Friends(ctx) | Friend list | Returns []im.Friend; Remark and Attributes are the user's own |
c.CheckFriends(ctx, usernames) | Check friendship in a batch | Returns []im.FriendCheck (Username and IsFriend) |
c.SetFriendRemark(ctx, username, remark, attributes) | Set a friend's remark and custom attributes | An empty string or nil leaves it unchanged |
c.RemoveFriend(ctx, username) | Remove a friend | Both sides' friend lists drop each other |
Remarks and custom attributes belong to the user's side only; the friend can't see them. Friendship changes arrive as events, im.EventFriendAdded, im.EventFriendUpdated and im.EventFriendRemoved, whose payload parses into im.FriendEventData (with fields such as FriendUsername, Remark and Reason). After removing a friend, the server may also cancel the user's presence subscription to them.
Friend requests
Sending a request returns a status string: pending when the other person requires approval and must handle it, or accepted when they let anyone add them and you're already friends.
| Method | Use | Key parameters |
|---|---|---|
c.SendFriendRequest(ctx, username, message) | Send a friend request | Returns status: pending or accepted |
c.FriendRequests(ctx, which) | List received or sent requests | which is received or sent; returns []im.FriendRequest |
c.AcceptFriendRequest(ctx, username) | Accept a request | The requester's username |
c.DeclineFriendRequest(ctx, username) | Decline a request | The requester's username |
c.MarkFriendRequestsRead(ctx) | Mark received requests read | No parameters |
c.FriendRequestUnreadCount(ctx) | Unread request count | Returns int64 |
The whole request flow:
// alice 向 bob 发起申请
status, err := c.SendFriendRequest(ctx, "bob", "我是 alice")
if err != nil {
log.Print(err)
} else if status == "accepted" {
fmt.Println("已成为好友")
}
// bob 这一侧:查未读、列出收到的申请、同意
n, _ := c.FriendRequestUnreadCount(ctx)
reqs, _ := c.FriendRequests(ctx, "received")
for _, r := range reqs {
fmt.Println(r.Username, r.Message, r.Status) // pending|accepted|declined
}
err = c.AcceptFriendRequest(ctx, "alice")
_ = c.MarkFriendRequestsRead(ctx)
// 发出的申请用 "sent" 查询;拒绝用 DeclineFriendRequest
sent, _ := c.FriendRequests(ctx, "sent")
_ = sentRequest events: im.EventFriendRequestReceived when a request arrives, im.EventFriendRequestDeclined when a sent request is declined (payload im.FriendRequestEventData), and im.EventFriendRequestRead when requests are marked read on another device, so you can refresh the unread count.
Friend settings
| Method | Use | Key parameters |
|---|---|---|
c.FriendSettings(ctx) | Read how others can add the user | Returns a string: anyone (anyone can add the user directly) or request (the user must approve) |
c.SetFriendSettings(ctx, mode) | Set how others can add the user | mode is anyone or request |
This isn't Do Not Disturb
FriendSettings controls what happens when someone sends the user a friend request; it has nothing to do with muting messages. In anyone mode, requests become friendships immediately, and the sender's SendFriendRequest gets accepted.
Blocklist
| Method | Use | Key parameters |
|---|---|---|
c.Blacklist(ctx) | The blocklist | Returns []string (usernames) |
c.BlockUser(ctx, username) | Block a user | Succeeds even if already blocked |
c.UnblockUser(ctx, username) | Unblock a user | Succeeds even if not blocked |
Once blocked, a user can't send the user one-to-one messages or friend requests. Changes arrive as im.EventBlacklistChanged (blacklist.changed); in the im.BlacklistChangedData payload, Blocked false means the user was unblocked.
Errors
All the methods above return *im.APIError on failure. Check the code with im.IsCode; for the codes, see Events, sync and Store. For example, a missing user returns not_found, and not being signed in returns unauthenticated.
if _, err := c.GetUser(ctx, "ghost"); err != nil {
if im.IsCode(err, im.CodeNotFound) {
fmt.Println("用户不存在")
}
}See also
- Initialization and sign-in: create a client, sign in, open the connection.
- Groups: create groups, manage members, invitations and join requests.
- Events, sync and Store: the event list, post-sign-in sync and error handling.
