Closed ToYashDeepSingh closed 9 months ago
Which interface do you use to interact with TDLib?
@levlam I am using Java 17.
No, which interface/classes do you use for interaction with TDLib?
I use the UpdateHandler class which implements Client.ResultHandler:
package in.nobroker.TelegramWebClient;
import lombok.extern.slf4j.Slf4j;
import org.drinkless.tdlib.Client;
import org.drinkless.tdlib.TdApi;
import static in.nobroker.TelegramWebClient.constants.Constants.basicGroups;
import static in.nobroker.TelegramWebClient.constants.Constants.basicGroupsFullInfo;
import static in.nobroker.TelegramWebClient.constants.Constants.chats;
import static in.nobroker.TelegramWebClient.constants.Constants.mainChatList;
import static in.nobroker.TelegramWebClient.constants.Constants.secretChats;
import static in.nobroker.TelegramWebClient.constants.Constants.supergroups;
import static in.nobroker.TelegramWebClient.constants.Constants.supergroupsFullInfo;
import static in.nobroker.TelegramWebClient.constants.Constants.users;
import static in.nobroker.TelegramWebClient.constants.Constants.usersFullInfo;
@Slf4j
public class UpdateHandler implements Client.ResultHandler {
AuthorizationStateUpdate authorizationStateUpdate = new AuthorizationStateUpdate();
@Override
public void onResult(TdApi.Object object) {
log.info(String.valueOf(object));
switch (object.getConstructor()) {
case TdApi.UpdateAuthorizationState.CONSTRUCTOR:
authorizationStateUpdate.onAuthorizationStateUpdated(((TdApi.UpdateAuthorizationState) object).authorizationState);
break;
case TdApi.UpdateUser.CONSTRUCTOR:
TdApi.UpdateUser updateUser = (TdApi.UpdateUser) object;
users.put(updateUser.user.id, updateUser.user);
break;
case TdApi.UpdateUserStatus.CONSTRUCTOR: {
TdApi.UpdateUserStatus updateUserStatus = (TdApi.UpdateUserStatus) object;
TdApi.User user = users.get(updateUserStatus.userId);
synchronized (user) {
user.status = updateUserStatus.status;
}
break;
}
case TdApi.UpdateBasicGroup.CONSTRUCTOR:
TdApi.UpdateBasicGroup updateBasicGroup = (TdApi.UpdateBasicGroup) object;
basicGroups.put(updateBasicGroup.basicGroup.id, updateBasicGroup.basicGroup);
break;
case TdApi.UpdateSupergroup.CONSTRUCTOR:
TdApi.UpdateSupergroup updateSupergroup = (TdApi.UpdateSupergroup) object;
supergroups.put(updateSupergroup.supergroup.id, updateSupergroup.supergroup);
break;
case TdApi.UpdateSecretChat.CONSTRUCTOR:
TdApi.UpdateSecretChat updateSecretChat = (TdApi.UpdateSecretChat) object;
secretChats.put(updateSecretChat.secretChat.id, updateSecretChat.secretChat);
break;
case TdApi.UpdateNewChat.CONSTRUCTOR: {
TdApi.UpdateNewChat updateNewChat = (TdApi.UpdateNewChat) object;
TdApi.Chat chat = updateNewChat.chat;
synchronized (chat) {
chats.put(chat.id, chat);
TdApi.ChatPosition[] positions = chat.positions;
chat.positions = new TdApi.ChatPosition[0];
setChatPositions(chat, positions);
}
break;
}
case TdApi.UpdateChatTitle.CONSTRUCTOR: {
TdApi.UpdateChatTitle updateChat = (TdApi.UpdateChatTitle) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.title = updateChat.title;
}
break;
}
case TdApi.UpdateChatPhoto.CONSTRUCTOR: {
TdApi.UpdateChatPhoto updateChat = (TdApi.UpdateChatPhoto) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.photo = updateChat.photo;
}
break;
}
case TdApi.UpdateChatPermissions.CONSTRUCTOR: {
TdApi.UpdateChatPermissions update = (TdApi.UpdateChatPermissions) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.permissions = update.permissions;
}
break;
}
case TdApi.UpdateChatLastMessage.CONSTRUCTOR: {
TdApi.UpdateChatLastMessage updateChat = (TdApi.UpdateChatLastMessage) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.lastMessage = updateChat.lastMessage;
setChatPositions(chat, updateChat.positions);
}
break;
}
case TdApi.UpdateChatPosition.CONSTRUCTOR: {
TdApi.UpdateChatPosition updateChat = (TdApi.UpdateChatPosition) object;
if (updateChat.position.list.getConstructor() != TdApi.ChatListMain.CONSTRUCTOR) {
break;
}
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
int i;
for (i = 0; i < chat.positions.length; i++) {
if (chat.positions[i].list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
break;
}
}
TdApi.ChatPosition[] new_positions = new TdApi.ChatPosition[chat.positions.length + (updateChat.position.order == 0 ? 0 : 1) - (i < chat.positions.length ? 1 : 0)];
int pos = 0;
if (updateChat.position.order != 0) {
new_positions[pos++] = updateChat.position;
}
for (int j = 0; j < chat.positions.length; j++) {
if (j != i) {
new_positions[pos++] = chat.positions[j];
}
}
assert pos == new_positions.length;
setChatPositions(chat, new_positions);
}
break;
}
case TdApi.UpdateChatReadInbox.CONSTRUCTOR: {
TdApi.UpdateChatReadInbox updateChat = (TdApi.UpdateChatReadInbox) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.lastReadInboxMessageId = updateChat.lastReadInboxMessageId;
chat.unreadCount = updateChat.unreadCount;
}
break;
}
case TdApi.UpdateChatReadOutbox.CONSTRUCTOR: {
TdApi.UpdateChatReadOutbox updateChat = (TdApi.UpdateChatReadOutbox) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.lastReadOutboxMessageId = updateChat.lastReadOutboxMessageId;
}
break;
}
case TdApi.UpdateChatActionBar.CONSTRUCTOR: {
TdApi.UpdateChatActionBar updateChat = (TdApi.UpdateChatActionBar) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.actionBar = updateChat.actionBar;
}
break;
}
case TdApi.UpdateChatAvailableReactions.CONSTRUCTOR: {
TdApi.UpdateChatAvailableReactions updateChat = (TdApi.UpdateChatAvailableReactions) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.availableReactions = updateChat.availableReactions;
}
break;
}
case TdApi.UpdateChatDraftMessage.CONSTRUCTOR: {
TdApi.UpdateChatDraftMessage updateChat = (TdApi.UpdateChatDraftMessage) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.draftMessage = updateChat.draftMessage;
setChatPositions(chat, updateChat.positions);
}
break;
}
case TdApi.UpdateChatMessageSender.CONSTRUCTOR: {
TdApi.UpdateChatMessageSender updateChat = (TdApi.UpdateChatMessageSender) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.messageSenderId = updateChat.messageSenderId;
}
break;
}
case TdApi.UpdateChatMessageAutoDeleteTime.CONSTRUCTOR: {
TdApi.UpdateChatMessageAutoDeleteTime updateChat = (TdApi.UpdateChatMessageAutoDeleteTime) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.messageAutoDeleteTime = updateChat.messageAutoDeleteTime;
}
break;
}
case TdApi.UpdateChatNotificationSettings.CONSTRUCTOR: {
TdApi.UpdateChatNotificationSettings update = (TdApi.UpdateChatNotificationSettings) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.notificationSettings = update.notificationSettings;
}
break;
}
case TdApi.UpdateChatPendingJoinRequests.CONSTRUCTOR: {
TdApi.UpdateChatPendingJoinRequests update = (TdApi.UpdateChatPendingJoinRequests) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.pendingJoinRequests = update.pendingJoinRequests;
}
break;
}
case TdApi.UpdateChatReplyMarkup.CONSTRUCTOR: {
TdApi.UpdateChatReplyMarkup updateChat = (TdApi.UpdateChatReplyMarkup) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.replyMarkupMessageId = updateChat.replyMarkupMessageId;
}
break;
}
case TdApi.UpdateChatBackground.CONSTRUCTOR: {
TdApi.UpdateChatBackground updateChat = (TdApi.UpdateChatBackground) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.background = updateChat.background;
}
break;
}
case TdApi.UpdateChatTheme.CONSTRUCTOR: {
TdApi.UpdateChatTheme updateChat = (TdApi.UpdateChatTheme) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.themeName = updateChat.themeName;
}
break;
}
case TdApi.UpdateChatUnreadMentionCount.CONSTRUCTOR: {
TdApi.UpdateChatUnreadMentionCount updateChat = (TdApi.UpdateChatUnreadMentionCount) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.unreadMentionCount = updateChat.unreadMentionCount;
}
break;
}
case TdApi.UpdateChatUnreadReactionCount.CONSTRUCTOR: {
TdApi.UpdateChatUnreadReactionCount updateChat = (TdApi.UpdateChatUnreadReactionCount) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.unreadReactionCount = updateChat.unreadReactionCount;
}
break;
}
case TdApi.UpdateChatVideoChat.CONSTRUCTOR: {
TdApi.UpdateChatVideoChat updateChat = (TdApi.UpdateChatVideoChat) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.videoChat = updateChat.videoChat;
}
break;
}
case TdApi.UpdateChatDefaultDisableNotification.CONSTRUCTOR: {
TdApi.UpdateChatDefaultDisableNotification update = (TdApi.UpdateChatDefaultDisableNotification) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.defaultDisableNotification = update.defaultDisableNotification;
}
break;
}
case TdApi.UpdateChatHasProtectedContent.CONSTRUCTOR: {
TdApi.UpdateChatHasProtectedContent updateChat = (TdApi.UpdateChatHasProtectedContent) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.hasProtectedContent = updateChat.hasProtectedContent;
}
break;
}
case TdApi.UpdateChatIsTranslatable.CONSTRUCTOR: {
TdApi.UpdateChatIsTranslatable update = (TdApi.UpdateChatIsTranslatable) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.isTranslatable = update.isTranslatable;
}
break;
}
case TdApi.UpdateChatIsMarkedAsUnread.CONSTRUCTOR: {
TdApi.UpdateChatIsMarkedAsUnread update = (TdApi.UpdateChatIsMarkedAsUnread) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.isMarkedAsUnread = update.isMarkedAsUnread;
}
break;
}
case TdApi.UpdateChatBlockList.CONSTRUCTOR: {
TdApi.UpdateChatBlockList update = (TdApi.UpdateChatBlockList) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.blockList = update.blockList;
}
break;
}
case TdApi.UpdateChatHasScheduledMessages.CONSTRUCTOR: {
TdApi.UpdateChatHasScheduledMessages update = (TdApi.UpdateChatHasScheduledMessages) object;
TdApi.Chat chat = chats.get(update.chatId);
synchronized (chat) {
chat.hasScheduledMessages = update.hasScheduledMessages;
}
break;
}
case TdApi.UpdateMessageMentionRead.CONSTRUCTOR: {
TdApi.UpdateMessageMentionRead updateChat = (TdApi.UpdateMessageMentionRead) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.unreadMentionCount = updateChat.unreadMentionCount;
}
break;
}
case TdApi.UpdateMessageUnreadReactions.CONSTRUCTOR: {
TdApi.UpdateMessageUnreadReactions updateChat = (TdApi.UpdateMessageUnreadReactions) object;
TdApi.Chat chat = chats.get(updateChat.chatId);
synchronized (chat) {
chat.unreadReactionCount = updateChat.unreadReactionCount;
}
break;
}
case TdApi.UpdateUserFullInfo.CONSTRUCTOR:
TdApi.UpdateUserFullInfo updateUserFullInfo = (TdApi.UpdateUserFullInfo) object;
usersFullInfo.put(updateUserFullInfo.userId, updateUserFullInfo.userFullInfo);
break;
case TdApi.UpdateBasicGroupFullInfo.CONSTRUCTOR:
TdApi.UpdateBasicGroupFullInfo updateBasicGroupFullInfo = (TdApi.UpdateBasicGroupFullInfo) object;
basicGroupsFullInfo.put(updateBasicGroupFullInfo.basicGroupId, updateBasicGroupFullInfo.basicGroupFullInfo);
break;
case TdApi.UpdateSupergroupFullInfo.CONSTRUCTOR:
TdApi.UpdateSupergroupFullInfo updateSupergroupFullInfo = (TdApi.UpdateSupergroupFullInfo) object;
supergroupsFullInfo.put(updateSupergroupFullInfo.supergroupId, updateSupergroupFullInfo.supergroupFullInfo);
break;
default:
log.info("Unsupported update:" + object);
}
}
private static void setChatPositions(TdApi.Chat chat, TdApi.ChatPosition[] positions) {
synchronized (mainChatList) {
synchronized (chat) {
for (TdApi.ChatPosition position : chat.positions) {
if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
boolean isRemoved = mainChatList.remove(new OrderedChat(chat.id, position));
assert isRemoved;
}
}
chat.positions = positions;
for (TdApi.ChatPosition position : chat.positions) {
if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
boolean isAdded = mainChatList.add(new OrderedChat(chat.id, position));
assert isAdded;
}
}
}
}
}
}
Then, you passed the UpdateHandler
when creating specifing Client
, so you can store in the updates handler any information about the client after it is created. You can also make the UpdatesHandler
self-contained and store all relevant data inside the object during updates handling.
Hello @levlam , I am creating a new springboot project from scratch and added TDApi and Client class as a jar file and added it as a dependency in my maven, so that I can update the said classes if any new updates/changes are made. I have restructured the given Example.java code only and changed how the setTDLibParameters are said for particular phoneNumber/User:
public void initializeClient(String phoneNumber) {
// set log message handler to handle only fatal errors (0) and plain log messages (-1)
Client.setLogMessageHandler(0, new LogMessageHandler());
// disable TDLib log and redirect fatal errors and plain log messages to a file
try {
Client.execute(new TdApi.SetLogVerbosityLevel(0));
Client.execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib_"+phoneNumber+".log", 1 << 27, false)));
} catch (Client.ExecutionException error) {
throw new IOError(new IOException("Write access to the current directory is required"));
}
// create client
Client client = Client.create(new UpdateHandler(), null, null);
Constants.clientHashMap.put(phoneNumber, client);
}
public void setTdlibParameters(String phoneNumber)
{
TdApi.SetTdlibParameters request = new TdApi.SetTdlibParameters();
request.databaseDirectory = "storage/"+phoneNumber+"/db";
request.filesDirectory = "storage/"+phoneNumber+"/files";
request.useMessageDatabase = false;
request.useFileDatabase = false;
request.useSecretChats = false;
request.apiId = **********;
request.apiHash = "*************************************";
request.systemLanguageCode = "en";
request.deviceModel = "Desktop";
request.applicationVersion = "1.0";
request.enableStorageOptimizer = true;
log.info("Initialized TDLibParams.");
clientHashMap.get(phoneNumber).send(request, new AuthorizationRequestHandler());
}
public void setReceivedOTP(String OTP, String phoneNumber){
clientHashMap.get(phoneNumber).send(new TdApi.CheckAuthenticationCode(OTP), new AuthorizationRequestHandler());
}
public void setEnteredPhoneNumber(String phoneNumber){
clientHashMap.get(phoneNumber).send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, null), new AuthorizationRequestHandler());
}
Are you suggesting that I make changes to TDApi.class and Client.class? Can it be done without changing TDApi or Client class?
No, you need only changes to the Example.java. The example doesn't support mulptiple users for simplicity and has most fields declared as static. This has to be changed to support multiple users.
Hello @levlam , Thanks for your prompt and helpful responses. I was able to accomplish what you said by writing the following code:
@Slf4j
@Getter
public class UpdateHandler implements Client.ResultHandler {
public UpdateHandler(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
private String phoneNumber;
AuthorizationStateUpdate authorizationStateUpdate = new AuthorizationStateUpdate();
@Override
public void onResult(TdApi.Object object) {
log.info(String.valueOf(object));
log.info("Event coming for phone number {}", phoneNumber); // this prints the passed phone number.
switch (object.getConstructor()) {
case TdApi.User.CONSTRUCTOR:
log.info("User " + object);
//...
//...
// other constructors
I guess I will apply this for AuthorizationRequestHandler as well to know for which phone numbers the authorization updates, if any, might have failed.
As I keep moving forward in exploring your library further I most probably would ask more questions that might be simple/stupid :stuck_out_tongue: ,
Thanks for your continued support and help.
Hi TDLib Community, I am trying to create a Telegram Web Client for multiple users in java.
I am able to log in multiple users by following suggestions in https://github.com/tdlib/td/issues/40 and https://github.com/tdlib/td/issues/718 and fetch all relevant details such as user details, chat-list, chat-id and messages successfully. Also for all logged-in users I am receiving all updates through UpdateHandler class in real time.
I want to segregate all the updates based on the phone number of the user that is currently logged-in, but I am unable to differentiate between the updates being received. For example, if users A and B are logged in at the same time and a message from a common user C is sent then the updates for both look the same with the sender ID being the same for both A and B. Below are the objects being received:
If anyone can point me towards a potential solution I thank you in advance.