Compare commits
14 Commits
d0014b1f5a
...
be261b5dcc
Author | SHA1 | Date | |
---|---|---|---|
|
be261b5dcc | ||
|
eef20412e9 | ||
|
bce9060db2 | ||
|
050972465a | ||
|
6c5441c8ff | ||
|
1202a4d957 | ||
|
335b110f9e | ||
|
da979c4631 | ||
|
59b1d7a4f6 | ||
|
32040c22cb | ||
|
5828e46046 | ||
|
acef6e61a0 | ||
|
516e2e8a07 | ||
|
b6b5b1b9ed |
50
.github/workflows/build.yaml
vendored
Normal file
50
.github/workflows/build.yaml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: Build TDLib
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [linux/386, linux/amd64, linux/arm/v6, linux/arm/v7, linux/arm64, linux/ppc64le]
|
||||
|
||||
steps:
|
||||
- name: Setup variables
|
||||
run: |
|
||||
ARCH=${{ matrix.arch }}
|
||||
SAFE_ARCH=$(echo $ARCH | sed 's/\//\-/g')
|
||||
echo "SAFE_ARCH=$SAFE_ARCH" >> $GITHUB_ENV
|
||||
- name: Install sudo package
|
||||
run: |
|
||||
(apt-get update || true) 2>/dev/null
|
||||
(apt-get install -y sudo || true) 2>/dev/null
|
||||
sudo apt update
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "recursive"
|
||||
- name: Cache ccache
|
||||
id: cache-ccache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{ runner.os }}-${{ env.SAFE_ARCH }}-ccache-all
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ env.SAFE_ARCH }}-ccache-
|
||||
- name: Install build tools
|
||||
run: sudo apt-get install -y make git zlib1g-dev libssl-dev gperf php-cli cmake clang-6.0 libc++-dev libc++abi-dev ccache
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
CXXFLAGS="-stdlib=libc++" CC=/usr/bin/clang-10 CXX=/usr/bin/clang++-10 cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../tdlib ..
|
||||
cmake --build . --target install -- -j4
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: tdlight-${{ env.SAFE_ARCH }}
|
||||
path: tdlib/lib
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -4,4 +4,12 @@
|
||||
**/auto/
|
||||
docs/
|
||||
tdlib/
|
||||
.idea/
|
||||
vcpkg/
|
||||
*.tlo
|
||||
|
||||
td.binlog
|
||||
|
||||
tg_cli.log
|
||||
|
||||
tg_cli.log.old
|
||||
|
@ -1024,7 +1024,7 @@ Changes in 1.5.0 (9 Sep 2019):
|
||||
* Added the class `chatEventPollStopped` representing the closing of a poll in a message in the chat event log.
|
||||
* Added ability to specify the exact types of problems with a call in the method `sendCallRating` and
|
||||
the new class `CallProblem`.
|
||||
* Changes in [tdweb](https://github.com/tdlib/td/blob/master/example/web/):
|
||||
* Changes in [tdweb](https://github.com/tdlight-team/tdlight/blob/master/example/web/):
|
||||
- Supported non-zero `offset` and `limit` in `readFilePart`.
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
@ -1034,7 +1034,7 @@ Changes in 1.4.0 (1 May 2019):
|
||||
* Added a [TDLib build instructions generator](https://tdlib.github.io/td/build.html), covering in details
|
||||
TDLib building on the most popular operating systems.
|
||||
* Added an example of TDLib building and usage from a browser.
|
||||
See https://github.com/tdlib/td/blob/master/example/web/ for more details.
|
||||
See https://github.com/tdlight-team/tdlight/blob/master/example/web/ for more details.
|
||||
* Allowed to pass NULL pointer to `td_json_client_execute` instead of a previously created JSON client.
|
||||
Now you can use synchronous TDLib methods through a JSON interface before creating a TDLib JSON client.
|
||||
* Added support for media streaming by allowing to download any part of a file:
|
||||
@ -1285,7 +1285,7 @@ Changes in 1.4.0 (1 May 2019):
|
||||
|
||||
Changes in 1.3.0 (5 Sep 2018):
|
||||
|
||||
* Added a review of existing TDLib based [frameworks](https://github.com/tdlib/td/blob/master/example/README.md)
|
||||
* Added a review of existing TDLib based [frameworks](https://github.com/tdlight-team/tdlight/blob/master/example/README.md)
|
||||
in different programming languages.
|
||||
* Added a [Getting started](https://core.telegram.org/tdlib/getting-started) guide describing the main TDLib concepts
|
||||
and basic principles required for library usage.
|
||||
|
56
CMake/FindAtomics.cmake
Normal file
56
CMake/FindAtomics.cmake
Normal file
@ -0,0 +1,56 @@
|
||||
# Original issue:
|
||||
# * https://gitlab.kitware.com/cmake/cmake/-/issues/23021#note_1098733
|
||||
#
|
||||
# For reference:
|
||||
# * https://gcc.gnu.org/wiki/Atomic/GCCMM
|
||||
#
|
||||
# riscv64 specific:
|
||||
# * https://lists.debian.org/debian-riscv/2022/01/msg00009.html
|
||||
#
|
||||
# ATOMICS_FOUND - system has c++ atomics
|
||||
# ATOMICS_LIBRARIES - libraries needed to use c++ atomics
|
||||
# ATOMICS_LIBRARY_FLAGS - flags required to link with c++ atomics library
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
# RISC-V only has 32-bit and 64-bit atomic instructions. GCC is supposed
|
||||
# to convert smaller atomics to those larger ones via masking and
|
||||
# shifting like LLVM, but it’s a known bug that it does not. This means
|
||||
# anything that wants to use atomics on 1-byte or 2-byte types needs
|
||||
# -latomic, but not 4-byte or 8-byte (though it does no harm).
|
||||
set(atomic_code
|
||||
"
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
std::atomic<uint8_t> n8 (0); // riscv64
|
||||
std::atomic<uint64_t> n64 (0); // armel, mipsel, powerpc
|
||||
int main() {
|
||||
++n8;
|
||||
++n64;
|
||||
return 0;
|
||||
}")
|
||||
|
||||
check_cxx_source_compiles("${atomic_code}" ATOMICS_LOCK_FREE_INSTRUCTIONS)
|
||||
|
||||
if (ATOMICS_LOCK_FREE_INSTRUCTIONS)
|
||||
set(ATOMICS_FOUND TRUE)
|
||||
set(ATOMICS_LIBRARIES)
|
||||
set(ATOMICS_LIBRARY_FLAGS)
|
||||
else()
|
||||
set(CMAKE_REQUIRED_LIBRARIES "-latomic")
|
||||
check_cxx_source_compiles("${atomic_code}" ATOMICS_IN_LIBRARY)
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
if (ATOMICS_IN_LIBRARY)
|
||||
set(ATOMICS_LIBRARY atomic)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Atomics DEFAULT_MSG ATOMICS_LIBRARY)
|
||||
set(ATOMICS_LIBRARIES ${ATOMICS_LIBRARY})
|
||||
set(ATOMICS_LIBRARY_FLAGS "-latomic")
|
||||
unset(ATOMICS_LIBRARY)
|
||||
else()
|
||||
if (Atomics_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Neither lock free instructions nor -latomic found.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
unset(atomic_code)
|
@ -124,6 +124,7 @@ function(td_set_up_compiler)
|
||||
add_cxx_compiler_flag("-Wno-unknown-warning-option")
|
||||
add_cxx_compiler_flag("-Wodr")
|
||||
add_cxx_compiler_flag("-flto-odr-type-merging")
|
||||
add_cxx_compiler_flag("-Wno-psabi")
|
||||
|
||||
# add_cxx_compiler_flag("-Werror")
|
||||
|
||||
|
@ -73,15 +73,15 @@ if (POLICY CMP0069)
|
||||
endif()
|
||||
|
||||
# Configure CCache if available
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
#find_program(CCACHE_FOUND ccache)
|
||||
#set(CCACHE_FOUND 0)
|
||||
if (CCACHE_FOUND)
|
||||
message(STATUS "Found ccache")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
else()
|
||||
message(STATUS "Could NOT find ccache (this is NOT an error)")
|
||||
endif()
|
||||
#if (CCACHE_FOUND)
|
||||
# message(STATUS "Found ccache")
|
||||
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
# set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
#else()
|
||||
# message(STATUS "Could NOT find ccache (this is NOT an error)")
|
||||
#endif()
|
||||
|
||||
set(MEMPROF "" CACHE STRING "Use one of \"ON\", \"FAST\" or \"SAFE\" to enable memory profiling. \
|
||||
Works under macOS and Linux when compiled using glibc. \
|
||||
@ -129,6 +129,11 @@ if (THREADS_HAVE_PTHREAD_ARG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
endif()
|
||||
|
||||
find_package(Atomics REQUIRED)
|
||||
if (ATOMICS_LIBRARY_FLAGS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ATOMICS_LIBRARY_FLAGS}")
|
||||
endif()
|
||||
|
||||
include(TdSetUpCompiler)
|
||||
td_set_up_compiler()
|
||||
|
||||
@ -207,9 +212,13 @@ add_subdirectory(sqlite)
|
||||
|
||||
add_subdirectory(tddb)
|
||||
|
||||
add_subdirectory(test)
|
||||
option(TD_SKIP_TEST "Use \"ON\" to skip building/running the test harness.")
|
||||
if (NOT TD_SKIP_TEST)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
option(TD_SKIP_BENCHMARK "Use \"ON\" to skip building/running the benchmarks.")
|
||||
if (NOT CMAKE_CROSSCOMPILING AND NOT TD_SKIP_BENCHMARK)
|
||||
add_subdirectory(benchmark)
|
||||
endif()
|
||||
|
||||
@ -495,6 +504,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/StickersManager.cpp
|
||||
td/telegram/StickerType.cpp
|
||||
td/telegram/StorageManager.cpp
|
||||
td/telegram/MemoryManager.cpp
|
||||
td/telegram/StoryContent.cpp
|
||||
td/telegram/StoryContentType.cpp
|
||||
td/telegram/StoryDb.cpp
|
||||
@ -827,6 +837,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/StickersManager.h
|
||||
td/telegram/StickerType.h
|
||||
td/telegram/StorageManager.h
|
||||
td/telegram/MemoryManager.h
|
||||
td/telegram/StoryContent.h
|
||||
td/telegram/StoryContentType.h
|
||||
td/telegram/StoryDb.h
|
||||
@ -1093,6 +1104,8 @@ endif()
|
||||
|
||||
#EXECUTABLES
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
option(TD_SKIP_TG_CLI "Use \"ON\" to skip building tg_cli.")
|
||||
if (NOT CMAKE_CROSSCOMPILING AND NOT TD_SKIP_TG_CLI)
|
||||
add_executable(tg_cli td/telegram/cli.cpp ${TL_TD_JSON_SOURCE})
|
||||
|
||||
if (NOT READLINE_FOUND)
|
||||
@ -1121,6 +1134,7 @@ if (NOT CMAKE_CROSSCOMPILING)
|
||||
target_link_libraries(tg_cli PRIVATE memprof tdclient tdcore)
|
||||
add_dependencies(tg_cli tl_generate_json)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#Exported libraries
|
||||
add_library(TdStatic INTERFACE)
|
||||
|
54
README.md
54
README.md
@ -1,9 +1,12 @@
|
||||
# TDLib
|
||||
# TDLight
|
||||
|
||||
TDLib (Telegram Database library) is a cross-platform library for building [Telegram](https://telegram.org) clients. It can be easily used from almost any programming language.
|
||||
TDLight is a fork of TDLib, a cross-platform library for building [Telegram](https://telegram.org) clients. It can be easily used from almost any programming language.
|
||||
|
||||
## Table of Contents
|
||||
- [Features](#features)
|
||||
- [TDLight extra features](#tdlight-extra-features)
|
||||
- [TDLight extra API functions](#tdlight-extra-api-functions)
|
||||
- [TDLight recommended options](#tdlight-recommended-options)
|
||||
- [Examples and documentation](#usage)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Building](#building)
|
||||
@ -28,17 +31,42 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele
|
||||
* **Secure**: all local data is encrypted using a user-provided encryption key.
|
||||
* **Fully-asynchronous**: requests to `TDLib` don't block each other or anything else, responses are sent when they are available.
|
||||
|
||||
<a name="tdlight-extra-features"></a>
|
||||
### TDLight extra features
|
||||
#### TDLight extra options
|
||||
* **disable_minithumbnails** (true/**false**) This setting removes minithumbnails everywhere. It reduces memory usage because tdlib keeps them in RAM
|
||||
* **disable_document_filenames** (true/**false**) If you don't care about having the original filenames of every file stored in RAM, you can disable them using this option. It reduces memory usage
|
||||
* **disable_notifications** (true/**false**) In TDLib pending notification updates are stored in ram until you "read" them. This option disables completely notifications and keeps the pending notifications queue empty, reducing memory usage
|
||||
* **ignore_update_chat_last_message** (true/**false**) If you don't care about have updateChatLastMessage updates enable this
|
||||
* **ignore_update_chat_read_inbox** (true/**false**) If you don't care about have updateChatReadInbox updates enable this
|
||||
* **ignore_update_user_chat_action** (true/**false**) If you don't care about have updateUserChatAction updates enable this
|
||||
* **ignore_server_deletes_and_reads** (true/**false**) If you don't care about receiving read receipts and remote deletes from other users, enable this, it will reduce memory usage
|
||||
* **receive_access_hashes** (true/**false**) Receive chats and users access hash as updates
|
||||
* **disable_auto_download** (true/**false**) Forcefully ignore auto download settings of all sessions
|
||||
<a name="tdlight-extra-api-functions"></a>
|
||||
### TDLight extra API functions
|
||||
#### TdApi.GetMemoryStatistics
|
||||
This method is used to read the size of all the internal TDLib data structures.
|
||||
The output contains a string that can be parsed as a JSON.
|
||||
<a name="tdlight-recommended-options"></a>
|
||||
## TDLight recommended options
|
||||
* Options:
|
||||
* ignore_inline_thumbnails: true
|
||||
* disable_top_chats: true
|
||||
* ignore_platform_restrictions: true
|
||||
* ignore_sensitive_content_restrictions: true
|
||||
* Disable all the databases (messages_db, users_db, files_db)
|
||||
<a name="usage"></a>
|
||||
## Examples and documentation
|
||||
See our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts.
|
||||
|
||||
Take a look at our [examples](https://github.com/tdlib/td/blob/master/example/README.md#tdlib-usage-and-build-examples).
|
||||
Take a look at our [examples](https://github.com/tdlight-team/tdlight/blob/master/example/README.md#tdlib-usage-and-build-examples).
|
||||
|
||||
See a [TDLib build instructions generator](https://tdlib.github.io/td/build.html) for detailed instructions on how to build TDLib.
|
||||
See a [TDLight build instructions generator](https://tdlight-team.github.io/tdlight/build.html) for detailed instructions on how to build TDLib.
|
||||
|
||||
See description of our [JSON](#using-json), [C++](#using-cxx), [Java](#using-java) and [.NET](#using-dotnet) interfaces.
|
||||
|
||||
See the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html)
|
||||
See the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html)
|
||||
for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
|
||||
|
||||
<a name="dependencies"></a>
|
||||
@ -55,7 +83,7 @@ for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/do
|
||||
<a name="building"></a>
|
||||
## Building
|
||||
|
||||
The simplest way to build `TDLib` is to use our [TDLib build instructions generator](https://tdlib.github.io/td/build.html).
|
||||
The simplest way to build `TDLight` is to use our [TDLight build instructions generator](https://tdlight-team.github.io/tdlight/build.html).
|
||||
You need only to choose your programming language and target operating system to receive complete build instructions.
|
||||
|
||||
In general, you need to install all `TDLib` [dependencies](#dependencies), enter directory containing `TDLib` sources and compile them using CMake:
|
||||
@ -67,7 +95,7 @@ cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
To build `TDLib` on low memory devices you can run [SplitSource.php](https://github.com/tdlib/td/blob/master/SplitSource.php) script
|
||||
To build `TDLib` on low memory devices you can run [SplitSource.php](https://github.com/tdlight-team/tdlight/blob/master/SplitSource.php) script
|
||||
before compiling main `TDLib` source code and compile only needed targets:
|
||||
```
|
||||
mkdir build
|
||||
@ -106,21 +134,21 @@ Or you could install `TDLib` and then reference it in your CMakeLists.txt like t
|
||||
find_package(Td 1.8.25 REQUIRED)
|
||||
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
|
||||
```
|
||||
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/blob/master/example/cpp/CMakeLists.txt).
|
||||
See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/blob/master/example/cpp/CMakeLists.txt).
|
||||
|
||||
<a name="using-java"></a>
|
||||
## Using in Java projects
|
||||
`TDLib` provides native Java interface through JNI. To enable it, specify option `-DTD_ENABLE_JNI=ON` to CMake.
|
||||
|
||||
See [example/java](https://github.com/tdlib/td/tree/master/example/java) for example of using `TDLib` from Java and detailed build and usage instructions.
|
||||
See [example/java](https://github.com/tdlight-team/tdlight/tree/master/example/java) for example of using `TDLib` from Java and detailed build and usage instructions.
|
||||
|
||||
<a name="using-dotnet"></a>
|
||||
## Using in .NET projects
|
||||
`TDLib` provides native .NET interface through `C++/CLI` and `C++/CX`. To enable it, specify option `-DTD_ENABLE_DOTNET=ON` to CMake.
|
||||
.NET Core supports `C++/CLI` only since version 3.1 and only on Windows, so if older .NET Core is used or portability is needed, then `TDLib` JSON interface should be used through P/Invoke instead.
|
||||
|
||||
See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions.
|
||||
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform".
|
||||
See [example/csharp](https://github.com/tdlight-team/tdlight/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions.
|
||||
See [example/uwp](https://github.com/tdlight-team/tdlight/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform".
|
||||
|
||||
When `TDLib` is built with `TD_ENABLE_DOTNET` option enabled, `C++` documentation is removed from some files. You need to checkout these files to return `C++` documentation back:
|
||||
```
|
||||
@ -132,13 +160,13 @@ git checkout td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h
|
||||
`TDLib` provides efficient native C++, Java, and .NET interfaces.
|
||||
But for most use cases we suggest to use the JSON interface, which can be easily used with any programming language that is able to execute C functions.
|
||||
See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) documentation for detailed JSON interface description,
|
||||
the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of
|
||||
the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of
|
||||
all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
|
||||
|
||||
`TDLib` JSON interface adheres to semantic versioning and versions with the same major version number are binary and backward compatible, but the underlying `TDLib` API can be different for different minor and even patch versions.
|
||||
If you need to support different `TDLib` versions, then you can use a value of the `version` option to find exact `TDLib` version to use appropriate API methods.
|
||||
|
||||
See [example/python/tdjson_example.py](https://github.com/tdlib/td/blob/master/example/python/tdjson_example.py) for an example of such usage.
|
||||
See [example/python/tdjson_example.py](https://github.com/tdlight-team/tdlight/tree/master/example/python/tdjson_example.py) for an example of such usage.
|
||||
|
||||
<a name="license"></a>
|
||||
## License
|
||||
|
50
build.html
50
build.html
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>TDLib build instructions</title>
|
||||
<title>TDLight build instructions</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style>
|
||||
:root {
|
||||
@ -193,7 +193,7 @@
|
||||
|
||||
<div class="main">
|
||||
<div id="languageSelectDiv">
|
||||
<p>Choose a programming language from which you want to use TDLib:</p>
|
||||
<p>Choose a programming language from which you want to use TDLight:</p>
|
||||
<select id="languageSelect" onchange="onLanguageChanged(false)" autofocus class="large">
|
||||
<option>Choose a programming language:</option>
|
||||
<option>Python</option>
|
||||
@ -226,7 +226,7 @@
|
||||
</div>
|
||||
|
||||
<div id="osSelectDiv" class="hide">
|
||||
<p>Choose an operating system on which you want to use TDLib:</p>
|
||||
<p>Choose an operating system on which you want to use TDLight:</p>
|
||||
<select id="osSelect" onchange="onOsChanged()" class="large">
|
||||
<option>Choose an operating system:</option>
|
||||
</select>
|
||||
@ -234,7 +234,7 @@
|
||||
</div>
|
||||
|
||||
<div id="linuxSelectDiv" class="hide">
|
||||
<p>Choose a Linux distro on which you want to use TDLib:</p>
|
||||
<p>Choose a Linux distro on which you want to use TDLight:</p>
|
||||
<select id="linuxSelect" onchange="onOsChanged()" class="large">
|
||||
<option>Choose a Linux distro:</option>
|
||||
<option>Alpine</option>
|
||||
@ -263,13 +263,13 @@
|
||||
</div>
|
||||
|
||||
<div id="buildInstallLocalDiv" class="hide">
|
||||
<label><input type="checkbox" id="buildInstallLocalCheckbox" onchange="onOptionsChanged()"/>Install built TDLib to /usr/local instead of placing the files to td/tdlib.</label>
|
||||
<label><input type="checkbox" id="buildInstallLocalCheckbox" onchange="onOptionsChanged()"/>Install built TDLight to /usr/local instead of placing the files to td/tdlib.</label>
|
||||
</div>
|
||||
|
||||
<p></p>
|
||||
|
||||
<div id="buildCompilerDiv" class="hide">
|
||||
<span>Choose which compiler you want to use to build TDLib:</span><br>
|
||||
<span>Choose which compiler you want to use to build TDLight:</span><br>
|
||||
<label><input type="radio" id="buildCompilerRadioGcc" name="buildCompilerRadio" onchange="onOptionsChanged()" checked/>g++</label>
|
||||
<label><input type="radio" id="buildCompilerRadioClang" name="buildCompilerRadio" onchange="onOptionsChanged()"/>clang (recommended)</label>
|
||||
<p></p>
|
||||
@ -305,7 +305,7 @@
|
||||
</div>
|
||||
|
||||
<div id="buildBitnessDiv" class="hide">
|
||||
<span>Choose for which bitness you want to build TDLib:</span><br>
|
||||
<span>Choose for which bitness you want to build TDLight:</span><br>
|
||||
<label><input type="radio" id="buildBitnessRadio32" name="buildBitnessRadio" onchange="onOptionsChanged()" checked/>32</label>
|
||||
<label><input type="radio" id="buildBitnessRadio64" name="buildBitnessRadio" onchange="onOptionsChanged()"/>64</label>
|
||||
<p></p>
|
||||
@ -327,7 +327,7 @@
|
||||
</div>
|
||||
|
||||
<div id="buildCommandsDiv" class="hide">
|
||||
<p id="buildCommandsHeader">Here is complete instruction for TDLib binaries building:</p>
|
||||
<p id="buildCommandsHeader">Here is complete instruction for TDLight binaries building:</p>
|
||||
<p id="buildPre">Hidden text</p>
|
||||
<code id="buildCommands">Empty commands</code>
|
||||
<button id="copyBuildCommandsButton" onclick="copyBuildInstructions()">
|
||||
@ -494,14 +494,14 @@ function getTargetName(target) {
|
||||
case 'tdjson':
|
||||
case 'WebAssembly':
|
||||
case 'iOS':
|
||||
return '<a href="https://github.com/tdlib/td#using-json">JSON</a>';
|
||||
return '<a href="https://github.com/tdlight-team/tdlight#using-json">JSON</a>';
|
||||
case 'tdclient':
|
||||
return '<a href="https://github.com/tdlib/td#using-cxx">a simple and convenient C++11-interface</a>';
|
||||
return '<a href="https://github.com/tdlight-team/tdlight#using-cxx">a simple and convenient C++11-interface</a>';
|
||||
case 'JNI':
|
||||
case 'Android':
|
||||
return '<a href="https://github.com/tdlib/td#using-java">native ' + target + '</a>';
|
||||
return '<a href="https://github.com/tdlight-team/tdlight#using-java">native ' + target + '</a>';
|
||||
default:
|
||||
return '<a href="https://github.com/tdlib/td#using-dotnet">native ' + target + '</a>';
|
||||
return '<a href="https://github.com/tdlight-team/tdlight#using-dotnet">native ' + target + '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
@ -515,17 +515,17 @@ function onOsChanged() {
|
||||
if (language === 'Other') {
|
||||
language = 'any other programming language';
|
||||
}
|
||||
var text = 'TDLib can be used from ' + language + ' on ' + os + ' through the ' + getTargetName(target) + ' interface.<br>' +
|
||||
'See <a href="https://github.com/tdlib/td/blob/master/example/README.md#' + getExampleAnchor(language) + '">examples</a> of such usage and already available third-party frameworks.<br>';
|
||||
var text = 'TDLight can be used from ' + language + ' on ' + os + ' through the ' + getTargetName(target) + ' interface.<br>' +
|
||||
'See <a href="https://github.com/tdlight-team/tdlight/blob/master/example/README.md#' + getExampleAnchor(language) + '">examples</a> of such usage and already available third-party frameworks.<br>';
|
||||
|
||||
if (target === 'WebAssembly') {
|
||||
text = 'TDLib is available in a prebuilt form as an <a href="https://www.npmjs.com/">NPM</a> package <a href="https://www.npmjs.com/package/tdweb">tdweb</a>.<br>' +
|
||||
'If you want to build it manually, take a look at our <a href="https://github.com/tdlib/td/tree/master/example/web">example</a>.';
|
||||
text = 'TDLight is available in a prebuilt form as an <a href="https://www.npmjs.com/">NPM</a> package <a href="https://www.npmjs.com/package/tdweb">tdweb</a>.<br>' +
|
||||
'If you want to build it manually, take a look at our <a href="https://github.com/tdlight-team/tdlight/tree/master/example/web">example</a>.';
|
||||
target = '';
|
||||
}
|
||||
if (target === 'Android') {
|
||||
text = 'TDLib for Android is available in a prebuilt form and can be downloaded from <a href="https://core.telegram.org/tdlib/tdlib.zip">there</a>.<br>' +
|
||||
'See <a href="https://github.com/tdlib/td/issues/77#issuecomment-640719893">build instructions</a> if you want to build the latest TDLib version or want to build TDLib with different interface.';
|
||||
text = 'TDLight for Android is available in a prebuilt form and can be downloaded from <a href="https://core.telegram.org/tdlight-team/tdlightlib.zip">there</a>.<br>' +
|
||||
'See <a href="https://github.com/tdlight-team/tdlight/issues/77#issuecomment-640719893">build instructions</a> if you want to build the latest TDLight version or want to build TDLight with different interface.';
|
||||
target = '';
|
||||
}
|
||||
if (target === 'iOS') {
|
||||
@ -590,7 +590,7 @@ function onOptionsChanged() {
|
||||
if (os_linux || os_freebsd || os_netbsd) {
|
||||
low_memory = document.getElementById('buildLowMemoryCheckbox').checked;
|
||||
document.getElementById('buildLowMemoryText').innerHTML = 'I have less than ' + (use_clang ? '1.5' : '3.5') +' GB of RAM.' +
|
||||
(low_memory ? ' Now you will need only ' + (use_clang ? '0.5' : '1') +' GB of RAM to build TDLib.' : '');
|
||||
(low_memory ? ' Now you will need only ' + (use_clang ? '0.5' : '1') +' GB of RAM to build TDLight.' : '');
|
||||
document.getElementById('buildLowMemoryDiv').style.display = 'block';
|
||||
} else {
|
||||
if (os_openbsd) {
|
||||
@ -751,8 +751,8 @@ function onOptionsChanged() {
|
||||
pre_text.push('Note that the following instruction is for NetBSD 8+ and default SH shell.');
|
||||
}
|
||||
if (os_mac) {
|
||||
pre_text.push('Note that the following instruction will build TDLib only for ' + os_mac_host_name + '.');
|
||||
pre_text.push('If you want to create a universal XCFramework, take a look at our <a href="https://github.com/tdlib/td/tree/master/example/ios">example</a> instead.');
|
||||
pre_text.push('Note that the following instruction will build TDLight only for ' + os_mac_host_name + '.');
|
||||
pre_text.push('If you want to create a universal XCFramework, take a look at our <a href="https://github.com/tdlight-team/tdlight/tree/master/example/ios">example</a> instead.');
|
||||
}
|
||||
|
||||
var terminal_name = (function () {
|
||||
@ -776,12 +776,12 @@ function onOptionsChanged() {
|
||||
if (os_windows) {
|
||||
pre_text.push('Close and re-open ' + terminal_name + ' if the PATH environment variable was changed.');
|
||||
}
|
||||
pre_text.push('Run these commands in ' + terminal_name + ' to build TDLib and to install it to ' + install_dir + ':');
|
||||
pre_text.push('Run these commands in ' + terminal_name + ' to build TDLight and to install it to ' + install_dir + ':');
|
||||
document.getElementById('buildPre').innerHTML = '<ul><li>' + pre_text.join('</li><li>') + '</li></ul>';
|
||||
document.getElementById('buildPre').style.display = 'block';
|
||||
|
||||
if (install_dir && install_dir !== '/usr/local') {
|
||||
install_dir = '../tdlib';
|
||||
install_dir = '../tdlight';
|
||||
if (target === 'JNI' || target === 'C++/CX') {
|
||||
install_dir = '../../' + install_dir;
|
||||
}
|
||||
@ -926,9 +926,9 @@ function onOptionsChanged() {
|
||||
commands.push('exit');
|
||||
}
|
||||
}
|
||||
commands.push('git clone https://github.com/tdlib/td.git');
|
||||
commands.push('git clone https://github.com/tdlight-team/tdlight.git');
|
||||
|
||||
commands.push('cd td');
|
||||
commands.push('cd tdlight');
|
||||
// commands.push('git checkout v1.8.0');
|
||||
|
||||
if (use_vcpkg) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
# TDLib usage and build examples
|
||||
|
||||
This directory contains basic examples of TDLib usage from different programming languages and examples of library building for different platforms.
|
||||
If you are looking for documentation of all available TDLib methods, see the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the
|
||||
If you are looking for documentation of all available TDLib methods, see the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the
|
||||
automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available TDLib
|
||||
[methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
|
||||
Also, take a look at our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts.
|
||||
@ -54,13 +54,13 @@ If you want to use TDLib with asyncio and Python >= 3.9, take a look at [aiotdli
|
||||
For older Python versions you can use [pytdlib](https://github.com/pytdlib/pytdlib).
|
||||
This wrapper contains generator for TDLib API classes and basic interface for interaction with TDLib.
|
||||
|
||||
You can also check out [example/python/tdjson_example.py](https://github.com/tdlib/td/blob/master/example/python/tdjson_example.py),
|
||||
You can also check out [example/python/tdjson_example.py](https://github.com/tdlight-team/tdlight/blob/master/example/python/tdjson_example.py),
|
||||
[tdlib-python](https://github.com/JunaidBabu/tdlib-python), or [Python Wrapper TDLib](https://github.com/alvhix/pywtdlib) for some basic examples of TDLib JSON interface integration with Python.
|
||||
|
||||
<a name="javascript"></a>
|
||||
## Using TDLib in JavaScript projects
|
||||
|
||||
TDLib can be compiled to WebAssembly or asm.js and used in a browser from JavaScript. See [tdweb](https://github.com/tdlib/td/tree/master/example/web) as a convenient wrapper for TDLib in a browser
|
||||
TDLib can be compiled to WebAssembly or asm.js and used in a browser from JavaScript. See [tdweb](https://github.com/tdlight-team/tdlight/tree/master/example/web) as a convenient wrapper for TDLib in a browser
|
||||
and [telegram-react](https://github.com/evgeny-nadymov/telegram-react) as an example of a TDLib-based Telegram client.
|
||||
|
||||
See also [Svelte-tdweb-starter](https://github.com/gennadypolakov/svelte-tdweb-starter) - Svelte wrapper for tdweb, and [Telegram-Photoframe](https://github.com/lukefx/telegram-photoframe) - a web application that displays your preferred group or channel as Photoframe.
|
||||
@ -95,7 +95,7 @@ You can also see [github.com/aliforever/go-tdlib](https://github.com/aliforever/
|
||||
TDLib can be used from the Java programming language through native [JNI](https://github.com/tdlib/td#using-java) binding.
|
||||
|
||||
We provide a generator for JNI bridge methods and Java classes for all TDLib API methods and objects.
|
||||
See [example/java](https://github.com/tdlib/td/tree/master/example/java) for an example of using TDLib from desktop Java along with detailed building and usage instructions.
|
||||
See [example/java](https://github.com/tdlight-team/tdlight/tree/master/example/java) for an example of using TDLib from desktop Java along with detailed building and usage instructions.
|
||||
To use TDLib to create Android Java applications, use our [prebuilt library for Android](https://core.telegram.org/tdlib/tdlib.zip).
|
||||
|
||||
<a name="kotlin"></a>
|
||||
@ -112,8 +112,8 @@ See also [td-ktx](https://github.com/tdlibx/td-ktx) - Kotlin coroutines wrapper
|
||||
|
||||
TDLib provides a native [.NET](https://github.com/tdlib/td#using-dotnet) interface through `C++/CLI` and `C++/CX`.
|
||||
See [tdlib-netcore](https://github.com/dantmnf/tdlib-netcore) for a SWIG-like binding with automatically generated classes for TDLib API.
|
||||
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for an example of building TDLib SDK for the Universal Windows Platform and an example of its usage from C#.
|
||||
See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C# on Windows.
|
||||
See [example/uwp](https://github.com/tdlight-team/tdlight/tree/master/example/uwp) for an example of building TDLib SDK for the Universal Windows Platform and an example of its usage from C#.
|
||||
See [example/csharp](https://github.com/tdlight-team/tdlight/tree/master/example/csharp) for an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C# on Windows.
|
||||
|
||||
If you want to write a cross-platform C# application using .NET Core, see [tdsharp](https://github.com/egramtel/tdsharp). It uses our [JSON](https://github.com/tdlib/td#using-json) interface,
|
||||
provides an asynchronous interface for interaction with TDLib, automatically generated classes for TDLib API and has some examples.
|
||||
@ -127,8 +127,8 @@ Also, see [Unigram](https://github.com/UnigramDev/Unigram), which is a full-feat
|
||||
|
||||
TDLib has a simple and convenient C++11-interface for sending and receiving requests and can be statically linked to your application.
|
||||
|
||||
See [example/cpp](https://github.com/tdlib/td/tree/master/example/cpp) for an example of TDLib usage from C++.
|
||||
[td_example.cpp](https://github.com/tdlib/td/blob/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message.
|
||||
See [example/cpp](https://github.com/tdlight-team/tdlight/tree/master/example/cpp) for an example of TDLib usage from C++.
|
||||
[td_example.cpp](https://github.com/tdlight-team/tdlight/blob/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message.
|
||||
|
||||
See also the source code of [Fernschreiber](https://github.com/Wunderfitz/harbour-fernschreiber) and [Depecher](https://github.com/blacksailer/depecher) – Telegram apps for Sailfish OS,
|
||||
[TELEports](https://gitlab.com/ubports/development/apps/teleports) – a Qt-client for Ubuntu Touch, [tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin,
|
||||
@ -140,20 +140,20 @@ or [MeeGram](https://github.com/qtinsider/meegram2) - a Telegram client for Noki
|
||||
|
||||
TDLib can be used from the Swift programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
|
||||
|
||||
See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
|
||||
See [example/ios](https://github.com/tdlight-team/tdlight/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
|
||||
|
||||
See [TDLibKit](https://github.com/Swiftgram/TDLibKit), [tdlib-swift](https://github.com/modestman/tdlib-swift), or [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
|
||||
See also the source code of [Moc](https://github.com/mock-foundation/moc) - a native and powerful macOS and iPadOS Telegram client, optimized for moderating large communities and personal use.
|
||||
|
||||
See [example/swift](https://github.com/tdlib/td/tree/master/example/swift) for an example of a macOS Swift application.
|
||||
See [example/swift](https://github.com/tdlight-team/tdlight/tree/master/example/swift) for an example of a macOS Swift application.
|
||||
|
||||
<a name="objective-c"></a>
|
||||
## Using TDLib in Objective-C projects
|
||||
|
||||
TDLib can be used from the Objective-C programming language through [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
|
||||
|
||||
See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
|
||||
See [example/ios](https://github.com/tdlight-team/tdlight/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
|
||||
|
||||
<a name="object-pascal"></a>
|
||||
## Using TDLib in Object Pascal projects with Delphi and Lazarus
|
||||
@ -300,7 +300,7 @@ TDLib can be used from the C programming language through the [JSON](https://git
|
||||
|
||||
See [easy-tg](https://github.com/Trumeet/easy-tg) for an example of such usage.
|
||||
|
||||
You can also try to use our [C](https://github.com/tdlib/td/blob/master/td/telegram/td_c_client.h) client, which was used by the private TDLib-based version of [telegram-cli](https://github.com/vysheng/tg).
|
||||
You can also try to use our [C](https://github.com/tdlight-team/tdlight/blob/master/td/telegram/td_c_client.h) client, which was used by the private TDLib-based version of [telegram-cli](https://github.com/vysheng/tg).
|
||||
|
||||
<a name="g"></a>
|
||||
## Using TDLib from G projects
|
||||
|
@ -4,7 +4,7 @@ Below are instructions for building TDLib for iOS, watchOS, tvOS, and also macOS
|
||||
|
||||
If you need only a macOS build for the current architecture, take a look at [TDLib build instructions generator](https://tdlib.github.io/td/build.html).
|
||||
|
||||
For example of usage take a look at our [Swift example](https://github.com/tdlib/td/tree/master/example/swift).
|
||||
For example of usage take a look at our [Swift example](https://github.com/tdlight-team/tdlight/tree/master/example/swift).
|
||||
|
||||
To compile `TDLib` you will need to:
|
||||
* Install the latest Xcode via `xcode-select --install` or downloading it from [Xcode website](https://developer.apple.com/xcode/).
|
||||
@ -37,7 +37,7 @@ cd <path to TDLib sources>/example/ios
|
||||
```
|
||||
This may take a while, because TDLib will be built about 16 times.
|
||||
Resulting XCFramework will work on any architecture and even on a simulator.
|
||||
We use [CMake/iOS.cmake](https://github.com/tdlib/td/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too.
|
||||
We use [CMake/iOS.cmake](https://github.com/tdlight-team/tdlight/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too.
|
||||
|
||||
Built libraries and XCFramework will be stored in `tdjson` directory.
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
To run this example, you will need installed JDK >= 1.6.
|
||||
For Javadoc documentation generation PHP is needed.
|
||||
|
||||
You can find complete build instructions for your operating system at https://tdlib.github.io/td/build.html?language=Java.
|
||||
You can find complete build instructions for your operating system at https://tdlight-team.github.io/tdlight/build.html?language=Java.
|
||||
|
||||
In general, the build process looks as follows.
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo>
|
||||
<Tags>Telegram, TDLib, library, client, API</Tags>
|
||||
<License>LICENSE_1_0.txt</License>
|
||||
<ReleaseNotes>https://github.com/tdlib/td/blob/master/CHANGELOG.md</ReleaseNotes>
|
||||
<ReleaseNotes>https://github.com/tdlight-team/tdlight/blob/master/CHANGELOG.md</ReleaseNotes>
|
||||
</Metadata>
|
||||
<Installation Scope="Global">
|
||||
<InstallationTarget Id="Microsoft.ExtensionSDK" TargetPlatformIdentifier="UAP" TargetPlatformVersion="v0.8.0.0" SdkName="Telegram.Td.UWP" SdkVersion="1.0" />
|
||||
|
@ -26,4 +26,4 @@ cd <path to TDLib sources>/example/web
|
||||
|
||||
## Using tdweb NPM package
|
||||
|
||||
See [tdweb](https://www.npmjs.com/package/tdweb) or [README.md](https://github.com/tdlib/td/tree/master/example/web/tdweb/README.md) for package documentation.
|
||||
See [tdweb](https://www.npmjs.com/package/tdweb) or [README.md](https://github.com/tdlight-team/tdlight/tree/master/example/web/tdweb/README.md) for package documentation.
|
||||
|
@ -8,11 +8,11 @@ Once this is done, you can send queries to the TDLib instance using the method `
|
||||
|
||||
See [Getting Started](https://core.telegram.org/tdlib/getting-started) for a description of basic TDLib concepts and a short introduction to TDLib usage.
|
||||
|
||||
See the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or
|
||||
See the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or
|
||||
the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available
|
||||
TDLib [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
|
||||
The JSON representation of TDLib API objects is straightforward: all API objects are represented as JSON objects with the same keys as the API object field names in the
|
||||
[td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore
|
||||
[td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore
|
||||
which shouldn't be used in the JSON interface. The object type name is stored in the special field '@type' which is optional in places where type is uniquely determined by the context.
|
||||
Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of int64 and string types are stored as String,
|
||||
fields of bytes type are base64 encoded and then stored as String, fields of array type are stored as Array.
|
||||
|
@ -65,7 +65,7 @@ class TdClient {
|
||||
*
|
||||
* If the query contains the field '@extra', the same field will be added into the result.
|
||||
*
|
||||
* @param {Object} query - The query for TDLib. See the [td_api.tl]{@link https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl} scheme or
|
||||
* @param {Object} query - The query for TDLib. See the [td_api.tl]{@link https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl} scheme or
|
||||
* the automatically generated [HTML documentation]{@link https://core.telegram.org/tdlib/docs/td__api_8h.html}
|
||||
* for a list of all available TDLib [methods]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html} and
|
||||
* [classes]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html}.
|
||||
|
1
td/generate/scheme/.gitignore
vendored
Normal file
1
td/generate/scheme/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.tlo
|
@ -561,6 +561,21 @@ userTypeBot can_be_edited:Bool can_join_groups:Bool can_read_all_group_messages:
|
||||
//@description No information on the user besides the user identifier is available, yet this user has not been deleted. This object is extremely rare and must be handled like a deleted user. It is not possible to perform any actions on users of this type
|
||||
userTypeUnknown = UserType;
|
||||
|
||||
//@class AccessHashType @description Represents the type of an access hash. The following types are possible: user, channel
|
||||
|
||||
//@description An access hash of an user
|
||||
accessHashTypeUser = AccessHashType;
|
||||
|
||||
//@description An access hash of a channel
|
||||
accessHashTypeChannel = AccessHashType;
|
||||
|
||||
|
||||
//@description Access hash
|
||||
//@chat_id Chat identifier
|
||||
//@type Access hash type
|
||||
//@access_hash Access hash
|
||||
accessHash chat_id:int53 type:AccessHashType access_hash:int64 = AccessHash;
|
||||
|
||||
|
||||
//@description Represents a command supported by a bot @command Text of the bot command @param_description Description of the bot command
|
||||
botCommand command:string description:string = BotCommand;
|
||||
@ -5955,6 +5970,10 @@ storageStatisticsFast files_size:int53 file_count:int32 database_size:int53 lang
|
||||
//@statistics Database statistics in an unspecified human-readable format
|
||||
databaseStatistics statistics:string = DatabaseStatistics;
|
||||
|
||||
//@description Contains memory statistics
|
||||
//@statistics Memory statistics in an unspecified human-readable format
|
||||
memoryStatistics statistics:string = MemoryStatistics;
|
||||
|
||||
|
||||
//@class NetworkType @description Represents the type of a network
|
||||
|
||||
@ -6590,6 +6609,9 @@ updateUserStatus user_id:int53 status:UserStatus = Update;
|
||||
//@description Some data of a user has changed. This update is guaranteed to come before the user identifier is returned to the application @user New data about the user
|
||||
updateUser user:user = Update;
|
||||
|
||||
//@description Some data of a user or a chat has changed. This update is guaranteed to come before the user or chat identifier is returned to the application @access_hash Access hash
|
||||
updateAccessHash access_hash:accessHash = Update;
|
||||
|
||||
//@description Some data of a basic group has changed. This update is guaranteed to come before the basic group identifier is returned to the application @basic_group New data about the group
|
||||
updateBasicGroup basic_group:basicGroup = Update;
|
||||
|
||||
@ -9694,6 +9716,10 @@ getStorageStatisticsFast = StorageStatisticsFast;
|
||||
//@description Returns database statistics
|
||||
getDatabaseStatistics = DatabaseStatistics;
|
||||
|
||||
//@description Returns memory statistics
|
||||
//@full Full memory statistics calculation
|
||||
getMemoryStatistics full:Bool = MemoryStatistics;
|
||||
|
||||
//@description Optimizes storage usage, i.e. deletes some files and returns new storage usage statistics. Secret thumbnails can't be deleted
|
||||
//@size Limit on the total size of files after deletion, in bytes. Pass -1 to use the default limit
|
||||
//@ttl Limit on the time that has passed since the last time a file was accessed (or creation time for some filesystems). Pass -1 to use the default limit
|
||||
|
@ -185,7 +185,7 @@ void tl_print_parse_error (void) {
|
||||
}
|
||||
|
||||
char *parse_lex (void) {
|
||||
while (1) {
|
||||
while (1) {
|
||||
while (curch && is_whitespace (curch)) { nextch (); }
|
||||
if (curch == '/' && nextch () == '/') {
|
||||
while (nextch () != 10);
|
||||
@ -235,7 +235,7 @@ char *parse_lex (void) {
|
||||
case '.':
|
||||
nextch ();
|
||||
parse.lex.len = 1;
|
||||
parse.lex.type = lex_char;
|
||||
parse.lex.type = lex_char;
|
||||
return (parse.lex.ptr = p);
|
||||
case 'a':
|
||||
case 'b':
|
||||
@ -334,10 +334,10 @@ char *parse_lex (void) {
|
||||
int ok = 1;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!is_hexdigit (nextch())) {
|
||||
if (curch == ' ' && i >= 5) {
|
||||
if (curch == ' ' && i >= 5) {
|
||||
ok = 2;
|
||||
break;
|
||||
} else {
|
||||
} else {
|
||||
parse_error ("Hex digit expected");
|
||||
parse.lex.type = lex_error;
|
||||
return (parse.lex.ptr = (void *)-1);
|
||||
@ -370,7 +370,7 @@ char *parse_lex (void) {
|
||||
parse.lex.type = lex_error;
|
||||
return (parse.lex.ptr = (void *)-1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int expect (char *s) {
|
||||
@ -453,7 +453,7 @@ struct tree *parse_full_combinator_id (void) {
|
||||
} else {
|
||||
parse_error ("Can not parse full combinator id");
|
||||
PARSE_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct tree *parse_combinator_id (void) {
|
||||
@ -467,7 +467,7 @@ struct tree *parse_combinator_id (void) {
|
||||
} else {
|
||||
parse_error ("Can not parse combinator id");
|
||||
PARSE_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct tree *parse_var_ident (void) {
|
||||
@ -595,7 +595,7 @@ struct tree *parse_subexpr (void) {
|
||||
was_term = 1;
|
||||
PARSE_TRY (parse_term);
|
||||
if (S) {
|
||||
tree_add_child (T, S);
|
||||
tree_add_child (T, S);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -714,7 +714,7 @@ struct tree *parse_args4 (void) {
|
||||
if (S) {
|
||||
tree_add_child (T, S);
|
||||
} else {
|
||||
load_parse (so);
|
||||
load_parse (so);
|
||||
}
|
||||
if (LEX_CHAR ('!')) {
|
||||
PARSE_ADD (type_exclam);
|
||||
@ -733,7 +733,7 @@ struct tree *parse_args3 (void) {
|
||||
if (S) {
|
||||
tree_add_child (T, S);
|
||||
} else {
|
||||
load_parse (so);
|
||||
load_parse (so);
|
||||
}
|
||||
if (LEX_CHAR ('!')) {
|
||||
PARSE_ADD (type_exclam);
|
||||
@ -757,7 +757,7 @@ struct tree *parse_args2 (void) {
|
||||
if (S) {
|
||||
tree_add_child (T, S);
|
||||
} else {
|
||||
load_parse (so);
|
||||
load_parse (so);
|
||||
}
|
||||
struct parse save2 = save_parse ();
|
||||
PARSE_TRY (parse_multiplicity);
|
||||
@ -789,7 +789,7 @@ struct tree *parse_args1 (void) {
|
||||
if (S) {
|
||||
tree_add_child (T, S);
|
||||
} else {
|
||||
load_parse (so);
|
||||
load_parse (so);
|
||||
}
|
||||
if (LEX_CHAR ('!')) {
|
||||
PARSE_ADD (type_exclam);
|
||||
@ -1041,7 +1041,7 @@ int tl_add_field (char *id) {
|
||||
|
||||
void tl_clear_fields (void) {
|
||||
// tree_act_tl_field (fields[namespace_level], (void *)free);
|
||||
fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]);
|
||||
fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]);
|
||||
}
|
||||
|
||||
struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) {
|
||||
@ -1151,9 +1151,9 @@ struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long
|
||||
|
||||
void tl_add_type_param (struct tl_type *t, int x) {
|
||||
assert (t->flags & 4);
|
||||
assert (t->params_num <= 64);
|
||||
assert (t->params_num <= 64);
|
||||
if (x) {
|
||||
t->params_types |= (1ull << (t->params_num ++));
|
||||
t->params_types |= (1ull << (t->params_num ++));
|
||||
} else {
|
||||
t->params_num ++;
|
||||
}
|
||||
@ -1222,7 +1222,7 @@ struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, i
|
||||
struct tl_constructor *t = talloc (sizeof (*t));
|
||||
t->type = a;
|
||||
t->name = magic;
|
||||
t->id = id;
|
||||
t->id = id;
|
||||
t->print_id = tstrdup (id);
|
||||
t->real_id = 0;
|
||||
|
||||
@ -1282,7 +1282,7 @@ struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int
|
||||
struct tl_constructor *t = talloc (sizeof (*t));
|
||||
t->type = a;
|
||||
t->name = magic;
|
||||
t->id = id;
|
||||
t->id = id;
|
||||
t->print_id = tstrdup (id);
|
||||
t->real_id = 0;
|
||||
|
||||
@ -1455,7 +1455,7 @@ void tl_buf_add_tree (struct tl_combinator_tree *T, int x) {
|
||||
tl_buf_add_tree (T->right, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type));
|
||||
assert (0);
|
||||
@ -1549,7 +1549,7 @@ struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_com
|
||||
tfree (v, sizeof (*v));
|
||||
R->type_flags += L->type_flags;
|
||||
return R;
|
||||
case type_list_item:
|
||||
case type_list_item:
|
||||
case type_list:
|
||||
if (R->type != type_list_item) {
|
||||
TL_ERROR ("Union: type mistmatch\n");
|
||||
@ -1561,7 +1561,7 @@ struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_com
|
||||
case type_type:
|
||||
if (L->type_len == 0) {
|
||||
TL_ERROR ("Arguments number exceeds type arity\n");
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
if (R->type != type_num && R->type != type_type && R->type != type_num_value) {
|
||||
TL_ERROR ("Union: type mistmatch\n");
|
||||
@ -1574,7 +1574,7 @@ struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_com
|
||||
}
|
||||
if (R->type_len > 0) {
|
||||
TL_ERROR ("Argument type must have full number of arguments\n");
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) {
|
||||
TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type));
|
||||
@ -1595,7 +1595,7 @@ struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s);
|
||||
struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) {
|
||||
assert (T->type == type_term);
|
||||
int i = 0;
|
||||
while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; }
|
||||
while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; }
|
||||
assert (i < T->nc);
|
||||
TL_INIT (L);
|
||||
while (i < T->nc) {
|
||||
@ -1610,7 +1610,7 @@ struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) {
|
||||
struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) {
|
||||
assert (T->type == type_type_term);
|
||||
assert (T->nc == 1);
|
||||
struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
|
||||
struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s);
|
||||
if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; }
|
||||
return Z;
|
||||
}
|
||||
@ -1674,7 +1674,7 @@ struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) {
|
||||
assert (!T->nc);
|
||||
struct tl_var *v = tl_get_var (T->text, T->len);
|
||||
TL_INIT (L);
|
||||
if (v) {
|
||||
if (v) {
|
||||
L = alloc_ctree_node ();
|
||||
L->act = act_var;
|
||||
L->type = v->type ? type_num : type_type;
|
||||
@ -1733,7 +1733,7 @@ struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) {
|
||||
L->data = t;
|
||||
L->type = type_type;
|
||||
L->type_len = t->params_num;
|
||||
L->type_flags = t->params_types;
|
||||
L->type_flags = t->params_types;
|
||||
return L;
|
||||
} else {
|
||||
TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text);
|
||||
@ -1761,7 +1761,7 @@ struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) {
|
||||
default:
|
||||
fprintf (stderr, "type = %d\n", T->type);
|
||||
assert (0);
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1834,11 +1834,11 @@ struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
|
||||
if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) {
|
||||
field_name = mystrdup (T->c[x]->text, T->c[x]->len);
|
||||
if (!tl_add_field (field_name)) {
|
||||
TL_ERROR ("Duplicate field name %s\n", field_name);
|
||||
TL_ERROR ("Duplicate field name %s\n", field_name);
|
||||
TL_FAIL;
|
||||
}
|
||||
x ++;
|
||||
}
|
||||
}
|
||||
//fprintf (stderr, "%d %d\n", x, T->nc);
|
||||
if (T->c[x]->type == type_multiplicity) {
|
||||
L = tl_parse_multiplicity (T->c[x]);
|
||||
@ -1846,7 +1846,7 @@ struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
|
||||
x ++;
|
||||
} else {
|
||||
struct tl_var *v = tl_get_last_num_var ();
|
||||
if (!v) {
|
||||
if (!v) {
|
||||
TL_ERROR ("Expected multiplicity or nat var\n");
|
||||
TL_FAIL;
|
||||
}
|
||||
@ -1880,7 +1880,7 @@ struct tl_combinator_tree *tl_parse_args2 (struct tree *T) {
|
||||
H->right = 0;
|
||||
H->data = field_name;
|
||||
H->type_len = 0;
|
||||
|
||||
|
||||
return H;
|
||||
}
|
||||
|
||||
@ -1971,7 +1971,7 @@ struct tl_combinator_tree *tl_parse_args134 (struct tree *T) {
|
||||
if (!v) {TL_FAIL;}
|
||||
v->flags |= 2;
|
||||
}
|
||||
|
||||
|
||||
H = tl_union (H, S);
|
||||
}
|
||||
return H;
|
||||
@ -1993,7 +1993,7 @@ struct tl_combinator_tree *tl_parse_args (struct tree *T) {
|
||||
default:
|
||||
assert (0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tl_mark_vars (struct tl_combinator_tree *T) {
|
||||
@ -2012,7 +2012,7 @@ struct tl_combinator_tree *tl_parse_result_type (struct tree *T) {
|
||||
assert (T->type == type_result_type);
|
||||
assert (T->nc >= 1);
|
||||
assert (T->nc <= 64);
|
||||
|
||||
|
||||
TL_INIT (L);
|
||||
|
||||
if (tl_get_var (T->c[0]->text, T->c[0]->len)) {
|
||||
@ -2043,7 +2043,7 @@ struct tl_combinator_tree *tl_parse_result_type (struct tree *T) {
|
||||
int i;
|
||||
for (i = 1; i < T->nc; i++) {
|
||||
TL_TRY (tl_parse_any_term (T->c[i], 0), L);
|
||||
assert (L->right);
|
||||
assert (L->right);
|
||||
assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0));
|
||||
}
|
||||
}
|
||||
@ -2090,7 +2090,7 @@ int tl_parse_combinator_decl (struct tree *T, int fun) {
|
||||
TL_ERROR ("Only functions can return variables\n");
|
||||
}
|
||||
assert (t || fun);
|
||||
|
||||
|
||||
assert (namespace_level == 0);
|
||||
__ok = 1;
|
||||
tree_act_tl_var (vars[0], tl_var_check_used);
|
||||
@ -2098,7 +2098,7 @@ int tl_parse_combinator_decl (struct tree *T, int fun) {
|
||||
TL_ERROR ("Not all variables are used in right side\n");
|
||||
TL_FAIL;
|
||||
}
|
||||
|
||||
|
||||
if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) {
|
||||
TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text);
|
||||
return 0;
|
||||
@ -2107,7 +2107,7 @@ int tl_parse_combinator_decl (struct tree *T, int fun) {
|
||||
if (!c) { TL_FAIL; }
|
||||
c->left = L;
|
||||
c->right = R;
|
||||
|
||||
|
||||
if (!c->name) {
|
||||
tl_count_combinator_name (c);
|
||||
}
|
||||
@ -2163,7 +2163,7 @@ struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struc
|
||||
if (O->data == *X) {
|
||||
struct tl_combinator_tree *R = tl_tree_dup (Y);
|
||||
if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; }
|
||||
return R;
|
||||
return R;
|
||||
}
|
||||
}
|
||||
struct tl_combinator_tree *t;
|
||||
@ -2174,7 +2174,7 @@ struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struc
|
||||
if (!t) { return 0;}
|
||||
if (t == (void *)-1l) { return (void *)-1l; }
|
||||
if (t != (void *)-2l) { return t;}
|
||||
return (void *)-1l;
|
||||
return (void *)-1l;
|
||||
}
|
||||
if (t != (void *)-2l) {
|
||||
O->left = t;
|
||||
@ -2182,7 +2182,7 @@ struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struc
|
||||
t = change_first_var (O->right, X, Y);
|
||||
if (!t) { return 0;}
|
||||
if (t == (void *)-1l) {
|
||||
return O->left;
|
||||
return O->left;
|
||||
}
|
||||
if (t != (void *)-2l) {
|
||||
O->right = t;
|
||||
@ -2267,7 +2267,7 @@ struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struc
|
||||
if (!t) { return 0;}
|
||||
if (t == (void *)-1l) { return (void *)-1l; }
|
||||
if (t != (void *)-2l) { return t;}
|
||||
return (void *)-1l;
|
||||
return (void *)-1l;
|
||||
}
|
||||
if (t != (void *)-2l) {
|
||||
O->left = t;
|
||||
@ -2275,7 +2275,7 @@ struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struc
|
||||
t = change_value_var (O->right, X);
|
||||
if (!t) { return 0;}
|
||||
if (t == (void *)-1l) {
|
||||
return O->left;
|
||||
return O->left;
|
||||
}
|
||||
if (t != (void *)-2l) {
|
||||
O->right = t;
|
||||
@ -2324,7 +2324,7 @@ int tl_parse_partial_type_app_decl (struct tree *T) {
|
||||
assert (nt);
|
||||
//snprintf (_buf, 100000, "%s #", t->id);
|
||||
//nt->real_id = strdup (_buf);
|
||||
|
||||
|
||||
for (i = 0; i < t->constructors_num; i++) {
|
||||
struct tl_constructor *c = t->constructors[i];
|
||||
struct tree_var_value *V = 0;
|
||||
@ -2332,7 +2332,7 @@ int tl_parse_partial_type_app_decl (struct tree *T) {
|
||||
TL_INIT (B);
|
||||
A = tl_tree_dup (c->left);
|
||||
B = tl_tree_dup (c->right);
|
||||
|
||||
|
||||
struct tree_var_value *W = 0;
|
||||
change_var_ptrs (c->left, A, &W);
|
||||
change_var_ptrs (c->right, B, &W);
|
||||
@ -2349,7 +2349,7 @@ int tl_parse_partial_type_app_decl (struct tree *T) {
|
||||
struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1);
|
||||
snprintf (_buf, 100000, "%s", c->id);
|
||||
r->real_id = tstrdup (_buf);
|
||||
|
||||
|
||||
r->left = A;
|
||||
r->right = B;
|
||||
if (!r->name) {
|
||||
@ -2377,8 +2377,8 @@ int tl_parse_partial_comb_app_decl (struct tree *T, int fun) {
|
||||
TL_INIT (R);
|
||||
L = tl_tree_dup (c->left);
|
||||
R = tl_tree_dup (c->right);
|
||||
|
||||
|
||||
|
||||
|
||||
struct tree_var_value *V = 0;
|
||||
change_var_ptrs (c->left, L, &V);
|
||||
change_var_ptrs (c->right, R, &V);
|
||||
@ -2391,7 +2391,7 @@ int tl_parse_partial_comb_app_decl (struct tree *T, int fun) {
|
||||
TL_INIT (Z);
|
||||
X = tl_parse_any_term (T->c[i], 0);
|
||||
struct tl_combinator_tree *K = 0;
|
||||
if (!(Z = change_first_var (L, &K, X))) {
|
||||
if (!(Z = change_first_var (L, &K, X))) {
|
||||
TL_FAIL;
|
||||
}
|
||||
L = Z;
|
||||
@ -2516,7 +2516,7 @@ int tl_parse_builtin_combinator_decl (struct tree *T, int fun) {
|
||||
if (!c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
c->left = alloc_ctree_node ();
|
||||
c->left->act = act_question_mark;
|
||||
c->left->type = type_list_item;
|
||||
@ -2615,7 +2615,7 @@ int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, stru
|
||||
if (R->act == act_var) {
|
||||
struct tl_combinator_tree *_ = R; R = L; L = _;
|
||||
}
|
||||
|
||||
|
||||
if (L->type == type_type) {
|
||||
if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) {
|
||||
return 0;
|
||||
@ -2695,14 +2695,14 @@ int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, stru
|
||||
M = tl_get_var_value (T, M->data);
|
||||
}
|
||||
if (K->type == type_num_value && M->type == type_num_value) {
|
||||
return x == y;
|
||||
return x == y;
|
||||
}
|
||||
if (M->type == type_num_value) {
|
||||
tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
|
||||
return 1;
|
||||
return 1;
|
||||
} else if (K->type == type_num_value) {
|
||||
tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags));
|
||||
return 1;
|
||||
return 1;
|
||||
} else {
|
||||
if (x >= y) {
|
||||
tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags));
|
||||
@ -2720,7 +2720,7 @@ void tl_type_check (struct tl_type *t) {
|
||||
if (!__ok) return;
|
||||
if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; }
|
||||
if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; }
|
||||
if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) {
|
||||
if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) {
|
||||
TL_ERROR ("Type %s has no constructors\n", t->id);
|
||||
__ok = 0;
|
||||
return;
|
||||
@ -2739,7 +2739,7 @@ void tl_type_check (struct tl_type *t) {
|
||||
}
|
||||
}
|
||||
if ((t->flags & 24) == 24) {
|
||||
TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id);
|
||||
TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id);
|
||||
}
|
||||
int z = 0;
|
||||
int sid = 0;
|
||||
@ -2907,7 +2907,7 @@ void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *l
|
||||
tl_set_var_value_num (v, T, 0, (*last_var) - 1);
|
||||
} else {
|
||||
write_field_flags (f);
|
||||
}
|
||||
}
|
||||
write_tree (T->left, 0, v, last_var);
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ int main (int argc, char **argv) {
|
||||
if (argc != optind + 1) {
|
||||
usage ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct parse *P = tl_init_parse_file (argv[optind]);
|
||||
if (!P) {
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/Document.h"
|
||||
#include "td/telegram/DocumentsManager.h"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/FileReferenceManager.h"
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/files/FileType.h"
|
||||
@ -191,8 +192,10 @@ FileId AnimationsManager::on_get_animation(unique_ptr<Animation> new_animation,
|
||||
LOG(DEBUG) << "Animation " << file_id << " duration has changed";
|
||||
a->duration = new_animation->duration;
|
||||
}
|
||||
if (a->minithumbnail != new_animation->minithumbnail) {
|
||||
a->minithumbnail = std::move(new_animation->minithumbnail);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
if (a->minithumbnail != new_animation->minithumbnail) {
|
||||
a->minithumbnail = std::move(new_animation->minithumbnail);
|
||||
}
|
||||
}
|
||||
if (a->thumbnail != new_animation->thumbnail) {
|
||||
if (!a->thumbnail.file_id.is_valid()) {
|
||||
@ -295,8 +298,10 @@ void AnimationsManager::create_animation(FileId file_id, string minithumbnail, P
|
||||
a->mime_type = std::move(mime_type);
|
||||
a->duration = max(duration, 0);
|
||||
a->dimensions = dimensions;
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
a->minithumbnail = std::move(minithumbnail);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
a->minithumbnail = std::move(minithumbnail);
|
||||
}
|
||||
}
|
||||
a->thumbnail = std::move(thumbnail);
|
||||
a->animated_thumbnail = std::move(animated_thumbnail);
|
||||
@ -831,7 +836,7 @@ void AnimationsManager::send_update_saved_animations(bool from_database) {
|
||||
if (animation->animated_thumbnail.file_id.is_valid()) {
|
||||
new_saved_animation_file_ids.push_back(animation->animated_thumbnail.file_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end());
|
||||
if (new_saved_animation_file_ids != saved_animation_file_ids_) {
|
||||
td_->file_manager_->change_files_source(get_saved_animations_file_source_id(), saved_animation_file_ids_,
|
||||
@ -882,4 +887,12 @@ void AnimationsManager::get_current_state(vector<td_api::object_ptr<td_api::Upda
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationsManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"animations_\":"); output.push_back(std::to_string(animations_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"saved_animation_ids_\":"); output.push_back(std::to_string(this->saved_animation_ids_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"saved_animation_file_ids_\":"); output.push_back(std::to_string(this->saved_animation_file_ids_.size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -35,6 +35,8 @@ class AnimationsManager final : public Actor {
|
||||
AnimationsManager &operator=(AnimationsManager &&) = delete;
|
||||
~AnimationsManager() final;
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
int32 get_animation_duration(FileId file_id) const;
|
||||
|
||||
tl_object_ptr<td_api::animation> get_animation_object(FileId file_id) const;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
|
||||
namespace td {
|
||||
|
||||
template <class StorerT>
|
||||
@ -55,10 +56,27 @@ FileId AnimationsManager::parse_animation(ParserT &parser) {
|
||||
parse(animation->duration, parser);
|
||||
}
|
||||
parse(animation->dimensions, parser);
|
||||
parse(animation->file_name, parser);
|
||||
|
||||
string tmp_filename;
|
||||
parse(tmp_filename, parser);
|
||||
|
||||
parse(animation->mime_type, parser);
|
||||
|
||||
if ( G()->get_option_boolean("disable_document_filenames") && (
|
||||
animation->mime_type.rfind("image/") == 0 ||
|
||||
animation->mime_type.rfind("video/") == 0 ||
|
||||
animation->mime_type.rfind("audio/") == 0)) {
|
||||
animation->file_name = "0";
|
||||
} else {
|
||||
animation->file_name = tmp_filename;
|
||||
}
|
||||
|
||||
if (parser.version() >= static_cast<int32>(Version::SupportMinithumbnails)) {
|
||||
parse(animation->minithumbnail, parser);
|
||||
string tmp_minithumbnail;
|
||||
parse(tmp_minithumbnail, parser);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
animation->minithumbnail = tmp_minithumbnail;
|
||||
}
|
||||
}
|
||||
parse(animation->thumbnail, parser);
|
||||
parse(animation->file_id, parser);
|
||||
|
@ -309,4 +309,9 @@ tl_object_ptr<telegram_api::InputMedia> AudiosManager::get_input_media(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AudiosManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"audios_\":"); output.push_back(std::to_string(audios_.calc_size()));
|
||||
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -29,6 +29,8 @@ class AudiosManager {
|
||||
AudiosManager &operator=(AudiosManager &&) = delete;
|
||||
~AudiosManager();
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
int32 get_audio_duration(FileId file_id) const;
|
||||
|
||||
tl_object_ptr<td_api::audio> get_audio_object(FileId file_id) const;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
|
||||
namespace td {
|
||||
|
||||
template <class StorerT>
|
||||
@ -99,7 +100,13 @@ FileId AudiosManager::parse_audio(ParserT &parser) {
|
||||
has_date = false;
|
||||
}
|
||||
if (has_file_name) {
|
||||
parse(audio->file_name, parser);
|
||||
string tmp_filename;
|
||||
parse(tmp_filename, parser);
|
||||
if (G()->get_option_boolean("disable_document_filenames")) {
|
||||
audio->file_name = "0";
|
||||
} else {
|
||||
audio->file_name = tmp_filename;
|
||||
}
|
||||
}
|
||||
if (has_mime_type) {
|
||||
parse(audio->mime_type, parser);
|
||||
@ -114,7 +121,11 @@ FileId AudiosManager::parse_audio(ParserT &parser) {
|
||||
parse(audio->performer, parser);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
parse(audio->minithumbnail, parser);
|
||||
string tmp_minithumbnail;
|
||||
parse(tmp_minithumbnail, parser);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
audio->minithumbnail = tmp_minithumbnail;
|
||||
}
|
||||
}
|
||||
if (has_thumbnail) {
|
||||
parse(audio->thumbnail, parser);
|
||||
|
@ -126,14 +126,27 @@ class SaveAutoDownloadSettingsQuery final : public Td::ResultHandler {
|
||||
AutoDownloadSettings get_auto_download_settings(const td_api::object_ptr<td_api::autoDownloadSettings> &settings) {
|
||||
CHECK(settings != nullptr);
|
||||
AutoDownloadSettings result;
|
||||
result.max_photo_file_size = settings->max_photo_file_size_;
|
||||
result.max_video_file_size = settings->max_video_file_size_;
|
||||
result.max_other_file_size = settings->max_other_file_size_;
|
||||
if (G()->get_option_boolean("disable_auto_download")) {
|
||||
result.max_photo_file_size = -1;
|
||||
result.max_video_file_size = -1;
|
||||
result.max_other_file_size = -1;
|
||||
} else {
|
||||
result.max_photo_file_size = settings->max_photo_file_size_;
|
||||
result.max_video_file_size = settings->max_video_file_size_;
|
||||
result.max_other_file_size = settings->max_other_file_size_;
|
||||
}
|
||||
result.video_upload_bitrate = settings->video_upload_bitrate_;
|
||||
result.is_enabled = settings->is_auto_download_enabled_;
|
||||
result.preload_large_videos = settings->preload_large_videos_;
|
||||
result.preload_next_audio = settings->preload_next_audio_;
|
||||
result.preload_stories = settings->preload_stories_;
|
||||
if (G()->get_option_boolean("disable_auto_download")) {
|
||||
result.is_enabled = false;
|
||||
result.preload_large_videos = false;
|
||||
result.preload_next_audio = false;
|
||||
result.preload_stories = false;
|
||||
} else {
|
||||
result.is_enabled = settings->is_auto_download_enabled_;
|
||||
result.preload_large_videos = settings->preload_large_videos_;
|
||||
result.preload_next_audio = settings->preload_next_audio_;
|
||||
result.preload_stories = settings->preload_stories_;
|
||||
}
|
||||
result.use_less_data_for_calls = settings->use_less_data_for_calls_;
|
||||
return result;
|
||||
}
|
||||
|
@ -1491,4 +1491,18 @@ void BackgroundManager::get_current_state(vector<td_api::object_ptr<td_api::Upda
|
||||
updates.push_back(get_update_default_background_object(true));
|
||||
}
|
||||
|
||||
void BackgroundManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"backgrounds_\":"); output.push_back(std::to_string(backgrounds_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"background_id_to_file_source_id_\":"); output.push_back(std::to_string(background_id_to_file_source_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"name_to_background_id_\":"); output.push_back(std::to_string(name_to_background_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"file_id_to_background_id_\":"); output.push_back(std::to_string(file_id_to_background_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_from_database_backgrounds_\":"); output.push_back(std::to_string(loaded_from_database_backgrounds_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"installed_backgrounds_\":"); output.push_back(std::to_string(installed_backgrounds_.size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -35,6 +35,8 @@ class BackgroundManager final : public Actor {
|
||||
public:
|
||||
BackgroundManager(Td *td, ActorShared<> parent);
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
void get_backgrounds(bool for_dark_theme, Promise<td_api::object_ptr<td_api::backgrounds>> &&promise);
|
||||
|
||||
void reload_background(BackgroundId background_id, int64 access_hash, Promise<Unit> &&promise);
|
||||
|
@ -435,8 +435,17 @@ class MultiImplPool {
|
||||
#if TD_OPENBSD
|
||||
max_client_threads = td::min(max_client_threads, 4u);
|
||||
#endif
|
||||
// Start TDLight - increment this to 128, otherwise the memory will not be freed when a session is closed
|
||||
max_client_threads = 128;
|
||||
// End TDLight - increment this to 128, otherwise the memory will not be freed when a session is closed
|
||||
impls_.resize(max_client_threads);
|
||||
// Start TDLight - disable check
|
||||
# if false
|
||||
// End TDLight - disable check
|
||||
CHECK(impls_.size() * (1 + MultiImpl::ADDITIONAL_THREAD_COUNT + 1 /* IOCP */) < 128);
|
||||
// Start TDLight - disable check
|
||||
# endif
|
||||
// End TDLight - disable check
|
||||
|
||||
net_query_stats_ = std::make_shared<NetQueryStats>();
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "td/telegram/LinkManager.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/logevent/LogEventHelper.h"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/MessageSender.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/MessageTtl.h"
|
||||
@ -3183,9 +3184,8 @@ ContactsManager::~ContactsManager() {
|
||||
Scheduler::instance()->destroy_on_scheduler(
|
||||
G()->get_gc_scheduler_id(), loaded_from_database_users_, unavailable_user_fulls_, loaded_from_database_chats_,
|
||||
unavailable_chat_fulls_, loaded_from_database_channels_, unavailable_channel_fulls_,
|
||||
loaded_from_database_secret_chats_, user_online_member_dialogs_, cached_channel_participants_,
|
||||
resolved_phone_numbers_, all_imported_contacts_, linked_channel_ids_, restricted_user_ids_,
|
||||
restricted_channel_ids_);
|
||||
loaded_from_database_secret_chats_, cached_channel_participants_, resolved_phone_numbers_, all_imported_contacts_,
|
||||
linked_channel_ids_, restricted_user_ids_, restricted_channel_ids_);
|
||||
}
|
||||
|
||||
void ContactsManager::start_up() {
|
||||
@ -3246,7 +3246,7 @@ void ContactsManager::on_user_online_timeout(UserId user_id) {
|
||||
td_api::make_object<td_api::updateUserStatus>(user_id.get(),
|
||||
get_user_status_object(user_id, u, G()->unix_time())));
|
||||
|
||||
update_user_online_member_count(user_id);
|
||||
td_->dialog_participant_manager_->update_user_online_member_count(user_id);
|
||||
}
|
||||
|
||||
void ContactsManager::on_user_emoji_status_timeout_callback(void *contacts_manager_ptr, int64 user_id_long) {
|
||||
@ -5330,43 +5330,38 @@ bool ContactsManager::get_user_read_dates_private(UserId user_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string ContactsManager::get_dialog_about(DialogId dialog_id) {
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User: {
|
||||
auto user_full = get_user_full_force(dialog_id.get_user_id(), "get_dialog_about");
|
||||
if (user_full != nullptr) {
|
||||
return user_full->about;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::Chat: {
|
||||
auto chat_full = get_chat_full_force(dialog_id.get_chat_id(), "get_dialog_about");
|
||||
if (chat_full != nullptr) {
|
||||
return chat_full->description;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::Channel: {
|
||||
auto channel_full = get_channel_full_force(dialog_id.get_channel_id(), false, "get_dialog_about");
|
||||
if (channel_full != nullptr) {
|
||||
return channel_full->description;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::SecretChat: {
|
||||
auto user_full = get_user_full_force(get_secret_chat_user_id(dialog_id.get_secret_chat_id()), "get_dialog_about");
|
||||
if (user_full != nullptr) {
|
||||
return user_full->about;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::None:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
string ContactsManager::get_user_about(UserId user_id) {
|
||||
auto user_full = get_user_full_force(user_id, "get_user_about");
|
||||
if (user_full != nullptr) {
|
||||
return user_full->about;
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
string ContactsManager::get_chat_about(ChatId chat_id) {
|
||||
auto chat_full = get_chat_full_force(chat_id, "get_chat_about");
|
||||
if (chat_full != nullptr) {
|
||||
return chat_full->description;
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
string ContactsManager::get_channel_about(ChannelId channel_id) {
|
||||
auto channel_full = get_channel_full_force(channel_id, false, "get_channel_about");
|
||||
if (channel_full != nullptr) {
|
||||
return channel_full->description;
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
string ContactsManager::get_secret_chat_about(SecretChatId secret_chat_id) {
|
||||
auto c = get_secret_chat(secret_chat_id);
|
||||
if (c == nullptr) {
|
||||
return string();
|
||||
}
|
||||
return get_user_about(c->user_id);
|
||||
}
|
||||
|
||||
string ContactsManager::get_dialog_search_text(DialogId dialog_id) const {
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
@ -9593,10 +9588,18 @@ class ContactsManager::UserLogEvent {
|
||||
|
||||
void ContactsManager::save_user(User *u, UserId user_id, bool from_binlog) {
|
||||
if (!G()->use_chat_info_database()) {
|
||||
if (u != nullptr && G()->get_option_boolean("receive_access_hashes", false)) {
|
||||
send_closure(G()->td(), &Td::send_update,
|
||||
make_tl_object<td_api::updateAccessHash>(get_user_access_hash_object(user_id, u)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
CHECK(u != nullptr);
|
||||
if (!u->is_saved || !u->is_status_saved) { // TODO more effective handling of !u->is_status_saved
|
||||
if (u != nullptr && G()->get_option_boolean("receive_access_hashes", false)) {
|
||||
send_closure(G()->td(), &Td::send_update,
|
||||
make_tl_object<td_api::updateAccessHash>(get_user_access_hash_object(user_id, u)));
|
||||
}
|
||||
if (!from_binlog) {
|
||||
auto log_event = UserLogEvent(user_id, u);
|
||||
auto storer = get_log_event_storer(log_event);
|
||||
@ -10172,10 +10175,18 @@ class ContactsManager::ChannelLogEvent {
|
||||
|
||||
void ContactsManager::save_channel(Channel *c, ChannelId channel_id, bool from_binlog) {
|
||||
if (!G()->use_chat_info_database()) {
|
||||
if (c != nullptr && G()->get_option_boolean("receive_access_hashes", false)) {
|
||||
send_closure(G()->td(), &Td::send_update,
|
||||
make_tl_object<td_api::updateAccessHash>(get_channel_access_hash_object(channel_id, c)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
CHECK(c != nullptr);
|
||||
if (!c->is_saved) {
|
||||
if (c != nullptr && G()->get_option_boolean("receive_access_hashes", false)) {
|
||||
send_closure(G()->td(), &Td::send_update,
|
||||
make_tl_object<td_api::updateAccessHash>(get_channel_access_hash_object(channel_id, c)));
|
||||
}
|
||||
if (!from_binlog) {
|
||||
auto log_event = ChannelLogEvent(channel_id, c);
|
||||
auto storer = get_log_event_storer(log_event);
|
||||
@ -11189,7 +11200,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo
|
||||
u->is_status_changed = false;
|
||||
}
|
||||
if (u->is_online_status_changed) {
|
||||
update_user_online_member_count(user_id);
|
||||
td_->dialog_participant_manager_->update_user_online_member_count(user_id);
|
||||
u->is_online_status_changed = false;
|
||||
}
|
||||
|
||||
@ -13590,60 +13601,16 @@ void ContactsManager::drop_user_full(UserId user_id) {
|
||||
td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true);
|
||||
}
|
||||
|
||||
void ContactsManager::update_user_online_member_count(UserId user_id) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
auto user_it = user_online_member_dialogs_.find(user_id);
|
||||
if (user_it == user_online_member_dialogs_.end()) {
|
||||
return;
|
||||
}
|
||||
CHECK(user_it->second != nullptr);
|
||||
auto &online_member_dialogs = user_it->second->online_member_dialogs_;
|
||||
|
||||
auto now = G()->unix_time();
|
||||
vector<DialogId> expired_dialog_ids;
|
||||
for (const auto &it : online_member_dialogs) {
|
||||
auto dialog_id = it.first;
|
||||
auto time = it.second;
|
||||
if (time < now - DialogParticipantManager::ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME) {
|
||||
expired_dialog_ids.push_back(dialog_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::Chat: {
|
||||
auto chat_id = dialog_id.get_chat_id();
|
||||
auto chat_full = get_chat_full(chat_id);
|
||||
CHECK(chat_full != nullptr);
|
||||
update_chat_online_member_count(chat_full, chat_id, false);
|
||||
break;
|
||||
}
|
||||
case DialogType::Channel: {
|
||||
auto channel_id = dialog_id.get_channel_id();
|
||||
update_channel_online_member_count(channel_id, false);
|
||||
break;
|
||||
}
|
||||
case DialogType::User:
|
||||
case DialogType::SecretChat:
|
||||
case DialogType::None:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (auto &dialog_id : expired_dialog_ids) {
|
||||
online_member_dialogs.erase(dialog_id);
|
||||
if (dialog_id.get_type() == DialogType::Channel) {
|
||||
cached_channel_participants_.erase(dialog_id.get_channel_id());
|
||||
}
|
||||
}
|
||||
if (online_member_dialogs.empty()) {
|
||||
user_online_member_dialogs_.erase(user_it);
|
||||
void ContactsManager::update_chat_online_member_count(ChatId chat_id, bool is_from_server) {
|
||||
auto chat_full = get_chat_full(chat_id);
|
||||
if (chat_full != nullptr) {
|
||||
update_chat_online_member_count(chat_full, chat_id, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsManager::update_chat_online_member_count(const ChatFull *chat_full, ChatId chat_id, bool is_from_server) {
|
||||
update_dialog_online_member_count(chat_full->participants, DialogId(chat_id), is_from_server);
|
||||
td_->dialog_participant_manager_->update_dialog_online_member_count(chat_full->participants, DialogId(chat_id),
|
||||
is_from_server);
|
||||
}
|
||||
|
||||
void ContactsManager::update_channel_online_member_count(ChannelId channel_id, bool is_from_server) {
|
||||
@ -13656,38 +13623,11 @@ void ContactsManager::update_channel_online_member_count(ChannelId channel_id, b
|
||||
if (it == cached_channel_participants_.end()) {
|
||||
return;
|
||||
}
|
||||
update_dialog_online_member_count(it->second, DialogId(channel_id), is_from_server);
|
||||
td_->dialog_participant_manager_->update_dialog_online_member_count(it->second, DialogId(channel_id), is_from_server);
|
||||
}
|
||||
|
||||
void ContactsManager::update_dialog_online_member_count(const vector<DialogParticipant> &participants,
|
||||
DialogId dialog_id, bool is_from_server) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
CHECK(dialog_id.is_valid());
|
||||
|
||||
int32 online_member_count = 0;
|
||||
int32 unix_time = G()->unix_time();
|
||||
for (const auto &participant : participants) {
|
||||
if (participant.dialog_id_.get_type() != DialogType::User) {
|
||||
continue;
|
||||
}
|
||||
auto user_id = participant.dialog_id_.get_user_id();
|
||||
if (!is_user_deleted(user_id) && !is_user_bot(user_id)) {
|
||||
if (is_user_online(user_id, 0, unix_time)) {
|
||||
online_member_count++;
|
||||
}
|
||||
if (is_from_server) {
|
||||
auto &online_member_dialogs = user_online_member_dialogs_[user_id];
|
||||
if (online_member_dialogs == nullptr) {
|
||||
online_member_dialogs = make_unique<UserOnlineMemberDialogs>();
|
||||
}
|
||||
online_member_dialogs->online_member_dialogs_[dialog_id] = unix_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
td_->dialog_participant_manager_->on_update_dialog_online_member_count(dialog_id, online_member_count,
|
||||
is_from_server);
|
||||
void ContactsManager::drop_cached_channel_participants(ChannelId channel_id) {
|
||||
cached_channel_participants_.erase(channel_id);
|
||||
}
|
||||
|
||||
void ContactsManager::on_get_chat_participants(tl_object_ptr<telegram_api::ChatParticipants> &&participants_ptr,
|
||||
@ -18038,6 +17978,32 @@ tl_object_ptr<td_api::user> ContactsManager::get_user_object(UserId user_id) con
|
||||
return get_user_object(user_id, get_user(user_id));
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::accessHash> ContactsManager::get_user_access_hash_object(UserId user_id, const User *u) const {
|
||||
if (u == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!u->is_min_access_hash && u->access_hash != 0) {
|
||||
tl_object_ptr<td_api::AccessHashType> type = make_tl_object<td_api::accessHashTypeUser>();
|
||||
DialogId dialog_id(user_id);
|
||||
return make_tl_object<td_api::accessHash>(dialog_id.get(), std::move(type), u->access_hash);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::accessHash> ContactsManager::get_channel_access_hash_object(ChannelId channel_id, const Channel *c) const {
|
||||
if (c == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (c->access_hash != 0) {
|
||||
tl_object_ptr<td_api::AccessHashType> type = make_tl_object<td_api::accessHashTypeChannel>();
|
||||
DialogId dialog_id(channel_id);
|
||||
return make_tl_object<td_api::accessHash>(dialog_id.get(), std::move(type), c->access_hash);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
tl_object_ptr<td_api::user> ContactsManager::get_user_object(UserId user_id, const User *u) const {
|
||||
if (u == nullptr) {
|
||||
return nullptr;
|
||||
@ -18448,4 +18414,96 @@ void ContactsManager::get_current_state(vector<td_api::object_ptr<td_api::Update
|
||||
});
|
||||
}
|
||||
|
||||
void ContactsManager::memory_stats(vector<string> &output) {
|
||||
|
||||
output.push_back("\"users_\":"); output.push_back(std::to_string(users_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"users_full_\":"); output.push_back(std::to_string(users_full_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"user_photos_\":"); output.push_back(std::to_string(user_photos_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unknown_users_\":"); output.push_back(std::to_string(unknown_users_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"pending_user_photos_\":"); output.push_back(std::to_string(pending_user_photos_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"user_profile_photo_file_source_ids_\":"); output.push_back(std::to_string(user_profile_photo_file_source_ids_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"my_photo_file_id_\":"); output.push_back(std::to_string(my_photo_file_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"chats_\":"); output.push_back(std::to_string(chats_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"chats_full_\":"); output.push_back(std::to_string(chats_full_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unknown_chats_\":"); output.push_back(std::to_string(unknown_chats_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"chat_full_file_source_ids_\":"); output.push_back(std::to_string(chat_full_file_source_ids_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"min_channels_\":"); output.push_back(std::to_string(min_channels_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"channels_\":"); output.push_back(std::to_string(channels_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"channels_full_\":"); output.push_back(std::to_string(channels_full_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unknown_channels_\":"); output.push_back(std::to_string(unknown_channels_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"channel_full_file_source_ids_\":"); output.push_back(std::to_string(channel_full_file_source_ids_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"secret_chats_\":"); output.push_back(std::to_string(secret_chats_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unknown_secret_chats_\":"); output.push_back(std::to_string(unknown_secret_chats_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"secret_chats_with_user_\":"); output.push_back(std::to_string(secret_chats_with_user_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"load_user_from_database_queries_\":"); output.push_back(std::to_string(load_user_from_database_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_from_database_users_\":"); output.push_back(std::to_string(loaded_from_database_users_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unavailable_user_fulls_\":"); output.push_back(std::to_string(unavailable_user_fulls_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"load_chat_from_database_queries_\":"); output.push_back(std::to_string(load_chat_from_database_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_from_database_chats_\":"); output.push_back(std::to_string(loaded_from_database_chats_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unavailable_chat_fulls_\":"); output.push_back(std::to_string(unavailable_chat_fulls_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"load_channel_from_database_queries_\":"); output.push_back(std::to_string(load_channel_from_database_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_from_database_channels_\":"); output.push_back(std::to_string(loaded_from_database_channels_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unavailable_channel_fulls_\":"); output.push_back(std::to_string(unavailable_channel_fulls_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"load_secret_chat_from_database_queries_\":"); output.push_back(std::to_string(load_secret_chat_from_database_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_from_database_secret_chats_\":"); output.push_back(std::to_string(loaded_from_database_secret_chats_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"uploaded_profile_photos_\":"); output.push_back(std::to_string(uploaded_profile_photos_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"imported_contacts_\":"); output.push_back(std::to_string(imported_contacts_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"cached_channel_participants_\":"); output.push_back(std::to_string(cached_channel_participants_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"load_contacts_queries_\":"); output.push_back(std::to_string(load_contacts_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"load_imported_contacts_queries_\":"); output.push_back(std::to_string(load_imported_contacts_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"all_imported_contacts_\":"); output.push_back(std::to_string(all_imported_contacts_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"users_nearby_\":"); output.push_back(std::to_string(users_nearby_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"channels_nearby_\":"); output.push_back(std::to_string(channels_nearby_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"all_users_nearby_\":"); output.push_back(std::to_string(all_users_nearby_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"linked_channel_ids_\":"); output.push_back(std::to_string(linked_channel_ids_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"restricted_user_ids_\":"); output.push_back(std::to_string(restricted_user_ids_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"restricted_channel_ids_\":"); output.push_back(std::to_string(restricted_channel_ids_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"next_all_imported_contacts_\":"); output.push_back(std::to_string(next_all_imported_contacts_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"imported_contact_user_ids_\":"); output.push_back(std::to_string(imported_contact_user_ids_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"unimported_contact_invites_\":"); output.push_back(std::to_string(unimported_contact_invites_.size()));
|
||||
}
|
||||
} // namespace td
|
||||
|
@ -85,6 +85,8 @@ class ContactsManager final : public Actor {
|
||||
|
||||
static UserId load_my_id();
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
static UserId get_user_id(const tl_object_ptr<telegram_api::User> &user);
|
||||
static ChatId get_chat_id(const tl_object_ptr<telegram_api::Chat> &chat);
|
||||
static ChannelId get_channel_id(const tl_object_ptr<telegram_api::Chat> &chat);
|
||||
@ -155,6 +157,11 @@ class ContactsManager final : public Actor {
|
||||
td_api::object_ptr<td_api::emojiStatus> get_channel_emoji_status_object(ChannelId channel_id) const;
|
||||
td_api::object_ptr<td_api::emojiStatus> get_secret_chat_emoji_status_object(SecretChatId secret_chat_id) const;
|
||||
|
||||
string get_user_about(UserId user_id);
|
||||
string get_chat_about(ChatId chat_id);
|
||||
string get_channel_about(ChannelId channel_id);
|
||||
string get_secret_chat_about(SecretChatId secret_chat_id);
|
||||
|
||||
bool get_chat_has_protected_content(ChatId chat_id) const;
|
||||
bool get_channel_has_protected_content(ChannelId channel_id) const;
|
||||
|
||||
@ -167,8 +174,6 @@ class ContactsManager final : public Actor {
|
||||
|
||||
bool get_user_read_dates_private(UserId user_id);
|
||||
|
||||
string get_dialog_about(DialogId dialog_id);
|
||||
|
||||
string get_dialog_search_text(DialogId dialog_id) const;
|
||||
|
||||
void for_each_secret_chat_with_user(UserId user_id, const std::function<void(SecretChatId)> &f);
|
||||
@ -350,6 +355,12 @@ class ContactsManager final : public Actor {
|
||||
|
||||
static ChannelId get_unsupported_channel_id();
|
||||
|
||||
void update_chat_online_member_count(ChatId chat_id, bool is_from_server);
|
||||
|
||||
void update_channel_online_member_count(ChannelId channel_id, bool is_from_server);
|
||||
|
||||
void drop_cached_channel_participants(ChannelId channel_id);
|
||||
|
||||
void on_update_username_is_active(UserId user_id, string &&username, bool is_active, Promise<Unit> &&promise);
|
||||
|
||||
void on_update_active_usernames_order(UserId user_id, vector<string> &&usernames, Promise<Unit> &&promise);
|
||||
@ -1548,11 +1559,7 @@ class ContactsManager final : public Actor {
|
||||
|
||||
void do_invalidate_channel_full(ChannelFull *channel_full, ChannelId channel_id, bool need_drop_slow_mode_delay);
|
||||
|
||||
void update_user_online_member_count(UserId user_id);
|
||||
void update_chat_online_member_count(const ChatFull *chat_full, ChatId chat_id, bool is_from_server);
|
||||
void update_channel_online_member_count(ChannelId channel_id, bool is_from_server);
|
||||
void update_dialog_online_member_count(const vector<DialogParticipant> &participants, DialogId dialog_id,
|
||||
bool is_from_server);
|
||||
|
||||
void on_get_chat_empty(telegram_api::chatEmpty &chat, const char *source);
|
||||
void on_get_chat(telegram_api::chat &chat, const char *source);
|
||||
@ -1758,6 +1765,10 @@ class ContactsManager final : public Actor {
|
||||
|
||||
tl_object_ptr<td_api::user> get_user_object(UserId user_id, const User *u) const;
|
||||
|
||||
tl_object_ptr<td_api::accessHash> get_user_access_hash_object(UserId user_id, const User *u) const;
|
||||
|
||||
tl_object_ptr<td_api::accessHash> get_channel_access_hash_object(ChannelId channel_id, const Channel *c) const;
|
||||
|
||||
tl_object_ptr<td_api::userFullInfo> get_user_full_info_object(UserId user_id, const UserFull *user_full) const;
|
||||
|
||||
td_api::object_ptr<td_api::updateBasicGroup> get_update_basic_group_object(ChatId chat_id, const Chat *c);
|
||||
@ -1976,11 +1987,6 @@ class ContactsManager final : public Actor {
|
||||
|
||||
FlatHashMap<int64, std::pair<vector<UserId>, vector<int32>>> imported_contacts_;
|
||||
|
||||
struct UserOnlineMemberDialogs {
|
||||
FlatHashMap<DialogId, int32, DialogIdHash> online_member_dialogs_; // dialog_id -> time
|
||||
};
|
||||
FlatHashMap<UserId, unique_ptr<UserOnlineMemberDialogs>, UserIdHash> user_online_member_dialogs_;
|
||||
|
||||
FlatHashMap<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;
|
||||
|
||||
FlatHashMap<string, UserId> resolved_phone_numbers_;
|
||||
|
@ -381,7 +381,7 @@ void DeviceTokenManager::dec_sync_cnt() {
|
||||
}
|
||||
|
||||
void DeviceTokenManager::loop() {
|
||||
if (sync_cnt_ != 0 || G()->close_flag()) {
|
||||
if (G()->close_flag() || sync_cnt_ != 0) {
|
||||
return;
|
||||
}
|
||||
for (int32 token_type = 1; token_type < TokenType::Size; token_type++) {
|
||||
|
@ -840,7 +840,7 @@ td_api::object_ptr<td_api::chatInviteLinkInfo> DialogInviteLinkManager::get_chat
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
description = td_->contacts_manager_->get_dialog_about(dialog_id);
|
||||
description = td_->dialog_manager_->get_dialog_about(dialog_id);
|
||||
} else {
|
||||
is_chat = invite_link_info->is_chat;
|
||||
is_megagroup = invite_link_info->is_megagroup;
|
||||
|
@ -1090,6 +1090,23 @@ td_api::object_ptr<td_api::emojiStatus> DialogManager::get_dialog_emoji_status_o
|
||||
}
|
||||
}
|
||||
|
||||
string DialogManager::get_dialog_about(DialogId dialog_id) {
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
return td_->contacts_manager_->get_user_about(dialog_id.get_user_id());
|
||||
case DialogType::Chat:
|
||||
return td_->contacts_manager_->get_chat_about(dialog_id.get_chat_id());
|
||||
case DialogType::Channel:
|
||||
return td_->contacts_manager_->get_channel_about(dialog_id.get_channel_id());
|
||||
case DialogType::SecretChat:
|
||||
return td_->contacts_manager_->get_secret_chat_about(dialog_id.get_secret_chat_id());
|
||||
case DialogType::None:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return string();
|
||||
}
|
||||
}
|
||||
|
||||
bool DialogManager::get_dialog_has_protected_content(DialogId dialog_id) const {
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
|
@ -132,6 +132,8 @@ class DialogManager final : public Actor {
|
||||
|
||||
td_api::object_ptr<td_api::emojiStatus> get_dialog_emoji_status_object(DialogId dialog_id) const;
|
||||
|
||||
string get_dialog_about(DialogId dialog_id);
|
||||
|
||||
bool get_dialog_has_protected_content(DialogId dialog_id) const;
|
||||
|
||||
bool is_dialog_action_unneeded(DialogId dialog_id) const;
|
||||
|
@ -591,8 +591,8 @@ DialogParticipantManager::DialogParticipantManager(Td *td, ActorShared<> parent)
|
||||
}
|
||||
|
||||
DialogParticipantManager::~DialogParticipantManager() {
|
||||
Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), dialog_administrators_,
|
||||
channel_participants_);
|
||||
Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), user_online_member_dialogs_,
|
||||
dialog_administrators_, channel_participants_);
|
||||
}
|
||||
|
||||
void DialogParticipantManager::tear_down() {
|
||||
@ -665,7 +665,7 @@ void DialogParticipantManager::on_update_dialog_online_member_count(DialogId dia
|
||||
}
|
||||
|
||||
set_dialog_online_member_count(dialog_id, online_member_count, is_from_server,
|
||||
"on_update_channel_online_member_count");
|
||||
"on_update_dialog_online_member_count");
|
||||
}
|
||||
|
||||
void DialogParticipantManager::on_dialog_opened(DialogId dialog_id) {
|
||||
@ -753,15 +753,80 @@ void DialogParticipantManager::send_update_chat_online_member_count(DialogId dia
|
||||
td_->dialog_manager_->get_chat_id_object(dialog_id, "updateChatOnlineMemberCount"), online_member_count));
|
||||
}
|
||||
|
||||
void DialogParticipantManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
|
||||
for (const auto &it : dialog_online_member_counts_) {
|
||||
void DialogParticipantManager::update_user_online_member_count(UserId user_id) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
auto user_it = user_online_member_dialogs_.find(user_id);
|
||||
if (user_it == user_online_member_dialogs_.end()) {
|
||||
return;
|
||||
}
|
||||
CHECK(user_it->second != nullptr);
|
||||
auto &online_member_dialogs = user_it->second->online_member_dialogs_;
|
||||
|
||||
auto now = G()->unix_time();
|
||||
vector<DialogId> expired_dialog_ids;
|
||||
for (const auto &it : online_member_dialogs) {
|
||||
auto dialog_id = it.first;
|
||||
if (it.second.is_update_sent && td_->messages_manager_->is_dialog_opened(dialog_id)) {
|
||||
updates.push_back(td_api::make_object<td_api::updateChatOnlineMemberCount>(
|
||||
td_->dialog_manager_->get_chat_id_object(dialog_id, "updateChatOnlineMemberCount"),
|
||||
it.second.online_member_count));
|
||||
auto time = it.second;
|
||||
if (time < now - ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME) {
|
||||
expired_dialog_ids.push_back(dialog_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::Chat:
|
||||
td_->contacts_manager_->update_chat_online_member_count(dialog_id.get_chat_id(), false);
|
||||
break;
|
||||
case DialogType::Channel:
|
||||
td_->contacts_manager_->update_channel_online_member_count(dialog_id.get_channel_id(), false);
|
||||
break;
|
||||
case DialogType::User:
|
||||
case DialogType::SecretChat:
|
||||
case DialogType::None:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (auto &dialog_id : expired_dialog_ids) {
|
||||
online_member_dialogs.erase(dialog_id);
|
||||
if (dialog_id.get_type() == DialogType::Channel) {
|
||||
td_->contacts_manager_->drop_cached_channel_participants(dialog_id.get_channel_id());
|
||||
}
|
||||
}
|
||||
if (online_member_dialogs.empty()) {
|
||||
user_online_member_dialogs_.erase(user_it);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogParticipantManager::update_dialog_online_member_count(const vector<DialogParticipant> &participants,
|
||||
DialogId dialog_id, bool is_from_server) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
CHECK(dialog_id.is_valid());
|
||||
|
||||
int32 online_member_count = 0;
|
||||
int32 unix_time = G()->unix_time();
|
||||
for (const auto &participant : participants) {
|
||||
if (participant.dialog_id_.get_type() != DialogType::User) {
|
||||
continue;
|
||||
}
|
||||
auto user_id = participant.dialog_id_.get_user_id();
|
||||
if (!td_->contacts_manager_->is_user_deleted(user_id) && !td_->contacts_manager_->is_user_bot(user_id)) {
|
||||
if (td_->contacts_manager_->is_user_online(user_id, 0, unix_time)) {
|
||||
online_member_count++;
|
||||
}
|
||||
if (is_from_server) {
|
||||
auto &online_member_dialogs = user_online_member_dialogs_[user_id];
|
||||
if (online_member_dialogs == nullptr) {
|
||||
online_member_dialogs = make_unique<UserOnlineMemberDialogs>();
|
||||
}
|
||||
online_member_dialogs->online_member_dialogs_[dialog_id] = unix_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
on_update_dialog_online_member_count(dialog_id, online_member_count, is_from_server);
|
||||
}
|
||||
|
||||
Status DialogParticipantManager::can_manage_dialog_join_requests(DialogId dialog_id) {
|
||||
@ -1994,4 +2059,15 @@ const DialogParticipant *DialogParticipantManager::get_channel_participant_from_
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DialogParticipantManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
|
||||
for (const auto &it : dialog_online_member_counts_) {
|
||||
auto dialog_id = it.first;
|
||||
if (it.second.is_update_sent && td_->messages_manager_->is_dialog_opened(dialog_id)) {
|
||||
updates.push_back(td_api::make_object<td_api::updateChatOnlineMemberCount>(
|
||||
td_->dialog_manager_->get_chat_id_object(dialog_id, "updateChatOnlineMemberCount"),
|
||||
it.second.online_member_count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -37,7 +37,10 @@ class DialogParticipantManager final : public Actor {
|
||||
DialogParticipantManager &operator=(DialogParticipantManager &&) = delete;
|
||||
~DialogParticipantManager() final;
|
||||
|
||||
static constexpr int32 ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME = 30 * 60;
|
||||
void update_user_online_member_count(UserId user_id);
|
||||
|
||||
void update_dialog_online_member_count(const vector<DialogParticipant> &participants, DialogId dialog_id,
|
||||
bool is_from_server);
|
||||
|
||||
void on_update_dialog_online_member_count(DialogId dialog_id, int32 online_member_count, bool is_from_server);
|
||||
|
||||
@ -114,12 +117,14 @@ class DialogParticipantManager final : public Actor {
|
||||
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
|
||||
|
||||
private:
|
||||
void tear_down() final;
|
||||
static constexpr int32 ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME = 30 * 60;
|
||||
|
||||
static constexpr int32 ONLINE_MEMBER_COUNT_UPDATE_TIME = 5 * 60;
|
||||
|
||||
static constexpr int32 CHANNEL_PARTICIPANT_CACHE_TIME = 1800; // some reasonable limit
|
||||
|
||||
void tear_down() final;
|
||||
|
||||
static void on_update_dialog_online_member_count_timeout_callback(void *dialog_participant_manager_ptr,
|
||||
int64 dialog_id_int);
|
||||
|
||||
@ -203,6 +208,11 @@ class DialogParticipantManager final : public Actor {
|
||||
};
|
||||
FlatHashMap<DialogId, OnlineMemberCountInfo, DialogIdHash> dialog_online_member_counts_;
|
||||
|
||||
struct UserOnlineMemberDialogs {
|
||||
FlatHashMap<DialogId, int32, DialogIdHash> online_member_dialogs_; // dialog_id -> time
|
||||
};
|
||||
FlatHashMap<UserId, unique_ptr<UserOnlineMemberDialogs>, UserIdHash> user_online_member_dialogs_;
|
||||
|
||||
FlatHashMap<DialogId, vector<DialogAdministrator>, DialogIdHash> dialog_administrators_;
|
||||
|
||||
// bot-administrators only
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/VideoNotesManager.h"
|
||||
#include "td/telegram/VideosManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
|
||||
@ -36,24 +37,26 @@ void Document::append_file_ids(const Td *td, vector<FileId> &file_ids) const {
|
||||
|
||||
file_ids.push_back(file_id);
|
||||
|
||||
FileId thumbnail_file_id = [&] {
|
||||
switch (type) {
|
||||
case Type::Animation:
|
||||
return td->animations_manager_->get_animation_thumbnail_file_id(file_id);
|
||||
case Type::Audio:
|
||||
return td->audios_manager_->get_audio_thumbnail_file_id(file_id);
|
||||
case Type::General:
|
||||
return td->documents_manager_->get_document_thumbnail_file_id(file_id);
|
||||
case Type::Video:
|
||||
return td->videos_manager_->get_video_thumbnail_file_id(file_id);
|
||||
case Type::VideoNote:
|
||||
return td->video_notes_manager_->get_video_note_thumbnail_file_id(file_id);
|
||||
default:
|
||||
return FileId();
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
FileId thumbnail_file_id = [&] {
|
||||
switch (type) {
|
||||
case Type::Animation:
|
||||
return td->animations_manager_->get_animation_thumbnail_file_id(file_id);
|
||||
case Type::Audio:
|
||||
return td->audios_manager_->get_audio_thumbnail_file_id(file_id);
|
||||
case Type::General:
|
||||
return td->documents_manager_->get_document_thumbnail_file_id(file_id);
|
||||
case Type::Video:
|
||||
return td->videos_manager_->get_video_thumbnail_file_id(file_id);
|
||||
case Type::VideoNote:
|
||||
return td->video_notes_manager_->get_video_note_thumbnail_file_id(file_id);
|
||||
default:
|
||||
return FileId();
|
||||
}
|
||||
}();
|
||||
if (thumbnail_file_id.is_valid()) {
|
||||
file_ids.push_back(thumbnail_file_id);
|
||||
}
|
||||
}();
|
||||
if (thumbnail_file_id.is_valid()) {
|
||||
file_ids.push_back(thumbnail_file_id);
|
||||
}
|
||||
|
||||
FileId animated_thumbnail_file_id = [&] {
|
||||
|
@ -757,6 +757,10 @@ void DocumentsManager::merge_documents(FileId new_id, FileId old_id) {
|
||||
LOG_STATUS(td_->file_manager_->merge(new_id, old_id));
|
||||
}
|
||||
|
||||
void DocumentsManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"documents_\":"); output.push_back(std::to_string(documents_.calc_size()));
|
||||
}
|
||||
|
||||
string DocumentsManager::get_document_search_text(FileId file_id) const {
|
||||
auto document = get_document(file_id);
|
||||
CHECK(document);
|
||||
|
@ -82,6 +82,7 @@ class DocumentsManager {
|
||||
|
||||
tl_object_ptr<td_api::document> get_document_object(FileId file_id, PhotoFormat thumbnail_format) const;
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
enum class Subtype : int32 { Background, Pattern, Ringtone, Story, Other };
|
||||
|
||||
Document on_get_document(RemoteDocument remote_document, DialogId owner_dialog_id,
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
#include "td/telegram/ConfigManager.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
template <class StorerT>
|
||||
@ -66,13 +68,25 @@ FileId DocumentsManager::parse_document(ParserT &parser) {
|
||||
has_thumbnail = true;
|
||||
}
|
||||
if (has_file_name) {
|
||||
parse(document->file_name, parser);
|
||||
string tmp_filename;
|
||||
parse(tmp_filename, parser);
|
||||
if (G()->get_option_boolean("disable_document_filenames") &&
|
||||
(document->mime_type.rfind("image/") == 0 || document->mime_type.rfind("video/") == 0 ||
|
||||
document->mime_type.rfind("audio/") == 0)) {
|
||||
document->file_name = "0";
|
||||
} else {
|
||||
document->file_name = tmp_filename;
|
||||
}
|
||||
}
|
||||
if (has_mime_type) {
|
||||
parse(document->mime_type, parser);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
parse(document->minithumbnail, parser);
|
||||
string tmp_minithumbnail;
|
||||
parse(tmp_minithumbnail, parser);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
document->minithumbnail = tmp_minithumbnail;
|
||||
}
|
||||
}
|
||||
if (has_thumbnail) {
|
||||
parse(document->thumbnail, parser);
|
||||
|
@ -495,4 +495,10 @@ td_api::object_ptr<td_api::message> FileReferenceManager::get_message_object(Fil
|
||||
return result;
|
||||
}
|
||||
|
||||
void FileReferenceManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"nodes_\":"); output.push_back(std::to_string(nodes_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"file_sources_\":"); output.push_back(std::to_string(file_sources_.size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -92,6 +92,8 @@ class FileReferenceManager final : public Actor {
|
||||
template <class ParserT>
|
||||
FileSourceId parse_file_source(Td *td, ParserT &parser);
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
private:
|
||||
struct Destination {
|
||||
NodeId node_id;
|
||||
|
@ -160,6 +160,10 @@ bool Global::use_message_database() const {
|
||||
return td_db_->use_message_database();
|
||||
}
|
||||
|
||||
bool Global::use_custom_database_format() const {
|
||||
return td_db_->use_custom_database_format();
|
||||
}
|
||||
|
||||
int32 Global::get_retry_after(int32 error_code, Slice error_message) {
|
||||
if (error_code != 429) {
|
||||
return 0;
|
||||
|
@ -68,6 +68,7 @@ class SponsoredMessageManager;
|
||||
class StateManager;
|
||||
class StickersManager;
|
||||
class StorageManager;
|
||||
class MemoryManager;
|
||||
class StoryManager;
|
||||
class Td;
|
||||
class TdDb;
|
||||
@ -104,6 +105,52 @@ class Global final : public ActorContext {
|
||||
|
||||
Status init(ActorId<Td> td, unique_ptr<TdDb> td_db_ptr) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
static bool get_use_custom_database(const std::string &database_directory) {
|
||||
auto s = get_database_directory_opts(database_directory);
|
||||
size_t qmarkpos;
|
||||
std::string token;
|
||||
size_t find_start_index = 0;
|
||||
while ((qmarkpos = s.find_first_of('&'), find_start_index) != std::string::npos) {
|
||||
token = s.substr(find_start_index, qmarkpos - find_start_index);
|
||||
find_start_index = qmarkpos;
|
||||
if ((qmarkpos = token.find_first_of('=')) != std::string::npos) {
|
||||
std::string propkey = token.substr(0, qmarkpos), propval = token.substr(qmarkpos + 1);
|
||||
if (propkey == "use_custom_database_format" && propval == "true") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string get_database_directory_path(const std::string &database_directory) {
|
||||
if (database_directory.empty()) {
|
||||
return database_directory;
|
||||
}
|
||||
size_t qmarkpos;
|
||||
if ((qmarkpos = database_directory.find_first_of('?')) != std::string::npos) {
|
||||
std::string path = database_directory.substr(0, qmarkpos),
|
||||
opts = database_directory.substr(qmarkpos + 1);
|
||||
return path;
|
||||
} else {
|
||||
return database_directory;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string get_database_directory_opts(const std::string &database_directory) {
|
||||
if (database_directory.empty()) {
|
||||
return database_directory;
|
||||
}
|
||||
size_t qmarkpos;
|
||||
if ((qmarkpos = database_directory.find_first_of('?')) != std::string::npos) {
|
||||
std::string path = database_directory.substr(0, qmarkpos),
|
||||
opts = database_directory.substr(qmarkpos + 1);
|
||||
return opts;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Slice get_dir() const;
|
||||
|
||||
Slice get_secure_files_dir() const {
|
||||
@ -423,6 +470,13 @@ class Global final : public ActorContext {
|
||||
storage_manager_ = storage_manager;
|
||||
}
|
||||
|
||||
ActorId<MemoryManager> memory_manager() const {
|
||||
return memory_manager_;
|
||||
}
|
||||
void set_memory_manager(ActorId<MemoryManager> memory_manager) {
|
||||
memory_manager_ = memory_manager;
|
||||
}
|
||||
|
||||
ActorId<StoryManager> story_manager() const {
|
||||
return story_manager_;
|
||||
}
|
||||
@ -485,6 +539,8 @@ class Global final : public ActorContext {
|
||||
|
||||
bool use_message_database() const;
|
||||
|
||||
bool use_custom_database_format() const;
|
||||
|
||||
bool keep_media_order() const {
|
||||
return use_file_database();
|
||||
}
|
||||
@ -618,6 +674,7 @@ class Global final : public ActorContext {
|
||||
ActorId<SponsoredMessageManager> sponsored_message_manager_;
|
||||
ActorId<StickersManager> stickers_manager_;
|
||||
ActorId<StorageManager> storage_manager_;
|
||||
ActorId<MemoryManager> memory_manager_;
|
||||
ActorId<StoryManager> story_manager_;
|
||||
ActorId<ThemeManager> theme_manager_;
|
||||
ActorId<TopDialogManager> top_dialog_manager_;
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "td/telegram/AccessRights.h"
|
||||
#include "td/telegram/AuthManager.h"
|
||||
#include "td/telegram/ConfigManager.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/DialogAction.h"
|
||||
#include "td/telegram/DialogActionManager.h"
|
||||
@ -15,6 +16,7 @@
|
||||
#include "td/telegram/DialogParticipantFilter.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/MessageSender.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/misc.h"
|
||||
@ -1003,6 +1005,18 @@ void GroupCallManager::tear_down() {
|
||||
parent_.reset();
|
||||
}
|
||||
|
||||
void GroupCallManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"group_call_participants_\":"); output.push_back(std::to_string(group_call_participants_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"group_call_recent_speakers_\":"); output.push_back(std::to_string(group_call_recent_speakers_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"group_calls_\":"); output.push_back(std::to_string(group_calls_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"input_group_call_ids_\":"); output.push_back(std::to_string(input_group_call_ids_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"pending_join_requests_\":"); output.push_back(std::to_string(pending_join_requests_.size()));
|
||||
}
|
||||
|
||||
void GroupCallManager::on_update_group_call_participant_order_timeout_callback(void *group_call_manager_ptr,
|
||||
int64 group_call_id_int) {
|
||||
if (G()->close_flag()) {
|
||||
@ -1162,7 +1176,7 @@ bool GroupCallManager::is_group_call_joined(InputGroupCallId input_group_call_id
|
||||
}
|
||||
|
||||
GroupCallId GroupCallManager::get_group_call_id(InputGroupCallId input_group_call_id, DialogId dialog_id) {
|
||||
if (td_->auth_manager_->is_bot() || !input_group_call_id.is_valid()) {
|
||||
if (G()->get_option_boolean("disable_group_calls") || td_->auth_manager_->is_bot() || !input_group_call_id.is_valid()) {
|
||||
return GroupCallId();
|
||||
}
|
||||
return add_group_call(input_group_call_id, dialog_id)->group_call_id;
|
||||
@ -2692,7 +2706,7 @@ void GroupCallManager::join_group_call(GroupCallId group_call_id, DialogId as_di
|
||||
GroupCallParticipant participant;
|
||||
participant.is_self = true;
|
||||
participant.dialog_id = as_dialog_id;
|
||||
participant.about = td_->contacts_manager_->get_dialog_about(participant.dialog_id);
|
||||
participant.about = td_->dialog_manager_->get_dialog_about(participant.dialog_id);
|
||||
participant.audio_source = audio_source;
|
||||
participant.joined_date = G()->unix_time();
|
||||
// if can_self_unmute has never been inited from self-participant,
|
||||
@ -4166,7 +4180,7 @@ void GroupCallManager::on_update_group_call_connection(string &&connection_param
|
||||
}
|
||||
|
||||
void GroupCallManager::on_update_group_call(tl_object_ptr<telegram_api::GroupCall> group_call_ptr, DialogId dialog_id) {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
if (G()->get_option_boolean("disable_group_calls") || td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
if (dialog_id != DialogId() && !dialog_id.is_valid()) {
|
||||
@ -4874,18 +4888,27 @@ tl_object_ptr<td_api::updateGroupCallParticipant> GroupCallManager::get_update_g
|
||||
|
||||
void GroupCallManager::send_update_group_call(const GroupCall *group_call, const char *source) {
|
||||
LOG(INFO) << "Send update about " << group_call->group_call_id << " from " << source;
|
||||
if (G()->get_option_boolean("disable_group_calls")) {
|
||||
return;
|
||||
}
|
||||
send_closure(G()->td(), &Td::send_update,
|
||||
get_update_group_call_object(group_call, get_recent_speakers(group_call, true)));
|
||||
}
|
||||
|
||||
void GroupCallManager::send_update_group_call_participant(GroupCallId group_call_id,
|
||||
const GroupCallParticipant &participant, const char *source) {
|
||||
if (G()->get_option_boolean("disable_group_calls")) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Send update about " << participant << " in " << group_call_id << " from " << source;
|
||||
send_closure(G()->td(), &Td::send_update, get_update_group_call_participant_object(group_call_id, participant));
|
||||
}
|
||||
|
||||
void GroupCallManager::send_update_group_call_participant(InputGroupCallId input_group_call_id,
|
||||
const GroupCallParticipant &participant, const char *source) {
|
||||
if (G()->get_option_boolean("disable_group_calls")) {
|
||||
return;
|
||||
}
|
||||
auto group_call = get_group_call(input_group_call_id);
|
||||
CHECK(group_call != nullptr && group_call->is_inited);
|
||||
send_update_group_call_participant(group_call->group_call_id, participant, source);
|
||||
|
@ -39,6 +39,10 @@ class GroupCallManager final : public Actor {
|
||||
GroupCallManager &operator=(GroupCallManager &&) = delete;
|
||||
~GroupCallManager() final;
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
DialogId get_group_call_participant_id(const td_api::object_ptr<td_api::MessageSender> &message_sender);
|
||||
|
||||
bool is_group_call_being_joined(InputGroupCallId input_group_call_id) const;
|
||||
|
||||
bool is_group_call_joined(InputGroupCallId input_group_call_id) const;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/DialogManager.h"
|
||||
#include "td/telegram/Document.h"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/DocumentsManager.h"
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/files/FileType.h"
|
||||
@ -2219,4 +2220,14 @@ void InlineQueriesManager::remove_recent_inline_bot(UserId bot_user_id, Promise<
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
void InlineQueriesManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"recently_used_bot_user_ids_\":"); output.push_back(std::to_string(recently_used_bot_user_ids_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"inline_query_results_\":"); output.push_back(std::to_string(inline_query_results_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"inline_message_contents_\":"); output.push_back(std::to_string(inline_message_contents_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"query_id_to_bot_user_id_\":"); output.push_back(std::to_string(query_id_to_bot_user_id_.size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -38,6 +38,8 @@ class InlineQueriesManager final : public Actor {
|
||||
public:
|
||||
InlineQueriesManager(Td *td, ActorShared<> parent);
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
void after_get_difference();
|
||||
|
||||
void answer_inline_query(int64 inline_query_id, bool is_personal,
|
||||
|
196
td/telegram/MemoryManager.cpp
Normal file
196
td/telegram/MemoryManager.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
//
|
||||
// Copyright Andrea Cavalli (nospam@warp.ovh) 2020
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
|
||||
#include "td/telegram/secret_api.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/telegram/AccessRights.h"
|
||||
#include "td/telegram/AuthManager.h"
|
||||
#include "td/telegram/ConfigManager.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/Document.h"
|
||||
#include "td/telegram/DocumentsManager.h"
|
||||
#include "td/telegram/FileReferenceManager.h"
|
||||
#include "td/telegram/files/FileLocation.h"
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/WebPagesManager.h"
|
||||
#include "td/telegram/StickersManager.h"
|
||||
#include "td/telegram/VideoNotesManager.h"
|
||||
#include "td/telegram/VideosManager.h"
|
||||
#include "td/telegram/AudiosManager.h"
|
||||
#include "td/telegram/AnimationsManager.h"
|
||||
#include "td/telegram/GroupCallManager.h"
|
||||
#include "td/telegram/BackgroundManager.h"
|
||||
#include "td/telegram/PollManager.h"
|
||||
#include "td/telegram/InlineQueriesManager.h"
|
||||
#include "td/telegram/files/FileType.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/LanguagePackManager.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/net/DcId.h"
|
||||
#include "td/telegram/net/MtprotoHeader.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/TdDb.h"
|
||||
|
||||
#include "td/actor/MultiPromise.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/actor/SleepActor.h"
|
||||
|
||||
#include "td/db/SqliteKeyValue.h"
|
||||
#include "td/db/SqliteKeyValueAsync.h"
|
||||
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/PathView.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Time.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
#include "td/utils/utf8.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
#include <numeric>
|
||||
|
||||
namespace td {
|
||||
|
||||
tl_object_ptr<td_api::memoryStatistics> MemoryStats::get_memory_statistics_object() const {
|
||||
return make_tl_object<td_api::memoryStatistics>(debug);
|
||||
}
|
||||
|
||||
MemoryManager::MemoryManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||
}
|
||||
|
||||
void MemoryManager::start_up() {
|
||||
}
|
||||
|
||||
void MemoryManager::tear_down() {
|
||||
parent_.reset();
|
||||
}
|
||||
|
||||
void MemoryManager::get_memory_stats(bool full, Promise<MemoryStats> promise) const {
|
||||
vector<string> output = {"{"};
|
||||
|
||||
output.push_back("\"memory_stats\":{");
|
||||
|
||||
output.push_back("\"messages_manager_\":{");
|
||||
td_->messages_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"contacts_manager_\":{");
|
||||
td_->contacts_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"web_pages_manager_\":{");
|
||||
td_->web_pages_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"stickers_manager_\":{");
|
||||
td_->stickers_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"documents_manager_\":{");
|
||||
td_->documents_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"video_notes_manager_\":{");
|
||||
td_->video_notes_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"videos_manager_\":{");
|
||||
td_->videos_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"audios_manager_\":{");
|
||||
td_->audios_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"animations_manager_\":{");
|
||||
td_->animations_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"file_manager_\":{");
|
||||
td_->file_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"file_reference_manager_\":{");
|
||||
td_->file_reference_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"group_call_manager_\":{");
|
||||
td_->group_call_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"background_manager_\":{");
|
||||
td_->background_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"inline_queries_manager_\":{");
|
||||
td_->inline_queries_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
|
||||
output.push_back(",");
|
||||
|
||||
output.push_back("\"poll_manager_\":{");
|
||||
td_->poll_manager_->memory_stats(output);
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back("}");
|
||||
|
||||
output.push_back("}");
|
||||
|
||||
string s;
|
||||
s = accumulate(output.begin(), output.end(), s);
|
||||
auto value = MemoryStats(s);
|
||||
|
||||
promise.set_value(std::move(value));
|
||||
}
|
||||
|
||||
void MemoryManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Never return updates
|
||||
}
|
||||
|
||||
} // namespace td
|
63
td/telegram/MemoryManager.h
Normal file
63
td/telegram/MemoryManager.h
Normal file
@ -0,0 +1,63 @@
|
||||
//
|
||||
// Copyright Andrea Cavalli (nospam@warp.ovh) 2020
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/MultiPromise.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/actor/Timeout.h"
|
||||
|
||||
#include "td/telegram/files/FileId.h"
|
||||
#include "td/telegram/files/FileSourceId.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/SecretInputMedia.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Hints.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
namespace td {
|
||||
|
||||
class Td;
|
||||
|
||||
struct MemoryStats {
|
||||
string debug;
|
||||
MemoryStats() = default;
|
||||
explicit MemoryStats(string debug) : debug(std::move(debug)) {
|
||||
}
|
||||
tl_object_ptr<td_api::memoryStatistics> get_memory_statistics_object() const;
|
||||
};
|
||||
|
||||
class MemoryManager : public Actor {
|
||||
public:
|
||||
MemoryManager(Td *td, ActorShared<> parent);
|
||||
|
||||
void get_memory_stats(bool full, Promise<MemoryStats> promise) const;
|
||||
|
||||
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
|
||||
|
||||
private:
|
||||
void start_up() override;
|
||||
|
||||
void tear_down() override;
|
||||
|
||||
Td *td_;
|
||||
ActorShared<> parent_;
|
||||
};
|
||||
|
||||
} // namespace td
|
@ -5907,7 +5907,7 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
|
||||
DialogId owner_dialog_id, int32 message_date, bool is_content_read,
|
||||
UserId via_bot_user_id, MessageSelfDestructType *ttl,
|
||||
bool *disable_web_page_preview, const char *source) {
|
||||
if (!td->auth_manager_->was_authorized() && !G()->close_flag() && media_ptr != nullptr &&
|
||||
if (!G()->close_flag() && !td->auth_manager_->was_authorized() && media_ptr != nullptr &&
|
||||
media_ptr->get_id() != telegram_api::messageMediaEmpty::ID) {
|
||||
LOG(ERROR) << "Receive without authorization from " << source << ": " << to_string(media_ptr);
|
||||
media_ptr = nullptr;
|
||||
@ -7464,6 +7464,7 @@ void update_message_content_file_id_remote(MessageContent *content, FileId file_
|
||||
}
|
||||
|
||||
FileId get_message_content_thumbnail_file_id(const MessageContent *content, const Td *td) {
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Animation:
|
||||
return td->animations_manager_->get_animation_thumbnail_file_id(
|
||||
@ -7489,6 +7490,7 @@ FileId get_message_content_thumbnail_file_id(const MessageContent *content, cons
|
||||
return FileId();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FileId();
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "td/telegram/LinkManager.h"
|
||||
#include "td/telegram/Location.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/MessageContent.h"
|
||||
#include "td/telegram/MessageDb.h"
|
||||
#include "td/telegram/MessageEntity.h"
|
||||
@ -5612,6 +5613,70 @@ void MessagesManager::update_message_reply_count(Dialog *d, MessageId message_id
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"being_sent_messages_\":"); output.push_back(std::to_string(this->being_sent_messages_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"being_loaded_secret_thumbnails_\":"); output.push_back(std::to_string(this->being_loaded_secret_thumbnails_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"being_uploaded_files_\":"); output.push_back(std::to_string(this->being_uploaded_files_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"being_uploaded_thumbnails_\":"); output.push_back(std::to_string(this->being_uploaded_thumbnails_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"dialog_folders_\":"); output.push_back(std::to_string(this->dialog_folders_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"dialog_lists_\":"); output.push_back(std::to_string(this->dialog_lists_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"dialogs_\":"); output.push_back(std::to_string(this->dialogs_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"found_call_messages_\":"); output.push_back(std::to_string(this->found_call_messages_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"found_dialog_messages_\":"); output.push_back(std::to_string(this->found_dialog_messages_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"found_dialog_messages_dialog_id_\":"); output.push_back(std::to_string(this->found_dialog_messages_dialog_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"found_fts_messages_\":"); output.push_back(std::to_string(this->found_fts_messages_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"postponed_channel_updates_\":"); output.push_back(std::to_string(this->postponed_channel_updates_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"is_channel_difference_finished_\":"); output.push_back(std::to_string(this->is_channel_difference_finished_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"get_dialogs_tasks_\":"); output.push_back(std::to_string(this->get_dialogs_tasks_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"dialog_bot_command_message_ids_\":"); output.push_back(std::to_string(this->dialog_bot_command_message_ids_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"found_messages_\":"); output.push_back(std::to_string(this->found_messages_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"found_on_server_dialogs_\":"); output.push_back(std::to_string(this->found_on_server_dialogs_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"found_public_dialogs_\":"); output.push_back(std::to_string(this->found_public_dialogs_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_dialogs_\":"); output.push_back(std::to_string(this->loaded_dialogs_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"search_public_dialogs_queries_\":"); output.push_back(std::to_string(this->search_public_dialogs_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"message_embedding_codes_\":"); output.push_back(std::to_string(this->message_embedding_codes_->size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"message_full_id_to_file_source_id_\":"); output.push_back(std::to_string(this->message_full_id_to_file_source_id_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"get_dialog_message_by_date_results_\":"); output.push_back(std::to_string(this->get_dialog_message_by_date_results_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"get_dialog_query_log_event_id_\":"); output.push_back(std::to_string(this->get_dialog_query_log_event_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"get_channel_difference_to_log_event_id_\":"); output.push_back(std::to_string(this->get_channel_difference_to_log_event_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"last_clear_history_message_id_to_dialog_id_\":"); output.push_back(std::to_string(this->last_clear_history_message_id_to_dialog_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"last_outgoing_forwarded_message_date_\":"); output.push_back(std::to_string(this->last_outgoing_forwarded_message_date_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"load_active_live_location_messages_queries_\":"); output.push_back(std::to_string(this->load_active_live_location_messages_queries_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"notification_group_id_to_dialog_id_\":"); output.push_back(std::to_string(this->notification_group_id_to_dialog_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"previous_repaired_read_inbox_max_message_id_\":"); output.push_back(std::to_string(this->previous_repaired_read_inbox_max_message_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"channel_get_difference_retry_timeouts_\":"); output.push_back(std::to_string(this->channel_get_difference_retry_timeouts_.size()));
|
||||
}
|
||||
|
||||
bool MessagesManager::have_dialog_scheduled_messages_in_memory(const Dialog *d) {
|
||||
return d->scheduled_messages != nullptr && !d->scheduled_messages->scheduled_messages_.empty();
|
||||
}
|
||||
@ -9293,6 +9358,9 @@ void MessagesManager::on_get_recent_locations(DialogId dialog_id, int32 limit, i
|
||||
}
|
||||
|
||||
void MessagesManager::delete_messages_from_updates(const vector<MessageId> &message_ids, bool is_permanent) {
|
||||
if (G()->get_option_boolean("ignore_server_deletes_and_reads", false)) {
|
||||
return;
|
||||
}
|
||||
FlatHashMap<DialogId, vector<int64>, DialogIdHash> deleted_message_ids;
|
||||
FlatHashMap<DialogId, bool, DialogIdHash> need_update_dialog_pos;
|
||||
vector<unique_ptr<Message>> deleted_messages;
|
||||
@ -10907,6 +10975,9 @@ void MessagesManager::read_all_dialog_reactions_on_server(DialogId dialog_id, ui
|
||||
}
|
||||
|
||||
void MessagesManager::read_message_content_from_updates(MessageId message_id, int32 read_date) {
|
||||
if (G()->get_option_boolean("ignore_server_deletes_and_reads", false)) {
|
||||
return;
|
||||
}
|
||||
if (!message_id.is_valid() || !message_id.is_server()) {
|
||||
LOG(ERROR) << "Incoming update tries to read content of " << message_id;
|
||||
return;
|
||||
@ -14606,7 +14677,8 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vector<tl_object_ptr<te
|
||||
}
|
||||
|
||||
bool MessagesManager::is_message_unload_enabled() const {
|
||||
return G()->use_message_database() || td_->auth_manager_->is_bot();
|
||||
auto has_custom_unload_time = G()->have_option("message_unload_delay");
|
||||
return G()->use_message_database() || td_->auth_manager_->is_bot() || has_custom_unload_time;
|
||||
}
|
||||
|
||||
bool MessagesManager::can_unload_message(const Dialog *d, const Message *m) const {
|
||||
@ -15128,7 +15200,9 @@ void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanen
|
||||
case DialogType::User:
|
||||
case DialogType::Chat:
|
||||
if (m->message_id.is_server()) {
|
||||
message_id_to_dialog_id_.erase(m->message_id);
|
||||
if (!G()->get_option_boolean("ignore_server_deletes_and_reads", false)) {
|
||||
message_id_to_dialog_id_.erase(m->message_id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DialogType::Channel:
|
||||
@ -23885,7 +23959,7 @@ void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Messag
|
||||
actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, message_id,
|
||||
PromiseCreator::lambda([this, dialog_id, input_media = std::move(input_media), file_id,
|
||||
thumbnail_file_id](Result<Message *> result) mutable {
|
||||
if (result.is_error() || G()->close_flag()) {
|
||||
if (G()->close_flag() || result.is_error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -23968,7 +24042,7 @@ void MessagesManager::on_secret_message_media_uploaded(DialogId dialog_id, const
|
||||
send_closure_later(actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, m->message_id,
|
||||
PromiseCreator::lambda([this, dialog_id, secret_input_media = std::move(secret_input_media)](
|
||||
Result<Message *> result) mutable {
|
||||
if (result.is_error() || G()->close_flag()) {
|
||||
if (G()->close_flag() || result.is_error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -24158,7 +24232,7 @@ void MessagesManager::on_upload_message_media_finished(int64 media_album_id, Dia
|
||||
for (auto request_message_id : message_ids) {
|
||||
LOG(INFO) << "Send on_media_message_ready_to_send for " << request_message_id << " in " << dialog_id;
|
||||
auto promise = PromiseCreator::lambda([this, media_album_id](Result<Message *> result) {
|
||||
if (result.is_error() || G()->close_flag()) {
|
||||
if (G()->close_flag() || result.is_error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -27891,7 +27965,7 @@ void MessagesManager::remove_message_notifications_by_message_ids(DialogId dialo
|
||||
void MessagesManager::do_remove_message_notification(DialogId dialog_id, bool from_mentions,
|
||||
NotificationId notification_id,
|
||||
vector<MessageDbDialogMessage> result) {
|
||||
if (result.empty() || G()->close_flag()) {
|
||||
if (G()->close_flag() || result.empty()) {
|
||||
return;
|
||||
}
|
||||
CHECK(result.size() == 1);
|
||||
@ -28523,6 +28597,10 @@ void MessagesManager::send_update_chat_last_message_impl(const Dialog *d, const
|
||||
return;
|
||||
}
|
||||
|
||||
if (G()->get_option_boolean("ignore_update_chat_last_message")) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(d != nullptr);
|
||||
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_last_message from "
|
||||
<< source;
|
||||
@ -28667,10 +28745,12 @@ void MessagesManager::send_update_chat_read_inbox(const Dialog *d, bool force, c
|
||||
LOG(INFO) << "Send updateChatReadInbox in " << d->dialog_id << "("
|
||||
<< td_->dialog_manager_->get_dialog_title(d->dialog_id) << ") to " << d->server_unread_count << " + "
|
||||
<< d->local_unread_count << " from " << source;
|
||||
if (!G()->get_option_boolean("ignore_update_chat_read_inbox")) {
|
||||
send_closure(G()->td(), &Td::send_update,
|
||||
td_api::make_object<td_api::updateChatReadInbox>(
|
||||
get_chat_id_object(d->dialog_id, "updateChatReadInbox"), d->last_read_inbox_message_id.get(),
|
||||
d->server_unread_count + d->local_unread_count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37806,6 +37886,10 @@ void MessagesManager::suffix_load_query_ready(DialogId dialog_id) {
|
||||
|
||||
LOG(INFO) << "Finished suffix load query in " << dialog_id;
|
||||
auto *d = get_dialog(dialog_id);
|
||||
if (d == nullptr) {
|
||||
LOG(ERROR) << "Unknown dialog " << dialog_id;
|
||||
return;
|
||||
}
|
||||
bool is_unchanged = queries->suffix_load_first_message_id_ == queries->suffix_load_query_message_id_;
|
||||
suffix_load_update_first_message_id(d, queries);
|
||||
if (is_unchanged && queries->suffix_load_first_message_id_ == queries->suffix_load_query_message_id_) {
|
||||
@ -38071,7 +38155,10 @@ void MessagesManager::set_sponsored_dialog(DialogId dialog_id, DialogSource sour
|
||||
CHECK(sponsored_dialog_id_.is_valid());
|
||||
sponsored_dialog_source_ = std::move(source);
|
||||
const Dialog *d = get_dialog(sponsored_dialog_id_);
|
||||
CHECK(d != nullptr);
|
||||
if (d == nullptr) {
|
||||
LOG(ERROR) << "Unknown dialog " << dialog_id;
|
||||
return;
|
||||
}
|
||||
send_update_chat_position(DialogListId(FolderId::main()), d, "set_sponsored_dialog");
|
||||
save_sponsored_dialog();
|
||||
}
|
||||
@ -38081,7 +38168,10 @@ void MessagesManager::set_sponsored_dialog(DialogId dialog_id, DialogSource sour
|
||||
bool need_update_total_chat_count = false;
|
||||
if (sponsored_dialog_id_.is_valid()) {
|
||||
const Dialog *d = get_dialog(sponsored_dialog_id_);
|
||||
CHECK(d != nullptr);
|
||||
if (d == nullptr) {
|
||||
LOG(ERROR) << "Unknown dialog " << dialog_id;
|
||||
return;
|
||||
}
|
||||
bool was_sponsored = is_dialog_sponsored(d);
|
||||
sponsored_dialog_id_ = DialogId();
|
||||
sponsored_dialog_source_ = DialogSource();
|
||||
@ -38094,7 +38184,10 @@ void MessagesManager::set_sponsored_dialog(DialogId dialog_id, DialogSource sour
|
||||
if (dialog_id.is_valid()) {
|
||||
force_create_dialog(dialog_id, "set_sponsored_dialog_id");
|
||||
const Dialog *d = get_dialog(dialog_id);
|
||||
CHECK(d != nullptr);
|
||||
if (d == nullptr) {
|
||||
LOG(ERROR) << "Unknown dialog " << dialog_id;
|
||||
return;
|
||||
}
|
||||
add_sponsored_dialog(d, std::move(source));
|
||||
if (is_dialog_sponsored(d)) {
|
||||
need_update_total_chat_count = !need_update_total_chat_count;
|
||||
|
@ -142,6 +142,8 @@ class MessagesManager final : public Actor {
|
||||
|
||||
static bool is_invalid_poll_message(const telegram_api::Message *message);
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
static int32 get_message_date(const tl_object_ptr<telegram_api::Message> &message_ptr);
|
||||
|
||||
void on_get_empty_messages(DialogId dialog_id, const vector<MessageId> &empty_message_ids);
|
||||
|
@ -166,7 +166,11 @@ void NotificationManager::on_flush_pending_updates_timeout_callback(void *notifi
|
||||
}
|
||||
|
||||
bool NotificationManager::is_disabled() const {
|
||||
return !td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot() || G()->close_flag();
|
||||
if ( G()->get_option_boolean("disable_notifications")) {
|
||||
return true;
|
||||
} else {
|
||||
return G()->close_flag() || !td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot();
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const NotificationManager::ActiveNotificationsUpdate &update) {
|
||||
|
@ -793,6 +793,26 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
|
||||
if (set_boolean_option("disable_time_adjustment_protection")) {
|
||||
return;
|
||||
}
|
||||
// Start TDLight options
|
||||
if (set_boolean_option("disable_document_filenames")) {
|
||||
return;
|
||||
}
|
||||
if (set_boolean_option("disable_minithumbnails")) {
|
||||
return;
|
||||
}
|
||||
if (set_boolean_option("disable_notifications")) {
|
||||
return;
|
||||
}
|
||||
if (set_boolean_option("disable_group_calls")) {
|
||||
return;
|
||||
}
|
||||
if (set_boolean_option("disable_auto_download")) {
|
||||
return;
|
||||
}
|
||||
// End TDLight options
|
||||
if (set_boolean_option("disable_persistent_network_statistics")) {
|
||||
return;
|
||||
}
|
||||
if (!is_bot && set_boolean_option("disable_top_chats")) {
|
||||
return;
|
||||
}
|
||||
@ -818,6 +838,20 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
|
||||
if (set_boolean_option("ignore_platform_restrictions")) {
|
||||
return;
|
||||
}
|
||||
// Start TDLight options
|
||||
if (set_boolean_option("ignore_server_deletes_and_reads")) {
|
||||
return;
|
||||
}
|
||||
if (set_boolean_option("ignore_update_chat_last_message")) {
|
||||
return;
|
||||
}
|
||||
if (set_boolean_option("ignore_update_chat_read_inbox")) {
|
||||
return;
|
||||
}
|
||||
if (set_boolean_option("ignore_update_user_chat_action")) {
|
||||
return;
|
||||
}
|
||||
// End TDLight options
|
||||
if (set_boolean_option("is_emulator")) {
|
||||
return;
|
||||
}
|
||||
@ -901,6 +935,11 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
|
||||
if (set_boolean_option("reuse_uploaded_photos_by_hash")) {
|
||||
return;
|
||||
}
|
||||
// Start TDLight options
|
||||
if (set_boolean_option("receive_access_hashes")) {
|
||||
return;
|
||||
}
|
||||
// End TDLight options
|
||||
break;
|
||||
case 's':
|
||||
if (set_integer_option("storage_max_files_size")) {
|
||||
|
@ -55,7 +55,9 @@ ProfilePhoto get_profile_photo(FileManager *file_manager, UserId user_id, int64
|
||||
result.has_animation = profile_photo->has_video_;
|
||||
result.is_personal = profile_photo->personal_;
|
||||
result.id = profile_photo->photo_id_;
|
||||
result.minithumbnail = profile_photo->stripped_thumb_.as_slice().str();
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
result.minithumbnail = profile_photo->stripped_thumb_.as_slice().str();
|
||||
}
|
||||
result.small_file_id =
|
||||
register_photo_size(file_manager, PhotoSizeSource::dialog_photo(DialogId(user_id), user_access_hash, false),
|
||||
result.id, 0 /*access_hash*/, "" /*file_reference*/, DialogId(), 0 /*file_size*/, dc_id,
|
||||
@ -333,7 +335,11 @@ Photo get_photo(Td *td, tl_object_ptr<telegram_api::photo> &&photo, DialogId own
|
||||
}
|
||||
res.photos.push_back(std::move(size));
|
||||
} else {
|
||||
res.minithumbnail = std::move(photo_size.get<1>());
|
||||
if (G()->get_option_boolean("disable_minithumbnails")) {
|
||||
res.minithumbnail = "";
|
||||
} else {
|
||||
res.minithumbnail = std::move(photo_size.get<1>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,14 +23,14 @@ void store(const DialogPhoto &dialog_photo, StorerT &storer) {
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_file_ids);
|
||||
STORE_FLAG(dialog_photo.has_animation);
|
||||
STORE_FLAG(has_minithumbnail);
|
||||
STORE_FLAG(!G()->get_option_boolean("disable_minithumbnails") && has_minithumbnail);
|
||||
STORE_FLAG(dialog_photo.is_personal);
|
||||
END_STORE_FLAGS();
|
||||
if (has_file_ids) {
|
||||
store(dialog_photo.small_file_id, storer);
|
||||
store(dialog_photo.big_file_id, storer);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
if (!G()->get_option_boolean("disable_minithumbnails") && has_minithumbnail) {
|
||||
store(dialog_photo.minithumbnail, storer);
|
||||
}
|
||||
}
|
||||
@ -52,7 +52,11 @@ void parse(DialogPhoto &dialog_photo, ParserT &parser) {
|
||||
parse(dialog_photo.big_file_id, parser);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
parse(dialog_photo.minithumbnail, parser);
|
||||
std::basic_string<char> minithumbnail;
|
||||
parse(minithumbnail, parser);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
dialog_photo.minithumbnail = minithumbnail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +79,7 @@ void store(const Photo &photo, StorerT &storer) {
|
||||
bool has_sticker_photo_size = photo.sticker_photo_size != nullptr;
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(photo.has_stickers);
|
||||
STORE_FLAG(has_minithumbnail);
|
||||
STORE_FLAG(!G()->get_option_boolean("disable_minithumbnails") && has_minithumbnail);
|
||||
STORE_FLAG(has_animations);
|
||||
STORE_FLAG(has_sticker_photo_size);
|
||||
END_STORE_FLAGS();
|
||||
@ -85,7 +89,7 @@ void store(const Photo &photo, StorerT &storer) {
|
||||
if (photo.has_stickers) {
|
||||
store(photo.sticker_file_ids, storer);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
if (!G()->get_option_boolean("disable_minithumbnails") && has_minithumbnail) {
|
||||
store(photo.minithumbnail, storer);
|
||||
}
|
||||
if (has_animations) {
|
||||
@ -116,7 +120,11 @@ void parse(Photo &photo, ParserT &parser) {
|
||||
parse(photo.sticker_file_ids, parser);
|
||||
}
|
||||
if (has_minithumbnail) {
|
||||
parse(photo.minithumbnail, parser);
|
||||
std::basic_string<char> minithumbnail;
|
||||
parse(minithumbnail, parser);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
photo.minithumbnail = minithumbnail;
|
||||
}
|
||||
}
|
||||
if (has_animations) {
|
||||
parse(photo.animations, parser);
|
||||
|
@ -46,6 +46,9 @@ bool need_update_dialog_photo_minithumbnail(const string &from, const string &to
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::minithumbnail> get_minithumbnail_object(const string &packed) {
|
||||
if (G()->get_option_boolean("disable_minithumbnails")) {
|
||||
return nullptr;
|
||||
}
|
||||
if (packed.size() < 3) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -195,11 +198,23 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
|
||||
case telegram_api::photoStrippedSize::ID: {
|
||||
auto size = move_tl_object_as<telegram_api::photoStrippedSize>(size_ptr);
|
||||
if (format != PhotoFormat::Jpeg) {
|
||||
LOG(ERROR) << "Receive unexpected JPEG minithumbnail in photo " << id << " from " << source << " of format "
|
||||
<< format;
|
||||
return std::move(res);
|
||||
if (G()->get_option_boolean("disable_minithumbnails")) {
|
||||
LOG(DEBUG) << "Receive unexpected JPEG minithumbnail";
|
||||
} else {
|
||||
LOG(ERROR) << "Receive unexpected JPEG minithumbnail in photo " << id << " from " << source << " of format "
|
||||
<< format;
|
||||
}
|
||||
if (G()->get_option_boolean("disable_minithumbnails")) {
|
||||
return std::string("");
|
||||
} else {
|
||||
return std::move(res);
|
||||
}
|
||||
}
|
||||
if (G()->get_option_boolean("disable_minithumbnails")) {
|
||||
return std::string("");
|
||||
} else {
|
||||
return size->bytes_.as_slice().str();
|
||||
}
|
||||
return size->bytes_.as_slice().str();
|
||||
}
|
||||
case telegram_api::photoSizeProgressive::ID: {
|
||||
auto size = move_tl_object_as<telegram_api::photoSizeProgressive>(size_ptr);
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "td/telegram/DialogManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/logevent/LogEventHelper.h"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/MessageSender.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
@ -246,6 +248,10 @@ PollManager::PollManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::m
|
||||
}
|
||||
|
||||
void PollManager::start_up() {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
class StateCallback final : public StateManager::Callback {
|
||||
public:
|
||||
explicit StateCallback(ActorId<PollManager> parent) : parent_(std::move(parent)) {
|
||||
@ -1963,4 +1969,16 @@ void PollManager::on_binlog_events(vector<BinlogEvent> &&events) {
|
||||
}
|
||||
}
|
||||
|
||||
void PollManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"polls_\":"); output.push_back(std::to_string(polls_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"pending_answers_\":"); output.push_back(std::to_string(pending_answers_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"poll_voters_\":"); output.push_back(std::to_string(poll_voters_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_from_database_polls_\":"); output.push_back(std::to_string(loaded_from_database_polls_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"being_closed_polls_\":"); output.push_back(std::to_string(being_closed_polls_.size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -47,6 +47,8 @@ class PollManager final : public Actor {
|
||||
PollManager &operator=(PollManager &&) = delete;
|
||||
~PollManager() final;
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
static bool is_local_poll_id(PollId poll_id);
|
||||
|
||||
PollId create_poll(string &&question, vector<string> &&options, bool is_anonymous, bool allow_multiple_answers,
|
||||
|
@ -208,7 +208,7 @@ void PrivacyManager::do_update_privacy(UserPrivacySetting user_privacy_setting,
|
||||
info.is_synchronized_ = true;
|
||||
|
||||
if (!(info.rules_ == privacy_rules)) {
|
||||
if ((from_update || was_synchronized) && !G()->close_flag()) {
|
||||
if (!G()->close_flag() && (from_update || was_synchronized)) {
|
||||
switch (user_privacy_setting.type()) {
|
||||
case UserPrivacySetting::Type::UserStatus: {
|
||||
send_closure_later(G()->contacts_manager(), &ContactsManager::on_update_online_status_privacy);
|
||||
|
@ -6,6 +6,8 @@
|
||||
//
|
||||
#include "td/telegram/StateManager.h"
|
||||
|
||||
#include "td/telegram/Global.h"
|
||||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
#include "td/actor/SleepActor.h"
|
||||
|
||||
@ -129,8 +131,10 @@ void StateManager::on_network_soft() {
|
||||
}
|
||||
|
||||
void StateManager::start_up() {
|
||||
create_actor<SleepActor>("SleepActor", 1, create_event_promise(self_closure(this, &StateManager::on_network_soft)))
|
||||
.release();
|
||||
if (!G()->get_option_boolean("disable_network_statistics")) {
|
||||
create_actor<SleepActor>("SleepActor", 1, create_event_promise(self_closure(this, &StateManager::on_network_soft)))
|
||||
.release();
|
||||
}
|
||||
loop();
|
||||
}
|
||||
|
||||
|
@ -10146,4 +10146,28 @@ void StickersManager::get_current_state(vector<td_api::object_ptr<td_api::Update
|
||||
}
|
||||
}
|
||||
|
||||
void StickersManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"archived_sticker_set_ids_\":"); output.push_back(std::to_string(archived_sticker_set_ids_->size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"attached_sticker_sets_\":"); output.push_back(std::to_string(attached_sticker_sets_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"favorite_sticker_file_ids_\":"); output.push_back(std::to_string(favorite_sticker_file_ids_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"favorite_sticker_ids_\":"); output.push_back(std::to_string(favorite_sticker_ids_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"installed_sticker_set_ids_\":"); output.push_back(std::to_string(installed_sticker_set_ids_->size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"recent_sticker_file_ids_\":"); output.push_back(std::to_string(recent_sticker_file_ids_->size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"recent_sticker_ids_\":"); output.push_back(std::to_string(recent_sticker_ids_->size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"short_name_to_sticker_set_id_\":"); output.push_back(std::to_string(short_name_to_sticker_set_id_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"special_sticker_sets_\":"); output.push_back(std::to_string(special_sticker_sets_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"sticker_sets_\":"); output.push_back(std::to_string(sticker_sets_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"stickers_\":"); output.push_back(std::to_string(stickers_.calc_size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -57,6 +57,8 @@ class StickersManager final : public Actor {
|
||||
public:
|
||||
static constexpr int64 GREAT_MINDS_SET_ID = 1842540969984001;
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
static vector<StickerSetId> convert_sticker_set_ids(const vector<int64> &sticker_set_ids);
|
||||
static vector<int64> convert_sticker_set_ids(const vector<StickerSetId> &sticker_set_ids);
|
||||
|
||||
|
@ -137,6 +137,7 @@
|
||||
#include "td/telegram/StickersManager.h"
|
||||
#include "td/telegram/StickerType.h"
|
||||
#include "td/telegram/StorageManager.h"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/StoryId.h"
|
||||
#include "td/telegram/StoryListId.h"
|
||||
#include "td/telegram/StoryManager.h"
|
||||
@ -2842,6 +2843,7 @@ bool Td::is_preauthentication_request(int32 id) {
|
||||
case td_api::getStorageStatistics::ID:
|
||||
case td_api::getStorageStatisticsFast::ID:
|
||||
case td_api::getDatabaseStatistics::ID:
|
||||
case td_api::getMemoryStatistics::ID:
|
||||
case td_api::setNetworkType::ID:
|
||||
case td_api::getNetworkStatistics::ID:
|
||||
case td_api::addNetworkStatistics::ID:
|
||||
@ -2894,12 +2896,15 @@ vector<td_api::object_ptr<td_api::Update>> Td::get_fake_current_state() const {
|
||||
return updates;
|
||||
}
|
||||
|
||||
DbKey Td::as_db_key(string key) {
|
||||
DbKey Td::as_db_key(string key, bool custom_db) {
|
||||
// Database will still be effectively not encrypted, but
|
||||
// 1. SQLite database will be protected from corruption, because that's how sqlcipher works
|
||||
// 2. security through obscurity
|
||||
// 3. no need for reencryption of SQLite database
|
||||
if (key.empty()) {
|
||||
if (custom_db) {
|
||||
return DbKey::empty();
|
||||
}
|
||||
return DbKey::raw_key("cucumber");
|
||||
}
|
||||
return DbKey::raw_key(std::move(key));
|
||||
@ -3249,9 +3254,20 @@ void Td::dec_actor_refcnt() {
|
||||
close_flag_ = 4;
|
||||
} else if (close_flag_ == 4) {
|
||||
on_closed();
|
||||
#ifdef __linux__
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)
|
||||
malloc_trim(0);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
#ifdef __linux__
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)
|
||||
malloc_trim(0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -3927,6 +3943,9 @@ void Td::init_managers() {
|
||||
stickers_manager_ = make_unique<StickersManager>(this, create_reference());
|
||||
stickers_manager_actor_ = register_actor("StickersManager", stickers_manager_.get());
|
||||
G()->set_stickers_manager(stickers_manager_actor_.get());
|
||||
memory_manager_ = make_unique<MemoryManager>(this, create_reference());
|
||||
memory_manager_actor_ = register_actor("MemoryManager", memory_manager_.get());
|
||||
G()->set_memory_manager(memory_manager_actor_.get());
|
||||
story_manager_ = make_unique<StoryManager>(this, create_reference());
|
||||
story_manager_actor_ = register_actor("StoryManager", story_manager_.get());
|
||||
G()->set_story_manager(story_manager_actor_.get());
|
||||
@ -4120,8 +4139,9 @@ Result<std::pair<Td::Parameters, TdDb::Parameters>> Td::get_parameters(
|
||||
result.first.api_hash_ = std::move(parameters->api_hash_);
|
||||
result.first.use_secret_chats_ = parameters->use_secret_chats_;
|
||||
|
||||
result.second.encryption_key_ = as_db_key(std::move(parameters->database_encryption_key_));
|
||||
result.second.database_directory_ = std::move(parameters->database_directory_);
|
||||
result.second.encryption_key_ = as_db_key(std::move(parameters->database_encryption_key_), Global::get_use_custom_database(parameters->database_directory_));
|
||||
result.second.database_directory_ = Global::get_database_directory_path(parameters->database_directory_);
|
||||
result.second.use_custom_database_format_ = Global::get_use_custom_database(parameters->database_directory_);
|
||||
result.second.files_directory_ = std::move(parameters->files_directory_);
|
||||
result.second.is_test_dc_ = parameters->use_test_dc_;
|
||||
result.second.use_file_database_ = parameters->use_file_database_;
|
||||
@ -4168,7 +4188,7 @@ void Td::on_request(uint64 id, const td_api::setTdlibParameters &request) {
|
||||
|
||||
void Td::on_request(uint64 id, td_api::setDatabaseEncryptionKey &request) {
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
G()->td_db()->get_binlog()->change_key(as_db_key(std::move(request.new_encryption_key_)), std::move(promise));
|
||||
G()->td_db()->get_binlog()->change_key(as_db_key(std::move(request.new_encryption_key_), G()->use_custom_database_format()), std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getAuthorizationState &request) {
|
||||
@ -4299,6 +4319,7 @@ void Td::on_request(uint64 id, const td_api::getCurrentState &request) {
|
||||
|
||||
dialog_filter_manager_->get_current_state(updates);
|
||||
|
||||
memory_manager_->get_current_state(updates);
|
||||
messages_manager_->get_current_state(updates);
|
||||
|
||||
dialog_participant_manager_->get_current_state(updates);
|
||||
@ -4853,6 +4874,18 @@ void Td::on_request(uint64 id, td_api::getDatabaseStatistics &request) {
|
||||
});
|
||||
send_closure(storage_manager_, &StorageManager::get_database_stats, std::move(query_promise));
|
||||
}
|
||||
void Td::on_request(uint64 id, td_api::getMemoryStatistics &request) {
|
||||
CREATE_REQUEST_PROMISE();
|
||||
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<MemoryStats> result) mutable {
|
||||
if (result.is_error()) {
|
||||
promise.set_error(result.move_as_error());
|
||||
} else {
|
||||
promise.set_value(result.ok().get_memory_statistics_object());
|
||||
}
|
||||
});
|
||||
|
||||
memory_manager_->get_memory_stats(request.full_, std::move(query_promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, td_api::optimizeStorage &request) {
|
||||
std::vector<FileType> file_types;
|
||||
|
@ -31,6 +31,12 @@
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
@ -88,6 +94,7 @@ class StateManager;
|
||||
class StatisticsManager;
|
||||
class StickersManager;
|
||||
class StorageManager;
|
||||
class MemoryManager;
|
||||
class StoryManager;
|
||||
class ThemeManager;
|
||||
class TopDialogManager;
|
||||
@ -245,6 +252,8 @@ class Td final : public Actor {
|
||||
ActorOwn<VideoNotesManager> video_notes_manager_actor_;
|
||||
unique_ptr<VoiceNotesManager> voice_notes_manager_;
|
||||
ActorOwn<VoiceNotesManager> voice_notes_manager_actor_;
|
||||
unique_ptr<MemoryManager> memory_manager_;
|
||||
ActorOwn<MemoryManager> memory_manager_actor_;
|
||||
unique_ptr<WebPagesManager> web_pages_manager_;
|
||||
ActorOwn<WebPagesManager> web_pages_manager_actor_;
|
||||
|
||||
@ -642,6 +651,8 @@ class Td final : public Actor {
|
||||
|
||||
void on_request(uint64 id, td_api::getDatabaseStatistics &request);
|
||||
|
||||
void on_request(uint64 id, td_api::getMemoryStatistics &request);
|
||||
|
||||
void on_request(uint64 id, td_api::optimizeStorage &request);
|
||||
|
||||
void on_request(uint64 id, td_api::getNetworkStatistics &request);
|
||||
@ -1859,7 +1870,7 @@ class Td final : public Actor {
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(const td_api::addLogMessage &request);
|
||||
static td_api::object_ptr<td_api::Object> do_static_request(td_api::testReturnError &request);
|
||||
|
||||
static DbKey as_db_key(string key);
|
||||
static DbKey as_db_key(string key, bool custom_db);
|
||||
|
||||
struct Parameters {
|
||||
int32 api_id_ = 0;
|
||||
|
@ -374,8 +374,16 @@ Status TdDb::init_sqlite(const Parameters ¶meters, const DbKey &key, const D
|
||||
sql_connection_ = std::make_shared<SqliteConnectionSafe>(sql_database_path, key, db_instance.get_cipher_version());
|
||||
sql_connection_->set(std::move(db_instance));
|
||||
auto &db = sql_connection_->get();
|
||||
TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
|
||||
TRY_STATUS(db.exec("PRAGMA secure_delete=1"));
|
||||
if (parameters.use_custom_database_format_) {
|
||||
TRY_STATUS(db.exec("PRAGMA journal_mode=OFF"));
|
||||
TRY_STATUS(db.exec("PRAGMA synchronous=OFF"))
|
||||
TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY"));
|
||||
TRY_STATUS(db.exec("PRAGMA secure_delete=0"));
|
||||
TRY_STATUS(db.exec("PRAGMA mmap_size=30000000000"));
|
||||
} else {
|
||||
TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
|
||||
TRY_STATUS(db.exec("PRAGMA secure_delete=1"));
|
||||
}
|
||||
|
||||
// Init databases
|
||||
// Do initialization once and before everything else to avoid "database is locked" error.
|
||||
|
@ -60,6 +60,7 @@ class TdDb {
|
||||
bool use_file_database_ = false;
|
||||
bool use_chat_info_database_ = false;
|
||||
bool use_message_database_ = false;
|
||||
bool use_custom_database_format_ = false;
|
||||
};
|
||||
|
||||
struct OpenedDatabase {
|
||||
@ -117,6 +118,10 @@ class TdDb {
|
||||
return was_dialog_db_created_;
|
||||
}
|
||||
|
||||
bool use_custom_database_format() const {
|
||||
return parameters_.use_custom_database_format_;
|
||||
}
|
||||
|
||||
std::shared_ptr<FileDbInterface> get_file_db_shared();
|
||||
std::shared_ptr<SqliteConnectionSafe> &get_sqlite_connection_safe();
|
||||
#define get_binlog() get_binlog_impl(__FILE__, __LINE__)
|
||||
|
@ -620,7 +620,7 @@ void TopDialogManager::on_first_sync() {
|
||||
}
|
||||
|
||||
void TopDialogManager::loop() {
|
||||
if (td_->auth_manager_->is_bot() || G()->close_flag()) {
|
||||
if (G()->close_flag() || td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -275,6 +275,10 @@ void UpdatesManager::tear_down() {
|
||||
}
|
||||
|
||||
void UpdatesManager::start_up() {
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
class StateCallback final : public StateManager::Callback {
|
||||
public:
|
||||
explicit StateCallback(ActorId<UpdatesManager> parent) : parent_(std::move(parent)) {
|
||||
|
@ -82,8 +82,10 @@ FileId VideoNotesManager::on_get_video_note(unique_ptr<VideoNote> new_video_note
|
||||
v->dimensions = new_video_note->dimensions;
|
||||
v->waveform = std::move(new_video_note->waveform);
|
||||
}
|
||||
if (v->minithumbnail != new_video_note->minithumbnail) {
|
||||
v->minithumbnail = std::move(new_video_note->minithumbnail);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
if (v->minithumbnail != new_video_note->minithumbnail) {
|
||||
v->minithumbnail = std::move(new_video_note->minithumbnail);
|
||||
}
|
||||
}
|
||||
if (v->thumbnail != new_video_note->thumbnail) {
|
||||
if (!v->thumbnail.file_id.is_valid()) {
|
||||
@ -169,7 +171,7 @@ void VideoNotesManager::create_video_note(FileId file_id, string minithumbnail,
|
||||
LOG(INFO) << "Receive wrong video note dimensions " << dimensions;
|
||||
}
|
||||
v->waveform = std::move(waveform);
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
if (!td_->auth_manager_->is_bot() && !G()->get_option_boolean("disable_minithumbnails")) {
|
||||
v->minithumbnail = std::move(minithumbnail);
|
||||
}
|
||||
v->thumbnail = std::move(thumbnail);
|
||||
@ -262,4 +264,8 @@ tl_object_ptr<telegram_api::InputMedia> VideoNotesManager::get_input_media(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VideoNotesManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"video_notes_\":"); output.push_back(std::to_string(video_notes_.calc_size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -33,6 +33,8 @@ class VideoNotesManager final : public Actor {
|
||||
VideoNotesManager &operator=(VideoNotesManager &&) = delete;
|
||||
~VideoNotesManager() final;
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
int32 get_video_note_duration(FileId file_id) const;
|
||||
|
||||
TranscriptionInfo *get_video_note_transcription_info(FileId file_id, bool allow_creation);
|
||||
|
@ -96,8 +96,10 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
|
||||
LOG(DEBUG) << "Video " << file_id << " file name has changed";
|
||||
v->file_name = std::move(new_video->file_name);
|
||||
}
|
||||
if (v->minithumbnail != new_video->minithumbnail) {
|
||||
v->minithumbnail = std::move(new_video->minithumbnail);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
if (v->minithumbnail != new_video->minithumbnail) {
|
||||
v->minithumbnail = std::move(new_video->minithumbnail);
|
||||
}
|
||||
}
|
||||
if (v->thumbnail != new_video->thumbnail) {
|
||||
if (!v->thumbnail.file_id.is_valid()) {
|
||||
@ -198,7 +200,7 @@ void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize
|
||||
v->duration = max(duration, 0);
|
||||
v->precise_duration = duration == 0 ? 0.0 : clamp(precise_duration, duration - 1.0, duration + 0.0);
|
||||
v->dimensions = dimensions;
|
||||
if (!td_->auth_manager_->is_bot()) {
|
||||
if (!td_->auth_manager_->is_bot() && G()->get_option_boolean("disable_minithumbnails")) {
|
||||
v->minithumbnail = std::move(minithumbnail);
|
||||
}
|
||||
v->thumbnail = std::move(thumbnail);
|
||||
@ -332,4 +334,8 @@ string VideosManager::get_video_search_text(FileId file_id) const {
|
||||
return video->file_name;
|
||||
}
|
||||
|
||||
void VideosManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"videos_\":"); output.push_back(std::to_string(videos_.calc_size()));
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -30,6 +30,8 @@ class VideosManager {
|
||||
VideosManager &operator=(VideosManager &&) = delete;
|
||||
~VideosManager();
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
int32 get_video_duration(FileId file_id) const;
|
||||
|
||||
td_api::object_ptr<td_api::video> get_video_object(FileId file_id) const;
|
||||
|
@ -67,12 +67,29 @@ FileId VideosManager::parse_video(ParserT &parser) {
|
||||
PARSE_FLAG(has_precise_duration);
|
||||
PARSE_FLAG(video->is_animation);
|
||||
END_PARSE_FLAGS();
|
||||
parse(video->file_name, parser);
|
||||
|
||||
string tmp_filename;
|
||||
parse(tmp_filename, parser);
|
||||
|
||||
parse(video->mime_type, parser);
|
||||
|
||||
if ( G()->get_option_boolean("disable_document_filenames") && (
|
||||
video->mime_type.rfind("image/") == 0 ||
|
||||
video->mime_type.rfind("video/") == 0 ||
|
||||
video->mime_type.rfind("audio/") == 0)) {
|
||||
video->file_name = "0";
|
||||
} else {
|
||||
video->file_name = tmp_filename;
|
||||
}
|
||||
|
||||
parse(video->duration, parser);
|
||||
parse(video->dimensions, parser);
|
||||
if (parser.version() >= static_cast<int32>(Version::SupportMinithumbnails)) {
|
||||
parse(video->minithumbnail, parser);
|
||||
string tmp_minithumbnail;
|
||||
parse(tmp_minithumbnail, parser);
|
||||
if (!G()->get_option_boolean("disable_minithumbnails")) {
|
||||
video->minithumbnail = tmp_minithumbnail;
|
||||
}
|
||||
}
|
||||
parse(video->thumbnail, parser);
|
||||
parse(video->file_id, parser);
|
||||
|
@ -1959,4 +1959,17 @@ vector<FileId> WebPagesManager::get_web_page_file_ids(const WebPage *web_page) c
|
||||
return result;
|
||||
}
|
||||
|
||||
void WebPagesManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"web_pages_\":"); output.push_back(std::to_string(web_pages_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"loaded_from_database_web_pages_\":"); output.push_back(std::to_string(loaded_from_database_web_pages_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"web_page_messages_\":"); output.push_back(std::to_string(web_page_messages_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"url_to_web_page_id_\":"); output.push_back(std::to_string(url_to_web_page_id_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"url_to_file_source_id_\":"); output.push_back(std::to_string(url_to_file_source_id_.size()));
|
||||
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -40,6 +40,8 @@ class WebPagesManager final : public Actor {
|
||||
public:
|
||||
WebPagesManager(Td *td, ActorShared<> parent);
|
||||
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
WebPagesManager(const WebPagesManager &) = delete;
|
||||
WebPagesManager &operator=(const WebPagesManager &) = delete;
|
||||
WebPagesManager(WebPagesManager &&) = delete;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "td/telegram/files/FileLoaderUtils.h"
|
||||
#include "td/telegram/files/FileLocation.h"
|
||||
#include "td/telegram/files/FileLocation.hpp"
|
||||
#include "td/telegram/MemoryManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/misc.h"
|
||||
@ -879,8 +880,8 @@ FileManager::FileManager(unique_ptr<Context> context) : context_(std::move(conte
|
||||
}
|
||||
|
||||
parent_ = context_->create_reference();
|
||||
next_file_id();
|
||||
next_file_node_id();
|
||||
next_file_id();
|
||||
next_file_node_id();
|
||||
|
||||
G()->td_db()->with_db_path([bad_paths = &bad_paths_](CSlice path) { bad_paths->insert(path.str()); });
|
||||
}
|
||||
@ -4172,6 +4173,16 @@ void FileManager::hangup() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void FileManager::memory_stats(vector<string> &output) {
|
||||
output.push_back("\"file_id_info_\":"); output.push_back(std::to_string(file_id_info_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"file_nodes_\":"); output.push_back(std::to_string(file_nodes_.size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"file_hash_to_file_id_\":"); output.push_back(std::to_string(file_hash_to_file_id_.calc_size()));
|
||||
output.push_back(",");
|
||||
output.push_back("\"empty_file_ids_\":"); output.push_back(std::to_string(empty_file_ids_.size()));
|
||||
}
|
||||
|
||||
void FileManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
|
@ -378,6 +378,8 @@ class FileView {
|
||||
|
||||
class FileManager final : public FileLoadManager::Callback {
|
||||
public:
|
||||
void memory_stats(vector<string> &output);
|
||||
|
||||
static constexpr int64 KEEP_DOWNLOAD_LIMIT = -1;
|
||||
static constexpr int64 KEEP_DOWNLOAD_OFFSET = -1;
|
||||
static constexpr int64 IGNORE_DOWNLOAD_LIMIT = -2;
|
||||
|
@ -194,8 +194,7 @@ class Scheduler {
|
||||
void add_to_mailbox(ActorInfo *actor_info, Event &&event);
|
||||
void clear_mailbox(ActorInfo *actor_info);
|
||||
|
||||
template <class RunFuncT, class EventFuncT>
|
||||
void flush_mailbox(ActorInfo *actor_info, const RunFuncT &run_func, const EventFuncT &event_func);
|
||||
void flush_mailbox(ActorInfo *actor_info);
|
||||
|
||||
template <ActorSendType send_type, class RunFuncT, class EventFuncT>
|
||||
void send_impl(const ActorId<> &actor_id, const RunFuncT &run_func, const EventFuncT &event_func);
|
||||
|
@ -493,6 +493,18 @@ void Scheduler::run_poll(Timestamp timeout) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void Scheduler::flush_mailbox(ActorInfo *actor_info) {
|
||||
auto &mailbox = actor_info->mailbox_;
|
||||
size_t mailbox_size = mailbox.size();
|
||||
CHECK(mailbox_size != 0);
|
||||
EventGuard guard(this, actor_info);
|
||||
size_t i = 0;
|
||||
for (; i < mailbox_size && guard.can_run(); i++) {
|
||||
do_event(actor_info, std::move(mailbox[i]));
|
||||
}
|
||||
mailbox.erase(mailbox.begin(), mailbox.begin() + i);
|
||||
}
|
||||
|
||||
void Scheduler::run_mailbox() {
|
||||
VLOG(actor) << "Run mailbox : begin";
|
||||
ListNode actors_list = std::move(ready_actors_list_);
|
||||
@ -500,7 +512,7 @@ void Scheduler::run_mailbox() {
|
||||
ListNode *node = actors_list.get();
|
||||
CHECK(node);
|
||||
auto actor_info = ActorInfo::from_list_node(node);
|
||||
flush_mailbox(actor_info, static_cast<void (*)(ActorInfo *)>(nullptr), static_cast<Event (*)()>(nullptr));
|
||||
flush_mailbox(actor_info);
|
||||
}
|
||||
VLOG(actor) << "Run mailbox : finish " << actor_count_;
|
||||
|
||||
|
@ -140,26 +140,6 @@ inline void Scheduler::destroy_actor(ActorInfo *actor_info) {
|
||||
CHECK(actor_count_ >= 0);
|
||||
}
|
||||
|
||||
template <class RunFuncT, class EventFuncT>
|
||||
void Scheduler::flush_mailbox(ActorInfo *actor_info, const RunFuncT &run_func, const EventFuncT &event_func) {
|
||||
auto &mailbox = actor_info->mailbox_;
|
||||
size_t mailbox_size = mailbox.size();
|
||||
CHECK(mailbox_size != 0);
|
||||
EventGuard guard(this, actor_info);
|
||||
size_t i = 0;
|
||||
for (; i < mailbox_size && guard.can_run(); i++) {
|
||||
do_event(actor_info, std::move(mailbox[i]));
|
||||
}
|
||||
if (run_func) {
|
||||
if (guard.can_run()) {
|
||||
(*run_func)(actor_info);
|
||||
} else {
|
||||
mailbox.insert(mailbox.begin() + i, (*event_func)());
|
||||
}
|
||||
}
|
||||
mailbox.erase(mailbox.begin(), mailbox.begin() + i);
|
||||
}
|
||||
|
||||
inline void Scheduler::send_to_scheduler(int32 sched_id, const ActorId<Actor> &actor_id, Event &&event) {
|
||||
if (sched_id == sched_id_) {
|
||||
ActorInfo *actor_info = actor_id.get_actor_info();
|
||||
|
@ -395,7 +395,7 @@ if (WIN32)
|
||||
target_link_libraries(tdutils PRIVATE ws2_32 Mswsock Normaliz psapi)
|
||||
endif()
|
||||
if (NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
target_link_libraries(tdutils PRIVATE shell32)
|
||||
target_link_libraries(tdutils PRIVATE shell32 crypt32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -238,6 +238,18 @@ static DefaultLog default_log;
|
||||
LogInterface *const default_log_interface = &default_log;
|
||||
LogInterface *log_interface = default_log_interface;
|
||||
|
||||
static OnFatalErrorCallback on_fatal_error_callback = nullptr;
|
||||
|
||||
static bool use_death_handler = true;
|
||||
|
||||
void set_log_fatal_error_callback(OnFatalErrorCallback callback) {
|
||||
on_fatal_error_callback = callback;
|
||||
}
|
||||
|
||||
void set_log_disable_death_handler(bool disabled) {
|
||||
use_death_handler = !disabled;
|
||||
}
|
||||
|
||||
void process_fatal_error(CSlice message) {
|
||||
if (0 <= max_callback_verbosity_level.load(std::memory_order_relaxed)) {
|
||||
auto callback = on_log_message_callback.load(std::memory_order_relaxed);
|
||||
|
@ -173,6 +173,10 @@ class LogInterface {
|
||||
extern LogInterface *const default_log_interface;
|
||||
extern LogInterface *log_interface;
|
||||
|
||||
using OnFatalErrorCallback = void (*)(CSlice message);
|
||||
void set_log_fatal_error_callback(OnFatalErrorCallback callback);
|
||||
void set_log_disable_death_handler(bool disabled);
|
||||
|
||||
[[noreturn]] void process_fatal_error(CSlice message);
|
||||
|
||||
using OnLogMessageCallback = void (*)(int verbosity_level, CSlice message);
|
||||
|
Loading…
Reference in New Issue
Block a user