From e1ec72eab6d00b3ba38e5932bc88920f103b6e4a Mon Sep 17 00:00:00 2001 From: aunsane Date: Fri, 27 Apr 2018 21:33:17 +0300 Subject: Telegram: initial commit - tdlib moved to telegram dir --- .../example/java/org/drinkless/tdlib/Client.java | 285 +++++++++++ .../td/example/java/org/drinkless/tdlib/Log.java | 75 +++ .../java/org/drinkless/tdlib/example/Example.java | 533 +++++++++++++++++++++ 3 files changed, 893 insertions(+) create mode 100644 protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java create mode 100644 protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java create mode 100644 protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java (limited to 'protocols/Telegram/tdlib/td/example/java/org') diff --git a/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java new file mode 100644 index 0000000000..efb38e9c5a --- /dev/null +++ b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java @@ -0,0 +1,285 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +package org.drinkless.tdlib; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * Main class for interaction with the TDLib. + */ +public final class Client implements Runnable { + /** + * Interface for handler for results of queries to TDLib and incoming updates from TDLib. + */ + public interface ResultHandler { + /** + * Callback called on result of query to TDLib or incoming update from TDLib. + * + * @param object Result of query or update of type TdApi.Update about new events. + */ + void onResult(TdApi.Object object); + } + + /** + * Interface for handler of exceptions thrown while invoking ResultHandler. + * By default, all such exceptions are ignored. + * All exceptions thrown from ExceptionHandler are ignored. + */ + public interface ExceptionHandler { + /** + * Callback called on exceptions thrown while invoking ResultHandler. + * + * @param e Exception thrown by ResultHandler. + */ + void onException(Throwable e); + } + + /** + * Sends a request to the TDLib. + * + * @param query Object representing a query to the TDLib. + * @param resultHandler Result handler with onResult method which will be called with result + * of the query or with TdApi.Error as parameter. If it is null, nothing + * will be called. + * @param exceptionHandler Exception handler with onException method which will be called on + * exception thrown from resultHandler. If it is null, then + * defaultExceptionHandler will be called. + * @throws NullPointerException if query is null. + */ + public void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler) { + if (query == null) { + throw new NullPointerException("query is null"); + } + + readLock.lock(); + try { + if (isClientDestroyed) { + if (resultHandler != null) { + handleResult(new TdApi.Error(500, "Client is closed"), resultHandler, exceptionHandler); + } + return; + } + + long queryId = currentQueryId.incrementAndGet(); + handlers.put(queryId, new Handler(resultHandler, exceptionHandler)); + nativeClientSend(nativeClientId, queryId, query); + } finally { + readLock.unlock(); + } + } + + /** + * Sends a request to the TDLib with an empty ExceptionHandler. + * + * @param query Object representing a query to the TDLib. + * @param resultHandler Result handler with onResult method which will be called with result + * of the query or with TdApi.Error as parameter. If it is null, then + * defaultExceptionHandler will be called. + * @throws NullPointerException if query is null. + */ + public void send(TdApi.Function query, ResultHandler resultHandler) { + send(query, resultHandler, null); + } + + /** + * Synchronously executes a TDLib request. Only a few marked accordingly requests can be executed synchronously. + * + * @param query Object representing a query to the TDLib. + * @return request result. + * @throws NullPointerException if query is null. + */ + public static TdApi.Object execute(TdApi.Function query) { + if (query == null) { + throw new NullPointerException("query is null"); + } + return nativeClientExecute(query); + } + + /** + * Replaces handler for incoming updates from the TDLib. + * + * @param updatesHandler Handler with onResult method which will be called for every incoming + * update from the TDLib. + * @param exceptionHandler Exception handler with onException method which will be called on + * exception thrown from updatesHandler, if it is null, defaultExceptionHandler will be invoked. + */ + public void setUpdatesHandler(ResultHandler updatesHandler, ExceptionHandler exceptionHandler) { + handlers.put(0L, new Handler(updatesHandler, exceptionHandler)); + } + + /** + * Replaces handler for incoming updates from the TDLib. Sets empty ExceptionHandler. + * + * @param updatesHandler Handler with onResult method which will be called for every incoming + * update from the TDLib. + */ + public void setUpdatesHandler(ResultHandler updatesHandler) { + setUpdatesHandler(updatesHandler, null); + } + + /** + * Replaces default exception handler to be invoked on exceptions thrown from updatesHandler and all other ResultHandler. + * + * @param defaultExceptionHandler Default exception handler. If null Exceptions are ignored. + */ + public void setDefaultExceptionHandler(Client.ExceptionHandler defaultExceptionHandler) { + this.defaultExceptionHandler = defaultExceptionHandler; + } + + /** + * Overridden method from Runnable, do not call it directly. + */ + @Override + public void run() { + while (!stopFlag) { + receiveQueries(300.0 /*seconds*/); + } + } + + /** + * Creates new Client. + * + * @param updatesHandler Handler for incoming updates. + * @param updatesExceptionHandler Handler for exceptions thrown from updatesHandler. If it is null, exceptions will be iggnored. + * @param defaultExceptionHandler Default handler for exceptions thrown from all ResultHandler. If it is null, exceptions will be iggnored. + * @return created Client + */ + public static Client create(ResultHandler updatesHandler, ExceptionHandler updatesExceptionHandler, ExceptionHandler defaultExceptionHandler) { + Client client = new Client(updatesHandler, updatesExceptionHandler, defaultExceptionHandler); + new Thread(client, "TDLib thread").start(); + return client; + } + + /** + * Closes Client. + */ + public void close() { + writeLock.lock(); + try { + if (isClientDestroyed) { + return; + } + if (!stopFlag) { + send(new TdApi.Close(), null); + } + isClientDestroyed = true; + while (!stopFlag) { + Thread.yield(); + } + while (handlers.size() != 1) { + receiveQueries(300.0); + } + destroyNativeClient(nativeClientId); + } finally { + writeLock.unlock(); + } + } + + private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock readLock = readWriteLock.readLock(); + private final Lock writeLock = readWriteLock.writeLock(); + + private volatile boolean stopFlag = false; + private volatile boolean isClientDestroyed = false; + private final long nativeClientId; + + private final ConcurrentHashMap handlers = new ConcurrentHashMap(); + private final AtomicLong currentQueryId = new AtomicLong(); + + private volatile ExceptionHandler defaultExceptionHandler = null; + + private static final int MAX_EVENTS = 1000; + private final long[] eventIds = new long[MAX_EVENTS]; + private final TdApi.Object[] events = new TdApi.Object[MAX_EVENTS]; + + private static class Handler { + final ResultHandler resultHandler; + final ExceptionHandler exceptionHandler; + + Handler(ResultHandler resultHandler, ExceptionHandler exceptionHandler) { + this.resultHandler = resultHandler; + this.exceptionHandler = exceptionHandler; + } + } + + private Client(ResultHandler updatesHandler, ExceptionHandler updateExceptionHandler, ExceptionHandler defaultExceptionHandler) { + nativeClientId = createNativeClient(); + handlers.put(0L, new Handler(updatesHandler, updateExceptionHandler)); + this.defaultExceptionHandler = defaultExceptionHandler; + } + + @Override + protected void finalize() throws Throwable { + try { + close(); + } finally { + super.finalize(); + } + } + + private void processResult(long id, TdApi.Object object) { + if (object instanceof TdApi.UpdateAuthorizationState) { + if (((TdApi.UpdateAuthorizationState) object).authorizationState instanceof TdApi.AuthorizationStateClosed) { + stopFlag = true; + } + } + Handler handler; + if (id == 0) { + // update handler stays forever + handler = handlers.get(id); + } else { + handler = handlers.remove(id); + } + if (handler == null) { + return; + } + + handleResult(object, handler.resultHandler, handler.exceptionHandler); + } + + private void handleResult(TdApi.Object object, ResultHandler resultHandler, ExceptionHandler exceptionHandler) { + if (resultHandler == null) { + return; + } + + try { + resultHandler.onResult(object); + } catch (Throwable cause) { + if (exceptionHandler == null) { + exceptionHandler = defaultExceptionHandler; + } + if (exceptionHandler != null) { + try { + exceptionHandler.onException(cause); + } catch (Throwable ignored) { + } + } + } + } + + private void receiveQueries(double timeout) { + int resultN = nativeClientReceive(nativeClientId, eventIds, events, timeout); + for (int i = 0; i < resultN; i++) { + processResult(eventIds[i], events[i]); + events[i] = null; + } + } + + private static native long createNativeClient(); + + private static native void nativeClientSend(long nativeClientId, long eventId, TdApi.Function function); + + private static native int nativeClientReceive(long nativeClientId, long[] eventIds, TdApi.Object[] events, double timeout); + + private static native TdApi.Object nativeClientExecute(TdApi.Function function); + + private static native void destroyNativeClient(long nativeClientId); +} diff --git a/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java new file mode 100644 index 0000000000..c81ffbeeb7 --- /dev/null +++ b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java @@ -0,0 +1,75 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +package org.drinkless.tdlib; + +/** + * Class for managing internal TDLib logging. + */ +public final class Log { + /** + * Changes TDLib log verbosity. + * + * @param verbosityLevel New value of log verbosity level. Must be non-negative. + * Value 0 corresponds to fatal errors, + * value 1 corresponds to java.util.logging.Level.SEVERE, + * value 2 corresponds to java.util.logging.Level.WARNING, + * value 3 corresponds to java.util.logging.Level.INFO, + * value 4 corresponds to java.util.logging.Level.FINE, + * value 5 corresponds to java.util.logging.Level.FINER, + * value greater than 5 can be used to enable even more logging. + * Default value of the log verbosity level is 5. + */ + public static native void setVerbosityLevel(int verbosityLevel); + + /** + * Sets file path for writing TDLib internal log. By default TDLib writes logs to the System.err. + * Use this method to write the log to a file instead. + * + * @param filePath Path to a file for writing TDLib internal log. Use an empty path to + * switch back to logging to the System.err. + * @return whether opening the log file succeeded. + */ + public static native boolean setFilePath(String filePath); + + /** + * Changes maximum size of TDLib log file. + * + * @param maxFileSize Maximum size of the file to where the internal TDLib log is written + * before the file will be auto-rotated. Must be positive. Defaults to 10 MB. + */ + public static native void setMaxFileSize(long maxFileSize); + + /** + * This function is called from the JNI when a fatal error happens to provide a better error message. + * The function does not return. + * + * @param errorMessage Error message. + */ + private static void onFatalError(String errorMessage) { + class ThrowError implements Runnable { + private ThrowError(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public void run() { + throw new RuntimeException("TDLib fatal error: " + errorMessage); + } + + private final String errorMessage; + } + + new Thread(new ThrowError(errorMessage), "TDLib fatal error thread").start(); + while (true) { + try { + Thread.sleep(1000); // milliseconds + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java new file mode 100644 index 0000000000..831de88f1d --- /dev/null +++ b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java @@ -0,0 +1,533 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +package org.drinkless.tdlib.example; + +import org.drinkless.tdlib.Client; +import org.drinkless.tdlib.Log; +import org.drinkless.tdlib.TdApi; + +import java.io.IOError; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.NavigableSet; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Example class for TDLib usage from Java. + */ +public final class Example { + private static Client client = null; + + private static TdApi.AuthorizationState authorizationState = null; + private static volatile boolean haveAuthorization = false; + private static volatile boolean quiting = false; + + private static final Client.ResultHandler defaultHandler = new DefaultHandler(); + + private static final Lock authorizationLock = new ReentrantLock(); + private static final Condition gotAuthorization = authorizationLock.newCondition(); + + private static final ConcurrentMap users = new ConcurrentHashMap(); + private static final ConcurrentMap basicGroups = new ConcurrentHashMap(); + private static final ConcurrentMap supergroups = new ConcurrentHashMap(); + private static final ConcurrentMap secretChats = new ConcurrentHashMap(); + + private static final ConcurrentMap chats = new ConcurrentHashMap(); + private static final NavigableSet chatList = new TreeSet(); + private static boolean haveFullChatList = false; + + private static final ConcurrentMap usersFullInfo = new ConcurrentHashMap(); + private static final ConcurrentMap basicGroupsFullInfo = new ConcurrentHashMap(); + private static final ConcurrentMap supergroupsFullInfo = new ConcurrentHashMap(); + + private static final String newLine = System.getProperty("line.separator"); + private static final String commandsLine = "Enter command (gcs - GetChats, gc - GetChat, me - GetMe, sm - SendMessage, lo - LogOut, q - Quit): "; + private static volatile String currentPrompt = null; + + static { + System.loadLibrary("tdjni"); + } + + private static void print(String str) { + if (currentPrompt != null) { + System.out.println(""); + } + System.out.println(str); + if (currentPrompt != null) { + System.out.print(currentPrompt); + } + } + + private static void setChatOrder(TdApi.Chat chat, long order) { + synchronized (chatList) { + if (chat.order != 0) { + boolean isRemoved = chatList.remove(new OrderedChat(chat.order, chat.id)); + assert isRemoved; + } + + chat.order = order; + + if (chat.order != 0) { + boolean isAdded = chatList.add(new OrderedChat(chat.order, chat.id)); + assert isAdded; + } + } + } + + private static void onAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState) { + if (authorizationState != null) { + Example.authorizationState = authorizationState; + } + switch (Example.authorizationState.getConstructor()) { + case TdApi.AuthorizationStateWaitTdlibParameters.CONSTRUCTOR: + TdApi.TdlibParameters parameters = new TdApi.TdlibParameters(); + parameters.databaseDirectory = "tdlib"; + parameters.useMessageDatabase = true; + parameters.useSecretChats = true; + parameters.apiId = 94575; + parameters.apiHash = "a3406de8d171bb422bb6ddf3bbd800e2"; + parameters.systemLanguageCode = "en"; + parameters.deviceModel = "Desktop"; + parameters.systemVersion = "Unknown"; + parameters.applicationVersion = "1.0"; + parameters.enableStorageOptimizer = true; + + client.send(new TdApi.SetTdlibParameters(parameters), new AuthorizationRequestHandler()); + break; + case TdApi.AuthorizationStateWaitEncryptionKey.CONSTRUCTOR: + client.send(new TdApi.CheckDatabaseEncryptionKey(), new AuthorizationRequestHandler()); + break; + case TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR: { + String phoneNumber = promptString("Please enter phone number: "); + client.send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, false, false), new AuthorizationRequestHandler()); + break; + } + case TdApi.AuthorizationStateWaitCode.CONSTRUCTOR: { + String code = promptString("Please enter authentication code: "); + client.send(new TdApi.CheckAuthenticationCode(code, "", ""), new AuthorizationRequestHandler()); + break; + } + case TdApi.AuthorizationStateWaitPassword.CONSTRUCTOR: { + String password = promptString("Please enter password: "); + client.send(new TdApi.CheckAuthenticationPassword(password), new AuthorizationRequestHandler()); + break; + } + case TdApi.AuthorizationStateReady.CONSTRUCTOR: + haveAuthorization = true; + authorizationLock.lock(); + try { + gotAuthorization.signal(); + } finally { + authorizationLock.unlock(); + } + break; + case TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR: + haveAuthorization = false; + print("Logging out"); + break; + case TdApi.AuthorizationStateClosing.CONSTRUCTOR: + haveAuthorization = false; + print("Closing"); + break; + case TdApi.AuthorizationStateClosed.CONSTRUCTOR: + print("Closed"); + if (!quiting) { + client = Client.create(new UpdatesHandler(), null, null); // recreate client after previous has closed + } + break; + default: + System.err.println("Unsupported authorization state:" + newLine + Example.authorizationState); + } + } + + private static int toInt(String arg) { + int result = 0; + try { + result = Integer.parseInt(arg); + } catch (NumberFormatException ignored) { + } + return result; + } + + private static long getChatId(String arg) { + long chatId = 0; + try { + chatId = Long.parseLong(arg); + } catch (NumberFormatException ignored) { + } + return chatId; + } + + private static String promptString(String prompt) { + System.out.print(prompt); + currentPrompt = prompt; + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + String str = ""; + try { + str = reader.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + currentPrompt = null; + return str; + } + + private static void getCommand() { + String command = promptString(commandsLine); + String[] commands = command.split(" ", 2); + try { + switch (commands[0]) { + case "gcs": { + int limit = 20; + if (commands.length > 1) { + limit = toInt(commands[1]); + } + getChatList(limit); + break; + } + case "gc": + client.send(new TdApi.GetChat(getChatId(commands[1])), defaultHandler); + break; + case "me": + client.send(new TdApi.GetMe(), defaultHandler); + break; + case "sm": { + String[] args = commands[1].split(" ", 2); + sendMessage(getChatId(args[0]), args[1]); + break; + } + case "lo": + haveAuthorization = false; + client.send(new TdApi.LogOut(), defaultHandler); + break; + case "q": + quiting = true; + haveAuthorization = false; + client.send(new TdApi.Close(), defaultHandler); + break; + default: + System.err.println("Unsupported command: " + command); + } + } catch (ArrayIndexOutOfBoundsException e) { + print("Not enough arguments"); + } + } + + private static void getChatList(final int limit) { + synchronized (chatList) { + if (!haveFullChatList && limit > chatList.size()) { + // have enough chats in the chat list or chat list is too small + long offsetOrder = Long.MAX_VALUE; + long offsetChatId = 0; + if (!chatList.isEmpty()) { + OrderedChat last = chatList.last(); + offsetOrder = last.order; + offsetChatId = last.chatId; + } + client.send(new TdApi.GetChats(offsetOrder, offsetChatId, limit - chatList.size()), new Client.ResultHandler() { + @Override + public void onResult(TdApi.Object object) { + switch (object.getConstructor()) { + case TdApi.Error.CONSTRUCTOR: + System.err.println("Receive an error for GetChats:" + newLine + object); + break; + case TdApi.Chats.CONSTRUCTOR: + long[] chatIds = ((TdApi.Chats) object).chatIds; + if (chatIds.length == 0) { + synchronized (chatList) { + haveFullChatList = true; + } + } + // chats had already been received through updates, let's retry request + getChatList(limit); + break; + default: + System.err.println("Receive wrong response from TDLib:" + newLine + object); + } + } + }); + return; + } + + // have enough chats in the chat list to answer request + java.util.Iterator iter = chatList.iterator(); + System.out.println(); + System.out.println("First " + limit + " chat(s) out of " + chatList.size() + " known chat(s):"); + for (int i = 0; i < limit; i++) { + long chatId = iter.next().chatId; + TdApi.Chat chat = chats.get(chatId); + synchronized (chat) { + System.out.println(chatId + ": " + chat.title); + } + } + print(""); + } + } + + private static void sendMessage(long chatId, String message) { + // initialize reply markup just for testing + TdApi.InlineKeyboardButton[] row = {new TdApi.InlineKeyboardButton("https://telegram.org?1", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?2", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?3", new TdApi.InlineKeyboardButtonTypeUrl())}; + TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][]{row, row, row}); + + TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true); + client.send(new TdApi.SendMessage(chatId, 0, false, false, replyMarkup, content), defaultHandler); + } + + public static void main(String[] args) throws InterruptedException { + // disable TDLib log + Log.setVerbosityLevel(0); + if (!Log.setFilePath("tdlib.log")) { + throw new IOError(new IOException("Write access to the current directory is required")); + } + + // create client + client = Client.create(new UpdatesHandler(), null, null); + + // test Client.execute + defaultHandler.onResult(Client.execute(new TdApi.GetTextEntities("@telegram /test_command https://telegram.org telegram.me @gif @test"))); + + // main loop + while (!quiting) { + // await authorization + authorizationLock.lock(); + try { + while (!haveAuthorization) { + gotAuthorization.await(); + } + } finally { + authorizationLock.unlock(); + } + + while (haveAuthorization) { + getCommand(); + } + } + } + + private static class OrderedChat implements Comparable { + final long order; + final long chatId; + + OrderedChat(long order, long chatId) { + this.order = order; + this.chatId = chatId; + } + + @Override + public int compareTo(OrderedChat o) { + if (this.order != o.order) { + return o.order < this.order ? -1 : 1; + } + if (this.chatId != o.chatId) { + return o.chatId < this.chatId ? -1 : 1; + } + return 0; + } + + @Override + public boolean equals(Object obj) { + OrderedChat o = (OrderedChat) obj; + return this.order == o.order && this.chatId == o.chatId; + } + } + + private static class DefaultHandler implements Client.ResultHandler { + @Override + public void onResult(TdApi.Object object) { + print(object.toString()); + } + } + + private static class UpdatesHandler implements Client.ResultHandler { + @Override + public void onResult(TdApi.Object object) { + switch (object.getConstructor()) { + case TdApi.UpdateAuthorizationState.CONSTRUCTOR: + 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); + + long order = chat.order; + chat.order = 0; + setChatOrder(chat, order); + } + 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.UpdateChatLastMessage.CONSTRUCTOR: { + TdApi.UpdateChatLastMessage updateChat = (TdApi.UpdateChatLastMessage) object; + TdApi.Chat chat = chats.get(updateChat.chatId); + synchronized (chat) { + chat.lastMessage = updateChat.lastMessage; + setChatOrder(chat, updateChat.order); + } + break; + } + case TdApi.UpdateChatOrder.CONSTRUCTOR: { + TdApi.UpdateChatOrder updateChat = (TdApi.UpdateChatOrder) object; + TdApi.Chat chat = chats.get(updateChat.chatId); + synchronized (chat) { + setChatOrder(chat, updateChat.order); + } + break; + } + case TdApi.UpdateChatIsPinned.CONSTRUCTOR: { + TdApi.UpdateChatIsPinned updateChat = (TdApi.UpdateChatIsPinned) object; + TdApi.Chat chat = chats.get(updateChat.chatId); + synchronized (chat) { + chat.isPinned = updateChat.isPinned; + setChatOrder(chat, updateChat.order); + } + 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.UpdateChatUnreadMentionCount.CONSTRUCTOR: { + TdApi.UpdateChatUnreadMentionCount updateChat = (TdApi.UpdateChatUnreadMentionCount) object; + TdApi.Chat chat = chats.get(updateChat.chatId); + synchronized (chat) { + chat.unreadMentionCount = updateChat.unreadMentionCount; + } + 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.UpdateChatReplyMarkup.CONSTRUCTOR: { + TdApi.UpdateChatReplyMarkup updateChat = (TdApi.UpdateChatReplyMarkup) object; + TdApi.Chat chat = chats.get(updateChat.chatId); + synchronized (chat) { + chat.replyMarkupMessageId = updateChat.replyMarkupMessageId; + } + break; + } + case TdApi.UpdateChatDraftMessage.CONSTRUCTOR: { + TdApi.UpdateChatDraftMessage updateChat = (TdApi.UpdateChatDraftMessage) object; + TdApi.Chat chat = chats.get(updateChat.chatId); + synchronized (chat) { + chat.draftMessage = updateChat.draftMessage; + setChatOrder(chat, updateChat.order); + } + break; + } + case TdApi.UpdateNotificationSettings.CONSTRUCTOR: { + TdApi.UpdateNotificationSettings update = (TdApi.UpdateNotificationSettings) object; + if (update.scope instanceof TdApi.NotificationSettingsScopeChat) { + TdApi.Chat chat = chats.get(((TdApi.NotificationSettingsScopeChat) update.scope).chatId); + synchronized (chat) { + chat.notificationSettings = update.notificationSettings; + } + } + 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: + // print("Unsupported update:" + newLine + object); + } + } + } + + private static class AuthorizationRequestHandler implements Client.ResultHandler { + @Override + public void onResult(TdApi.Object object) { + switch (object.getConstructor()) { + case TdApi.Error.CONSTRUCTOR: + System.err.println("Receive an error:" + newLine + object); + onAuthorizationStateUpdated(null); // repeat last action + break; + case TdApi.Ok.CONSTRUCTOR: + // result is already received through UpdateAuthorizationState, nothing to do + break; + default: + System.err.println("Receive wrong response from TDLib:" + newLine + object); + } + } + } +} \ No newline at end of file -- cgit v1.2.3