Building a Discord-like Platform with Tencent RTC Chat

Tencent RTC-Dev Team
Oct 8, 2024

Scenario Overview

Discord is a free online real-time messaging app and digital distribution platform designed for the communities. It allows users in the gaming, education, and business fields to communicate with each other through messages, pictures, videos, and audio in the software's chat channel.

Discord Concepts

  • Server: In Discord, there is a kind of group chat, which is different from the normal communication software groups, called servers (similar to communities), and server owners can create their own communities in the servers.
  • Channel: In servers, you can create chat channels, including the voice and text channels. The voice channel can be used for game broadcasting, chatting, etc. Channels can be set to integrate various permissions with identity groups, making the Discord community system more diverse.
  • Threads: Users can discuss specific topics in threads.

Products Applied

Tencent RTC Chat

Basic Integration Guidelines

Creating Chat apps

This tutorial is based on Chat. Therefore, you need to create an app in the console.



After the app is created successfully, you can view the basic information of the app on the basic information page of the app in the Chat console.

Understanding related configuration and capabilities

To use Chat to implement Discord features, you need to understand the basic concepts related to Chat in advance and some proper terms that will be mentioned later in this tutorial, including but not limited to the following:

  • SDKAppID: Chat assigns an SDKAppID for each app. The SDKAppID of an app can be viewed on the app details page after the app is created in the console and used when initializing the Chat SDK and calculating user login tickets. For more information, see UI SDK Initialization and Login.
  • Key: The key of an app can be viewed on the Chat console app details page and used to calculate SDK login tickets for users.
  • User account: Only users with Chat accounts can log in to Chat. When a user successfully logs in via a client SDK, the Chat backend automatically creates a Chat account for the user. In addition, you can use the server API that Chat provides to import the user to the user system of Chat.
  • Group: So far, Chat offers five types of groups for different scenarios, where users can send and receive messages.
  • Webhook configuration: You can proactively integrate the client and server APIs provided by Chat, and Chat will automatically return necessary information to your server when specific business logic is triggered. What you need to do is to simply complete related configuration in the Webhook Configuration module of the Chat console. Chat provides various webhook configuration and ensures high reliability for webhook events. You can use webhooks to implement various custom requirements.
  • Custom field: By default, Chat provides developers with fields that meet most of their needs. It also provides the following custom fields for each module to meet users' needs for extended fields:

Note:

To use custom fields, you can configure them in the console and then read/write them via SDK/API.

Integrating client and server SDKs

To implement Discord related features, you need to integrate Chat SDK. Chat provides diverse and easy-to-use SDKs and server APIs. Messages are synced across clients if you log in to the app with the same SDKAppID. Select an appropriate SDK according to your business requirement scenario and technology stack.

Scenario-specific implementation

As the figure above shows, Discord features include servers, channels, and threads. Different servers are used for different content. For example, we have the Honor of Kings server and Game for Peace server. You can create different types of channel in a server, such as the text channel, voice channel, and notice channel. Users communicate with each other in channels. If they have more ideas on a certain topic, they can create a thread for further discussion. The following will introduce how to implement these key Discord features through Chat one by one.

Note:

For code demos, we use the Android client (Java SDK) as an example. For the calling of APIs of other SDK editions, see Integration Solution (No UI).

Server

Creating a server

Analysis found the following characteristics with the Discord server list:

  1. Servers can have a huge number of users.
  2. Users don't actually communicate with each other in servers. Instead, they chat only in channels or threads in a server.
  3. Historical chat messages in servers need to be stored on roaming servers.
  4. Users have free access to servers.
  5. Channels can be created in servers.

Though Chat provides five types of groups, only community groups meet the characteristics of Discord servers. A Chat community group allows users to join and leave freely, supports up to 100,000 members, and stores the message history. To join the group, a user needs to search for the group ID and send an application, and the application does not need to be approved by an admin before the user can join the group.

You can use the createGroup API to create a server (group). Note that the group type should be Community and setSupportTopic be true so that channels can be created in the server. The following is sample code:

V2TIMGroupInfo  groupinfo = new V2TIMGroupInfo();
groupinfo.setGroupName("Test server");
groupinfo.setSupportTopic(true);
// Initial group members
List<V2TIMCreateGroupMemberInfo> memberList = new LinkedList<V2TIMCreateGroupMemberInfo>();
// Other settings, such as the server profile photo
V2TIMManager.getGroupManager().createGroup(groupinfo, memberList, new V2TIMValueCallback<String>() {
            @Override
            public void onError(int i, String s) {
                // Creation failed
            }

            @Override
            public void onSuccess(String s) {
                // The server is created successfully, and the server ID is returned.
            }
});

After the API is called successfully, the server ID will be returned in the onSuccess callback, which will be used later when you create a channel in the server.

Note:You can also use the server creation API provided by Chat. Key parameters are as follows:

{
    "Type": "Community", // Group type (required)
    "Name": "TestCommunityGroup", // Group name (required)
    "SupportTopic": 1// Whether the topic option is supported. Valid values: `1`: yes; `0`: no.
}

###### Server list

There is a list of servers that the current user has joined on the far left of Discord. For the community scenario, Chat provides a dedicated API for querying the server list.

```java
V2TIMManager.getGroupManager().getJoinedCommunityList(new V2TIMValueCallback<List<V2TIMGroupInfo>>() {
            @Override
            public void onSuccess(List<V2TIMGroupInfo> v2TIMGroupInfos) {
                // The server list is got successfully, and the basic information of the server list is provided in the returned `List<V2TIMGroupInfo>`.
            }

            @Override
            public void onError(int i, String s) {
              // Failed to get the service list.
            }
});

The returned V2TIMGroupInfo provides the basic server information. However, the returned server information does not include information such as the unread message count and custom status. To achieve the same effect as that on Discord, we need to use other APIs provided by Chat to implement the unread message count for the server list, which will be discussed later in the document.

Server categories

When a server is created, a default category will be created for it. After the server is created, you can create a new category. In Chat, a server is essentially a community. Therefore, we can set a custom field for a community group to implement the server type feature. To use a custom group field, perform the steps below:

1. Enable the custom field key in the console.

2. User the client SDK or server API to read/write the custom field.

Set the custom group field by using the server API and client SDK.

Caution:

The community group feature is only available in the Ultimate edition. Before setting a custom field for the community group, you need to purchase the Ultimate edition.

Display of the unread message count and custom status for the server



As mentioned previously, the API for getting the list of joined servers does not return information such as the unread message count and server status. It should be noted that we not only need to obtain this data, but also need to listen to the change of this data to update the client UI in time. Since the server is implemented by a Chat community group, and a community group does not generate conversations in Chat, we need to count the sum of unread messages in all public and private channel conversations. We can use the getUnreadCount API of V2TIMTopicInfo to get the unread message count of public channels and use the getConversation API to get the unread message count of private channels (because private channels are implemented by work groups).

// Public channels
List<String> conversationIDList = new LinkedList();
conversationIDList.add("GROUP_$GROUPID");
V2TIMManager.getConversationManager().getConversationList(conversationIDList, new V2TIMValueCallback<List<V2TIMConversation>>() {
            @Override
            public void onError(int i, String s) {
                // Failed to get the conversation information of the server
            }

            @Override
            public void onSuccess(V2TIMConversationList List<V2TIMConversation>) {
               // Got the conversation information of the server successfully
            }
});
// Private channels
V2TIMManager.getGroupManager().getTopicInfoList(groupID, topicIDList, new V2TIMValueCallback<List<V2TIMTopicInfoResult>>() {
                @Override
                public void onSuccess(List<V2TIMTopicInfoResult> v2TIMTopicInfoResults) {

                }

                @Override
                public void onError(int i, String s) {
                }
});

To implement the custom status feature for servers, we can use the setConversationCustomData API to set custom server conversation data.

List<String> conversationIDList = new LinkedList();
String customData = "Busy"
V2TIMManager.getConversationManager().setConversationCustomData(conversationIDList, customData, new V2TIMValueCallback<List<V2TIMConversationOperationResult>>() {
            @Override
            public void onSuccess(List<V2TIMConversationOperationResult> v2TIMConversationOperationResults) {
                // The custom group conversation data is set successfully
            }

            @Override
            public void onError(int i, String s) {
                // Failed to set the custom group conversation data
            }
});

When data related to the server conversation changes, the client needs to try to update the UI display. For listening for server conversation changes, Chat provides a corresponding event listener function addConversationListener. This callback function will be triggered in the following cases:

1. Server messages are added, deleted, or modified.

2. The unread count of server messages changes.

3. The custom server information is modified.

4. The server is pinned to the top.

5. The message receiving configuration of the server is modified.

6. The server mark is modified.

7. The server group is modified.

8. ...

V2TIMConversationListener conversationLister = new V2TIMConversationListener() {
            @Override
            public void onSyncServerStart() {
            }

            @Override
            public void onSyncServerFinish() {
            }

            @Override
            public void onSyncServerFailed() {
            }

            @Override
            public void onNewConversation(List<V2TIMConversation> conversationList) {
            }

            @Override
            public void onConversationChanged(List<V2TIMConversation> conversationList) {
            }
            @Override
            public void onTotalUnreadMessageCountChanged(long totalUnreadCount) {
            }

            @Override
            public void onConversationGroupCreated(String groupName, List<V2TIMConversation> conversationList) {
            }

            @Override
            public void onConversationGroupDeleted(String groupName) {
            }

            @Override
            public void onConversationGroupNameChanged(String oldName, String newName) {
            }

            @Override
            public void onConversationsAddedToGroup(String groupName, List<V2TIMConversation> conversationList) {、
            }

            @Override
            public void onConversationsDeletedFromGroup(String groupName, List<V2TIMConversation> conversationList) {
            }
}
V2TIMManager.getConversationManager().addConversationListener(conversationLister);

To sum up, we can use the getJoinedCommunityList and getConversationList APIs and the addConversationListener callback to implement the Discord feature of displaying the server list.

Channel

Multiple channels can be created in a server. As the figure below shows, channels are created under the server, and the channels can be placed in different categories.

Users can invite others to join a channel and modify the basic settings of the channel. Users do most of their chatting within channels, so channel capabilities are of paramount importance in Discord. Channel capabilities in Discord correspond to topic capabilities in Chat. Chat's community groups provide the capability to create topics in groups.

Default channels

When a server is created, Discord will create four default channels for the server. Chat can also implement such a feature. The process is as follows:

1. Notify the business server that the server is created successfully via the After a group is created webhook.

2. The business side determines whether the created group is a community group, so as not to affect the business related to other groups.

3. Create a topic on the server based on the server attributes.

Parameters for creating a topic on the server are as follows:

{
    "GroupId": "@TGS#_@TGS#cQVLVHIM62CJ", // Group ID of the topic, which is required
    "TopicId": "@TGS#_@TGS#cQVLVHIM62CJ@TOPIC#_TestTopic", // Custom topic ID, which is optional
    "TopicName": "TestTopic", // Topic name, which is required
    "From_Account": "1400187352", // Member creating the topic
    "CustomString": "This is a custom string",// Custom string
    "FaceUrl": "http://this.is.face.url", // (Optional) Topic profile photo URL
    "Notification": "This is topic Notification", // (Optional) Topic notice
    "Introduction": "This is topic Introduction" // (Optional) Topic introduction
}

Creating a channel

On a Discord client, users can create channels under different channel categories, as shown in the figure below:

Creating a channel in Discord is equivalent to creating a topic in a community group in Chat. When creating a topic in Chat, you can set the category and basic information of the topic.



You can use the createTopicInCommunity API to implement related features.

String groupID = "Server ID"
V2TIMTopicInfo info = new V2TIMTopicInfo();
info.setCustomString("{'categray':'Game','type':'text'}") // Set the channel category and type
// Set the basic information for `V2TIMTopicInfo`
V2TIMManager.getGroupManager().createTopicInCommunity(groupID, info, new V2TIMValueCallback<String>() {
            @Override
            public void onSuccess(String s) {
                // Channel created successfully
            }

            @Override
            public void onError(int i, String s) {
                // Failed to create the channel
            }
});

When creating a channel, you can call the V2TIMTopicInfo method to set the channel information and call the setCustomString API to set the channel category and type.



1. Can be received only by online users.

2. Will not be stored on a roaming server.

In addition, we've made the following optimizations for better performance:

  • The sending of the "typing..." status message will only be triggered if two users send messages to each other within 20s.
  • The same text message does not trigger online message sending multiple times.

Private messages

Private messages are messages that Discord users send to each other, regardless of whether they are friends or not.

The relevant code is as follows:

// Add a friend
V2TIMManager.getFriendshipManager().addFriend(info, new V2TIMValueCallback<V2TIMFriendOperationResult>() {
            @Override
            public void onError(int i, String s) {
                // Failed to add the friend
            }

            @Override
            public void onSuccess(V2TIMFriendOperationResult v2TIMFriendOperationResult) {
               // Friend added successfully
            }
});
// Obtain the contacts
V2TIMManager.getFriendshipManager().getFriendList(new V2TIMValueCallback<List<V2TIMFriendInfo>>() {
            @Override
            public void onError(int i, String s) {
               // Failed to obtain the contacts
            }

            @Override
            public void onSuccess(List<V2TIMFriendInfo> v2TIMFriendInfos) {
               // The contacts obtained successfully
            }
});

Personal center

Online status

The online status capabilities of Discord's user panel can be implemented by the following online status APIs provided by Chat:

  • setSelfStatus: API for setting one's own custom online status. Users' online/offline statuses are set by Chat and cannot be modified by developers.
  • getUserStatus: API for getting the online statuses of friends.
  • onUserStatusChanged: API for listening for the online status changes of friends.

The relevant code is as follows:

// Set your own online status
V2TIMUserStatus customStatus = new V2TIMUserStatus();
V2TIMManager.getInstance().setSelfStatus(customStatus, new V2TIMCallback() {
    @Override
    public void onSuccess() {

    }

    @Override
    public void onError(int i, String s) {

    }
});
// Get the online statuses of friends
List<String> userIDList = new LinkerList();
V2TIMManager.getInstance().getUserStatus(userIDList, new V2TIMValueCallback<List<V2TIMUserStatus>>() {
    @Override
    public void onSuccess(List<V2TIMUserStatus> v2TIMUserStatuses) {

    }

    @Override
    public void onError(int i, String s) {

    }
});

Personal information

Personal information related features can be implemented by the following relationship chain related APIs provided by Chat:

// Set the user's profile
final V2TIMUserFullInfo userFullInfo = new V2TIMUserFullInfo();
V2TIMManager.getInstance().setSelfInfo(userFullInfo, new V2TIMCallback() {
    @Override
    public void onError(int i, String s) {

    }

    @Override
    public void onSuccess() {

    }
});
// Get user profiles
List<String> userIDList = new LinkedList();
V2TIMManager.getInstance().getUsersInfo(userIDList, new V2TIMValueCallback<List<V2TIMUserFullInfo>>() {
    @Override
    public void onError(int i, String s) {

    }

    @Override
    public void onSuccess(List<V2TIMUserFullInfo> v2TIMUserFullInfos) {

    }
});

Others

Search

Discord provides the following search capabilities:

Chat provides rich search capabilities, including:

For how to use the APIs, see the official documentation.

Offline push

Chat's online messages cannot reach offline users. To address this issue, we need to integrate the offline push capabilities provided by device vendors to Chat. For more information, see Offline Push.

Sensitive word verification

When you send information and configuration in Discord, the content needs to be filtered. Chat also provides a similar scheme to help users use Chat with compliance.

Order Now

Click here to quickly go to the purchase page to order.