Compare commits

...

14 Commits

Author SHA1 Message Date
Andrea Cavalli
be261b5dcc Fix json 2024-02-21 02:45:12 +01:00
Andrea Cavalli
eef20412e9 Always use 128 client threads (todo: make this behavior optional)
This change fixes some memory management issues
2024-02-20 22:46:06 +01:00
Andrea Cavalli
bce9060db2 Disable ccache script 2024-02-20 22:46:06 +01:00
Andrea Cavalli
050972465a Apply tdlight patch 2024-02-20 22:46:06 +01:00
levlam
6c5441c8ff Add ATOMICS_LIBRARY_FLAGS. 2024-02-19 16:54:29 +03:00
levlam
1202a4d957 Use https://github.com/libjxl/libjxl/blob/main/cmake/FindAtomics.cmake to find libatomic. 2024-02-19 16:31:00 +03:00
levlam
335b110f9e Add -Wno-psabi option to disable ABI compatibility warnings on ARM. 2024-02-19 15:44:26 +03:00
levlam
da979c4631 Move user_online_member_dialogs_ to DialogParticipantManager. 2024-02-19 02:15:05 +03:00
levlam
59b1d7a4f6 Add ContactsManager::update_chat_online_member_count(ChatId). 2024-02-19 01:46:57 +03:00
levlam
32040c22cb Move get_dialog_about to DialogManager. 2024-02-19 01:10:57 +03:00
levlam
5828e46046 Don't subscribe to some state changes by bots. 2024-02-19 00:23:46 +03:00
levlam
acef6e61a0 Check close_flag() first. 2024-02-18 20:55:41 +03:00
levlam
516e2e8a07 Remove legacy parameters in Scheduler::flush_mailbox. 2024-02-17 21:42:51 +03:00
levlam
b6b5b1b9ed Don't set network type if network statistics is disabled. 2024-02-17 21:39:12 +03:00
86 changed files with 1556 additions and 376 deletions

50
.github/workflows/build.yaml vendored Normal file
View 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
View File

@ -4,4 +4,12 @@
**/auto/
docs/
tdlib/
.idea/
vcpkg/
*.tlo
td.binlog
tg_cli.log
tg_cli.log.old

View File

@ -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
View 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)

View File

@ -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")

View File

@ -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)

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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" />

View File

@ -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.

View File

@ -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.

View File

@ -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
View File

@ -0,0 +1 @@
*.tlo

View File

@ -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

View File

@ -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);
}

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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>();
}

View File

@ -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

View File

@ -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_;

View File

@ -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++) {

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 = [&] {

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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_;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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,

View 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

View 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

View File

@ -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();
}

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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")) {

View File

@ -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>());
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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();
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -374,8 +374,16 @@ Status TdDb::init_sqlite(const Parameters &parameters, 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.

View File

@ -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__)

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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_;

View File

@ -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();

View File

@ -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()

View File

@ -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);

View File

@ -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);