Remove embedded td
194
third-party/td/td/.clang-format
vendored
@ -1,194 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: None # All
|
||||
AllowShortIfStatementsOnASingleLine: Never # WithoutElse
|
||||
AllowShortLambdasOnASingleLine: Inline # All
|
||||
AllowShortLoopsOnASingleLine: false # true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
# AttributeMacros:
|
||||
# - __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAfterAttributes: Never
|
||||
# BreakAfterJavaFieldAnnotations: false
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma # BeforeColon
|
||||
BreakInheritanceList: BeforeComma # BeforeColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120 # 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- Q_FOREACH_THIS_LIST_MUST_BE_NON_EMPTY
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 0
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: true
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: false
|
||||
# InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
Decimal: 0
|
||||
Hex: 0
|
||||
# JavaScriptQuotes: Leave
|
||||
# JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
# ObjCBinPackProtocolList: Never
|
||||
# ObjCBlockIndentWidth: 2
|
||||
# ObjCBreakBeforeNestedBlockParam: true
|
||||
# ObjCSpaceAfterProperty: false
|
||||
# ObjCSpaceBeforeProtocolList: true
|
||||
PackConstructorInitializers: NextLine
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Right # Left
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Leave
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false # true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 0 # 1
|
||||
SortIncludes: CaseInsensitive # CaseSensitive
|
||||
# SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: Lexicographic # LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: 1 # -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 100 # 8
|
||||
UseTab: Never
|
||||
...
|
39
third-party/td/td/.gitattributes
vendored
@ -1,39 +0,0 @@
|
||||
* text=auto
|
||||
|
||||
*.cpp text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.hpp text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.h text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.c text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.tl text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.mm text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.txt text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.sh text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent eol=lf
|
||||
*.php text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.ps1 text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent eol=crlf
|
||||
*.cmake text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.md text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.in text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.html text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
|
||||
*.java text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.py text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.js text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.patch text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.swift text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.pbxproj text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.cs text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.xaml text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.appxmanifest text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.vsixmanifest text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.nuspec text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.targets text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.json text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.csproj text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.sln text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.xml text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
*.config text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
|
||||
|
||||
sqlite/sqlite/* linguist-vendored
|
||||
|
||||
*.pfx binary
|
||||
*.png binary
|
8
third-party/td/td/.gitignore
vendored
@ -1,8 +0,0 @@
|
||||
**/*build*/
|
||||
**/.*.swp
|
||||
**/.DS_Store
|
||||
**/auto/
|
||||
docs/
|
||||
/tdlib/
|
||||
vcpkg/
|
||||
.clang-tidy
|
1520
third-party/td/td/CHANGELOG.md
vendored
74
third-party/td/td/CMake/AddCXXCompilerFlag.cmake
vendored
@ -1,74 +0,0 @@
|
||||
# - Adds a compiler flag if it is supported by the compiler
|
||||
#
|
||||
# This function checks that the supplied compiler flag is supported and then
|
||||
# adds it to the corresponding compiler flags
|
||||
#
|
||||
# add_cxx_compiler_flag(<FLAG> [<VARIANT>])
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(AddCXXCompilerFlag)
|
||||
# add_cxx_compiler_flag(-Wall)
|
||||
# add_cxx_compiler_flag(-no-strict-aliasing RELEASE)
|
||||
# Requires CMake 2.6+
|
||||
|
||||
if (__add_cxx_compiler_flag)
|
||||
return()
|
||||
endif()
|
||||
set(__add_cxx_compiler_flag INCLUDED)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
function(mangle_compiler_flag FLAG OUTPUT)
|
||||
string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG)
|
||||
string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE)
|
||||
endfunction(mangle_compiler_flag)
|
||||
|
||||
function(add_cxx_compiler_flag FLAG)
|
||||
string(REPLACE "-Wno-" "-W" MAIN_FLAG ${FLAG})
|
||||
mangle_compiler_flag("${MAIN_FLAG}" MANGLED_FLAG_NAME)
|
||||
if (DEFINED CMAKE_REQUIRED_FLAGS)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
else()
|
||||
set(CMAKE_REQUIRED_FLAGS "${FLAG}")
|
||||
endif()
|
||||
check_cxx_compiler_flag("${MAIN_FLAG}" ${MANGLED_FLAG_NAME})
|
||||
if (DEFINED OLD_CMAKE_REQUIRED_FLAGS)
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
else()
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
endif()
|
||||
if (${MANGLED_FLAG_NAME})
|
||||
set(VARIANT ${ARGV1})
|
||||
if (ARGV1)
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(add_required_cxx_compiler_flag FLAG)
|
||||
string(REPLACE "-Wno-" "-W" MAIN_FLAG ${FLAG})
|
||||
mangle_compiler_flag("${MAIN_FLAG}" MANGLED_FLAG_NAME)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
check_cxx_compiler_flag("${MAIN_FLAG}" ${MANGLED_FLAG_NAME})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
if (${MANGLED_FLAG_NAME})
|
||||
set(VARIANT ${ARGV1})
|
||||
if (ARGV1)
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
else()
|
||||
message(FATAL_ERROR "Required flag '${FLAG}' is not supported by the compiler")
|
||||
endif()
|
||||
endfunction()
|
62
third-party/td/td/CMake/FindAtomics.cmake
vendored
@ -1,62 +0,0 @@
|
||||
# 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
|
||||
|
||||
if (ATOMICS_FOUND)
|
||||
return()
|
||||
endif()
|
||||
|
||||
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
|
||||
# to link atomic library, but not 4-byte or 8-byte (though it does no harm).
|
||||
set(ATOMIC_CODE
|
||||
"
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
std::atomic<std::uint8_t> n8{0}; // riscv64
|
||||
std::atomic<std::uint64_t> n64{0}; // armel, mipsel, powerpc
|
||||
int main() {
|
||||
++n8;
|
||||
++n64;
|
||||
}")
|
||||
|
||||
set(ATOMICS_LIBS " " "-latomic")
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
set(ATOMICS_LIBS "${ATOMICS_LIBS}" /usr/pkg/gcc12/x86_64--netbsd/lib/libatomic.so /usr/pkg/gcc12/i486--netbsdelf/lib/libatomic.so)
|
||||
endif()
|
||||
|
||||
foreach (ATOMICS_LIBRARY ${ATOMICS_LIBS})
|
||||
unset(ATOMICS_FOUND CACHE)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${ATOMICS_LIBRARY}")
|
||||
check_cxx_source_compiles("${ATOMIC_CODE}" ATOMICS_FOUND)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
if (ATOMICS_FOUND)
|
||||
if (NOT ATOMICS_LIBRARY STREQUAL " ")
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Atomics DEFAULT_MSG ATOMICS_LIBRARY)
|
||||
set(ATOMICS_LIBRARIES "${ATOMICS_LIBRARY}" CACHE STRING "Atomic library" FORCE)
|
||||
else()
|
||||
set(ATOMICS_LIBRARIES "" CACHE STRING "Atomic operations library" FORCE)
|
||||
endif()
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
if (Atomics_FIND_REQUIRED AND NOT ATOMICS_FOUND)
|
||||
message(FATAL_ERROR "Atomic operations library isn't found.")
|
||||
endif()
|
||||
|
||||
unset(ATOMICS_LIBRARY)
|
||||
unset(ATOMICS_LIBS)
|
||||
unset(ATOMIC_CODE)
|
25
third-party/td/td/CMake/FindReadline.cmake
vendored
@ -1,25 +0,0 @@
|
||||
if (APPLE)
|
||||
find_path(READLINE_INCLUDE_DIR readline/readline.h /opt/homebrew/opt/readline/include /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include NO_DEFAULT_PATH)
|
||||
endif()
|
||||
find_path(READLINE_INCLUDE_DIR readline/readline.h)
|
||||
|
||||
if (APPLE)
|
||||
find_library(READLINE_LIBRARY readline /opt/homebrew/opt/readline/lib /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib NO_DEFAULT_PATH)
|
||||
endif()
|
||||
find_library(READLINE_LIBRARY readline)
|
||||
|
||||
if (READLINE_INCLUDE_DIR AND READLINE_LIBRARY AND NOT GNU_READLINE_FOUND)
|
||||
set(CMAKE_REQUIRED_INCLUDES "${READLINE_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${READLINE_LIBRARY}")
|
||||
include(CheckCXXSourceCompiles)
|
||||
unset(GNU_READLINE_FOUND CACHE)
|
||||
check_cxx_source_compiles("#include <stdio.h>\n#include <readline/readline.h>\nint main() { rl_replace_line(\"\", 0); }" GNU_READLINE_FOUND)
|
||||
if (NOT GNU_READLINE_FOUND)
|
||||
unset(READLINE_INCLUDE_DIR CACHE)
|
||||
unset(READLINE_LIBRARY CACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Readline DEFAULT_MSG READLINE_INCLUDE_DIR READLINE_LIBRARY)
|
||||
mark_as_advanced(READLINE_INCLUDE_DIR READLINE_LIBRARY)
|
99
third-party/td/td/CMake/GeneratePkgConfig.cmake
vendored
@ -1,99 +0,0 @@
|
||||
function(get_relative_link OUTPUT PATH)
|
||||
if (PATH MATCHES "^[$]<[$]<CONFIG:DEBUG>:")
|
||||
set(${OUTPUT} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
string(REGEX REPLACE "^[$]<[$]<NOT:[$]<CONFIG:DEBUG>>:(.*)>$" "\\1" PATH "${PATH}")
|
||||
|
||||
get_filename_component(NAME "${PATH}" NAME_WE)
|
||||
if (IS_ABSOLUTE ${PATH})
|
||||
get_filename_component(DIRECTORY_NAME "${PATH}" DIRECTORY)
|
||||
if (WIN32)
|
||||
set(${OUTPUT} "-l\"${DIRECTORY_NAME}/${NAME}\"" PARENT_SCOPE)
|
||||
else()
|
||||
get_filename_component(FULL_NAME "${PATH}" NAME)
|
||||
set(${OUTPUT} "-L\"${DIRECTORY_NAME}\" -l:${FULL_NAME}" PARENT_SCOPE)
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NAME MATCHES "^lib")
|
||||
string(REGEX REPLACE "^lib" "-l" LINK "${NAME}")
|
||||
elseif (NAME MATCHES "^-")
|
||||
set(LINK "${NAME}")
|
||||
else()
|
||||
string(CONCAT LINK "-l" "${NAME}")
|
||||
endif()
|
||||
set(${OUTPUT} "${LINK}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(generate_pkgconfig TARGET DESCRIPTION)
|
||||
# message("Generating pkg-config for ${TARGET}")
|
||||
get_filename_component(PREFIX "${CMAKE_INSTALL_PREFIX}" REALPATH)
|
||||
|
||||
get_target_property(LIST "${TARGET}" LINK_LIBRARIES)
|
||||
set(REQS "")
|
||||
set(LIBS "")
|
||||
foreach (LIB ${LIST})
|
||||
if (TARGET "${LIB}")
|
||||
set(HAS_REQS 1)
|
||||
list(APPEND REQS "${LIB}")
|
||||
else()
|
||||
set(HAS_LIBS 1)
|
||||
get_relative_link(LINK "${LIB}")
|
||||
if (NOT LINK EQUAL "")
|
||||
list(APPEND LIBS "${LINK}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (HAS_REQS)
|
||||
set(REQUIRES "")
|
||||
foreach (REQ ${REQS})
|
||||
set(REQUIRES "${REQUIRES} ${REQ}")
|
||||
endforeach()
|
||||
set(REQUIRES "Requires.private:${REQUIRES}\n")
|
||||
endif()
|
||||
if (HAS_LIBS)
|
||||
set(LIBRARIES "")
|
||||
list(REVERSE LIBS)
|
||||
list(REMOVE_DUPLICATES LIBS)
|
||||
foreach (LIB ${LIBS})
|
||||
set(LIBRARIES " ${LIB}${LIBRARIES}")
|
||||
endforeach()
|
||||
set(LIBRARIES "Libs.private:${LIBRARIES}\n")
|
||||
endif()
|
||||
|
||||
if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
set(PKGCONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
else()
|
||||
set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
endif()
|
||||
|
||||
if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
|
||||
set(PKGCONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
else()
|
||||
set(PKGCONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig")
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${TARGET}.pc" CONTENT
|
||||
"prefix=${PREFIX}
|
||||
|
||||
Name: ${TARGET}
|
||||
Description: ${DESCRIPTION}
|
||||
Version: ${PROJECT_VERSION}
|
||||
|
||||
CFlags: -I\"${PKGCONFIG_INCLUDEDIR}\"
|
||||
Libs: -L\"${PKGCONFIG_LIBDIR}\" -l${TARGET}
|
||||
${REQUIRES}${LIBRARIES}")
|
||||
|
||||
get_target_property(LIBRARY_TYPE "${TARGET}" TYPE)
|
||||
if (LIBRARY_TYPE STREQUAL "STATIC_LIBRARY" OR LIBRARY_TYPE STREQUAL "SHARED_LIBRARY")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${TARGET}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
elseif (LIBRARY_TYPE STREQUAL "INTERFACE_LIBRARY")
|
||||
# TODO: support interface libraries
|
||||
else()
|
||||
message(FATAL_ERROR "Don't know how to handle ${TARGET} of type ${LIBRARY_TYPE}")
|
||||
endif()
|
||||
endfunction()
|
@ -1,127 +0,0 @@
|
||||
# - Returns a version string from Git
|
||||
#
|
||||
# These functions force a re-configure on each git commit so that you can
|
||||
# trust the values of the variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar>)
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
#
|
||||
# Copyright 2009-2013, Iowa State University.
|
||||
# Copyright 2013-2020, Ryan Pavlik
|
||||
# Copyright 2013-2020, Contributors
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
# 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)
|
||||
|
||||
if (__get_git_revision_description)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_revision_description YES)
|
||||
|
||||
# We must run the following at "include" time, not at function call time,
|
||||
# to find the path to this module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||
# that is part of any directory in the path defined by _start_dir.
|
||||
# The result is returned in the parent scope variable whose name is passed
|
||||
# as variable _git_dir_var. If no .git directory can be found, the
|
||||
# function returns an empty string via _git_dir_var.
|
||||
#
|
||||
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||
# neither foo nor bar contain a file/directory .git. This will return
|
||||
# C:/bla/.git
|
||||
#
|
||||
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||
set(cur_dir "${_start_dir}")
|
||||
set(git_dir "${_start_dir}/.git")
|
||||
while (NOT EXISTS "${git_dir}")
|
||||
# .git dir not found, search parent directories
|
||||
set(git_previous_parent "${cur_dir}")
|
||||
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||
if (cur_dir STREQUAL git_previous_parent)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_git_dir_var} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(git_dir "${cur_dir}/.git")
|
||||
endwhile()
|
||||
set(${_git_dir_var} "${git_dir}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||
|
||||
if (NOT GIT_DIR STREQUAL "")
|
||||
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_CURRENT_SOURCE_DIR}" "${GIT_DIR}")
|
||||
if (_relative_to_source_dir MATCHES "^[.][.]")
|
||||
# We've gone above the CMake root dir.
|
||||
set(GIT_DIR "")
|
||||
endif()
|
||||
endif()
|
||||
if (GIT_DIR STREQUAL "")
|
||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_package(Git QUIET)
|
||||
|
||||
# Check if the current source dir is a git submodule or a worktree.
|
||||
# In both cases .git is a file instead of a directory.
|
||||
#
|
||||
if ((NOT IS_DIRECTORY ${GIT_DIR}) AND Git_FOUND)
|
||||
# The following git command will return a non empty string that
|
||||
# points to the super project working tree if the current
|
||||
# source dir is inside a git submodule.
|
||||
# Otherwise, the command will return an empty string.
|
||||
#
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" rev-parse --show-superproject-working-tree
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if (NOT out STREQUAL "")
|
||||
# If out is non-empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||
else()
|
||||
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||
file(READ ${GIT_DIR} worktree_ref)
|
||||
# The .git directory contains a path to the worktree information directory
|
||||
# inside the parent git repo of the worktree.
|
||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir ${worktree_ref})
|
||||
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||
endif()
|
||||
else()
|
||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||
endif()
|
||||
if (NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if (NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" "${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
endfunction()
|
@ -1,43 +0,0 @@
|
||||
#
|
||||
# Internal file for GetGitRevisionDescription.cmake
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright 2009-2012, Iowa State University
|
||||
# Copyright 2011-2015, Contributors
|
||||
# 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)
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if (HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if (EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if (PACKED_REFS MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if (NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
@ -1,14 +0,0 @@
|
||||
function(prevent_in_source_build)
|
||||
get_filename_component(REAL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH)
|
||||
get_filename_component(REAL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" REALPATH)
|
||||
|
||||
if (REAL_BINARY_DIR STREQUAL REAL_SOURCE_DIR)
|
||||
message(" Out-of-source build must be used. Remove the files already")
|
||||
message(" created by CMake and rerun CMake from a new directory:")
|
||||
message(" rm -rf CMakeFiles CMakeCache.txt")
|
||||
message(" mkdir build")
|
||||
message(" cd build")
|
||||
message(" cmake ..")
|
||||
message(FATAL_ERROR "In-source build failed.")
|
||||
endif()
|
||||
endfunction()
|
185
third-party/td/td/CMake/TdSetUpCompiler.cmake
vendored
@ -1,185 +0,0 @@
|
||||
# Configures C++17 compiler, setting TDLib-specific compilation options.
|
||||
|
||||
function(td_set_up_compiler)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1 PARENT_SCOPE)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON PARENT_SCOPE)
|
||||
|
||||
include(illumos)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(GCC 1)
|
||||
set(GCC 1 PARENT_SCOPE)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CLANG 1)
|
||||
set(CLANG 1 PARENT_SCOPE)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
set(INTEL 1)
|
||||
set(INTEL 1 PARENT_SCOPE)
|
||||
elseif (NOT MSVC)
|
||||
message(FATAL_ERROR "Compiler isn't supported")
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if (GCC OR CLANG OR INTEL)
|
||||
if (WIN32 AND INTEL)
|
||||
set(STD17_FLAG /Qstd=c++17)
|
||||
else()
|
||||
set(STD17_FLAG -std=c++17)
|
||||
endif()
|
||||
if (GCC AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0))
|
||||
message(FATAL_ERROR "No C++17 support in the compiler. Please upgrade the compiler to at least GCC 7.0.")
|
||||
endif()
|
||||
if (CLANG AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0))
|
||||
message(FATAL_ERROR "No C++17 support in the compiler. Please upgrade the compiler to at least clang 5.0.")
|
||||
endif()
|
||||
check_cxx_compiler_flag(${STD17_FLAG} HAVE_STD17)
|
||||
elseif (MSVC)
|
||||
set(HAVE_STD17 MSVC_VERSION>=1914) # MSVC 2017 version 15.7
|
||||
endif()
|
||||
|
||||
if (NOT HAVE_STD17)
|
||||
message(FATAL_ERROR "No C++17 support in the compiler. Please upgrade the compiler.")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
|
||||
string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
endif()
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17 /utf-8 /GR- /W4 /wd4100 /wd4127 /wd4324 /wd4505 /wd4814 /wd4702 /bigobj")
|
||||
elseif (CLANG OR GCC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STD17_FLAG} -fno-omit-frame-pointer -fno-exceptions -fno-rtti")
|
||||
if (APPLE)
|
||||
set(TD_LINKER_FLAGS "-Wl,-dead_strip")
|
||||
if (NOT CMAKE_BUILD_TYPE MATCHES "Deb")
|
||||
set(TD_LINKER_FLAGS "${TD_LINKER_FLAGS},-x,-S")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
|
||||
set(TD_LINKER_FLAGS "-Wl,-z,ignore")
|
||||
elseif (EMSCRIPTEN)
|
||||
set(TD_LINKER_FLAGS "-Wl,--gc-sections")
|
||||
elseif (ANDROID)
|
||||
set(TD_LINKER_FLAGS "-Wl,--gc-sections -Wl,--exclude-libs,ALL -Wl,--icf=safe")
|
||||
else()
|
||||
set(TD_LINKER_FLAGS "-Wl,--gc-sections -Wl,--exclude-libs,ALL")
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${TD_LINKER_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TD_LINKER_FLAGS}")
|
||||
|
||||
if (WIN32 OR CYGWIN)
|
||||
if (GCC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
|
||||
endif()
|
||||
endif()
|
||||
elseif (INTEL)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STD17_FLAG}")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
add_definitions(-DNTDDI_VERSION=0x06020000 -DWINVER=0x0602 -D_WIN32_WINNT=0x0602 -DPSAPI_VERSION=1 -DNOMINMAX -DUNICODE -D_UNICODE -DWIN32_LEAN_AND_MEAN)
|
||||
endif()
|
||||
if (CYGWIN)
|
||||
add_definitions(-D_DEFAULT_SOURCE=1 -DFD_SETSIZE=4096)
|
||||
endif()
|
||||
|
||||
# _FILE_OFFSET_BITS is broken in Android NDK r15, r15b and r17 and doesn't work prior to Android 7.0
|
||||
add_definitions(-D_FILE_OFFSET_BITS=64)
|
||||
|
||||
# _GNU_SOURCE might not be defined by g++
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lsocket -lnsl")
|
||||
if (ILLUMOS)
|
||||
add_definitions(-DTD_ILLUMOS=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(AddCXXCompilerFlag)
|
||||
if (NOT MSVC)
|
||||
add_cxx_compiler_flag("-Wall")
|
||||
add_cxx_compiler_flag("-Wextra")
|
||||
add_cxx_compiler_flag("-Wimplicit-fallthrough=2")
|
||||
add_cxx_compiler_flag("-Wpointer-arith")
|
||||
add_cxx_compiler_flag("-Wcast-qual")
|
||||
add_cxx_compiler_flag("-Wsign-compare")
|
||||
add_cxx_compiler_flag("-Wduplicated-branches")
|
||||
add_cxx_compiler_flag("-Wduplicated-cond")
|
||||
add_cxx_compiler_flag("-Walloc-zero")
|
||||
add_cxx_compiler_flag("-Wlogical-op")
|
||||
add_cxx_compiler_flag("-Wno-tautological-compare")
|
||||
add_cxx_compiler_flag("-Wpointer-arith")
|
||||
add_cxx_compiler_flag("-Wvla")
|
||||
add_cxx_compiler_flag("-Wnon-virtual-dtor")
|
||||
add_cxx_compiler_flag("-Wno-unused-parameter")
|
||||
add_cxx_compiler_flag("-Wconversion")
|
||||
add_cxx_compiler_flag("-Wno-sign-conversion")
|
||||
add_cxx_compiler_flag("-Wc++17-compat-pedantic")
|
||||
add_cxx_compiler_flag("-Wdeprecated")
|
||||
add_cxx_compiler_flag("-Wno-unused-command-line-argument")
|
||||
add_cxx_compiler_flag("-Qunused-arguments")
|
||||
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("-Wunused-member-function")
|
||||
add_cxx_compiler_flag("-Wunused-private-field")
|
||||
|
||||
# add_cxx_compiler_flag("-Werror")
|
||||
|
||||
# add_cxx_compiler_flag("-Wcast-align")
|
||||
|
||||
#std::int32_t <-> int and off_t <-> std::size_t/std::int64_t
|
||||
# add_cxx_compiler_flag("-Wuseless-cast")
|
||||
|
||||
#external headers like openssl
|
||||
# add_cxx_compiler_flag("-Wzero-as-null-pointer-constant")
|
||||
endif()
|
||||
|
||||
if (GCC)
|
||||
add_cxx_compiler_flag("-Wno-maybe-uninitialized") # too many false positives
|
||||
endif()
|
||||
if (WIN32 AND GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0))
|
||||
# warns about casts of function pointers returned by GetProcAddress
|
||||
add_cxx_compiler_flag("-Wno-cast-function-type")
|
||||
endif()
|
||||
if (GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0))
|
||||
# warns about a lot of "return std::move", which are not redundant for compilers without fix for DR 1579, i.e. GCC 4.9 or clang 3.8
|
||||
# see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579
|
||||
add_cxx_compiler_flag("-Wno-redundant-move")
|
||||
endif()
|
||||
if (GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0))
|
||||
add_cxx_compiler_flag("-Wno-stringop-overflow") # some false positives
|
||||
endif()
|
||||
if (CLANG AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5))
|
||||
# https://stackoverflow.com/questions/26744556/warning-returning-a-captured-reference-from-a-lambda
|
||||
add_cxx_compiler_flag("-Wno-return-stack-address")
|
||||
endif()
|
||||
if (GCC AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0))
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104030
|
||||
add_cxx_compiler_flag("-Wbidi-chars=none")
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
add_cxx_compiler_flag("-ftrack-macro-expansion=0")
|
||||
endif()
|
||||
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem /usr/include/c++/v1")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" PARENT_SCOPE)
|
||||
endfunction()
|
278
third-party/td/td/CMake/iOS.cmake
vendored
@ -1,278 +0,0 @@
|
||||
# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
|
||||
# files which are included with CMake 2.8.4
|
||||
# It has been altered for iOS development
|
||||
|
||||
# Options:
|
||||
#
|
||||
# IOS_PLATFORM = OS (default) or SIMULATOR
|
||||
# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
|
||||
# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
|
||||
# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
|
||||
#
|
||||
# IOS_ARCH = automatic(default) or "arch1;arch2" (e.q. "x86_64;arm64")
|
||||
# By default this value will be automatically chosen based on the IOS_PLATFORM value above.
|
||||
# If set manually, it will override the default and force to build those architectures only.
|
||||
#
|
||||
# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
|
||||
# By default this location is automatically chosen based on the IOS_PLATFORM value above.
|
||||
# If set manually, it will override the default location and force the user of a particular Developer Platform
|
||||
#
|
||||
# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
|
||||
# By default this location is automatically chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
|
||||
# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
|
||||
# If set manually, this will force the use of a specific SDK version
|
||||
|
||||
# Macros:
|
||||
#
|
||||
# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
|
||||
# A convenience macro for setting xcode specific properties on targets
|
||||
# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
|
||||
#
|
||||
# find_host_package (PROGRAM ARGS)
|
||||
# A macro used to find executable programs on the host system, not within the iOS environment.
|
||||
# Thanks to the android-cmake project for providing the command
|
||||
|
||||
# Standard settings
|
||||
set (CMAKE_SYSTEM_NAME Darwin)
|
||||
set (CMAKE_SYSTEM_VERSION 1)
|
||||
set (UNIX True)
|
||||
set (APPLE True)
|
||||
set (IOS True)
|
||||
|
||||
# Required as of cmake 2.8.10
|
||||
set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
|
||||
|
||||
# Determine the cmake host system version so we know where to find the iOS SDKs
|
||||
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
|
||||
if (CMAKE_UNAME)
|
||||
execute_process(COMMAND uname -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
|
||||
endif (CMAKE_UNAME)
|
||||
|
||||
# Force the compilers to gcc for iOS
|
||||
set (CMAKE_C_COMPILER /usr/bin/gcc)
|
||||
set (CMAKE_CXX_COMPILER /usr/bin/g++)
|
||||
set (CMAKE_AR ar CACHE FILEPATH "" FORCE)
|
||||
set (CMAKE_RANLIB ranlib CACHE FILEPATH "" FORCE)
|
||||
set (PKG_CONFIG_EXECUTABLE pkg-config CACHE FILEPATH "" FORCE)
|
||||
|
||||
# Setup iOS platform unless specified manually with IOS_PLATFORM
|
||||
if (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM "OS")
|
||||
endif (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
|
||||
|
||||
# Check the platform selection and setup for developer root
|
||||
if (IOS_PLATFORM STREQUAL "OS")
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
|
||||
set (XCODE_IOS_PLATFORM ios)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
|
||||
|
||||
set (APPLE_IOS True)
|
||||
elseif (IOS_PLATFORM STREQUAL "SIMULATOR")
|
||||
set (SIMULATOR_FLAG true)
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
|
||||
set (XCODE_IOS_PLATFORM ios-simulator)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
|
||||
|
||||
set (APPLE_IOS True)
|
||||
elseif (IOS_PLATFORM STREQUAL "WATCHOS")
|
||||
set (IOS_PLATFORM_LOCATION "WatchOS.platform")
|
||||
set (XCODE_IOS_PLATFORM watchos)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-watchos")
|
||||
|
||||
set (APPLE_WATCH True)
|
||||
elseif (IOS_PLATFORM STREQUAL "WATCHSIMULATOR")
|
||||
set (SIMULATOR_FLAG true)
|
||||
set (IOS_PLATFORM_LOCATION "WatchSimulator.platform")
|
||||
set (XCODE_IOS_PLATFORM watchos-simulator)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-watchsimulator")
|
||||
|
||||
set (APPLE_WATCH True)
|
||||
elseif (IOS_PLATFORM STREQUAL "TVOS")
|
||||
set (IOS_PLATFORM_LOCATION "AppleTvOS.platform")
|
||||
set (XCODE_IOS_PLATFORM tvos)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-appletvos")
|
||||
|
||||
set (APPLE_TV True)
|
||||
elseif (IOS_PLATFORM STREQUAL "TVSIMULATOR")
|
||||
set (SIMULATOR_FLAG true)
|
||||
set (IOS_PLATFORM_LOCATION "AppleTvSimulator.platform")
|
||||
set (XCODE_IOS_PLATFORM tvos-simulator)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-tvsimulator")
|
||||
|
||||
set (APPLE_TV True)
|
||||
elseif (IOS_PLATFORM STREQUAL "VISIONOS")
|
||||
set (IOS_PLATFORM_LOCATION "XROS.platform")
|
||||
set (XCODE_IOS_PLATFORM xros)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-xros")
|
||||
|
||||
set (APPLE_VISION True)
|
||||
elseif (IOS_PLATFORM STREQUAL "VISIONSIMULATOR")
|
||||
set (SIMULATOR_FLAG true)
|
||||
set (IOS_PLATFORM_LOCATION "XRSimulator.platform")
|
||||
set (XCODE_IOS_PLATFORM xros-simulator)
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-xrsimulator")
|
||||
|
||||
set (APPLE_VISION True)
|
||||
else (IOS_PLATFORM STREQUAL "OS")
|
||||
message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS, SIMULATOR, or WATCHOS.")
|
||||
endif ()
|
||||
|
||||
# All iOS/Darwin specific settings - some may be redundant
|
||||
set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
|
||||
set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
|
||||
set (CMAKE_SHARED_MODULE_PREFIX "lib")
|
||||
set (CMAKE_SHARED_MODULE_SUFFIX ".so")
|
||||
set (CMAKE_MODULE_EXISTS 1)
|
||||
set (CMAKE_DL_LIBS "")
|
||||
|
||||
set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
|
||||
set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
|
||||
set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
|
||||
set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
|
||||
|
||||
if (IOS_DEPLOYMENT_TARGET)
|
||||
set (XCODE_IOS_PLATFORM_VERSION_FLAGS "-m${XCODE_IOS_PLATFORM}-version-min=${IOS_DEPLOYMENT_TARGET}")
|
||||
endif()
|
||||
|
||||
set (CMAKE_SHARED_LINKER_FLAGS_INIT "-fapplication-extension")
|
||||
set (CMAKE_C_FLAGS_INIT "${XCODE_IOS_PLATFORM_VERSION_FLAGS}")
|
||||
# Hidden visibility is required for cxx on iOS
|
||||
set (CMAKE_CXX_FLAGS_INIT "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fvisibility-inlines-hidden")
|
||||
|
||||
set (CMAKE_C_LINK_FLAGS "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fapplication-extension -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
|
||||
set (CMAKE_CXX_LINK_FLAGS "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fapplication-extension -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
|
||||
|
||||
set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
|
||||
set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
|
||||
|
||||
# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
|
||||
# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
|
||||
# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
|
||||
# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
|
||||
if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||
find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
|
||||
endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||
|
||||
# Setup iOS deployment target
|
||||
set (IOS_DEPLOYMENT_TARGET ${IOS_DEPLOYMENT_TARGET} CACHE STRING "Minimum iOS version")
|
||||
|
||||
# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
|
||||
# Note Xcode 4.3 changed the installation location, choose the most recent one available
|
||||
execute_process(COMMAND /usr/bin/xcode-select -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set (XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||
set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||
if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||
if (EXISTS ${XCODE_POST_43_ROOT})
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
|
||||
elseif (EXISTS ${XCODE_PRE_43_ROOT})
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
|
||||
endif (EXISTS ${XCODE_POST_43_ROOT})
|
||||
endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
|
||||
|
||||
# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
|
||||
if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||
file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
|
||||
if (_CMAKE_IOS_SDKS)
|
||||
list (SORT _CMAKE_IOS_SDKS)
|
||||
list (REVERSE _CMAKE_IOS_SDKS)
|
||||
list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
|
||||
else (_CMAKE_IOS_SDKS)
|
||||
message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
|
||||
endif (_CMAKE_IOS_SDKS)
|
||||
message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
|
||||
endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||
set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
|
||||
|
||||
# Set the sysroot default to the most recent SDK
|
||||
set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
|
||||
|
||||
# Set the architectures unless specified manually with IOS_ARCH
|
||||
if (NOT DEFINED IOS_ARCH)
|
||||
if (IOS_PLATFORM STREQUAL "OS")
|
||||
set (IOS_ARCH "arm64")
|
||||
elseif (IOS_PLATFORM STREQUAL "SIMULATOR")
|
||||
set (IOS_ARCH "x86_64;arm64")
|
||||
elseif (IOS_PLATFORM STREQUAL "WATCHOS")
|
||||
set (IOS_ARCH "armv7k;arm64_32;arm64")
|
||||
|
||||
# Include C++ Standard Library for Xcode 15 builds.
|
||||
include_directories(SYSTEM "${CMAKE_IOS_SDK_ROOT}/usr/include/c++/v1")
|
||||
elseif (IOS_PLATFORM STREQUAL "WATCHSIMULATOR")
|
||||
set (IOS_ARCH "x86_64;arm64")
|
||||
|
||||
# Include C++ Standard Library for Xcode 15 builds.
|
||||
include_directories(SYSTEM "${CMAKE_IOS_SDK_ROOT}/usr/include/c++/v1")
|
||||
elseif (IOS_PLATFORM STREQUAL "TVOS")
|
||||
set (IOS_ARCH "arm64")
|
||||
elseif (IOS_PLATFORM STREQUAL "TVSIMULATOR")
|
||||
set (IOS_ARCH "x86_64;arm64")
|
||||
elseif (IOS_PLATFORM STREQUAL "VISIONOS")
|
||||
set (IOS_ARCH "arm64")
|
||||
elseif (IOS_PLATFORM STREQUAL "VISIONSIMULATOR")
|
||||
set (IOS_ARCH "x86_64;arm64")
|
||||
endif()
|
||||
endif()
|
||||
message (STATUS "The iOS architectures: ${IOS_ARCH}")
|
||||
|
||||
set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS")
|
||||
|
||||
# Set the find root to the iOS developer roots and to user defined paths
|
||||
set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE STRING "iOS find search path root")
|
||||
|
||||
# default to searching for frameworks first
|
||||
set (CMAKE_FIND_FRAMEWORK FIRST)
|
||||
|
||||
# set up the default search directories for frameworks
|
||||
set (CMAKE_SYSTEM_FRAMEWORK_PATH
|
||||
${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
|
||||
${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
|
||||
${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
|
||||
)
|
||||
|
||||
# only search the iOS sdks, not the remainder of the host filesystem
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
# This little macro lets you set any Xcode specific property
|
||||
macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
|
||||
set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
|
||||
endmacro (set_xcode_property)
|
||||
|
||||
# This macro lets you find executable programs on the host system
|
||||
macro (find_host_package)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
|
||||
set (IOS FALSE)
|
||||
|
||||
find_package(${ARGN})
|
||||
|
||||
set (IOS TRUE)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endmacro (find_host_package)
|
10
third-party/td/td/CMake/illumos.cmake
vendored
@ -1,10 +0,0 @@
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
|
||||
#
|
||||
# Determine if the host is running an illumos distribution:
|
||||
#
|
||||
execute_process(COMMAND /usr/bin/uname -o OUTPUT_VARIABLE UNAME_O OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if (UNAME_O STREQUAL "illumos")
|
||||
set(ILLUMOS 1)
|
||||
endif()
|
||||
endif()
|
1449
third-party/td/td/CMakeLists.txt
vendored
2473
third-party/td/td/Doxyfile
vendored
23
third-party/td/td/LICENSE_1_0.txt
vendored
@ -1,23 +0,0 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
145
third-party/td/td/README.md
vendored
@ -1,145 +0,0 @@
|
||||
# TDLib
|
||||
|
||||
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.
|
||||
|
||||
## Table of Contents
|
||||
- [Features](#features)
|
||||
- [Examples and documentation](#usage)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Building](#building)
|
||||
- [Using in CMake C++ projects](#using-cxx)
|
||||
- [Using in Java projects](#using-java)
|
||||
- [Using in .NET projects](#using-dotnet)
|
||||
- [Using with other programming languages](#using-json)
|
||||
- [License](#license)
|
||||
|
||||
<a name="features"></a>
|
||||
## Features
|
||||
|
||||
`TDLib` has many advantages. Notably `TDLib` is:
|
||||
|
||||
* **Cross-platform**: `TDLib` can be used on Android, iOS, Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, illumos, Windows Phone, WebAssembly, watchOS, tvOS, visionOS, Tizen, Cygwin. It should also work on other *nix systems with or without minimal effort.
|
||||
* **Multilanguage**: `TDLib` can be easily used with any programming language that is able to execute C functions. Additionally, it already has native Java (using `JNI`) bindings and .NET (using `C++/CLI` and `C++/CX`) bindings.
|
||||
* **Easy to use**: `TDLib` takes care of all network implementation details, encryption and local data storage.
|
||||
* **High-performance**: in the [Telegram Bot API](https://core.telegram.org/bots/api), each `TDLib` instance handles more than 25000 active bots simultaneously.
|
||||
* **Well-documented**: all `TDLib` API methods and public interfaces are fully documented.
|
||||
* **Consistent**: `TDLib` guarantees that all updates are delivered in the right order.
|
||||
* **Reliable**: `TDLib` remains stable on slow and unreliable Internet connections.
|
||||
* **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="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).
|
||||
|
||||
See a [TDLib build instructions generator](https://tdlib.github.io/td/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)
|
||||
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>
|
||||
## Dependencies
|
||||
`TDLib` depends on:
|
||||
|
||||
* C++17 compatible compiler (Clang 5.0+, GCC 7.0+, MSVC 19.1+ (Visual Studio 2017.7+), Intel C++ Compiler 19+)
|
||||
* OpenSSL
|
||||
* zlib
|
||||
* gperf (build only)
|
||||
* CMake (3.10+, build only)
|
||||
* PHP (optional, for documentation generation)
|
||||
|
||||
<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).
|
||||
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:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
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
|
||||
before compiling main `TDLib` source code and compile only needed targets:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
cmake --build . --target prepare_cross_compiling
|
||||
cd ..
|
||||
php SplitSource.php
|
||||
cd build
|
||||
cmake --build . --target tdjson
|
||||
cmake --build . --target tdjson_static
|
||||
cd ..
|
||||
php SplitSource.php --undo
|
||||
```
|
||||
In our tests clang 6.0 with libc++ required less than 500 MB of RAM per file and GCC 4.9/6.3 used less than 1 GB of RAM per file.
|
||||
|
||||
<a name="using-cxx"></a>
|
||||
## Using in CMake C++ projects
|
||||
For C++ projects that use CMake, the best approach is to build `TDLib` as part of your project or to install it system-wide.
|
||||
|
||||
There are several libraries that you could use in your CMake project:
|
||||
|
||||
* Td::TdJson, Td::TdJsonStatic — dynamic and static version of a JSON interface. This has a simple C interface, so it 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 more information.
|
||||
* Td::TdStatic — static library with C++ interface for general usage.
|
||||
See [ClientManager](https://core.telegram.org/tdlib/docs/classtd_1_1_client_manager.html) and [Client](https://core.telegram.org/tdlib/docs/classtd_1_1_client.html) documentation for more information.
|
||||
|
||||
For example, part of your CMakeLists.txt may look like this:
|
||||
```
|
||||
add_subdirectory(td)
|
||||
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
|
||||
```
|
||||
|
||||
Or you could install `TDLib` and then reference it in your CMakeLists.txt like this:
|
||||
```
|
||||
find_package(Td 1.8.46 REQUIRED)
|
||||
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
|
||||
```
|
||||
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/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.
|
||||
|
||||
<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".
|
||||
|
||||
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:
|
||||
```
|
||||
git checkout td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h
|
||||
```
|
||||
|
||||
<a name="using-json"></a>
|
||||
## Using from other programming languages
|
||||
`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
|
||||
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.
|
||||
|
||||
<a name="license"></a>
|
||||
## License
|
||||
`TDLib` is licensed under the terms of the Boost Software License. See [LICENSE_1_0.txt](http://www.boost.org/LICENSE_1_0.txt) for more information.
|
511
third-party/td/td/SplitSource.php
vendored
@ -1,511 +0,0 @@
|
||||
<?php
|
||||
|
||||
function disjoint_set_find(&$parents, $x) {
|
||||
if ($parents[$x] !== $x) {
|
||||
return $parents[$x] = disjoint_set_find($parents, $parents[$x]);
|
||||
}
|
||||
return $x;
|
||||
}
|
||||
|
||||
function disjoint_set_union(&$parents, $x, $y) {
|
||||
$x = disjoint_set_find($parents, $x);
|
||||
$y = disjoint_set_find($parents, $y);
|
||||
|
||||
if ($x !== $y) {
|
||||
if (rand(0, 1) == 0) {
|
||||
$parents[$x] = $y;
|
||||
} else {
|
||||
$parents[$y] = $x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function split_file($file, $chunks, $undo) {
|
||||
$cpp_name = "$file.cpp";
|
||||
|
||||
echo "Processing file $cpp_name".PHP_EOL;
|
||||
|
||||
$new_files = array();
|
||||
foreach (range(0, $chunks - 1) as $n) {
|
||||
$new_files[] = "$file$n.cpp";
|
||||
}
|
||||
|
||||
$is_generated = (strpos($file, 'td/generate/') === 0);
|
||||
|
||||
$cmake_file = $is_generated ? 'td/generate/CMakeLists.txt' : 'CMakeLists.txt';
|
||||
$cmake = file_get_contents($cmake_file);
|
||||
|
||||
$cmake_cpp_name = $cpp_name;
|
||||
$cmake_new_files = $new_files;
|
||||
if ($is_generated) {
|
||||
foreach ($cmake_new_files as &$file_ref) {
|
||||
$file_ref = str_replace('td/generate/auto/td', '${TD_AUTO_INCLUDE_DIR}', $file_ref);
|
||||
}
|
||||
$cmake_cpp_name = str_replace('td/generate/auto/td', '${TD_AUTO_INCLUDE_DIR}', $cmake_cpp_name);
|
||||
}
|
||||
|
||||
if ($undo) {
|
||||
foreach ($new_files as $file) {
|
||||
if (file_exists($file)) {
|
||||
echo "Unlinking ".$file.PHP_EOL;
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($cmake, $cmake_cpp_name) === false) {
|
||||
$cmake = str_replace(implode(PHP_EOL.' ', $cmake_new_files), $cmake_cpp_name, $cmake);
|
||||
file_put_contents($cmake_file, $cmake);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($cmake, $cmake_cpp_name) !== false) {
|
||||
$cmake = str_replace($cmake_cpp_name, implode(PHP_EOL.' ', $cmake_new_files), $cmake);
|
||||
file_put_contents($cmake_file, $cmake);
|
||||
}
|
||||
|
||||
if (!file_exists($cpp_name)) {
|
||||
echo "ERROR: skip nonexistent file $cpp_name".PHP_EOL;
|
||||
return;
|
||||
}
|
||||
|
||||
$lines = file($cpp_name);
|
||||
$depth = 0;
|
||||
$target_depth = 1 + $is_generated;
|
||||
$is_static = false;
|
||||
$in_define = false;
|
||||
$in_comment = false;
|
||||
$current = '';
|
||||
$common = '';
|
||||
$functions = array();
|
||||
$namespace_begin = '';
|
||||
$namespace_end = '';
|
||||
foreach ($lines as $line) {
|
||||
$add_depth = strpos($line, 'namespace ') === 0 ? 1 : (strpos($line, '} // namespace') === 0 ? -1 : 0);
|
||||
if ($add_depth) {
|
||||
# namespace begin/end
|
||||
if ($add_depth > 0) {
|
||||
$depth += $add_depth;
|
||||
}
|
||||
if ($depth <= $target_depth) {
|
||||
if ($add_depth > 0) {
|
||||
$namespace_begin .= $line;
|
||||
} else {
|
||||
$namespace_end .= $line;
|
||||
}
|
||||
}
|
||||
if ($add_depth < 0) {
|
||||
$depth += $add_depth;
|
||||
}
|
||||
if ($is_static) {
|
||||
$common .= $current;
|
||||
} else {
|
||||
$functions[] = $current;
|
||||
}
|
||||
$common .= $line;
|
||||
$current = '';
|
||||
$is_static = false;
|
||||
$in_define = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($line, '#undef') === 0 && !trim($current)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($in_comment && strpos($line, '*/') === 0) {
|
||||
$in_comment = false;
|
||||
continue;
|
||||
}
|
||||
if (strpos($line, '/*') === 0) {
|
||||
$in_comment = true;
|
||||
}
|
||||
if ($in_comment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($depth !== $target_depth) {
|
||||
$common .= $line;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($line, 'static ') === 0 && $depth === $target_depth) {
|
||||
$is_static = true;
|
||||
}
|
||||
if (!trim($current) && strpos($line, '#define ') === 0) {
|
||||
$is_static = true;
|
||||
$in_define = true;
|
||||
}
|
||||
|
||||
$current .= $line;
|
||||
if ((strpos($line, '}') === 0 || ($in_define && !trim($line)) || preg_match('/^[a-z].*;\s*$/i', $line)) && $depth === $target_depth) {
|
||||
# block end
|
||||
if ($is_static) {
|
||||
$common .= $current;
|
||||
} else {
|
||||
$functions[] = $current;
|
||||
}
|
||||
$current = '';
|
||||
$is_static = false;
|
||||
$in_define = false;
|
||||
}
|
||||
}
|
||||
$current = trim($current);
|
||||
if (!empty($current)) {
|
||||
fwrite(STDERR, "ERROR: $current".PHP_EOL);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (count($functions) < $chunks) {
|
||||
fwrite(STDERR, "ERROR: file is too small to be split more".PHP_EOL);
|
||||
return;
|
||||
}
|
||||
|
||||
$deps = array(); // all functions from the same subarray must be in the same file
|
||||
$parents = array();
|
||||
foreach ($functions as $i => $f) {
|
||||
if (preg_match_all('/(?J)create_handler<(?<name>[A-Z][A-Za-z]*)>|'.
|
||||
'(?<name>[A-Z][A-Za-z]*) (final )?: public (Td::ResultHandler|Request)|'.
|
||||
'(CREATE_REQUEST|CREATE_NO_ARGS_REQUEST)[(](?<name>[A-Z][A-Za-z]*)|'.
|
||||
'(?<name>complete_pending_preauthentication_requests)|'.
|
||||
'(?<name>get_message_history_slice)|'.
|
||||
'(Up|Down)load(?!ManagerCallback)[a-zA-Z]+C(?<name>allback)|(up|down)load_[a-z_]*_c(?<name>allback)_|'.
|
||||
'(?<name>lazy_to_json)|'.
|
||||
'(?<name>LogEvent)[^sA]|'.
|
||||
'(?<name>parse)[(]|'.
|
||||
'(?<name>store)[(]/', $f, $matches, PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
$name = $match['name'];
|
||||
if ($name === 'parse' || $name === 'store') {
|
||||
if ($is_generated) {
|
||||
continue;
|
||||
}
|
||||
$name = 'LogEvent';
|
||||
}
|
||||
$deps[$name][] = $i;
|
||||
}
|
||||
}
|
||||
$parents[$i] = $i;
|
||||
}
|
||||
|
||||
foreach ($deps as $func_ids) {
|
||||
foreach ($func_ids as $func_id) {
|
||||
disjoint_set_union($parents, $func_ids[0], $func_id);
|
||||
}
|
||||
}
|
||||
$sets = array();
|
||||
$set_sizes = array();
|
||||
foreach ($functions as $i => $f) {
|
||||
$parent = disjoint_set_find($parents, $i);
|
||||
if (!isset($sets[$parent])) {
|
||||
$sets[$parent] = '';
|
||||
$set_sizes[$parent] = 0;
|
||||
}
|
||||
$sets[$parent] .= $f;
|
||||
$set_sizes[$parent] += strlen($f);
|
||||
}
|
||||
arsort($set_sizes);
|
||||
|
||||
$files = array_fill(0, $chunks, '');
|
||||
$file_sizes = array_fill(0, $chunks, 0);
|
||||
foreach ($set_sizes as $parent => $size) {
|
||||
$file_id = array_search(min($file_sizes), $file_sizes);
|
||||
$files[$file_id] .= $sets[$parent];
|
||||
$file_sizes[$file_id] += $size;
|
||||
}
|
||||
|
||||
foreach ($files as $n => $f) {
|
||||
$new_content = $common.$namespace_begin.$f.$namespace_end;
|
||||
|
||||
$std_methods = array();
|
||||
preg_match_all('/std::[a-z_0-9]*|td::unique(?!_)/', $new_content, $std_methods);
|
||||
$std_methods = array_unique($std_methods[0]);
|
||||
|
||||
$needed_std_headers = array();
|
||||
$type_headers = array(
|
||||
'std::move' => '',
|
||||
'std::vector' => '',
|
||||
'std::string' => '',
|
||||
'std::uint32_t' => '',
|
||||
'std::int32_t' => '',
|
||||
'std::int64_t' => '',
|
||||
'td::unique' => 'algorithm',
|
||||
'std::count_if' => 'algorithm',
|
||||
'std::fill' => 'algorithm',
|
||||
'std::find' => 'algorithm',
|
||||
'std::is_sorted' => 'algorithm',
|
||||
'std::lower_bound' => 'algorithm',
|
||||
'std::max' => 'algorithm',
|
||||
'std::merge' => 'algorithm',
|
||||
'std::min' => 'algorithm',
|
||||
'std::partial_sort' => 'algorithm',
|
||||
'std::partition' => 'algorithm',
|
||||
'std::remove' => 'algorithm',
|
||||
'std::reverse' => 'algorithm',
|
||||
'std::rotate' => 'algorithm',
|
||||
'std::sort' => 'algorithm',
|
||||
'std::stable_sort' => 'algorithm',
|
||||
'std::upper_bound' => 'algorithm',
|
||||
'std::abs' => 'cmath',
|
||||
'std::isfinite' => 'cmath',
|
||||
'std::function' => 'functional',
|
||||
'std::greater' => 'functional',
|
||||
'std::reference_wrapper' => 'functional',
|
||||
'std::make_move_iterator' => 'iterator',
|
||||
'std::numeric_limits' => 'limits',
|
||||
'std::map' => 'map',
|
||||
'std::multimap' => 'map',
|
||||
'std::make_shared' => 'memory',
|
||||
'std::shared_ptr' => 'memory',
|
||||
'std::multiset' => 'set',
|
||||
'std::set' => 'set',
|
||||
'std::get' => 'tuple',
|
||||
'std::make_tuple' => 'tuple',
|
||||
'std::tie' => 'tuple',
|
||||
'std::tuple' => 'tuple',
|
||||
'std::decay_t' => 'type_traits',
|
||||
'std::is_same' => 'type_traits',
|
||||
'std::unordered_map' => 'unordered_map',
|
||||
'std::unordered_set' => 'unordered_set',
|
||||
'std::make_pair' => 'utility',
|
||||
'std::pair' => 'utility',
|
||||
'std::swap' => 'utility');
|
||||
foreach ($type_headers as $type => $header) {
|
||||
if (in_array($type, $std_methods)) {
|
||||
$std_methods = array_diff($std_methods, array($type));
|
||||
if ($header && !in_array($header, $needed_std_headers)) {
|
||||
$needed_std_headers[] = $header;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$std_methods) { // know all needed std headers
|
||||
$new_content = preg_replace_callback(
|
||||
'/#include <([a-z_]*)>/',
|
||||
function ($matches) use ($needed_std_headers) {
|
||||
if (in_array($matches[1], $needed_std_headers)) {
|
||||
return $matches[0];
|
||||
}
|
||||
return '';
|
||||
},
|
||||
$new_content
|
||||
);
|
||||
}
|
||||
|
||||
$td_methods = array(
|
||||
'AccentColorId' => 'AccentColorId',
|
||||
'account_manager[_(-](?![.]get[(][)])|AccountManager[^;>]' => 'AccountManager',
|
||||
'AffiliateType' => 'AffiliateType',
|
||||
'alarm_manager[_(-](?![.]get[(][)])|AlarmManager' => 'AlarmManager',
|
||||
'animations_manager[_(-](?![.]get[(][)])|AnimationsManager[^;>]' => 'AnimationsManager',
|
||||
'attach_menu_manager[_(-](?![.]get[(][)])|AttachMenuManager[^;>]' => 'AttachMenuManager',
|
||||
'audios_manager[_(-](?![.]get[(][)])|AudiosManager' => 'AudiosManager',
|
||||
'auth_manager[_(-](?![.]get[(][)])|AuthManager' => 'AuthManager',
|
||||
'AutoDownloadSettings|[a-z_]*auto_download_settings' => 'AutoDownloadSettings',
|
||||
'autosave_manager[_(-](?![.]get[(][)])|AutosaveManager' => 'AutosaveManager',
|
||||
'BackgroundId' => 'BackgroundId',
|
||||
'background_manager[_(-](?![.]get[(][)])|BackgroundManager' => 'BackgroundManager',
|
||||
'BackgroundType' => 'BackgroundType',
|
||||
'Birthdate' => 'Birthdate',
|
||||
'boost_manager[_(-](?![.]get[(][)])|BoostManager' => 'BoostManager',
|
||||
'bot_info_manager[_(-](?![.]get[(][)])|BotInfoManager' => 'BotInfoManager',
|
||||
'BotMenuButton|[a-z_]*_menu_button' => 'BotMenuButton',
|
||||
'send_bot_custom_query|answer_bot_custom_query|set_bot_updates_status' => 'BotQueries',
|
||||
'bot_recommendation_manager[_(-](?![.]get[(][)])|BotRecommendationManager' => 'BotRecommendationManager',
|
||||
'BotVerification' => 'BotVerification',
|
||||
'BotVerifierSettings' => 'BotVerifierSettings',
|
||||
'BusinessAwayMessage' => 'BusinessAwayMessage',
|
||||
'BusinessBotRights' => 'BusinessBotRights',
|
||||
'BusinessChatLink' => 'BusinessChatLink',
|
||||
'BusinessConnectedBot' => 'BusinessConnectedBot',
|
||||
'BusinessConnectionId' => 'BusinessConnectionId',
|
||||
'business_connection_manager[_(-](?![.]get[(][)])|BusinessConnectionManager' => 'BusinessConnectionManager',
|
||||
'BusinessGreetingMessage' => 'BusinessGreetingMessage',
|
||||
'BusinessInfo|business_info' => 'BusinessInfo',
|
||||
'BusinessIntro' => 'BusinessIntro',
|
||||
'business_manager[_(-](?![.]get[(][)])|BusinessManager' => 'BusinessManager',
|
||||
'BusinessRecipients' => 'BusinessRecipients',
|
||||
'BusinessWorkHours' => 'BusinessWorkHours',
|
||||
'callback_queries_manager[_(-](?![.]get[(][)])|CallbackQueriesManager' => 'CallbackQueriesManager',
|
||||
'CallId' => 'CallId',
|
||||
'call_manager[_(-](?![.]get[(][)])|CallManager' => 'CallManager',
|
||||
'ChannelId' => 'ChannelId',
|
||||
'channel_recommendation_manager[_(-](?![.]get[(][)])|ChannelRecommendationManager' => 'ChannelRecommendationManager',
|
||||
'ChatId' => 'ChatId',
|
||||
'chat_manager[_(-](?![.]get[(][)])|ChatManager([^ ;.]| [^*])' => 'ChatManager',
|
||||
'common_dialog_manager[_(-](?![.]get[(][)])|CommonDialogManager' => 'CommonDialogManager',
|
||||
'connection_state_manager[_(-](?![.]get[(][)])|ConnectionStateManager' => 'ConnectionStateManager',
|
||||
'country_info_manager[_(-](?![.]get[(][)])|CountryInfoManager' => 'CountryInfoManager',
|
||||
'CustomEmojiId' => 'CustomEmojiId',
|
||||
'device_token_manager[_(-](?![.]get[(][)])|DeviceTokenManager' => 'DeviceTokenManager',
|
||||
'DialogAction[^M]' => 'DialogAction',
|
||||
'dialog_action_manager[_(-](?![.]get[(][)])|DialogActionManager' => 'DialogActionManager',
|
||||
'DialogFilter[^A-Z]' => 'DialogFilter',
|
||||
'DialogFilterId' => 'DialogFilterId',
|
||||
'dialog_filter_manager[_(-](?![.]get[(][)])|DialogFilterManager' => 'DialogFilterManager',
|
||||
'DialogId' => 'DialogId',
|
||||
'dialog_invite_link_manager[_(-](?![.]get[(][)])|DialogInviteLinkManager' => 'DialogInviteLinkManager',
|
||||
'DialogListId' => 'DialogListId',
|
||||
'DialogLocation' => 'DialogLocation',
|
||||
'dialog_manager[_(-](?![.]get[(][)])|DialogManager' => 'DialogManager',
|
||||
'DialogParticipantFilter' => 'DialogParticipantFilter',
|
||||
'dialog_participant_manager[_(-](?![.]get[(][)])|DialogParticipantManager' => 'DialogParticipantManager',
|
||||
'DialogSource' => 'DialogSource',
|
||||
'DisallowedGiftsSettings' => 'DisallowedGiftsSettings',
|
||||
'documents_manager[_(-](?![.]get[(][)])|DocumentsManager' => 'DocumentsManager',
|
||||
'download_manager[_(-](?![.]get[(][)])|DownloadManager[^C]' => 'DownloadManager',
|
||||
'DownloadManagerCallback' => 'DownloadManagerCallback',
|
||||
'EmailVerification' => 'EmailVerification',
|
||||
'EmojiGroup' => 'EmojiGroup',
|
||||
'FactCheck' => 'FactCheck',
|
||||
'file_reference_manager[_(-](?![.]get[(][)])|FileReferenceManager|file_references[)]' => 'FileReferenceManager',
|
||||
'file_manager[_(-](?![.]get[(][)])|FileManager([^ ;.]| [^*])|update_file[)]' => 'files/FileManager',
|
||||
'FolderId' => 'FolderId',
|
||||
'forum_topic_manager[_(-](?![.]get[(][)])|ForumTopicManager' => 'ForumTopicManager',
|
||||
'game_manager[_(-](?![.]get[(][)])|GameManager' => 'GameManager',
|
||||
'G[(][)]|Global[^A-Za-z]' => 'Global',
|
||||
'GlobalPrivacySettings' => 'GlobalPrivacySettings',
|
||||
'GroupCallId' => 'GroupCallId',
|
||||
'group_call_manager[_(-](?![.]get[(][)])|GroupCallManager' => 'GroupCallManager',
|
||||
'hashtag_hints[_(-](?![.]get[(][)])|HashtagHints' => 'HashtagHints',
|
||||
'inline_message_manager[_(-](?![.]get[(][)])|InlineMessageManager' => 'InlineMessageManager',
|
||||
'inline_queries_manager[_(-](?![.]get[(][)])|InlineQueriesManager' => 'InlineQueriesManager',
|
||||
'InputBusinessChatLink' => 'InputBusinessChatLink',
|
||||
'language_pack_manager[_(-]|LanguagePackManager' => 'LanguagePackManager',
|
||||
'link_manager[_(-](?![.]get[(][)])|LinkManager' => 'LinkManager',
|
||||
'LogeventIdWithGeneration|add_log_event|delete_log_event|get_erase_log_event_promise|parse_time|store_time' => 'logevent/LogEventHelper',
|
||||
'MessageCopyOptions' => 'MessageCopyOptions',
|
||||
'MessageEffectId' => 'MessageEffectId',
|
||||
'MessageForwardInfo|LastForwardedMessageInfo|forward_info' => 'MessageForwardInfo',
|
||||
'MessageFullId' => 'MessageFullId',
|
||||
'MessageId' => 'MessageId',
|
||||
'message_import_manager[_(-](?![.]get[(][)])|MessageImportManager' => 'MessageImportManager',
|
||||
'message_query_manager[_(-](?![.]get[(][)])|MessageQueryManager' => 'MessageQueryManager',
|
||||
'MessageLinkInfo' => 'MessageLinkInfo',
|
||||
'MessageQuote' => 'MessageQuote',
|
||||
'MessageReaction|UnreadMessageReaction|[a-z_]*message[a-z_]*reaction|reload_paid_reaction_privacy|get_chosen_tags' => 'MessageReaction',
|
||||
'MessageReactor' => 'MessageReactor',
|
||||
'MessageSearchOffset' => 'MessageSearchOffset',
|
||||
'[a-z_]*_message_sender' => 'MessageSender',
|
||||
'messages_manager[_(-](?![.]get[(][)])|MessagesManager' => 'MessagesManager',
|
||||
'MessageThreadInfo' => 'MessageThreadInfo',
|
||||
'MessageTtl' => 'MessageTtl',
|
||||
'MissingInvitee' => 'MissingInvitee',
|
||||
'notification_manager[_(-](?![.]get[(][)])|NotificationManager|notifications[)]' => 'NotificationManager',
|
||||
'notification_settings_manager[_(-](?![.]get[(][)])|NotificationSettingsManager' => 'NotificationSettingsManager',
|
||||
'online_manager[_(-](?![.]get[(][)])|OnlineManager' => 'OnlineManager',
|
||||
'option_manager[_(-](?![.]get[(][)])|OptionManager' => 'OptionManager',
|
||||
'PaidReactionType' => 'PaidReactionType',
|
||||
'password_manager[_(-](?![.]get[(][)])|PasswordManager' => 'PasswordManager',
|
||||
'people_nearby_manager[_(-](?![.]get[(][)])|PeopleNearbyManager' => 'PeopleNearbyManager',
|
||||
'phone_number_manager[_(-](?![.]get[(][)])|PhoneNumberManager' => 'PhoneNumberManager',
|
||||
'PhotoSizeSource' => 'PhotoSizeSource',
|
||||
'poll_manager[_(-](?![.]get[(][)])|PollManager' => 'PollManager',
|
||||
'privacy_manager[_(-](?![.]get[(][)])|PrivacyManager' => 'PrivacyManager',
|
||||
'promo_data_manager[_(-](?![.]get[(][)])|PromoDataManager' => 'PromoDataManager',
|
||||
'PublicDialogType|get_public_dialog_type' => 'PublicDialogType',
|
||||
'quick_reply_manager[_(-](?![.]get[(][)])|QuickReplyManager' => 'QuickReplyManager',
|
||||
'ReactionListType|[a-z_]*_reaction_list_type' => 'ReactionListType',
|
||||
'reaction_manager[_(-](?![.]get[(][)])|ReactionManager' => 'ReactionManager',
|
||||
'ReactionNotificationSettings' => 'ReactionNotificationSettings',
|
||||
'ReactionNotificationsFrom' => 'ReactionNotificationsFrom',
|
||||
'ReactionType|[a-z_]*_reaction_type' => 'ReactionType',
|
||||
'ReferralProgramInfo' => 'ReferralProgramInfo',
|
||||
'referral_program_manager[_(-](?![.]get[(][)])|ReferralProgramManager' => 'ReferralProgramManager',
|
||||
'ReferralProgramParameters' => 'ReferralProgramParameters',
|
||||
'RequestActor|RequestOnceActor' => 'RequestActor',
|
||||
'saved_messages_manager[_(-](?![.]get[(][)])|SavedMessagesManager' => 'SavedMessagesManager',
|
||||
'ScopeNotificationSettings|[a-z_]*_scope_notification_settings' => 'ScopeNotificationSettings',
|
||||
'SecretChatActor' => 'SecretChatActor',
|
||||
'secret_chats_manager[_(-]|SecretChatsManager' => 'SecretChatsManager',
|
||||
'secure_manager[_(-](?![.]get[(][)])|SecureManager' => 'SecureManager',
|
||||
'SentEmailCode' => 'SentEmailCode',
|
||||
'SharedDialog' => 'SharedDialog',
|
||||
'sponsored_message_manager[_(-](?![.]get[(][)])|SponsoredMessageManager' => 'SponsoredMessageManager',
|
||||
'StarAmount' => 'StarAmount',
|
||||
'StarGift[^A-Z]' => 'StarGift',
|
||||
'StarGiftAttribute' => 'StarGiftAttribute',
|
||||
'StarGiftId' => 'StarGiftId',
|
||||
'star_gift_manager[_(-](?![.]get[(][)])|StarGiftManager' => 'StarGiftManager',
|
||||
'StarGiftSettings' => 'StarGiftSettings',
|
||||
'star_manager[_(-](?![.]get[(][)])|StarManager' => 'StarManager',
|
||||
'StarSubscription[^P]' => 'StarSubscription',
|
||||
'StarSubscriptionPricing' => 'StarSubscriptionPricing',
|
||||
'state_manager[_(-](?![.]get[(][)])|StateManager' => 'StateManager',
|
||||
'statistics_manager[_(-](?![.]get[(][)])|StatisticsManager' => 'StatisticsManager',
|
||||
'StickerSetId' => 'StickerSetId',
|
||||
'stickers_manager[_(-](?![.]get[(][)])|StickersManager' => 'StickersManager',
|
||||
'storage_manager[_(-](?![.]get[(][)])|StorageManager' => 'StorageManager',
|
||||
'StoryId' => 'StoryId',
|
||||
'StoryListId' => 'StoryListId',
|
||||
'story_manager[_(-](?![.]get[(][)])|StoryManager' => 'StoryManager',
|
||||
'SuggestedAction|[a-z_]*_suggested_action' => 'SuggestedAction',
|
||||
'suggested_action_manager[_(-](?![.]get[(][)])|SuggestedActionManager' => 'SuggestedActionManager',
|
||||
'SynchronousRequests' => 'SynchronousRequests',
|
||||
'TargetDialogTypes' => 'TargetDialogTypes',
|
||||
'td_api' => 'td_api',
|
||||
'td_db[(][)]|TdDb[^A-Za-z]' => 'TdDb',
|
||||
'telegram_api' => 'telegram_api',
|
||||
'terms_of_service_manager[_(-](?![.]get[(][)])|TermsOfServiceManager' => 'TermsOfServiceManager',
|
||||
'theme_manager[_(-](?![.]get[(][)])|ThemeManager' => 'ThemeManager',
|
||||
'ThemeSettings' => 'ThemeSettings',
|
||||
'time_zone_manager[_(-](?![.]get[(][)])|TimeZoneManager' => 'TimeZoneManager',
|
||||
'TopDialogCategory|get_top_dialog_category' => 'TopDialogCategory',
|
||||
'top_dialog_manager[_(-](?![.]get[(][)])|TopDialogManager' => 'TopDialogManager',
|
||||
'translation_manager[_(-](?![.]get[(][)])|TranslationManager' => 'TranslationManager',
|
||||
'transcription_manager[_(-](?![.]get[(][)])|TranscriptionManager' => 'TranscriptionManager',
|
||||
'updates_manager[_(-](?![.]get[(][)])|UpdatesManager|get_difference[)]|updateSentMessage|dummyUpdate' => 'UpdatesManager',
|
||||
'UserId' => 'UserId',
|
||||
'user_manager[_(-](?![.]get[(][)])|UserManager([^ ;.]| [^*])' => 'UserManager',
|
||||
'UserStarGift' => 'UserStarGift',
|
||||
'video_notes_manager[_(-](?![.]get[(][)])|VideoNotesManager' => 'VideoNotesManager',
|
||||
'videos_manager[_(-](?![.]get[(][)])|VideosManager' => 'VideosManager',
|
||||
'voice_notes_manager[_(-](?![.]get[(][)])|VoiceNotesManager' => 'VoiceNotesManager',
|
||||
'web_app_manager[_(-](?![.]get[(][)])|WebAppManager' => 'WebAppManager',
|
||||
'WebAppOpenParameters' => 'WebAppOpenParameters',
|
||||
'WebPageId(Hash)?' => 'WebPageId',
|
||||
'web_pages_manager[_(-](?![.]get[(][)])|WebPagesManager' => 'WebPagesManager');
|
||||
|
||||
foreach ($td_methods as $pattern => $header) {
|
||||
if (strpos($cpp_name, $header) !== false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$include_name = '#include "td/telegram/'.$header.'.h"';
|
||||
if (strpos($new_content, $include_name) !== false && preg_match('/[^a-zA-Z0-9_]('.$pattern.')/', str_replace($include_name, '', $new_content)) === 0) {
|
||||
$new_content = str_replace($include_name, '', $new_content);
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_exists($new_files[$n]) || file_get_contents($new_files[$n]) !== $new_content) {
|
||||
echo "Writing file ".$new_files[$n].PHP_EOL;
|
||||
file_put_contents($new_files[$n], $new_content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('--help', $argv) || in_array('-h', $argv)) {
|
||||
echo "Usage: php SplitSource.php [OPTION]...\n".
|
||||
"Splits some source files to reduce a maximum amount of RAM needed for compiling a single file.\n".
|
||||
" -u, --undo Undo all source code changes.\n".
|
||||
" -h, --help Show this help.\n";
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$undo = in_array('--undo', $argv) || in_array('-u', $argv);
|
||||
$files = array('td/telegram/ChatManager' => 10,
|
||||
'td/telegram/MessagesManager' => 50,
|
||||
'td/telegram/NotificationManager' => 10,
|
||||
'td/telegram/Requests' => 50,
|
||||
'td/telegram/StickersManager' => 10,
|
||||
'td/telegram/StoryManager' => 10,
|
||||
'td/telegram/UpdatesManager' => 10,
|
||||
'td/telegram/UserManager' => 10,
|
||||
'td/generate/auto/td/telegram/td_api' => 10,
|
||||
'td/generate/auto/td/telegram/td_api_json' => 10,
|
||||
'td/generate/auto/td/telegram/telegram_api' => 10);
|
||||
|
||||
foreach ($files as $file => $chunks) {
|
||||
split_file($file, $chunks, $undo);
|
||||
}
|
8
third-party/td/td/TdConfig.cmake
vendored
@ -1,8 +0,0 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
#TODO: write all external dependencies
|
||||
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/TdTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/TdTargets.cmake")
|
||||
endif()
|
||||
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/TdStaticTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/TdStaticTargets.cmake")
|
||||
endif()
|
93
third-party/td/td/benchmark/CMakeLists.txt
vendored
@ -1,93 +0,0 @@
|
||||
if ((CMAKE_MAJOR_VERSION LESS 3) OR (CMAKE_VERSION VERSION_LESS "3.10"))
|
||||
message(FATAL_ERROR "CMake >= 3.10 is required")
|
||||
endif()
|
||||
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
# TODO: all benchmarks in one file
|
||||
add_executable(bench_crypto bench_crypto.cpp)
|
||||
target_link_libraries(bench_crypto PRIVATE tdutils ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES})
|
||||
if (WIN32)
|
||||
if (MINGW)
|
||||
target_link_libraries(bench_crypto PRIVATE ws2_32 mswsock crypt32)
|
||||
else()
|
||||
target_link_libraries(bench_crypto PRIVATE ws2_32 Mswsock Crypt32)
|
||||
endif()
|
||||
endif()
|
||||
target_include_directories(bench_crypto SYSTEM PRIVATE ${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
add_executable(bench_actor bench_actor.cpp)
|
||||
target_link_libraries(bench_actor PRIVATE tdactor tdutils)
|
||||
|
||||
add_executable(bench_http bench_http.cpp)
|
||||
target_link_libraries(bench_http PRIVATE tdnet tdutils)
|
||||
|
||||
add_executable(bench_http_server bench_http_server.cpp)
|
||||
target_link_libraries(bench_http_server PRIVATE tdnet tdutils)
|
||||
|
||||
add_executable(bench_http_server_cheat bench_http_server_cheat.cpp)
|
||||
target_link_libraries(bench_http_server_cheat PRIVATE tdnet tdutils)
|
||||
|
||||
add_executable(bench_http_server_fast bench_http_server_fast.cpp)
|
||||
target_link_libraries(bench_http_server_fast PRIVATE tdnet tdutils)
|
||||
|
||||
add_executable(bench_http_reader bench_http_reader.cpp)
|
||||
target_link_libraries(bench_http_reader PRIVATE tdnet tdutils)
|
||||
|
||||
add_executable(bench_handshake bench_handshake.cpp)
|
||||
target_link_libraries(bench_handshake PRIVATE tdmtproto tdutils)
|
||||
|
||||
add_executable(bench_db bench_db.cpp)
|
||||
target_link_libraries(bench_db PRIVATE tdactor tddb tdutils)
|
||||
|
||||
add_executable(bench_tddb bench_tddb.cpp)
|
||||
target_link_libraries(bench_tddb PRIVATE tdcore tddb tdutils)
|
||||
|
||||
add_executable(bench_misc bench_misc.cpp)
|
||||
target_link_libraries(bench_misc PRIVATE tdcore tdutils)
|
||||
|
||||
add_executable(check_proxy check_proxy.cpp)
|
||||
target_link_libraries(check_proxy PRIVATE tdclient tdutils)
|
||||
|
||||
add_executable(check_tls check_tls.cpp)
|
||||
target_link_libraries(check_tls PRIVATE tdutils)
|
||||
|
||||
add_executable(rmdir rmdir.cpp)
|
||||
target_link_libraries(rmdir PRIVATE tdutils)
|
||||
|
||||
add_executable(wget wget.cpp)
|
||||
target_link_libraries(wget PRIVATE tdnet tdutils)
|
||||
|
||||
add_executable(bench_empty bench_empty.cpp)
|
||||
target_link_libraries(bench_empty PRIVATE tdutils)
|
||||
|
||||
if (NOT WIN32 AND NOT CYGWIN)
|
||||
add_executable(bench_log bench_log.cpp)
|
||||
target_link_libraries(bench_log PRIVATE tdutils)
|
||||
|
||||
set_source_files_properties(bench_queue.cpp PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations)
|
||||
add_executable(bench_queue bench_queue.cpp)
|
||||
target_link_libraries(bench_queue PRIVATE tdutils)
|
||||
endif()
|
||||
|
||||
if (TD_TEST_FOLLY AND TD_WITH_ABSEIL)
|
||||
find_package(ABSL QUIET)
|
||||
find_package(folly QUIET)
|
||||
find_package(gflags QUIET)
|
||||
|
||||
if (ABSL_FOUND AND folly_FOUND)
|
||||
add_executable(memory-hashset-memprof EXCLUDE_FROM_ALL hashset_memory.cpp)
|
||||
target_compile_definitions(memory-hashset-memprof PRIVATE USE_MEMPROF=1)
|
||||
target_link_libraries(memory-hashset-memprof PRIVATE tdutils memprof_stat Folly::folly absl::flat_hash_map absl::hash)
|
||||
|
||||
add_executable(memory-hashset-os hashset_memory.cpp)
|
||||
target_compile_definitions(memory-hashset-os PRIVATE USE_MEMPROF=0)
|
||||
target_link_libraries(memory-hashset-os PRIVATE tdutils Folly::folly absl::flat_hash_map absl::hash)
|
||||
|
||||
add_executable(hashmap-build hashmap_build.cpp)
|
||||
target_link_libraries(hashmap-build PRIVATE tdutils Folly::folly absl::flat_hash_map absl::hash)
|
||||
endif()
|
||||
endif()
|
349
third-party/td/td/benchmark/bench_actor.cpp
vendored
@ -1,349 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/actor/actor.h"
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
|
||||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
|
||||
#if TD_MSVC
|
||||
#pragma comment(linker, "/STACK:16777216")
|
||||
#endif
|
||||
|
||||
struct TestActor final : public td::Actor {
|
||||
static td::int32 actor_count_;
|
||||
|
||||
void start_up() final {
|
||||
actor_count_++;
|
||||
stop();
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
if (--actor_count_ == 0) {
|
||||
td::Scheduler::instance()->finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
td::int32 TestActor::actor_count_;
|
||||
|
||||
namespace td {
|
||||
template <>
|
||||
class ActorTraits<TestActor> {
|
||||
public:
|
||||
static constexpr bool need_context = false;
|
||||
static constexpr bool need_start_up = true;
|
||||
};
|
||||
} // namespace td
|
||||
|
||||
class CreateActorBench final : public td::Benchmark {
|
||||
td::unique_ptr<td::ConcurrentScheduler> scheduler_;
|
||||
|
||||
void start_up() final {
|
||||
scheduler_ = td::make_unique<td::ConcurrentScheduler>(0, 0);
|
||||
scheduler_->start();
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
scheduler_->finish();
|
||||
scheduler_.reset();
|
||||
}
|
||||
|
||||
public:
|
||||
td::string get_description() const final {
|
||||
return "CreateActor";
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
scheduler_->create_actor_unsafe<TestActor>(0, "TestActor").release();
|
||||
}
|
||||
while (scheduler_->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <int type>
|
||||
class RingBench final : public td::Benchmark {
|
||||
public:
|
||||
struct PassActor;
|
||||
|
||||
private:
|
||||
int actor_n_ = -1;
|
||||
int thread_n_ = -1;
|
||||
td::vector<td::ActorId<PassActor>> actor_array_;
|
||||
td::unique_ptr<td::ConcurrentScheduler> scheduler_;
|
||||
|
||||
public:
|
||||
td::string get_description() const final {
|
||||
static const char *types[] = {"later", "immediate", "raw", "tail", "lambda"};
|
||||
static_assert(0 <= type && type < 5, "");
|
||||
return PSTRING() << "Ring (send_" << types[type] << ") (threads_n = " << thread_n_ << ")";
|
||||
}
|
||||
|
||||
struct PassActor final : public td::Actor {
|
||||
int id = -1;
|
||||
td::ActorId<PassActor> next_actor;
|
||||
int start_n = 0;
|
||||
|
||||
void pass(int n) {
|
||||
// LOG(INFO) << "Pass: " << n;
|
||||
if (n == 0) {
|
||||
td::Scheduler::instance()->finish();
|
||||
} else {
|
||||
if (type == 0) {
|
||||
send_closure_later(next_actor, &PassActor::pass, n - 1);
|
||||
} else if (type == 1) {
|
||||
send_closure(next_actor, &PassActor::pass, n - 1);
|
||||
} else if (type == 2) {
|
||||
send_event(next_actor, td::Event::raw(static_cast<td::uint32>(n - 1)));
|
||||
} else if (type == 3) {
|
||||
if (n % 5000 == 0) {
|
||||
send_closure_later(next_actor, &PassActor::pass, n - 1);
|
||||
} else {
|
||||
// TODO: it is three times faster than send_event
|
||||
// maybe send event could be further optimized?
|
||||
next_actor.get_actor_unsafe()->raw_event(td::Event::raw(static_cast<td::uint32>(n - 1)).data);
|
||||
}
|
||||
} else if (type == 4) {
|
||||
send_lambda(next_actor, [n, ptr = next_actor.get_actor_unsafe()] { ptr->pass(n - 1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void raw_event(const td::Event::Raw &raw) final {
|
||||
pass(static_cast<int>(raw.u32));
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
yield();
|
||||
}
|
||||
void wakeup() final {
|
||||
if (start_n != 0) {
|
||||
int n = start_n;
|
||||
start_n = 0;
|
||||
pass(n);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RingBench(int actor_n, int thread_n) : actor_n_(actor_n), thread_n_(thread_n) {
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
scheduler_ = td::make_unique<td::ConcurrentScheduler>(thread_n_, 0);
|
||||
|
||||
actor_array_ = td::vector<td::ActorId<PassActor>>(actor_n_);
|
||||
for (int i = 0; i < actor_n_; i++) {
|
||||
actor_array_[i] =
|
||||
scheduler_->create_actor_unsafe<PassActor>(thread_n_ ? i % thread_n_ : 0, "PassActor").release();
|
||||
actor_array_[i].get_actor_unsafe()->id = i;
|
||||
}
|
||||
for (int i = 0; i < actor_n_; i++) {
|
||||
actor_array_[i].get_actor_unsafe()->next_actor = actor_array_[(i + 1) % actor_n_];
|
||||
}
|
||||
scheduler_->start();
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
// first actor is on main_thread
|
||||
actor_array_[0].get_actor_unsafe()->start_n = td::max(n, 100);
|
||||
while (scheduler_->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
scheduler_->finish();
|
||||
scheduler_.reset();
|
||||
}
|
||||
};
|
||||
|
||||
template <int type>
|
||||
class QueryBench final : public td::Benchmark {
|
||||
public:
|
||||
td::string get_description() const final {
|
||||
static const char *types[] = {"callback", "immediate future", "delayed future", "dummy", "lambda", "lambda_future"};
|
||||
static_assert(0 <= type && type < 6, "");
|
||||
return PSTRING() << "QueryBench: " << types[type];
|
||||
}
|
||||
|
||||
class ClientActor final : public td::Actor {
|
||||
public:
|
||||
class Callback {
|
||||
public:
|
||||
Callback() = default;
|
||||
Callback(const Callback &) = delete;
|
||||
Callback &operator=(const Callback &) = delete;
|
||||
Callback(Callback &&) = delete;
|
||||
Callback &operator=(Callback &&) = delete;
|
||||
virtual ~Callback() = default;
|
||||
virtual void on_result(int x) = 0;
|
||||
};
|
||||
explicit ClientActor(td::unique_ptr<Callback> callback) : callback_(std::move(callback)) {
|
||||
}
|
||||
void f(int x) {
|
||||
callback_->on_result(x * x);
|
||||
}
|
||||
void dummy(int x, int *y) {
|
||||
*y = x * x;
|
||||
}
|
||||
void f_immediate_promise(int x, td::PromiseActor<int> &&promise) {
|
||||
promise.set_value(x * x);
|
||||
}
|
||||
void f_promise(td::Promise<> promise) {
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
private:
|
||||
td::unique_ptr<Callback> callback_;
|
||||
};
|
||||
|
||||
class ServerActor final : public td::Actor {
|
||||
public:
|
||||
class ClientCallback final : public ClientActor::Callback {
|
||||
public:
|
||||
explicit ClientCallback(td::ActorId<ServerActor> server) : server_(server) {
|
||||
}
|
||||
void on_result(int x) final {
|
||||
send_closure(server_, &ServerActor::on_result, x);
|
||||
}
|
||||
|
||||
private:
|
||||
td::ActorId<ServerActor> server_;
|
||||
};
|
||||
void start_up() final {
|
||||
client_ = td::create_actor<ClientActor>("Client", td::make_unique<ClientCallback>(actor_id(this))).release();
|
||||
}
|
||||
|
||||
void on_result(int x) {
|
||||
CHECK(x == n_ * n_);
|
||||
wakeup();
|
||||
}
|
||||
|
||||
void wakeup() final {
|
||||
while (true) {
|
||||
if (n_ < 0) {
|
||||
td::Scheduler::instance()->finish();
|
||||
return;
|
||||
}
|
||||
n_--;
|
||||
if (type == 0) {
|
||||
send_closure(client_, &ClientActor::f, n_);
|
||||
return;
|
||||
} else if (type == 1) {
|
||||
td::PromiseActor<int> promise;
|
||||
td::FutureActor<int> future;
|
||||
init_promise_future(&promise, &future);
|
||||
send_closure(client_, &ClientActor::f_immediate_promise, n_, std::move(promise));
|
||||
CHECK(!future.is_ready());
|
||||
CHECK(!future.empty());
|
||||
CHECK(future.get_state() == td::FutureActor<int>::State::Waiting);
|
||||
// int val = future.move_as_ok();
|
||||
// CHECK(val == n_ * n_);
|
||||
} else if (type == 2) {
|
||||
td::PromiseActor<int> promise;
|
||||
init_promise_future(&promise, &future_);
|
||||
future_.set_event(td::EventCreator::raw(actor_id(), static_cast<td::uint64>(1)));
|
||||
send_closure(client_, &ClientActor::f_immediate_promise, n_, std::move(promise));
|
||||
return;
|
||||
} else if (type == 3) {
|
||||
int res;
|
||||
send_closure(client_, &ClientActor::dummy, n_, &res);
|
||||
} else if (type == 4) {
|
||||
int val = 0;
|
||||
send_lambda(client_, [&] { val = n_ * n_; });
|
||||
CHECK(val == 0 || val == n_ * n_);
|
||||
} else if (type == 5) {
|
||||
send_closure(client_, &ClientActor::f_promise,
|
||||
td::PromiseCreator::lambda([actor_id = actor_id(this), n = n_](td::Unit) {
|
||||
send_closure(actor_id, &ServerActor::result, n * n);
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run(int n) {
|
||||
n_ = n;
|
||||
wakeup();
|
||||
}
|
||||
|
||||
void raw_event(const td::Event::Raw &event) final {
|
||||
int val = future_.move_as_ok();
|
||||
CHECK(val == n_ * n_);
|
||||
wakeup();
|
||||
}
|
||||
void result(int val) {
|
||||
CHECK(val == n_ * n_);
|
||||
wakeup();
|
||||
}
|
||||
|
||||
private:
|
||||
td::ActorId<ClientActor> client_;
|
||||
int n_ = 0;
|
||||
td::FutureActor<int> future_;
|
||||
};
|
||||
|
||||
void start_up() final {
|
||||
scheduler_ = td::make_unique<td::ConcurrentScheduler>(0, 0);
|
||||
|
||||
server_ = scheduler_->create_actor_unsafe<ServerActor>(0, "Server");
|
||||
scheduler_->start();
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
// first actor is on main_thread
|
||||
{
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
send_closure(server_, &ServerActor::run, n);
|
||||
}
|
||||
while (scheduler_->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
server_.release();
|
||||
scheduler_->finish();
|
||||
scheduler_.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
td::unique_ptr<td::ConcurrentScheduler> scheduler_;
|
||||
td::ActorOwn<ServerActor> server_;
|
||||
};
|
||||
|
||||
int main() {
|
||||
td::init_openssl_threads();
|
||||
|
||||
bench(CreateActorBench());
|
||||
bench(RingBench<4>(504, 0));
|
||||
bench(RingBench<3>(504, 0));
|
||||
bench(RingBench<0>(504, 0));
|
||||
bench(RingBench<1>(504, 0));
|
||||
bench(RingBench<2>(504, 0));
|
||||
bench(QueryBench<5>());
|
||||
bench(QueryBench<4>());
|
||||
bench(QueryBench<3>());
|
||||
bench(QueryBench<2>());
|
||||
bench(QueryBench<1>());
|
||||
bench(QueryBench<0>());
|
||||
bench(RingBench<3>(504, 0));
|
||||
bench(RingBench<0>(504, 10));
|
||||
bench(RingBench<1>(504, 10));
|
||||
bench(RingBench<2>(504, 10));
|
||||
bench(RingBench<0>(504, 2));
|
||||
bench(RingBench<1>(504, 2));
|
||||
bench(RingBench<2>(504, 2));
|
||||
}
|
528
third-party/td/td/benchmark/bench_crypto.cpp
vendored
@ -1,528 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/utils/benchmark.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/port/thread.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
#include "td/utils/UInt.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static constexpr std::size_t DATA_SIZE = 8 << 10;
|
||||
static constexpr std::size_t SHORT_DATA_SIZE = 64;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER <= 0x10100000L
|
||||
class SHA1Bench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "SHA1 OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
unsigned char md[20];
|
||||
SHA1(data, DATA_SIZE, md);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class SHA1ShortBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[SHORT_DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "SHA1 [" << SHORT_DATA_SIZE << "B]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
unsigned char md[20];
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::sha1(td::Slice(data, SHORT_DATA_SIZE), md);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SHA256ShortBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[SHORT_DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "SHA256 [" << SHORT_DATA_SIZE << "B]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
unsigned char md[32];
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::sha256(td::Slice(data, SHORT_DATA_SIZE), td::MutableSlice(md, 32));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SHA512ShortBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[SHORT_DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "SHA512 [" << SHORT_DATA_SIZE << "B]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
unsigned char md[64];
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::sha512(td::Slice(data, SHORT_DATA_SIZE), td::MutableSlice(md, 64));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class HmacSha256ShortBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[SHORT_DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "HMAC-SHA256 [" << SHORT_DATA_SIZE << "B]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
unsigned char md[32];
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::hmac_sha256(td::Slice(data, td::min(static_cast<std::size_t>(32), SHORT_DATA_SIZE)),
|
||||
td::Slice(data, SHORT_DATA_SIZE), td::MutableSlice(md, 32));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class HmacSha512ShortBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[SHORT_DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "HMAC-SHA512 [" << SHORT_DATA_SIZE << "B]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
unsigned char md[64];
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::hmac_sha512(td::Slice(data, td::min(static_cast<std::size_t>(64), SHORT_DATA_SIZE)),
|
||||
td::Slice(data, SHORT_DATA_SIZE), td::MutableSlice(md, 64));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AesEcbBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt256 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES ECB OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(key.raw, sizeof(key));
|
||||
td::Random::secure_bytes(iv.raw, sizeof(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::AesState state;
|
||||
state.init(td::as_slice(key), true);
|
||||
td::MutableSlice data_slice(data, DATA_SIZE);
|
||||
for (int i = 0; i <= n; i++) {
|
||||
size_t step = 16;
|
||||
for (size_t offset = 0; offset + step <= data_slice.size(); offset += step) {
|
||||
state.encrypt(data_slice.ubegin() + offset, data_slice.ubegin() + offset, static_cast<int>(step));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AesIgeEncryptBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt256 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES IGE OpenSSL encrypt [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(key.raw, sizeof(key));
|
||||
td::Random::secure_bytes(iv.raw, sizeof(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::MutableSlice data_slice(data, DATA_SIZE);
|
||||
td::AesIgeState state;
|
||||
state.init(as_slice(key), as_slice(iv), true);
|
||||
for (int i = 0; i < n; i++) {
|
||||
state.encrypt(data_slice, data_slice);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AesIgeDecryptBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt256 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES IGE OpenSSL decrypt [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(key.raw, sizeof(key));
|
||||
td::Random::secure_bytes(iv.raw, sizeof(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::MutableSlice data_slice(data, DATA_SIZE);
|
||||
td::AesIgeState state;
|
||||
state.init(as_slice(key), as_slice(iv), false);
|
||||
for (int i = 0; i < n; i++) {
|
||||
state.decrypt(data_slice, data_slice);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AesCtrBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt128 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES CTR OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(key.raw, sizeof(key));
|
||||
td::Random::secure_bytes(iv.raw, sizeof(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::MutableSlice data_slice(data, DATA_SIZE);
|
||||
td::AesCtrState state;
|
||||
state.init(as_slice(key), as_slice(iv));
|
||||
for (int i = 0; i < n; i++) {
|
||||
state.encrypt(data_slice, data_slice);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
class AesCtrOpenSSLBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt128 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES CTR RAW OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(key.raw, sizeof(key));
|
||||
td::Random::secure_bytes(iv.raw, sizeof(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), nullptr, key.raw, iv.raw);
|
||||
|
||||
td::MutableSlice data_slice(data, DATA_SIZE);
|
||||
td::AesCtrState state;
|
||||
state.init(as_slice(key), as_slice(iv));
|
||||
for (int i = 0; i < n; i++) {
|
||||
int len = 0;
|
||||
auto int_size = static_cast<int>(DATA_SIZE);
|
||||
EVP_EncryptUpdate(ctx, data_slice.ubegin(), &len, data_slice.ubegin(), int_size);
|
||||
CHECK(len == int_size);
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class AesCbcDecryptBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt128 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES CBC Decrypt OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(as_mutable_slice(key));
|
||||
td::Random::secure_bytes(as_mutable_slice(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::MutableSlice data_slice(data, DATA_SIZE);
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::aes_cbc_decrypt(as_slice(key), as_mutable_slice(iv), data_slice, data_slice);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class AesCbcEncryptBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt128 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES CBC Encrypt OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(as_mutable_slice(key));
|
||||
td::Random::secure_bytes(as_mutable_slice(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::MutableSlice data_slice(data, DATA_SIZE);
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::aes_cbc_encrypt(as_slice(key), as_mutable_slice(iv), data_slice, data_slice);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <bool use_state>
|
||||
class AesIgeShortBench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[SHORT_DATA_SIZE];
|
||||
td::UInt256 key;
|
||||
td::UInt256 iv;
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "AES IGE OpenSSL " << (use_state ? "EVP" : "C ") << "[" << SHORT_DATA_SIZE << "B]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
td::Random::secure_bytes(as_mutable_slice(key));
|
||||
td::Random::secure_bytes(as_mutable_slice(iv));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::MutableSlice data_slice(data, SHORT_DATA_SIZE);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (use_state) {
|
||||
td::AesIgeState ige;
|
||||
ige.init(as_slice(key), as_slice(iv), false);
|
||||
ige.decrypt(data_slice, data_slice);
|
||||
} else {
|
||||
td::aes_ige_decrypt(as_slice(key), as_mutable_slice(iv), data_slice, data_slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BENCH(Rand, "std_rand") {
|
||||
int res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res ^= std::rand();
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
BENCH(CppRand, "mt19937_rand") {
|
||||
std::uint_fast32_t res = 0;
|
||||
std::mt19937 g(123);
|
||||
for (int i = 0; i < n; i++) {
|
||||
res ^= g();
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
BENCH(TdRand32, "td_rand_fast32") {
|
||||
td::uint32 res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res ^= td::Random::fast_uint32();
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
BENCH(TdRandFast, "td_rand_fast") {
|
||||
int res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res ^= td::Random::fast(0, RAND_MAX);
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
#if !TD_THREAD_UNSUPPORTED
|
||||
BENCH(SslRand, "ssl_rand_int32") {
|
||||
std::vector<td::thread> v;
|
||||
std::atomic<td::uint32> sum{0};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
v.emplace_back([&sum, n] {
|
||||
td::int32 res = 0;
|
||||
for (int j = 0; j < n; j++) {
|
||||
res ^= td::Random::secure_int32();
|
||||
}
|
||||
sum += res;
|
||||
});
|
||||
}
|
||||
for (auto &x : v) {
|
||||
x.join();
|
||||
}
|
||||
v.clear();
|
||||
td::do_not_optimize_away(sum.load());
|
||||
}
|
||||
#endif
|
||||
|
||||
BENCH(SslRandBuf, "ssl_rand_bytes") {
|
||||
td::int32 res = 0;
|
||||
std::array<td::int32, 1000> buf;
|
||||
for (int i = 0; i < n; i += static_cast<int>(buf.size())) {
|
||||
td::Random::secure_bytes(reinterpret_cast<td::uint8 *>(buf.data()), sizeof(buf[0]) * buf.size());
|
||||
for (auto x : buf) {
|
||||
res ^= x;
|
||||
}
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
BENCH(Pbkdf2, "pbkdf2") {
|
||||
std::string password = "cucumber";
|
||||
std::string salt = "abcdefghijklmnopqrstuvw";
|
||||
std::string key(32, ' ');
|
||||
td::pbkdf2_sha256(password, salt, n, key);
|
||||
}
|
||||
|
||||
class Crc32Bench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "CRC32 zlib [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::uint64 res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res += td::crc32(td::Slice(data, DATA_SIZE));
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
};
|
||||
|
||||
class Crc64Bench final : public td::Benchmark {
|
||||
public:
|
||||
alignas(64) unsigned char data[DATA_SIZE];
|
||||
|
||||
std::string get_description() const final {
|
||||
return PSTRING() << "CRC64 Anton [" << (DATA_SIZE >> 10) << "KB]";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
std::fill(std::begin(data), std::end(data), static_cast<unsigned char>(123));
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
td::uint64 res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res += td::crc64(td::Slice(data, DATA_SIZE));
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
td::init_openssl_threads();
|
||||
td::bench(AesCtrBench());
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
td::bench(AesCtrOpenSSLBench());
|
||||
#endif
|
||||
|
||||
td::bench(AesCbcDecryptBench());
|
||||
td::bench(AesCbcEncryptBench());
|
||||
td::bench(AesIgeShortBench<true>());
|
||||
td::bench(AesIgeShortBench<false>());
|
||||
td::bench(AesIgeEncryptBench());
|
||||
td::bench(AesIgeDecryptBench());
|
||||
td::bench(AesEcbBench());
|
||||
|
||||
td::bench(Pbkdf2Bench());
|
||||
td::bench(RandBench());
|
||||
td::bench(CppRandBench());
|
||||
td::bench(TdRand32Bench());
|
||||
td::bench(TdRandFastBench());
|
||||
#if !TD_THREAD_UNSUPPORTED
|
||||
td::bench(SslRandBench());
|
||||
#endif
|
||||
td::bench(SslRandBufBench());
|
||||
#if OPENSSL_VERSION_NUMBER <= 0x10100000L
|
||||
td::bench(SHA1Bench());
|
||||
#endif
|
||||
td::bench(SHA1ShortBench());
|
||||
td::bench(SHA256ShortBench());
|
||||
td::bench(SHA512ShortBench());
|
||||
td::bench(HmacSha256ShortBench());
|
||||
td::bench(HmacSha512ShortBench());
|
||||
td::bench(Crc32Bench());
|
||||
td::bench(Crc64Bench());
|
||||
}
|
244
third-party/td/td/benchmark/bench_db.cpp
vendored
@ -1,244 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/db/binlog/Binlog.h"
|
||||
#include "td/db/binlog/ConcurrentBinlog.h"
|
||||
#include "td/db/BinlogKeyValue.h"
|
||||
#include "td/db/DbKey.h"
|
||||
#include "td/db/SeqKeyValue.h"
|
||||
#include "td/db/SqliteConnectionSafe.h"
|
||||
#include "td/db/SqliteDb.h"
|
||||
#include "td/db/SqliteKeyValueAsync.h"
|
||||
#include "td/db/SqliteKeyValueSafe.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
|
||||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
template <class KeyValueT>
|
||||
class TdKvBench final : public td::Benchmark {
|
||||
td::unique_ptr<td::ConcurrentScheduler> scheduler_;
|
||||
td::string name_;
|
||||
|
||||
public:
|
||||
explicit TdKvBench(td::string name) {
|
||||
name_ = std::move(name);
|
||||
}
|
||||
|
||||
td::string get_description() const final {
|
||||
return name_;
|
||||
}
|
||||
|
||||
class Main final : public td::Actor {
|
||||
public:
|
||||
explicit Main(int n) : n_(n) {
|
||||
}
|
||||
|
||||
private:
|
||||
void loop() final {
|
||||
KeyValueT::destroy("test_tddb").ignore();
|
||||
|
||||
class Worker final : public Actor {
|
||||
public:
|
||||
Worker(int n, td::string db_name) : n_(n) {
|
||||
kv_.init(db_name).ensure();
|
||||
}
|
||||
|
||||
private:
|
||||
void loop() final {
|
||||
for (int i = 0; i < n_; i++) {
|
||||
kv_.set(td::to_string(i % 10), td::to_string(i));
|
||||
}
|
||||
td::Scheduler::instance()->finish();
|
||||
}
|
||||
int n_;
|
||||
KeyValueT kv_;
|
||||
};
|
||||
td::create_actor_on_scheduler<Worker>("Worker", 0, n_, "test_tddb").release();
|
||||
}
|
||||
int n_;
|
||||
};
|
||||
|
||||
void start_up_n(int n) final {
|
||||
scheduler_ = td::make_unique<td::ConcurrentScheduler>(1, 0);
|
||||
scheduler_->create_actor_unsafe<Main>(1, "Main", n).release();
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
scheduler_->start();
|
||||
while (scheduler_->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
scheduler_->finish();
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
scheduler_.reset();
|
||||
}
|
||||
};
|
||||
|
||||
template <bool is_encrypted = false>
|
||||
class SqliteKVBench final : public td::Benchmark {
|
||||
td::SqliteDb db;
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "SqliteKV " << td::tag("is_encrypted", is_encrypted);
|
||||
}
|
||||
void start_up() final {
|
||||
td::string path = "testdb.sqlite";
|
||||
td::SqliteDb::destroy(path).ignore();
|
||||
if (is_encrypted) {
|
||||
db = td::SqliteDb::change_key(path, true, td::DbKey::password("cucumber"), td::DbKey::empty()).move_as_ok();
|
||||
} else {
|
||||
db = td::SqliteDb::open_with_key(path, true, td::DbKey::empty()).move_as_ok();
|
||||
}
|
||||
db.exec("PRAGMA encoding=\"UTF-8\"").ensure();
|
||||
db.exec("PRAGMA synchronous=NORMAL").ensure();
|
||||
db.exec("PRAGMA journal_mode=WAL").ensure();
|
||||
db.exec("PRAGMA temp_store=MEMORY").ensure();
|
||||
db.exec("DROP TABLE IF EXISTS KV").ensure();
|
||||
db.exec("CREATE TABLE IF NOT EXISTS KV (k BLOB PRIMARY KEY, v BLOB)").ensure();
|
||||
}
|
||||
void run(int n) final {
|
||||
auto stmt = db.get_statement("REPLACE INTO KV (k, v) VALUES(?1, ?2)").move_as_ok();
|
||||
db.exec("BEGIN TRANSACTION").ensure();
|
||||
for (int i = 0; i < n; i++) {
|
||||
auto key = td::to_string(i % 10);
|
||||
auto value = td::to_string(i);
|
||||
stmt.bind_blob(1, key).ensure();
|
||||
stmt.bind_blob(2, value).ensure();
|
||||
stmt.step().ensure();
|
||||
CHECK(!stmt.can_step());
|
||||
stmt.reset();
|
||||
|
||||
if (i % 10 == 0) {
|
||||
db.exec("COMMIT TRANSACTION").ensure();
|
||||
db.exec("BEGIN TRANSACTION").ensure();
|
||||
}
|
||||
}
|
||||
db.exec("COMMIT TRANSACTION").ensure();
|
||||
}
|
||||
};
|
||||
|
||||
static td::Status init_db(td::SqliteDb &db) {
|
||||
TRY_STATUS(db.exec("PRAGMA encoding=\"UTF-8\""));
|
||||
TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
|
||||
|
||||
TRY_STATUS(db.exec("PRAGMA synchronous=NORMAL"));
|
||||
TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY"));
|
||||
// TRY_STATUS(db.exec("PRAGMA secure_delete=1"));
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
class SqliteKeyValueAsyncBench final : public td::Benchmark {
|
||||
public:
|
||||
td::string get_description() const final {
|
||||
return "SqliteKeyValueAsync";
|
||||
}
|
||||
void start_up() final {
|
||||
do_start_up().ensure();
|
||||
scheduler_->start();
|
||||
}
|
||||
void run(int n) final {
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
auto key = td::to_string(i % 10);
|
||||
auto value = td::to_string(i);
|
||||
sqlite_kv_async_->set(key, value, td::Auto());
|
||||
}
|
||||
}
|
||||
void tear_down() final {
|
||||
scheduler_->run_main(0.1);
|
||||
{
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
sqlite_kv_async_.reset();
|
||||
sqlite_kv_safe_.reset();
|
||||
sql_connection_->close_and_destroy();
|
||||
}
|
||||
|
||||
scheduler_->finish();
|
||||
scheduler_.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
td::unique_ptr<td::ConcurrentScheduler> scheduler_;
|
||||
std::shared_ptr<td::SqliteConnectionSafe> sql_connection_;
|
||||
std::shared_ptr<td::SqliteKeyValueSafe> sqlite_kv_safe_;
|
||||
td::unique_ptr<td::SqliteKeyValueAsyncInterface> sqlite_kv_async_;
|
||||
|
||||
td::Status do_start_up() {
|
||||
scheduler_ = td::make_unique<td::ConcurrentScheduler>(1, 0);
|
||||
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
|
||||
td::string sql_db_name = "testdb.sqlite";
|
||||
td::SqliteDb::destroy(sql_db_name).ignore();
|
||||
td::SqliteDb::open_with_key(sql_db_name, true, td::DbKey::empty()).move_as_ok();
|
||||
|
||||
sql_connection_ = std::make_shared<td::SqliteConnectionSafe>(sql_db_name, td::DbKey::empty());
|
||||
auto &db = sql_connection_->get();
|
||||
TRY_STATUS(init_db(db));
|
||||
|
||||
sqlite_kv_safe_ = std::make_shared<td::SqliteKeyValueSafe>("common", sql_connection_);
|
||||
sqlite_kv_async_ = create_sqlite_key_value_async(sqlite_kv_safe_, 0);
|
||||
|
||||
return td::Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
class SeqKvBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return "SeqKvBench";
|
||||
}
|
||||
|
||||
td::SeqKeyValue kv;
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
kv.set(PSLICE() << i % 10, PSLICE() << i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <bool is_encrypted = false>
|
||||
class BinlogKeyValueBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "BinlogKeyValue " << td::tag("is_encrypted", is_encrypted);
|
||||
}
|
||||
|
||||
td::BinlogKeyValue<td::Binlog> kv;
|
||||
void start_up() final {
|
||||
td::SqliteDb::destroy("test_binlog").ignore();
|
||||
kv.init("test_binlog", is_encrypted ? td::DbKey::password("cucumber") : td::DbKey::empty()).ensure();
|
||||
}
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
kv.set(td::to_string(i % 10), td::to_string(i));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING));
|
||||
bench(TdKvBench<td::BinlogKeyValue<td::Binlog>>("BinlogKeyValue<Binlog>"));
|
||||
bench(TdKvBench<td::BinlogKeyValue<td::ConcurrentBinlog>>("BinlogKeyValue<ConcurrentBinlog>"));
|
||||
|
||||
bench(BinlogKeyValueBench<true>());
|
||||
bench(BinlogKeyValueBench<false>());
|
||||
bench(SqliteKVBench<false>());
|
||||
bench(SqliteKVBench<true>());
|
||||
bench(SqliteKeyValueAsyncBench());
|
||||
bench(SeqKvBench());
|
||||
}
|
8
third-party/td/td/benchmark/bench_empty.cpp
vendored
@ -1,8 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
int main() {
|
||||
}
|
72
third-party/td/td/benchmark/bench_handshake.cpp
vendored
@ -1,72 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/mtproto/DhCallback.h"
|
||||
#include "td/mtproto/DhHandshake.h"
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#if TD_LINUX || TD_ANDROID || TD_TIZEN
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
static td::int32 g = 3;
|
||||
static td::string prime_base64 =
|
||||
"xxyuucaxyQSObFIvcPE_c5gNQCOOPiHBSTTQN1Y9kw9IGYoKp8FAWCKUk9IlMPTb-jNvbgrJJROVQ67UTM58NyD9UfaUWHBaxozU_mtrE6vcl0ZRKW"
|
||||
"kyhFTxj6-MWV9kJHf-lrsqlB1bzR1KyMxJiAcI-ps3jjxPOpBgvuZ8-aSkppWBEFGQfhYnU7VrD2tBDbp02KhLKhSzFE4O8ShHVP0X7ZUNWWW0ud1G"
|
||||
"WC2xF40WnGvEZbDW_5yjko_vW5rk5Bj8Feg-vqD4f6n_Xu1wBQ3tKEn0e_lZ2VaFDOkphR8NgRX2NbEF7i5OFdBLJFS_b0-t8DSxBAMRnNjjuS_MW"
|
||||
"w";
|
||||
|
||||
class HandshakeBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return "Handshake";
|
||||
}
|
||||
|
||||
class FakeDhCallback final : public td::mtproto::DhCallback {
|
||||
public:
|
||||
int is_good_prime(td::Slice prime_str) const final {
|
||||
auto it = cache.find(prime_str.str());
|
||||
if (it == cache.end()) {
|
||||
return -1;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
void add_good_prime(td::Slice prime_str) const final {
|
||||
cache[prime_str.str()] = 1;
|
||||
}
|
||||
void add_bad_prime(td::Slice prime_str) const final {
|
||||
cache[prime_str.str()] = 0;
|
||||
}
|
||||
mutable std::map<td::string, int> cache;
|
||||
} dh_callback;
|
||||
|
||||
void run(int n) final {
|
||||
td::mtproto::DhHandshake a;
|
||||
td::mtproto::DhHandshake b;
|
||||
auto prime = td::base64url_decode(prime_base64).move_as_ok();
|
||||
td::mtproto::DhHandshake::check_config(g, prime, &dh_callback).ensure();
|
||||
for (int i = 0; i < n; i += 2) {
|
||||
a.set_config(g, prime);
|
||||
b.set_config(g, prime);
|
||||
b.set_g_a(a.get_g_b());
|
||||
a.set_g_a(b.get_g_b());
|
||||
a.run_checks(true, &dh_callback).ensure();
|
||||
b.run_checks(true, &dh_callback).ensure();
|
||||
auto a_key = a.gen_key();
|
||||
auto b_key = b.gen_key();
|
||||
CHECK(a_key.first == b_key.first);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
td::bench(HandshakeBench());
|
||||
}
|
77
third-party/td/td/benchmark/bench_http.cpp
vendored
@ -1,77 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/net/HttpOutboundConnection.h"
|
||||
#include "td/net/HttpQuery.h"
|
||||
#include "td/net/SslStream.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/BufferedFd.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
#include "td/utils/port/SocketFd.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
|
||||
std::atomic<int> counter;
|
||||
|
||||
class HttpClient final : public td::HttpOutboundConnection::Callback {
|
||||
void start_up() final {
|
||||
td::IPAddress addr;
|
||||
addr.init_ipv4_port("127.0.0.1", 8082).ensure();
|
||||
auto fd = td::SocketFd::open(addr);
|
||||
LOG_CHECK(fd.is_ok()) << fd.error();
|
||||
connection_ = td::create_actor<td::HttpOutboundConnection>(
|
||||
"Connect", td::BufferedFd<td::SocketFd>(fd.move_as_ok()), td::SslStream{}, std::numeric_limits<size_t>::max(),
|
||||
0, 0, td::ActorOwn<td::HttpOutboundConnection::Callback>(actor_id(this)));
|
||||
yield();
|
||||
cnt_ = 100000;
|
||||
counter++;
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
if (--counter == 0) {
|
||||
td::Scheduler::instance()->finish();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() final {
|
||||
if (cnt_-- < 0) {
|
||||
return stop();
|
||||
}
|
||||
send_closure(connection_, &td::HttpOutboundConnection::write_next, td::BufferSlice("GET / HTTP/1.1\r\n\r\n"));
|
||||
send_closure(connection_, &td::HttpOutboundConnection::write_ok);
|
||||
LOG(INFO) << "SEND";
|
||||
}
|
||||
|
||||
void handle(td::unique_ptr<td::HttpQuery> result) final {
|
||||
loop();
|
||||
}
|
||||
|
||||
void on_connection_error(td::Status error) final {
|
||||
LOG(ERROR) << "ERROR: " << error;
|
||||
}
|
||||
|
||||
td::ActorOwn<td::HttpOutboundConnection> connection_;
|
||||
int cnt_ = 0;
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
auto scheduler = td::make_unique<td::ConcurrentScheduler>(0, 0);
|
||||
scheduler->create_actor_unsafe<HttpClient>(0, "Client1").release();
|
||||
scheduler->create_actor_unsafe<HttpClient>(0, "Client2").release();
|
||||
scheduler->start();
|
||||
while (scheduler->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
scheduler->finish();
|
||||
}
|
119
third-party/td/td/benchmark/bench_http_reader.cpp
vendored
@ -1,119 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/net/HttpQuery.h"
|
||||
#include "td/net/HttpReader.h"
|
||||
|
||||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/find_boundary.h"
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
static std::string http_query = "GET / HTTP/1.1\r\nConnection:keep-alive\r\nhost:127.0.0.1:8080\r\n\r\n";
|
||||
static const size_t block_size = 2500;
|
||||
|
||||
class HttpReaderBench final : public td::Benchmark {
|
||||
std::string get_description() const final {
|
||||
return "HttpReaderBench";
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
auto cnt = static_cast<int>(block_size / http_query.size());
|
||||
td::HttpQuery q;
|
||||
int parsed = 0;
|
||||
int sent = 0;
|
||||
for (int i = 0; i < n; i += cnt) {
|
||||
for (int j = 0; j < cnt; j++) {
|
||||
writer_.append(http_query);
|
||||
sent++;
|
||||
}
|
||||
reader_.sync_with_writer();
|
||||
while (true) {
|
||||
auto wait = http_reader_.read_next(&q).ok();
|
||||
if (wait != 0) {
|
||||
break;
|
||||
}
|
||||
parsed++;
|
||||
}
|
||||
}
|
||||
CHECK(parsed == sent);
|
||||
}
|
||||
td::ChainBufferWriter writer_;
|
||||
td::ChainBufferReader reader_;
|
||||
td::HttpReader http_reader_;
|
||||
|
||||
void start_up() final {
|
||||
writer_ = {};
|
||||
reader_ = writer_.extract_reader();
|
||||
http_reader_.init(&reader_, 10000, 0);
|
||||
}
|
||||
};
|
||||
|
||||
class BufferBench final : public td::Benchmark {
|
||||
std::string get_description() const final {
|
||||
return "BufferBench";
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
auto cnt = static_cast<int>(block_size / http_query.size());
|
||||
for (int i = 0; i < n; i += cnt) {
|
||||
for (int j = 0; j < cnt; j++) {
|
||||
writer_.append(http_query);
|
||||
}
|
||||
reader_.sync_with_writer();
|
||||
for (int j = 0; j < cnt; j++) {
|
||||
auto result = reader_.cut_head(http_query.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
td::ChainBufferWriter writer_;
|
||||
td::ChainBufferReader reader_;
|
||||
td::HttpReader http_reader_;
|
||||
|
||||
void start_up() final {
|
||||
writer_ = {};
|
||||
reader_ = writer_.extract_reader();
|
||||
}
|
||||
};
|
||||
|
||||
class FindBoundaryBench final : public td::Benchmark {
|
||||
std::string get_description() const final {
|
||||
return "FindBoundaryBench";
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
auto cnt = static_cast<int>(block_size / http_query.size());
|
||||
for (int i = 0; i < n; i += cnt) {
|
||||
for (int j = 0; j < cnt; j++) {
|
||||
writer_.append(http_query);
|
||||
}
|
||||
reader_.sync_with_writer();
|
||||
for (int j = 0; j < cnt; j++) {
|
||||
size_t len = 0;
|
||||
find_boundary(reader_.clone(), "\r\n\r\n", len);
|
||||
CHECK(size_t(len) + 4 == http_query.size());
|
||||
auto result = reader_.cut_head(len + 2);
|
||||
reader_.advance(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
td::ChainBufferWriter writer_;
|
||||
td::ChainBufferReader reader_;
|
||||
td::HttpReader http_reader_;
|
||||
|
||||
void start_up() final {
|
||||
writer_ = {};
|
||||
reader_ = writer_.extract_reader();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING));
|
||||
td::bench(BufferBench());
|
||||
td::bench(FindBoundaryBench());
|
||||
td::bench(HttpReaderBench());
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/net/HttpHeaderCreator.h"
|
||||
#include "td/net/HttpInboundConnection.h"
|
||||
#include "td/net/HttpQuery.h"
|
||||
#include "td/net/TcpListener.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/BufferedFd.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/SocketFd.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
static int cnt = 0;
|
||||
|
||||
class HelloWorld final : public td::HttpInboundConnection::Callback {
|
||||
public:
|
||||
void handle(td::unique_ptr<td::HttpQuery> query, td::ActorOwn<td::HttpInboundConnection> connection) final {
|
||||
// LOG(ERROR) << *query;
|
||||
td::HttpHeaderCreator hc;
|
||||
td::Slice content = "hello world";
|
||||
//auto content = td::BufferSlice("hello world");
|
||||
hc.init_ok();
|
||||
hc.set_keep_alive();
|
||||
hc.set_content_size(content.size());
|
||||
hc.add_header("Server", "TDLib/test");
|
||||
hc.add_header("Date", "Thu Dec 14 01:41:50 2017");
|
||||
hc.add_header("Content-Type:", "text/html");
|
||||
|
||||
auto res = hc.finish(content);
|
||||
LOG_IF(FATAL, res.is_error()) << res.error();
|
||||
send_closure(connection, &td::HttpInboundConnection::write_next, td::BufferSlice(res.ok()));
|
||||
send_closure(connection.release(), &td::HttpInboundConnection::write_ok);
|
||||
}
|
||||
void hangup() final {
|
||||
LOG(ERROR) << "CLOSE " << cnt--;
|
||||
stop();
|
||||
}
|
||||
};
|
||||
|
||||
const int N = 0;
|
||||
class Server final : public td::TcpListener::Callback {
|
||||
public:
|
||||
void start_up() final {
|
||||
listener_ =
|
||||
td::create_actor<td::TcpListener>("Listener", 8082, td::ActorOwn<td::TcpListener::Callback>(actor_id(this)));
|
||||
}
|
||||
void accept(td::SocketFd fd) final {
|
||||
LOG(ERROR) << "ACCEPT " << cnt++;
|
||||
pos_++;
|
||||
auto scheduler_id = pos_ % (N != 0 ? N : 1) + (N != 0);
|
||||
td::create_actor_on_scheduler<td::HttpInboundConnection>(
|
||||
"HttpInboundConnection", scheduler_id, td::BufferedFd<td::SocketFd>(std::move(fd)), 1024 * 1024, 0, 0,
|
||||
td::create_actor_on_scheduler<HelloWorld>("HelloWorld", scheduler_id))
|
||||
.release();
|
||||
}
|
||||
void hangup() final {
|
||||
// may be it should be default?..
|
||||
LOG(ERROR) << "Hanging up..";
|
||||
stop();
|
||||
}
|
||||
|
||||
private:
|
||||
td::ActorOwn<td::TcpListener> listener_;
|
||||
int pos_{0};
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
auto scheduler = td::make_unique<td::ConcurrentScheduler>(N, 0);
|
||||
scheduler->create_actor_unsafe<Server>(0, "Server").release();
|
||||
scheduler->start();
|
||||
while (scheduler->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
scheduler->finish();
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/net/HttpHeaderCreator.h"
|
||||
#include "td/net/TcpListener.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/detail/PollableFd.h"
|
||||
#include "td/utils/port/SocketFd.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
static int cnt = 0;
|
||||
|
||||
class HelloWorld final : public td::Actor {
|
||||
public:
|
||||
explicit HelloWorld(td::SocketFd socket_fd) : socket_fd_(std::move(socket_fd)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::SocketFd socket_fd_;
|
||||
|
||||
std::array<char, 1024> read_buf;
|
||||
size_t read_new_lines{0};
|
||||
|
||||
td::string hello_;
|
||||
td::string write_buf_;
|
||||
size_t write_pos_{0};
|
||||
|
||||
void start_up() final {
|
||||
td::Scheduler::subscribe(socket_fd_.get_poll_info().extract_pollable_fd(this));
|
||||
td::HttpHeaderCreator hc;
|
||||
td::Slice content = "hello world";
|
||||
//auto content = td::BufferSlice("hello world");
|
||||
hc.init_ok();
|
||||
hc.set_keep_alive();
|
||||
hc.set_content_size(content.size());
|
||||
hc.add_header("Server", "TDLib/test");
|
||||
hc.add_header("Date", "Thu Dec 14 01:41:50 2017");
|
||||
hc.add_header("Content-Type:", "text/html");
|
||||
hello_ = hc.finish(content).ok().str();
|
||||
}
|
||||
|
||||
void loop() final {
|
||||
auto status = do_loop();
|
||||
if (status.is_error()) {
|
||||
td::Scheduler::unsubscribe(socket_fd_.get_poll_info().get_pollable_fd_ref());
|
||||
stop();
|
||||
LOG(ERROR) << "CLOSE: " << status;
|
||||
}
|
||||
}
|
||||
td::Status do_loop() {
|
||||
sync_with_poll(socket_fd_);
|
||||
TRY_STATUS(read_loop());
|
||||
TRY_STATUS(write_loop());
|
||||
if (can_close_local(socket_fd_)) {
|
||||
return td::Status::Error("CLOSE");
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Status write_loop() {
|
||||
while (can_write_local(socket_fd_) && write_pos_ < write_buf_.size()) {
|
||||
TRY_RESULT(written, socket_fd_.write(td::Slice(write_buf_).substr(write_pos_)));
|
||||
write_pos_ += written;
|
||||
if (write_pos_ == write_buf_.size()) {
|
||||
write_pos_ = 0;
|
||||
write_buf_.clear();
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Status read_loop() {
|
||||
while (can_read_local(socket_fd_)) {
|
||||
TRY_RESULT(read_size, socket_fd_.read(td::MutableSlice(read_buf.data(), read_buf.size())));
|
||||
for (size_t i = 0; i < read_size; i++) {
|
||||
if (read_buf[i] == '\n') {
|
||||
read_new_lines++;
|
||||
if (read_new_lines == 2) {
|
||||
read_new_lines = 0;
|
||||
write_buf_.append(hello_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
const int N = 0;
|
||||
class Server final : public td::TcpListener::Callback {
|
||||
public:
|
||||
void start_up() final {
|
||||
listener_ =
|
||||
td::create_actor<td::TcpListener>("Listener", 8082, td::ActorOwn<td::TcpListener::Callback>(actor_id(this)));
|
||||
}
|
||||
void accept(td::SocketFd fd) final {
|
||||
LOG(ERROR) << "ACCEPT " << cnt++;
|
||||
pos_++;
|
||||
auto scheduler_id = pos_ % (N != 0 ? N : 1) + (N != 0);
|
||||
td::create_actor_on_scheduler<HelloWorld>("HelloWorld", scheduler_id, std::move(fd)).release();
|
||||
}
|
||||
void hangup() final {
|
||||
// may be it should be default?..
|
||||
LOG(ERROR) << "Hanging up..";
|
||||
stop();
|
||||
}
|
||||
|
||||
private:
|
||||
td::ActorOwn<td::TcpListener> listener_;
|
||||
int pos_{0};
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
auto scheduler = td::make_unique<td::ConcurrentScheduler>(N, 0);
|
||||
scheduler->create_actor_unsafe<Server>(0, "Server").release();
|
||||
scheduler->start();
|
||||
while (scheduler->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
scheduler->finish();
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/net/HttpHeaderCreator.h"
|
||||
#include "td/net/HttpQuery.h"
|
||||
#include "td/net/HttpReader.h"
|
||||
#include "td/net/TcpListener.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/BufferedFd.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/detail/PollableFd.h"
|
||||
#include "td/utils/port/SocketFd.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
class HttpEchoConnection final : public td::Actor {
|
||||
public:
|
||||
explicit HttpEchoConnection(td::SocketFd fd) : fd_(std::move(fd)) {
|
||||
}
|
||||
|
||||
private:
|
||||
td::BufferedFd<td::SocketFd> fd_;
|
||||
td::HttpReader reader_;
|
||||
td::HttpQuery query_;
|
||||
void start_up() final {
|
||||
td::Scheduler::subscribe(fd_.get_poll_info().extract_pollable_fd(this));
|
||||
reader_.init(&fd_.input_buffer(), 1024 * 1024, 0);
|
||||
}
|
||||
void tear_down() final {
|
||||
td::Scheduler::unsubscribe_before_close(fd_.get_poll_info().get_pollable_fd_ref());
|
||||
fd_.close();
|
||||
}
|
||||
|
||||
void handle_query() {
|
||||
query_ = td::HttpQuery();
|
||||
td::HttpHeaderCreator hc;
|
||||
td::Slice content = "hello world";
|
||||
//auto content = td::BufferSlice("hello world");
|
||||
hc.init_ok();
|
||||
hc.set_keep_alive();
|
||||
hc.set_content_size(content.size());
|
||||
hc.add_header("Server", "TDLib/test");
|
||||
hc.add_header("Date", "Thu Dec 14 01:41:50 2017");
|
||||
hc.add_header("Content-Type:", "text/html");
|
||||
auto res = hc.finish(content);
|
||||
fd_.output_buffer().append(res.ok());
|
||||
}
|
||||
|
||||
void loop() final {
|
||||
sync_with_poll(fd_);
|
||||
auto status = [&] {
|
||||
TRY_STATUS(loop_read());
|
||||
TRY_STATUS(loop_write());
|
||||
return td::Status::OK();
|
||||
}();
|
||||
if (status.is_error() || can_close_local(fd_)) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
td::Status loop_read() {
|
||||
TRY_STATUS(fd_.flush_read());
|
||||
while (true) {
|
||||
TRY_RESULT(need, reader_.read_next(&query_));
|
||||
if (need == 0) {
|
||||
handle_query();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Status loop_write() {
|
||||
TRY_STATUS(fd_.flush_write());
|
||||
return td::Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
const int N = 8;
|
||||
class Server final : public td::TcpListener::Callback {
|
||||
public:
|
||||
void start_up() final {
|
||||
listener_ =
|
||||
td::create_actor<td::TcpListener>("Listener", 8082, td::ActorOwn<td::TcpListener::Callback>(actor_id(this)));
|
||||
}
|
||||
void accept(td::SocketFd fd) final {
|
||||
pos_++;
|
||||
auto scheduler_id = pos_ % (N != 0 ? N : 1) + (N != 0);
|
||||
td::create_actor_on_scheduler<HttpEchoConnection>("HttpEchoConnection", scheduler_id, std::move(fd)).release();
|
||||
}
|
||||
void hangup() final {
|
||||
LOG(ERROR) << "Hanging up..";
|
||||
stop();
|
||||
}
|
||||
|
||||
private:
|
||||
td::ActorOwn<td::TcpListener> listener_;
|
||||
int pos_{0};
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||
auto scheduler = td::make_unique<td::ConcurrentScheduler>(N, 0);
|
||||
scheduler->create_actor_unsafe<Server>(0, "Server").release();
|
||||
scheduler->start();
|
||||
while (scheduler->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
scheduler->finish();
|
||||
}
|
160
third-party/td/td/benchmark/bench_log.cpp
vendored
@ -1,160 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/utils/benchmark.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
std::string create_tmp_file() {
|
||||
#if TD_ANDROID
|
||||
std::string name = "/data/local/tmp/large_file.txt";
|
||||
unlink(name.c_str());
|
||||
return name;
|
||||
#else
|
||||
char file_name[] = "largefileXXXXXX";
|
||||
int fd = mkstemp(file_name);
|
||||
if (fd == -1) {
|
||||
perror("Can't cretate temporary file");
|
||||
}
|
||||
CHECK(fd != -1);
|
||||
|
||||
close(fd);
|
||||
return file_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
class IostreamWriteBench final : public td::Benchmark {
|
||||
protected:
|
||||
std::string file_name_;
|
||||
std::ofstream stream;
|
||||
static constexpr std::size_t BUFFER_SIZE = 1 << 20;
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
public:
|
||||
std::string get_description() const final {
|
||||
return "ostream (to file, no buf, no flush)";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
file_name_ = create_tmp_file();
|
||||
stream.open(file_name_.c_str());
|
||||
CHECK(stream.is_open());
|
||||
// stream.rdbuf()->pubsetbuf(buffer, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
stream << "This is just for test" << 987654321 << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
stream.close();
|
||||
unlink(file_name_.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
class FILEWriteBench final : public td::Benchmark {
|
||||
protected:
|
||||
std::string file_name_;
|
||||
FILE *file;
|
||||
static constexpr std::size_t BUFFER_SIZE = 1 << 20;
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
public:
|
||||
std::string get_description() const final {
|
||||
return "std::fprintf (to file, no buf, no flush)";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
file_name_ = create_tmp_file();
|
||||
file = fopen(file_name_.c_str(), "w");
|
||||
// setvbuf(file, buffer, _IOFBF, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
std::fprintf(file, "This is just for test%d\n", 987654321);
|
||||
// std::fflush(file);
|
||||
}
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
std::fclose(file);
|
||||
unlink(file_name_.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
#if TD_ANDROID
|
||||
#include <android/log.h>
|
||||
#define ALOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "XXX", __VA_ARGS__)
|
||||
class ALogWriteBench final : public td::Benchmark {
|
||||
public:
|
||||
std::string get_description() const final {
|
||||
return "android_log";
|
||||
}
|
||||
void start_up() final {
|
||||
}
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
ALOG("This is just for test%d\n", 987654321);
|
||||
}
|
||||
}
|
||||
void tear_down() final {
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class LogWriteBench final : public td::Benchmark {
|
||||
protected:
|
||||
std::string file_name_;
|
||||
std::ofstream stream;
|
||||
std::streambuf *old_buf;
|
||||
static constexpr std::size_t BUFFER_SIZE = 1 << 20;
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
public:
|
||||
std::string get_description() const final {
|
||||
return "td_log (slow in debug mode)";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
file_name_ = create_tmp_file();
|
||||
stream.open(file_name_.c_str());
|
||||
CHECK(stream.is_open());
|
||||
old_buf = std::cerr.rdbuf(stream.rdbuf());
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
LOG(DEBUG) << "This is just for test" << 987654321;
|
||||
}
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
stream.close();
|
||||
unlink(file_name_.c_str());
|
||||
std::cerr.rdbuf(old_buf);
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
td::bench(LogWriteBench());
|
||||
#if TD_ANDROID
|
||||
td::bench(ALogWriteBench());
|
||||
#endif
|
||||
td::bench(IostreamWriteBench());
|
||||
td::bench(FILEWriteBench());
|
||||
}
|
841
third-party/td/td/benchmark/bench_misc.cpp
vendored
@ -1,841 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/telegram_api.hpp"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/Clocks.h"
|
||||
#include "td/utils/port/EventFd.h"
|
||||
#include "td/utils/port/FileFd.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/port/RwMutex.h"
|
||||
#include "td/utils/port/Stat.h"
|
||||
#include "td/utils/port/thread.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
#include "td/utils/StackAllocator.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
#include "td/utils/ThreadSafeCounter.h"
|
||||
|
||||
#if !TD_WINDOWS
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#if TD_LINUX || TD_ANDROID || TD_TIZEN
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
|
||||
class F {
|
||||
td::uint32 ∑
|
||||
|
||||
public:
|
||||
explicit F(td::uint32 &sum) : sum(sum) {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void operator()(const T &x) const {
|
||||
sum += static_cast<td::uint32>(reinterpret_cast<std::uintptr_t>(&x));
|
||||
}
|
||||
};
|
||||
|
||||
BENCH(TlCall, "TL Call") {
|
||||
td::tl_object_ptr<td::telegram_api::Function> x = td::make_tl_object<td::telegram_api::account_getWallPapers>(0);
|
||||
td::uint32 res = 0;
|
||||
F f(res);
|
||||
for (int i = 0; i < n; i++) {
|
||||
downcast_call(*x, f);
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
static td::td_api::object_ptr<td::td_api::file> get_file_object() {
|
||||
return td::td_api::make_object<td::td_api::file>(
|
||||
12345, 123456, 123456,
|
||||
td::td_api::make_object<td::td_api::localFile>(
|
||||
"/android/data/0/data/org.telegram.data/files/photos/12345678901234567890_123.jpg", true, true, false, true,
|
||||
0, 123456, 123456),
|
||||
td::td_api::make_object<td::td_api::remoteFile>("abacabadabacabaeabacabadabacabafabacabadabacabaeabacabadabacaba",
|
||||
"abacabadabacabaeabacabadabacaba", false, true, 123456));
|
||||
}
|
||||
|
||||
BENCH(ToStringIntSmall, "to_string<int> small") {
|
||||
auto buf = td::StackAllocator::alloc(1000);
|
||||
td::StringBuilder sb(buf.as_slice());
|
||||
for (int i = 0; i < n; i++) {
|
||||
sb << td::Random::fast(0, 100);
|
||||
sb.clear();
|
||||
}
|
||||
}
|
||||
|
||||
BENCH(ToStringIntBig, "to_string<int> big") {
|
||||
auto buf = td::StackAllocator::alloc(1000);
|
||||
td::StringBuilder sb(buf.as_slice());
|
||||
for (int i = 0; i < n; i++) {
|
||||
sb << 1234567890;
|
||||
sb.clear();
|
||||
}
|
||||
}
|
||||
|
||||
BENCH(TlToStringUpdateFile, "TL to_string updateFile") {
|
||||
auto x = td::td_api::make_object<td::td_api::updateFile>(get_file_object());
|
||||
|
||||
std::size_t res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res += to_string(x).size();
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
BENCH(TlToStringMessage, "TL to_string message") {
|
||||
auto x = td::td_api::make_object<td::td_api::message>();
|
||||
x->id_ = 123456000111;
|
||||
x->sender_id_ = td::td_api::make_object<td::td_api::messageSenderUser>(123456000112);
|
||||
x->chat_id_ = 123456000112;
|
||||
x->sending_state_ = td::td_api::make_object<td::td_api::messageSendingStatePending>(0);
|
||||
x->date_ = 1699999999;
|
||||
auto photo = td::td_api::make_object<td::td_api::photo>();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
photo->sizes_.push_back(td::td_api::make_object<td::td_api::photoSize>(
|
||||
"a", get_file_object(), 160, 160,
|
||||
td::vector<td::int32>{10000, 20000, 30000, 50000, 70000, 90000, 120000, 150000, 180000, 220000}));
|
||||
}
|
||||
x->content_ = td::td_api::make_object<td::td_api::messagePhoto>(
|
||||
std::move(photo), td::td_api::make_object<td::td_api::formattedText>(), false, false, false);
|
||||
|
||||
std::size_t res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res += to_string(x).size();
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
#if !TD_EVENTFD_UNSUPPORTED
|
||||
BENCH(EventFd, "EventFd") {
|
||||
td::EventFd fd;
|
||||
fd.init();
|
||||
for (int i = 0; i < n; i++) {
|
||||
fd.release();
|
||||
fd.acquire();
|
||||
}
|
||||
fd.close();
|
||||
}
|
||||
#endif
|
||||
|
||||
BENCH(NewInt, "new int + delete") {
|
||||
std::uintptr_t res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int *x = new int;
|
||||
res += reinterpret_cast<std::uintptr_t>(x);
|
||||
delete x;
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
BENCH(NewObj, "new struct, then delete") {
|
||||
struct A {
|
||||
td::int32 a = 0;
|
||||
td::int32 b = 0;
|
||||
td::int32 c = 0;
|
||||
td::int32 d = 0;
|
||||
};
|
||||
std::uintptr_t res = 0;
|
||||
A **ptr = new A *[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
ptr[i] = new A();
|
||||
res += reinterpret_cast<std::uintptr_t>(ptr[i]);
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
delete ptr[i];
|
||||
}
|
||||
delete[] ptr;
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
#if !TD_THREAD_UNSUPPORTED
|
||||
BENCH(ThreadNew, "new struct, then delete in 2 threads") {
|
||||
NewObjBench a;
|
||||
NewObjBench b;
|
||||
td::thread ta([&] { a.run(n / 2); });
|
||||
td::thread tb([&] { b.run(n - n / 2); });
|
||||
ta.join();
|
||||
tb.join();
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
// Too hard for clang (?)
|
||||
BENCH(Time, "Clocks::monotonic") {
|
||||
double res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
res += td::Clocks::monotonic();
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
*/
|
||||
#if !TD_WINDOWS
|
||||
class PipeBench final : public td::Benchmark {
|
||||
public:
|
||||
int p[2];
|
||||
|
||||
td::string get_description() const final {
|
||||
return "pipe write + read int32";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
int res = pipe(p);
|
||||
CHECK(res == 0);
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
int res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int val = 1;
|
||||
auto write_len = write(p[1], &val, sizeof(val));
|
||||
CHECK(write_len == sizeof(val));
|
||||
auto read_len = read(p[0], &val, sizeof(val));
|
||||
CHECK(read_len == sizeof(val));
|
||||
res += val;
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if TD_LINUX || TD_ANDROID || TD_TIZEN
|
||||
class SemBench final : public td::Benchmark {
|
||||
sem_t sem;
|
||||
|
||||
public:
|
||||
td::string get_description() const final {
|
||||
return "sem post + wait";
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
int err = sem_init(&sem, 0, 0);
|
||||
CHECK(err != -1);
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
sem_post(&sem);
|
||||
sem_wait(&sem);
|
||||
}
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
sem_destroy(&sem);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !TD_WINDOWS
|
||||
class UtimeBench final : public td::Benchmark {
|
||||
public:
|
||||
void start_up() final {
|
||||
td::FileFd::open("test", td::FileFd::Create | td::FileFd::Write).move_as_ok().close();
|
||||
}
|
||||
td::string get_description() const final {
|
||||
return "utime";
|
||||
}
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
int err = utime("test", nullptr);
|
||||
CHECK(err >= 0);
|
||||
utimbuf buf;
|
||||
buf.modtime = 123;
|
||||
buf.actime = 321;
|
||||
err = utime("test", &buf);
|
||||
CHECK(err >= 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
BENCH(Pwrite, "pwrite") {
|
||||
auto fd = td::FileFd::open("test", td::FileFd::Create | td::FileFd::Write).move_as_ok();
|
||||
for (int i = 0; i < n; i++) {
|
||||
fd.pwrite("a", 0).ok();
|
||||
}
|
||||
fd.close();
|
||||
}
|
||||
|
||||
class CreateFileBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return "create_file";
|
||||
}
|
||||
void start_up() final {
|
||||
td::mkdir("A").ensure();
|
||||
}
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::FileFd::open(PSLICE() << "A/" << i, td::FileFd::Write | td::FileFd::Create).move_as_ok().close();
|
||||
}
|
||||
}
|
||||
void tear_down() final {
|
||||
td::rmrf("A/").ignore();
|
||||
}
|
||||
};
|
||||
|
||||
class WalkPathBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return "walk_path";
|
||||
}
|
||||
void start_up_n(int n) final {
|
||||
td::mkdir("A").ensure();
|
||||
for (int i = 0; i < n; i++) {
|
||||
td::FileFd::open(PSLICE() << "A/" << i, td::FileFd::Write | td::FileFd::Create).move_as_ok().close();
|
||||
}
|
||||
}
|
||||
void run(int n) final {
|
||||
int cnt = 0;
|
||||
td::walk_path("A/", [&](td::CSlice path, auto type) {
|
||||
if (type == td::WalkPath::Type::EnterDir) {
|
||||
return;
|
||||
}
|
||||
td::stat(path).ok();
|
||||
cnt++;
|
||||
}).ignore();
|
||||
}
|
||||
void tear_down() final {
|
||||
td::rmrf("A/").ignore();
|
||||
}
|
||||
};
|
||||
|
||||
#if !TD_THREAD_UNSUPPORTED
|
||||
template <int ThreadN = 2>
|
||||
class AtomicReleaseIncBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "AtomicReleaseInc" << ThreadN;
|
||||
}
|
||||
|
||||
static std::atomic<td::uint64> a_;
|
||||
void run(int n) final {
|
||||
td::vector<td::thread> threads;
|
||||
for (int i = 0; i < ThreadN; i++) {
|
||||
threads.emplace_back([&] {
|
||||
for (int i = 0; i < n / ThreadN; i++) {
|
||||
a_.fetch_add(1, std::memory_order_release);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
template <int ThreadN>
|
||||
std::atomic<td::uint64> AtomicReleaseIncBench<ThreadN>::a_;
|
||||
|
||||
template <int ThreadN = 2>
|
||||
class AtomicReleaseCasIncBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "AtomicReleaseCasInc" << ThreadN;
|
||||
}
|
||||
|
||||
static std::atomic<td::uint64> a_;
|
||||
void run(int n) final {
|
||||
td::vector<td::thread> threads;
|
||||
for (int i = 0; i < ThreadN; i++) {
|
||||
threads.emplace_back([&] {
|
||||
for (int i = 0; i < n / ThreadN; i++) {
|
||||
auto value = a_.load(std::memory_order_relaxed);
|
||||
while (!a_.compare_exchange_strong(value, value + 1, std::memory_order_release, std::memory_order_relaxed)) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
template <int ThreadN>
|
||||
std::atomic<td::uint64> AtomicReleaseCasIncBench<ThreadN>::a_;
|
||||
|
||||
template <int ThreadN>
|
||||
class RwMutexReadBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "RwMutexRead" << ThreadN;
|
||||
}
|
||||
td::RwMutex mutex_;
|
||||
void run(int n) final {
|
||||
td::vector<td::thread> threads;
|
||||
for (int i = 0; i < ThreadN; i++) {
|
||||
threads.emplace_back([&] {
|
||||
for (int i = 0; i < n / ThreadN; i++) {
|
||||
auto lock = mutex_.lock_read();
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <int ThreadN>
|
||||
class RwMutexWriteBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "RwMutexWrite" << ThreadN;
|
||||
}
|
||||
td::RwMutex mutex_;
|
||||
void run(int n) final {
|
||||
td::vector<td::thread> threads;
|
||||
for (int i = 0; i < ThreadN; i++) {
|
||||
threads.emplace_back([&] {
|
||||
for (int i = 0; i < n / ThreadN; i++) {
|
||||
auto lock = mutex_.lock_write();
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ThreadSafeCounterBench final : public td::Benchmark {
|
||||
static td::ThreadSafeCounter counter_;
|
||||
int thread_count_;
|
||||
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "ThreadSafeCounter" << thread_count_;
|
||||
}
|
||||
void run(int n) final {
|
||||
counter_.clear();
|
||||
td::vector<td::thread> threads;
|
||||
for (int i = 0; i < thread_count_; i++) {
|
||||
threads.emplace_back([n] {
|
||||
for (int i = 0; i < n; i++) {
|
||||
counter_.add(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
CHECK(counter_.sum() == n * thread_count_);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ThreadSafeCounterBench(int thread_count) : thread_count_(thread_count) {
|
||||
}
|
||||
};
|
||||
td::ThreadSafeCounter ThreadSafeCounterBench::counter_;
|
||||
|
||||
template <bool StrictOrder>
|
||||
class AtomicCounterBench final : public td::Benchmark {
|
||||
static std::atomic<td::int64> counter_;
|
||||
int thread_count_;
|
||||
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "AtomicCounter" << thread_count_;
|
||||
}
|
||||
void run(int n) final {
|
||||
counter_.store(0);
|
||||
td::vector<td::thread> threads;
|
||||
for (int i = 0; i < thread_count_; i++) {
|
||||
threads.emplace_back([n] {
|
||||
for (int i = 0; i < n; i++) {
|
||||
counter_.fetch_add(1, StrictOrder ? std::memory_order_seq_cst : std::memory_order_relaxed);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
CHECK(counter_.load() == n * thread_count_);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit AtomicCounterBench(int thread_count) : thread_count_(thread_count) {
|
||||
}
|
||||
};
|
||||
template <bool StrictOrder>
|
||||
std::atomic<td::int64> AtomicCounterBench<StrictOrder>::counter_;
|
||||
|
||||
#endif
|
||||
|
||||
class IdDuplicateCheckerOld {
|
||||
public:
|
||||
static td::string get_description() {
|
||||
return "Old";
|
||||
}
|
||||
td::Status check(td::uint64 message_id) {
|
||||
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS) {
|
||||
auto oldest_message_id = *saved_message_ids_.begin();
|
||||
if (message_id < oldest_message_id) {
|
||||
return td::Status::Error(2, PSLICE() << "Ignore very old message " << message_id
|
||||
<< " older than the oldest known message " << oldest_message_id);
|
||||
}
|
||||
}
|
||||
if (saved_message_ids_.count(message_id) != 0) {
|
||||
return td::Status::Error(1, PSLICE() << "Ignore already processed message " << message_id);
|
||||
}
|
||||
|
||||
saved_message_ids_.insert(message_id);
|
||||
if (saved_message_ids_.size() > MAX_SAVED_MESSAGE_IDS) {
|
||||
saved_message_ids_.erase(saved_message_ids_.begin());
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000;
|
||||
std::set<td::uint64> saved_message_ids_;
|
||||
};
|
||||
|
||||
template <size_t MAX_SAVED_MESSAGE_IDS>
|
||||
class IdDuplicateCheckerNew {
|
||||
public:
|
||||
static td::string get_description() {
|
||||
return PSTRING() << "New" << MAX_SAVED_MESSAGE_IDS;
|
||||
}
|
||||
td::Status check(td::uint64 message_id) {
|
||||
auto insert_result = saved_message_ids_.insert(message_id);
|
||||
if (!insert_result.second) {
|
||||
return td::Status::Error(1, PSLICE() << "Ignore already processed message " << message_id);
|
||||
}
|
||||
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) {
|
||||
auto begin_it = saved_message_ids_.begin();
|
||||
bool is_very_old = begin_it == insert_result.first;
|
||||
saved_message_ids_.erase(begin_it);
|
||||
if (is_very_old) {
|
||||
return td::Status::Error(2, PSLICE() << "Ignore very old message " << message_id
|
||||
<< " older than the oldest known message " << *saved_message_ids_.begin());
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<td::uint64> saved_message_ids_;
|
||||
};
|
||||
|
||||
class IdDuplicateCheckerNewOther {
|
||||
public:
|
||||
static td::string get_description() {
|
||||
return "NewOther";
|
||||
}
|
||||
td::Status check(td::uint64 message_id) {
|
||||
if (!saved_message_ids_.insert(message_id).second) {
|
||||
return td::Status::Error(1, PSLICE() << "Ignore already processed message " << message_id);
|
||||
}
|
||||
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) {
|
||||
auto begin_it = saved_message_ids_.begin();
|
||||
bool is_very_old = *begin_it == message_id;
|
||||
saved_message_ids_.erase(begin_it);
|
||||
if (is_very_old) {
|
||||
return td::Status::Error(2, PSLICE() << "Ignore very old message " << message_id
|
||||
<< " older than the oldest known message " << *saved_message_ids_.begin());
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000;
|
||||
std::set<td::uint64> saved_message_ids_;
|
||||
};
|
||||
|
||||
class IdDuplicateCheckerNewSimple {
|
||||
public:
|
||||
static td::string get_description() {
|
||||
return "NewSimple";
|
||||
}
|
||||
td::Status check(td::uint64 message_id) {
|
||||
auto insert_result = saved_message_ids_.insert(message_id);
|
||||
if (!insert_result.second) {
|
||||
return td::Status::Error(1, "Ignore already processed message");
|
||||
}
|
||||
if (saved_message_ids_.size() == MAX_SAVED_MESSAGE_IDS + 1) {
|
||||
auto begin_it = saved_message_ids_.begin();
|
||||
bool is_very_old = begin_it == insert_result.first;
|
||||
saved_message_ids_.erase(begin_it);
|
||||
if (is_very_old) {
|
||||
return td::Status::Error(2, "Ignore very old message");
|
||||
}
|
||||
}
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_SAVED_MESSAGE_IDS = 1000;
|
||||
std::set<td::uint64> saved_message_ids_;
|
||||
};
|
||||
|
||||
template <size_t max_size>
|
||||
class IdDuplicateCheckerArray {
|
||||
public:
|
||||
static td::string get_description() {
|
||||
return PSTRING() << "Array" << max_size;
|
||||
}
|
||||
td::Status check(td::uint64 message_id) {
|
||||
if (end_pos_ == 2 * max_size) {
|
||||
std::copy_n(&saved_message_ids_[max_size], max_size, &saved_message_ids_[0]);
|
||||
end_pos_ = max_size;
|
||||
}
|
||||
if (end_pos_ == 0 || message_id > saved_message_ids_[end_pos_ - 1]) {
|
||||
// fast path
|
||||
saved_message_ids_[end_pos_++] = message_id;
|
||||
return td::Status::OK();
|
||||
}
|
||||
if (end_pos_ >= max_size && message_id < saved_message_ids_[0]) {
|
||||
return td::Status::Error(2, PSLICE() << "Ignore very old message " << message_id
|
||||
<< " older than the oldest known message " << saved_message_ids_[0]);
|
||||
}
|
||||
auto it = std::lower_bound(&saved_message_ids_[0], &saved_message_ids_[end_pos_], message_id);
|
||||
if (*it == message_id) {
|
||||
return td::Status::Error(1, PSLICE() << "Ignore already processed message " << message_id);
|
||||
}
|
||||
std::copy_backward(it, &saved_message_ids_[end_pos_], &saved_message_ids_[end_pos_ + 1]);
|
||||
*it = message_id;
|
||||
++end_pos_;
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<td::uint64, 2 * max_size> saved_message_ids_;
|
||||
std::size_t end_pos_ = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DuplicateCheckerBench final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "DuplicateCheckerBench" << T::get_description();
|
||||
}
|
||||
void run(int n) final {
|
||||
T checker_;
|
||||
for (int i = 0; i < n; i++) {
|
||||
checker_.check(i).ensure();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DuplicateCheckerBenchRepeat final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "DuplicateCheckerBenchRepeat" << T::get_description();
|
||||
}
|
||||
void run(int n) final {
|
||||
T checker_;
|
||||
for (int i = 0; i < n; i++) {
|
||||
auto iter = i >> 10;
|
||||
auto pos = i - (iter << 10);
|
||||
if (pos < 768) {
|
||||
if (iter >= 3 && pos == 0) {
|
||||
auto error = checker_.check((iter - 3) * 768 + pos);
|
||||
CHECK(error.error().code() == 2);
|
||||
}
|
||||
checker_.check(iter * 768 + pos).ensure();
|
||||
} else {
|
||||
checker_.check(iter * 768 + pos - 256).ensure_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DuplicateCheckerBenchRepeatOnly final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "DuplicateCheckerBenchRepeatOnly" << T::get_description();
|
||||
}
|
||||
void run(int n) final {
|
||||
T checker_;
|
||||
for (int i = 0; i < n; i++) {
|
||||
auto result = checker_.check(i & 255);
|
||||
CHECK(result.is_error() == (i >= 256));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DuplicateCheckerBenchReverse final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "DuplicateCheckerBenchReverseAdd" << T::get_description();
|
||||
}
|
||||
void run(int n) final {
|
||||
T checker_;
|
||||
for (int i = 0; i < n; i++) {
|
||||
auto pos = i & 255;
|
||||
checker_.check(i - pos + (255 - pos)).ensure();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DuplicateCheckerBenchEvenOdd final : public td::Benchmark {
|
||||
td::string get_description() const final {
|
||||
return PSTRING() << "DuplicateCheckerBenchEvenOdd" << T::get_description();
|
||||
}
|
||||
void run(int n) final {
|
||||
T checker_;
|
||||
for (int i = 0; i < n; i++) {
|
||||
auto pos = i & 255;
|
||||
checker_.check(i - pos + (pos * 2) % 256 + (pos * 2) / 256).ensure();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BENCH(AddToTopStd, "add_to_top std") {
|
||||
td::vector<int> v;
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (size_t j = 0; j < 10; j++) {
|
||||
auto value = td::Random::fast(0, 9);
|
||||
auto it = std::find(v.begin(), v.end(), value);
|
||||
if (it == v.end()) {
|
||||
if (v.size() == 8) {
|
||||
v.back() = value;
|
||||
} else {
|
||||
v.push_back(value);
|
||||
}
|
||||
it = v.end() - 1;
|
||||
}
|
||||
std::rotate(v.begin(), it, it + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCH(AddToTopTd, "add_to_top td") {
|
||||
td::vector<int> v;
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (size_t j = 0; j < 10; j++) {
|
||||
td::add_to_top(v, 8, td::Random::fast(0, 9));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCH(AnyOfStd, "any_of std") {
|
||||
td::vector<int> v;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
v.push_back(i);
|
||||
}
|
||||
int res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int rem = td::Random::fast(0, 127);
|
||||
res += static_cast<int>(std::any_of(v.begin(), v.end(), [rem](int x) { return (x & 127) == rem; }));
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
BENCH(AnyOfTd, "any_of td") {
|
||||
td::vector<int> v;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
v.push_back(i);
|
||||
}
|
||||
int res = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
int rem = td::Random::fast(0, 127);
|
||||
res += static_cast<int>(td::any_of(v, [rem](int x) { return (x & 127) == rem; }));
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
}
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG));
|
||||
|
||||
td::bench(AnyOfStdBench());
|
||||
td::bench(AnyOfTdBench());
|
||||
|
||||
td::bench(ToStringIntSmallBench());
|
||||
td::bench(ToStringIntBigBench());
|
||||
|
||||
td::bench(AddToTopStdBench());
|
||||
td::bench(AddToTopTdBench());
|
||||
|
||||
td::bench(TlToStringUpdateFileBench());
|
||||
td::bench(TlToStringMessageBench());
|
||||
|
||||
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerNew<1000>>());
|
||||
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerNew<300>>());
|
||||
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerArray<1000>>());
|
||||
td::bench(DuplicateCheckerBenchEvenOdd<IdDuplicateCheckerArray<300>>());
|
||||
|
||||
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerNew<1000>>());
|
||||
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerNew<300>>());
|
||||
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerArray<1000>>());
|
||||
td::bench(DuplicateCheckerBenchReverse<IdDuplicateCheckerArray<300>>());
|
||||
|
||||
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerNew<1000>>());
|
||||
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerNew<300>>());
|
||||
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerArray<1000>>());
|
||||
td::bench(DuplicateCheckerBenchRepeatOnly<IdDuplicateCheckerArray<300>>());
|
||||
|
||||
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerOld>());
|
||||
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNew<1000>>());
|
||||
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNewOther>());
|
||||
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNewSimple>());
|
||||
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerNew<300>>());
|
||||
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerArray<1000>>());
|
||||
td::bench(DuplicateCheckerBenchRepeat<IdDuplicateCheckerArray<300>>());
|
||||
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerOld>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<1000>>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNewOther>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNewSimple>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<300>>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<100>>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerNew<10>>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerArray<1000>>());
|
||||
td::bench(DuplicateCheckerBench<IdDuplicateCheckerArray<300>>());
|
||||
|
||||
#if !TD_THREAD_UNSUPPORTED
|
||||
for (int i = 1; i <= 16; i *= 2) {
|
||||
td::bench(ThreadSafeCounterBench(i));
|
||||
td::bench(AtomicCounterBench<false>(i));
|
||||
td::bench(AtomicCounterBench<true>(i));
|
||||
}
|
||||
|
||||
td::bench(AtomicReleaseIncBench<1>());
|
||||
td::bench(AtomicReleaseIncBench<2>());
|
||||
td::bench(AtomicReleaseCasIncBench<1>());
|
||||
td::bench(AtomicReleaseCasIncBench<2>());
|
||||
td::bench(RwMutexWriteBench<1>());
|
||||
td::bench(RwMutexReadBench<1>());
|
||||
td::bench(RwMutexWriteBench<2>());
|
||||
td::bench(RwMutexReadBench<2>());
|
||||
#endif
|
||||
#if !TD_WINDOWS
|
||||
td::bench(UtimeBench());
|
||||
#endif
|
||||
td::bench(WalkPathBench());
|
||||
td::bench(CreateFileBench());
|
||||
td::bench(PwriteBench());
|
||||
|
||||
td::bench(TlCallBench());
|
||||
#if !TD_THREAD_UNSUPPORTED
|
||||
td::bench(ThreadNewBench());
|
||||
#endif
|
||||
#if !TD_EVENTFD_UNSUPPORTED
|
||||
td::bench(EventFdBench());
|
||||
#endif
|
||||
td::bench(NewObjBench());
|
||||
td::bench(NewIntBench());
|
||||
#if !TD_WINDOWS
|
||||
td::bench(PipeBench());
|
||||
#endif
|
||||
#if TD_LINUX || TD_ANDROID || TD_TIZEN
|
||||
td::bench(SemBench());
|
||||
#endif
|
||||
}
|
932
third-party/td/td/benchmark/bench_queue.cpp
vendored
@ -1,932 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/utils/benchmark.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/MpscPollableQueue.h"
|
||||
#include "td/utils/port/sleep.h"
|
||||
#include "td/utils/port/thread.h"
|
||||
#include "td/utils/queue.h"
|
||||
#include "td/utils/Random.h"
|
||||
|
||||
// TODO: check system calls
|
||||
// TODO: all return values must be checked
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if TD_LINUX
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
#define MODE std::memory_order_relaxed
|
||||
|
||||
// void set_affinity(int mask) {
|
||||
// pid_t pid = gettid();
|
||||
// int syscallres = syscall(__NR_sched_setaffinity, pid, sizeof(mask), &mask);
|
||||
// if (syscallres) {
|
||||
// perror("Failed to set affinity");
|
||||
// }
|
||||
// }
|
||||
|
||||
using qvalue_t = int;
|
||||
|
||||
class Backoff {
|
||||
int cnt = 0;
|
||||
|
||||
public:
|
||||
bool next() {
|
||||
cnt++;
|
||||
if (cnt < 50) {
|
||||
return true;
|
||||
} else {
|
||||
td::usleep_for(1);
|
||||
return cnt < 500;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
// Just for testing, not production
|
||||
class PipeQueue {
|
||||
int input;
|
||||
int output;
|
||||
|
||||
public:
|
||||
void init() {
|
||||
int new_pipe[2];
|
||||
int res = pipe(new_pipe);
|
||||
CHECK(res == 0);
|
||||
output = new_pipe[0];
|
||||
input = new_pipe[1];
|
||||
}
|
||||
|
||||
void put(qvalue_t value) {
|
||||
auto len = write(input, &value, sizeof(value));
|
||||
CHECK(len == sizeof(value));
|
||||
}
|
||||
|
||||
qvalue_t get() {
|
||||
qvalue_t res;
|
||||
auto len = read(output, &res, sizeof(res));
|
||||
CHECK(len == sizeof(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
close(input);
|
||||
close(output);
|
||||
}
|
||||
};
|
||||
|
||||
class VarQueue {
|
||||
std::atomic<qvalue_t> data{0};
|
||||
|
||||
public:
|
||||
void init() {
|
||||
data.store(-1, MODE);
|
||||
}
|
||||
|
||||
void put(qvalue_t value) {
|
||||
data.store(value, MODE);
|
||||
}
|
||||
|
||||
qvalue_t try_get() {
|
||||
__sync_synchronize(); // TODO: it is wrong place for barrier, but it results in fastest queue
|
||||
qvalue_t res = data.load(MODE);
|
||||
return res;
|
||||
}
|
||||
|
||||
void acquire() {
|
||||
data.store(-1, MODE);
|
||||
}
|
||||
|
||||
qvalue_t get() {
|
||||
qvalue_t res;
|
||||
Backoff backoff;
|
||||
|
||||
do {
|
||||
res = try_get();
|
||||
} while (res == -1 && (backoff.next(), true));
|
||||
acquire();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
}
|
||||
};
|
||||
|
||||
class SemQueue {
|
||||
sem_t sem;
|
||||
VarQueue q;
|
||||
|
||||
public:
|
||||
void init() {
|
||||
q.init();
|
||||
sem_init(&sem, 0, 0);
|
||||
}
|
||||
|
||||
void put(qvalue_t value) {
|
||||
q.put(value);
|
||||
sem_post(&sem);
|
||||
}
|
||||
|
||||
qvalue_t get() {
|
||||
sem_wait(&sem);
|
||||
qvalue_t res = q.get();
|
||||
return res;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
q.destroy();
|
||||
sem_destroy(&sem);
|
||||
}
|
||||
|
||||
// HACK for benchmark
|
||||
void reader_flush() {
|
||||
}
|
||||
|
||||
void writer_flush() {
|
||||
}
|
||||
|
||||
void writer_put(qvalue_t value) {
|
||||
put(value);
|
||||
}
|
||||
|
||||
int reader_wait() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
qvalue_t reader_get_unsafe() {
|
||||
return get();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if TD_LINUX
|
||||
class EventfdQueue {
|
||||
int fd;
|
||||
VarQueue q;
|
||||
|
||||
public:
|
||||
void init() {
|
||||
q.init();
|
||||
fd = eventfd(0, 0);
|
||||
}
|
||||
void put(qvalue_t value) {
|
||||
q.put(value);
|
||||
td::int64 x = 1;
|
||||
auto len = write(fd, &x, sizeof(x));
|
||||
CHECK(len == sizeof(x));
|
||||
}
|
||||
qvalue_t get() {
|
||||
td::int64 x;
|
||||
auto len = read(fd, &x, sizeof(x));
|
||||
CHECK(len == sizeof(x));
|
||||
CHECK(x == 1);
|
||||
return q.get();
|
||||
}
|
||||
void destroy() {
|
||||
q.destroy();
|
||||
close(fd);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
const int queue_buf_size = 1 << 10;
|
||||
|
||||
class BufferQueue {
|
||||
struct node {
|
||||
qvalue_t val;
|
||||
char pad[64 - sizeof(std::atomic<qvalue_t>)];
|
||||
};
|
||||
node q[queue_buf_size];
|
||||
|
||||
struct Position {
|
||||
std::atomic<td::uint32> i{0};
|
||||
char pad[64 - sizeof(std::atomic<td::uint32>)];
|
||||
|
||||
td::uint32 local_read_i;
|
||||
td::uint32 local_write_i;
|
||||
char pad2[64 - sizeof(td::uint32) * 2];
|
||||
|
||||
void init() {
|
||||
i = 0;
|
||||
local_read_i = 0;
|
||||
local_write_i = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Position writer;
|
||||
Position reader;
|
||||
|
||||
public:
|
||||
void init() {
|
||||
writer.init();
|
||||
reader.init();
|
||||
}
|
||||
|
||||
bool reader_empty() {
|
||||
return reader.local_write_i == reader.local_read_i;
|
||||
}
|
||||
|
||||
bool writer_empty() {
|
||||
return writer.local_write_i == writer.local_read_i + queue_buf_size;
|
||||
}
|
||||
|
||||
int reader_ready() {
|
||||
return static_cast<int>(reader.local_write_i - reader.local_read_i);
|
||||
}
|
||||
|
||||
int writer_ready() {
|
||||
return static_cast<int>(writer.local_read_i + queue_buf_size - writer.local_write_i);
|
||||
}
|
||||
|
||||
qvalue_t get_unsafe() {
|
||||
return q[reader.local_read_i++ & (queue_buf_size - 1)].val;
|
||||
}
|
||||
|
||||
void flush_reader() {
|
||||
reader.i.store(reader.local_read_i, std::memory_order_release);
|
||||
}
|
||||
|
||||
int update_reader() {
|
||||
reader.local_write_i = writer.i.load(std::memory_order_acquire);
|
||||
return reader_ready();
|
||||
}
|
||||
|
||||
void put_unsafe(qvalue_t val) {
|
||||
q[writer.local_write_i++ & (queue_buf_size - 1)].val = val;
|
||||
}
|
||||
|
||||
void flush_writer() {
|
||||
writer.i.store(writer.local_write_i, std::memory_order_release);
|
||||
}
|
||||
|
||||
int update_writer() {
|
||||
writer.local_read_i = reader.i.load(std::memory_order_acquire);
|
||||
return writer_ready();
|
||||
}
|
||||
|
||||
int wait_reader() {
|
||||
Backoff backoff;
|
||||
int res = 0;
|
||||
while (res == 0) {
|
||||
backoff.next();
|
||||
res = update_reader();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
qvalue_t get_noflush() {
|
||||
if (!reader_empty()) {
|
||||
return get_unsafe();
|
||||
}
|
||||
|
||||
Backoff backoff;
|
||||
while (true) {
|
||||
backoff.next();
|
||||
if (update_reader()) {
|
||||
return get_unsafe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qvalue_t get() {
|
||||
qvalue_t res = get_noflush();
|
||||
flush_reader();
|
||||
return res;
|
||||
}
|
||||
|
||||
void put_noflush(qvalue_t val) {
|
||||
if (!writer_empty()) {
|
||||
put_unsafe(val);
|
||||
return;
|
||||
}
|
||||
if (!update_writer()) {
|
||||
LOG(FATAL) << "Put strong failed";
|
||||
}
|
||||
put_unsafe(val);
|
||||
}
|
||||
|
||||
void put(qvalue_t val) {
|
||||
put_noflush(val);
|
||||
flush_writer();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
}
|
||||
};
|
||||
|
||||
#if TD_LINUX
|
||||
class BufferedFdQueue {
|
||||
int fd;
|
||||
std::atomic<int> wait_flag{0};
|
||||
BufferQueue q;
|
||||
char pad[64];
|
||||
|
||||
public:
|
||||
void init() {
|
||||
q.init();
|
||||
fd = eventfd(0, 0);
|
||||
(void)pad[0];
|
||||
}
|
||||
void put(qvalue_t value) {
|
||||
q.put(value);
|
||||
td::int64 x = 1;
|
||||
__sync_synchronize();
|
||||
if (wait_flag.load(MODE)) {
|
||||
auto len = write(fd, &x, sizeof(x));
|
||||
CHECK(len == sizeof(x));
|
||||
}
|
||||
}
|
||||
void put_noflush(qvalue_t value) {
|
||||
q.put_noflush(value);
|
||||
}
|
||||
void flush_writer() {
|
||||
q.flush_writer();
|
||||
td::int64 x = 1;
|
||||
__sync_synchronize();
|
||||
if (wait_flag.load(MODE)) {
|
||||
auto len = write(fd, &x, sizeof(x));
|
||||
CHECK(len == sizeof(x));
|
||||
}
|
||||
}
|
||||
void flush_reader() {
|
||||
q.flush_reader();
|
||||
}
|
||||
|
||||
qvalue_t get_unsafe_flush() {
|
||||
qvalue_t res = q.get_unsafe();
|
||||
q.flush_reader();
|
||||
return res;
|
||||
}
|
||||
|
||||
qvalue_t get_unsafe() {
|
||||
return q.get_unsafe();
|
||||
}
|
||||
|
||||
int wait_reader() {
|
||||
int res = 0;
|
||||
Backoff backoff;
|
||||
while (res == 0 && backoff.next()) {
|
||||
res = q.update_reader();
|
||||
}
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
td::int64 x;
|
||||
wait_flag.store(1, MODE);
|
||||
__sync_synchronize();
|
||||
while (!(res = q.update_reader())) {
|
||||
auto len = read(fd, &x, sizeof(x));
|
||||
CHECK(len == sizeof(x));
|
||||
__sync_synchronize();
|
||||
}
|
||||
wait_flag.store(0, MODE);
|
||||
return res;
|
||||
}
|
||||
|
||||
qvalue_t get() {
|
||||
if (!q.reader_empty()) {
|
||||
return get_unsafe_flush();
|
||||
}
|
||||
|
||||
Backoff backoff;
|
||||
while (backoff.next()) {
|
||||
if (q.update_reader()) {
|
||||
return get_unsafe_flush();
|
||||
}
|
||||
}
|
||||
|
||||
td::int64 x;
|
||||
wait_flag.store(1, MODE);
|
||||
__sync_synchronize();
|
||||
while (!q.update_reader()) {
|
||||
auto len = read(fd, &x, sizeof(x));
|
||||
CHECK(len == sizeof(x));
|
||||
__sync_synchronize();
|
||||
}
|
||||
wait_flag.store(0, MODE);
|
||||
return get_unsafe_flush();
|
||||
}
|
||||
void destroy() {
|
||||
q.destroy();
|
||||
close(fd);
|
||||
}
|
||||
};
|
||||
|
||||
class FdQueue {
|
||||
int fd;
|
||||
std::atomic<int> wait_flag{0};
|
||||
VarQueue q;
|
||||
char pad[64];
|
||||
|
||||
public:
|
||||
void init() {
|
||||
q.init();
|
||||
fd = eventfd(0, 0);
|
||||
(void)pad[0];
|
||||
}
|
||||
void put(qvalue_t value) {
|
||||
q.put(value);
|
||||
td::int64 x = 1;
|
||||
__sync_synchronize();
|
||||
if (wait_flag.load(MODE)) {
|
||||
auto len = write(fd, &x, sizeof(x));
|
||||
CHECK(len == sizeof(x));
|
||||
}
|
||||
}
|
||||
qvalue_t get() {
|
||||
// td::int64 x;
|
||||
// auto len = read(fd, &x, sizeof(x));
|
||||
// CHECK(len == sizeof(x));
|
||||
// return q.get();
|
||||
|
||||
Backoff backoff;
|
||||
qvalue_t res = -1;
|
||||
do {
|
||||
res = q.try_get();
|
||||
} while (res == -1 && backoff.next());
|
||||
if (res != -1) {
|
||||
q.acquire();
|
||||
return res;
|
||||
}
|
||||
|
||||
td::int64 x;
|
||||
wait_flag.store(1, MODE);
|
||||
__sync_synchronize();
|
||||
// while (res == -1 && read(fd, &x, sizeof(x)) == sizeof(x)) {
|
||||
// res = q.try_get();
|
||||
// }
|
||||
do {
|
||||
__sync_synchronize();
|
||||
res = q.try_get();
|
||||
} while (res == -1 && read(fd, &x, sizeof(x)) == sizeof(x));
|
||||
q.acquire();
|
||||
wait_flag.store(0, MODE);
|
||||
return res;
|
||||
}
|
||||
void destroy() {
|
||||
q.destroy();
|
||||
close(fd);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
class SemBackoffQueue {
|
||||
sem_t sem;
|
||||
VarQueue q;
|
||||
|
||||
public:
|
||||
void init() {
|
||||
q.init();
|
||||
sem_init(&sem, 0, 0);
|
||||
}
|
||||
|
||||
void put(qvalue_t value) {
|
||||
q.put(value);
|
||||
sem_post(&sem);
|
||||
}
|
||||
|
||||
qvalue_t get() {
|
||||
Backoff backoff;
|
||||
int sem_flag = -1;
|
||||
do {
|
||||
sem_flag = sem_trywait(&sem);
|
||||
} while (sem_flag != 0 && backoff.next());
|
||||
if (sem_flag != 0) {
|
||||
sem_wait(&sem);
|
||||
}
|
||||
return q.get();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
q.destroy();
|
||||
sem_destroy(&sem);
|
||||
}
|
||||
};
|
||||
|
||||
class SemCheatQueue {
|
||||
sem_t sem;
|
||||
VarQueue q;
|
||||
|
||||
public:
|
||||
void init() {
|
||||
q.init();
|
||||
sem_init(&sem, 0, 0);
|
||||
}
|
||||
|
||||
void put(qvalue_t value) {
|
||||
q.put(value);
|
||||
sem_post(&sem);
|
||||
}
|
||||
|
||||
qvalue_t get() {
|
||||
Backoff backoff;
|
||||
qvalue_t res = -1;
|
||||
do {
|
||||
res = q.try_get();
|
||||
} while (res == -1 && backoff.next());
|
||||
sem_wait(&sem);
|
||||
if (res != -1) {
|
||||
q.acquire();
|
||||
return res;
|
||||
}
|
||||
return q.get();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
q.destroy();
|
||||
sem_destroy(&sem);
|
||||
}
|
||||
};
|
||||
|
||||
template <class QueueT>
|
||||
class QueueBenchmark2 final : public td::Benchmark {
|
||||
QueueT client, server;
|
||||
int connections_n, queries_n;
|
||||
|
||||
int server_active_connections;
|
||||
int client_active_connections;
|
||||
td::vector<td::int64> server_conn;
|
||||
td::vector<td::int64> client_conn;
|
||||
|
||||
td::string name;
|
||||
|
||||
public:
|
||||
QueueBenchmark2(int connections_n, td::string name) : connections_n(connections_n), name(std::move(name)) {
|
||||
}
|
||||
|
||||
td::string get_description() const final {
|
||||
return name;
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
client.init();
|
||||
server.init();
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
client.destroy();
|
||||
server.destroy();
|
||||
}
|
||||
|
||||
void server_process(qvalue_t value) {
|
||||
int no = value & 0x00FFFFFF;
|
||||
auto co = static_cast<int>(static_cast<td::uint32>(value) >> 24);
|
||||
CHECK(co >= 0 && co < connections_n);
|
||||
CHECK(no == server_conn[co]++);
|
||||
|
||||
client.writer_put(value);
|
||||
client.writer_flush();
|
||||
if (no + 1 >= queries_n) {
|
||||
server_active_connections--;
|
||||
}
|
||||
}
|
||||
|
||||
void *server_run(void *) {
|
||||
server_conn = td::vector<td::int64>(connections_n);
|
||||
server_active_connections = connections_n;
|
||||
|
||||
while (server_active_connections > 0) {
|
||||
int cnt = server.reader_wait();
|
||||
CHECK(cnt != 0);
|
||||
while (cnt-- > 0) {
|
||||
server_process(server.reader_get_unsafe());
|
||||
server.reader_flush();
|
||||
}
|
||||
// client.writer_flush();
|
||||
server.reader_flush();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void client_process(qvalue_t value) {
|
||||
int no = value & 0x00FFFFFF;
|
||||
auto co = static_cast<int>(static_cast<td::uint32>(value) >> 24);
|
||||
CHECK(co >= 0 && co < connections_n);
|
||||
CHECK(no == client_conn[co]++);
|
||||
if (no + 1 < queries_n) {
|
||||
server.writer_put(value + 1);
|
||||
server.writer_flush();
|
||||
} else {
|
||||
client_active_connections--;
|
||||
}
|
||||
}
|
||||
|
||||
void *client_run(void *) {
|
||||
client_conn = td::vector<td::int64>(connections_n);
|
||||
client_active_connections = connections_n;
|
||||
CHECK(queries_n < (1 << 24));
|
||||
|
||||
for (int i = 0; i < connections_n; i++) {
|
||||
server.writer_put(static_cast<qvalue_t>(i) << 24);
|
||||
}
|
||||
server.writer_flush();
|
||||
|
||||
while (client_active_connections > 0) {
|
||||
int cnt = client.reader_wait();
|
||||
CHECK(cnt != 0);
|
||||
while (cnt-- > 0) {
|
||||
client_process(client.reader_get_unsafe());
|
||||
client.reader_flush();
|
||||
}
|
||||
// server.writer_flush();
|
||||
client.reader_flush();
|
||||
}
|
||||
// system("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void *client_run_gateway(void *arg) {
|
||||
return static_cast<QueueBenchmark2 *>(arg)->client_run(nullptr);
|
||||
}
|
||||
|
||||
static void *server_run_gateway(void *arg) {
|
||||
return static_cast<QueueBenchmark2 *>(arg)->server_run(nullptr);
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
pthread_t client_thread_id;
|
||||
pthread_t server_thread_id;
|
||||
|
||||
queries_n = (n + connections_n - 1) / connections_n;
|
||||
|
||||
pthread_create(&client_thread_id, nullptr, client_run_gateway, this);
|
||||
pthread_create(&server_thread_id, nullptr, server_run_gateway, this);
|
||||
|
||||
pthread_join(client_thread_id, nullptr);
|
||||
pthread_join(server_thread_id, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <class QueueT>
|
||||
class QueueBenchmark final : public td::Benchmark {
|
||||
QueueT client, server;
|
||||
const int connections_n;
|
||||
int queries_n;
|
||||
|
||||
td::string name;
|
||||
|
||||
public:
|
||||
QueueBenchmark(int connections_n, td::string name) : connections_n(connections_n), name(std::move(name)) {
|
||||
}
|
||||
|
||||
td::string get_description() const final {
|
||||
return name;
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
client.init();
|
||||
server.init();
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
client.destroy();
|
||||
server.destroy();
|
||||
}
|
||||
|
||||
void *server_run(void *) {
|
||||
td::vector<td::int64> conn(connections_n);
|
||||
int active_connections = connections_n;
|
||||
while (active_connections > 0) {
|
||||
qvalue_t value = server.get();
|
||||
int no = value & 0x00FFFFFF;
|
||||
auto co = static_cast<int>(value >> 24);
|
||||
CHECK(co >= 0 && co < connections_n);
|
||||
CHECK(no == conn[co]++);
|
||||
client.put(value);
|
||||
if (no + 1 >= queries_n) {
|
||||
active_connections--;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *client_run(void *) {
|
||||
td::vector<td::int64> conn(connections_n);
|
||||
CHECK(queries_n < (1 << 24));
|
||||
for (int i = 0; i < connections_n; i++) {
|
||||
server.put(static_cast<qvalue_t>(i) << 24);
|
||||
}
|
||||
int active_connections = connections_n;
|
||||
while (active_connections > 0) {
|
||||
qvalue_t value = client.get();
|
||||
int no = value & 0x00FFFFFF;
|
||||
auto co = static_cast<int>(value >> 24);
|
||||
CHECK(co >= 0 && co < connections_n);
|
||||
CHECK(no == conn[co]++);
|
||||
if (no + 1 < queries_n) {
|
||||
server.put(value + 1);
|
||||
} else {
|
||||
active_connections--;
|
||||
}
|
||||
}
|
||||
// system("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *client_run2(void *) {
|
||||
td::vector<td::int64> conn(connections_n);
|
||||
CHECK(queries_n < (1 << 24));
|
||||
for (int query = 0; query < queries_n; query++) {
|
||||
for (int i = 0; i < connections_n; i++) {
|
||||
server.put((static_cast<td::int64>(i) << 24) + query);
|
||||
}
|
||||
for (int i = 0; i < connections_n; i++) {
|
||||
qvalue_t value = client.get();
|
||||
int no = value & 0x00FFFFFF;
|
||||
auto co = static_cast<int>(value >> 24);
|
||||
CHECK(co >= 0 && co < connections_n);
|
||||
CHECK(no == conn[co]++);
|
||||
}
|
||||
}
|
||||
// system("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void *client_run_gateway(void *arg) {
|
||||
return static_cast<QueueBenchmark *>(arg)->client_run(nullptr);
|
||||
}
|
||||
|
||||
static void *server_run_gateway(void *arg) {
|
||||
return static_cast<QueueBenchmark *>(arg)->server_run(nullptr);
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
pthread_t client_thread_id;
|
||||
pthread_t server_thread_id;
|
||||
|
||||
queries_n = (n + connections_n - 1) / connections_n;
|
||||
|
||||
pthread_create(&client_thread_id, nullptr, client_run_gateway, this);
|
||||
pthread_create(&server_thread_id, nullptr, server_run_gateway, this);
|
||||
|
||||
pthread_join(client_thread_id, nullptr);
|
||||
pthread_join(server_thread_id, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <class QueueT>
|
||||
class RingBenchmark final : public td::Benchmark {
|
||||
static constexpr int QN = 504;
|
||||
|
||||
struct Thread {
|
||||
int int_id;
|
||||
pthread_t id;
|
||||
QueueT queue;
|
||||
Thread *next;
|
||||
char pad[64];
|
||||
|
||||
void *run() {
|
||||
qvalue_t value;
|
||||
do {
|
||||
int cnt = queue.reader_wait();
|
||||
CHECK(cnt == 1);
|
||||
value = queue.reader_get_unsafe();
|
||||
queue.reader_flush();
|
||||
|
||||
next->queue.writer_put(value - 1);
|
||||
next->queue.writer_flush();
|
||||
} while (value >= QN);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
Thread q[QN];
|
||||
|
||||
public:
|
||||
static void *run_gateway(void *arg) {
|
||||
return static_cast<Thread *>(arg)->run();
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
for (int i = 0; i < QN; i++) {
|
||||
q[i].int_id = i;
|
||||
q[i].queue.init();
|
||||
q[i].next = &q[(i + 1) % QN];
|
||||
}
|
||||
}
|
||||
|
||||
void tear_down() final {
|
||||
for (int i = 0; i < QN; i++) {
|
||||
q[i].queue.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void run(int n) final {
|
||||
for (int i = 0; i < QN; i++) {
|
||||
pthread_create(&q[i].id, nullptr, run_gateway, &q[i]);
|
||||
}
|
||||
|
||||
if (n < 1000) {
|
||||
n = 1000;
|
||||
}
|
||||
q[0].queue.writer_put(n);
|
||||
q[0].queue.writer_flush();
|
||||
|
||||
for (int i = 0; i < QN; i++) {
|
||||
pthread_join(q[i].id, nullptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED
|
||||
static void test_queue() {
|
||||
td::vector<td::thread> threads;
|
||||
static constexpr size_t THREAD_COUNT = 100;
|
||||
td::vector<td::MpscPollableQueue<int>> queues(THREAD_COUNT);
|
||||
for (auto &q : queues) {
|
||||
q.init();
|
||||
}
|
||||
for (size_t i = 0; i < THREAD_COUNT; i++) {
|
||||
threads.emplace_back([&q = queues[i]] {
|
||||
while (true) {
|
||||
auto ready_count = q.reader_wait_nonblock();
|
||||
while (ready_count-- > 0) {
|
||||
q.reader_get_unsafe();
|
||||
}
|
||||
q.reader_get_event_fd().wait(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (size_t iter = 0; iter < THREAD_COUNT; iter++) {
|
||||
td::usleep_for(100);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
queues[td::Random::fast(0, THREAD_COUNT - 1)].writer_put(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < THREAD_COUNT; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
int main() {
|
||||
#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED
|
||||
// test_queue();
|
||||
#endif
|
||||
|
||||
#if TD_PORT_POSIX
|
||||
// td::bench(RingBenchmark<SemQueue>());
|
||||
// td::bench(RingBenchmark<td::PollQueue<qvalue_t>>());
|
||||
|
||||
#define BENCH_Q2(Q, N) td::bench(QueueBenchmark2<Q<qvalue_t>>(N, #Q "(" #N ")"))
|
||||
|
||||
#if !TD_THREAD_UNSUPPORTED && !TD_EVENTFD_UNSUPPORTED
|
||||
BENCH_Q2(td::InfBackoffQueue, 1);
|
||||
BENCH_Q2(td::MpscPollableQueue, 1);
|
||||
BENCH_Q2(td::PollQueue, 1);
|
||||
|
||||
BENCH_Q2(td::InfBackoffQueue, 10);
|
||||
BENCH_Q2(td::MpscPollableQueue, 10);
|
||||
BENCH_Q2(td::PollQueue, 10);
|
||||
|
||||
BENCH_Q2(td::InfBackoffQueue, 100);
|
||||
BENCH_Q2(td::MpscPollableQueue, 100);
|
||||
BENCH_Q2(td::PollQueue, 100);
|
||||
|
||||
BENCH_Q2(td::PollQueue, 4);
|
||||
BENCH_Q2(td::PollQueue, 10);
|
||||
BENCH_Q2(td::PollQueue, 100);
|
||||
#endif
|
||||
|
||||
#define BENCH_Q(Q, N) td::bench(QueueBenchmark<Q>(N, #Q "(" #N ")"))
|
||||
|
||||
#if TD_LINUX
|
||||
BENCH_Q(BufferQueue, 1);
|
||||
BENCH_Q(BufferedFdQueue, 1);
|
||||
BENCH_Q(FdQueue, 1);
|
||||
#endif
|
||||
BENCH_Q(PipeQueue, 1);
|
||||
BENCH_Q(SemCheatQueue, 1);
|
||||
BENCH_Q(SemQueue, 1);
|
||||
BENCH_Q(VarQueue, 1);
|
||||
|
||||
#if TD_LINUX
|
||||
BENCH_Q(BufferQueue, 4);
|
||||
BENCH_Q(BufferQueue, 10);
|
||||
BENCH_Q(BufferQueue, 100);
|
||||
#endif
|
||||
#endif
|
||||
}
|
113
third-party/td/td/benchmark/bench_tddb.cpp
vendored
@ -1,113 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/DialogId.h"
|
||||
#include "td/telegram/MessageDb.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/NotificationId.h"
|
||||
#include "td/telegram/ServerMessageId.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/db/DbKey.h"
|
||||
#include "td/db/SqliteConnectionSafe.h"
|
||||
#include "td/db/SqliteDb.h"
|
||||
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
|
||||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
static td::Status init_db(td::SqliteDb &db) {
|
||||
TRY_STATUS(db.exec("PRAGMA encoding=\"UTF-8\""));
|
||||
TRY_STATUS(db.exec("PRAGMA synchronous=NORMAL"));
|
||||
TRY_STATUS(db.exec("PRAGMA journal_mode=WAL"));
|
||||
TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY"));
|
||||
TRY_STATUS(db.exec("PRAGMA secure_delete=1"));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
class MessageDbBench final : public td::Benchmark {
|
||||
public:
|
||||
td::string get_description() const final {
|
||||
return "MessageDb";
|
||||
}
|
||||
void start_up() final {
|
||||
LOG(ERROR) << "START UP";
|
||||
do_start_up().ensure();
|
||||
scheduler_->start();
|
||||
}
|
||||
void run(int n) final {
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
for (int i = 0; i < n; i += 20) {
|
||||
auto dialog_id = td::DialogId(td::UserId(static_cast<td::int64>(td::Random::fast(1, 100))));
|
||||
auto message_id_raw = td::Random::fast(1, 100000);
|
||||
for (int j = 0; j < 20; j++) {
|
||||
auto message_id = td::MessageId{td::ServerMessageId{message_id_raw + j}};
|
||||
auto unique_message_id = td::ServerMessageId{i + 1};
|
||||
auto sender_dialog_id = td::DialogId(td::UserId(static_cast<td::int64>(td::Random::fast(1, 1000))));
|
||||
auto random_id = i + 1;
|
||||
auto ttl_expires_at = 0;
|
||||
auto data = td::BufferSlice(td::Random::fast(100, 299));
|
||||
|
||||
// use async on same thread.
|
||||
message_db_async_->add_message({dialog_id, message_id}, unique_message_id, sender_dialog_id, random_id,
|
||||
ttl_expires_at, 0, 0, "", td::NotificationId(), td::MessageId(), std::move(data),
|
||||
td::Promise<>());
|
||||
}
|
||||
}
|
||||
}
|
||||
void tear_down() final {
|
||||
scheduler_->run_main(0.1);
|
||||
{
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
sql_connection_.reset();
|
||||
message_db_sync_safe_.reset();
|
||||
message_db_async_.reset();
|
||||
}
|
||||
|
||||
scheduler_->finish();
|
||||
scheduler_.reset();
|
||||
LOG(ERROR) << "TEAR DOWN";
|
||||
}
|
||||
|
||||
private:
|
||||
td::unique_ptr<td::ConcurrentScheduler> scheduler_;
|
||||
std::shared_ptr<td::SqliteConnectionSafe> sql_connection_;
|
||||
std::shared_ptr<td::MessageDbSyncSafeInterface> message_db_sync_safe_;
|
||||
std::shared_ptr<td::MessageDbAsyncInterface> message_db_async_;
|
||||
|
||||
td::Status do_start_up() {
|
||||
scheduler_ = td::make_unique<td::ConcurrentScheduler>(1, 0);
|
||||
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
|
||||
td::string sql_db_name = "testdb.sqlite";
|
||||
sql_connection_ = std::make_shared<td::SqliteConnectionSafe>(sql_db_name, td::DbKey::empty());
|
||||
auto &db = sql_connection_->get();
|
||||
TRY_STATUS(init_db(db));
|
||||
|
||||
db.exec("BEGIN TRANSACTION").ensure();
|
||||
// version == 0 ==> db will be destroyed
|
||||
TRY_STATUS(init_message_db(db, 0));
|
||||
db.exec("COMMIT TRANSACTION").ensure();
|
||||
|
||||
message_db_sync_safe_ = td::create_message_db_sync(sql_connection_);
|
||||
message_db_async_ = td::create_message_db_async(message_db_sync_safe_, 0);
|
||||
return td::Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING));
|
||||
td::bench(MessageDbBench());
|
||||
}
|
193
third-party/td/td/benchmark/check_proxy.cpp
vendored
@ -1,193 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/Client.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/TsCerr.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
static void usage() {
|
||||
td::TsCerr() << "Tests specified MTProto-proxies, outputs working proxies to stdout; exits with code 0 if a working "
|
||||
"proxy was found.\n";
|
||||
td::TsCerr() << "Usage: check_proxy [options] server:port:secret [server2:port2:secret2 ...]\n";
|
||||
td::TsCerr() << "Options:\n";
|
||||
td::TsCerr() << " -v<N>\tSet verbosity level to N\n";
|
||||
td::TsCerr() << " -h/--help\tDisplay this information\n";
|
||||
td::TsCerr() << " -d/--dc-id\tIdentifier of a datacenter to which try to connect (default is 2)\n";
|
||||
td::TsCerr() << " -l/--proxy-list\tName of a file with proxies to check; one proxy per line\n";
|
||||
td::TsCerr() << " -t/--timeout\tMaximum overall timeout for the request (default is 10 seconds)\n";
|
||||
std::exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int new_verbosity_level = VERBOSITY_NAME(FATAL);
|
||||
|
||||
td::vector<std::pair<td::string, td::td_api::object_ptr<td::td_api::testProxy>>> requests;
|
||||
|
||||
auto add_proxy = [&requests](td::string arg) {
|
||||
if (arg.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t offset = 0;
|
||||
if (arg[0] == '[') {
|
||||
auto end_ipv6_pos = arg.find(']');
|
||||
if (end_ipv6_pos == td::string::npos) {
|
||||
td::TsCerr() << "Error: failed to find end of IPv6 address in \"" << arg << "\"\n";
|
||||
usage();
|
||||
}
|
||||
offset = end_ipv6_pos;
|
||||
}
|
||||
if (std::count(arg.begin() + offset, arg.end(), ':') == 3) {
|
||||
auto secret_domain_pos = arg.find(':', arg.find(':', offset) + 1) + 1;
|
||||
auto domain_pos = arg.find(':', secret_domain_pos);
|
||||
auto secret = arg.substr(secret_domain_pos, domain_pos - secret_domain_pos);
|
||||
auto domain = arg.substr(domain_pos + 1);
|
||||
auto r_decoded_secret = td::hex_decode(secret);
|
||||
if (r_decoded_secret.is_error()) {
|
||||
r_decoded_secret = td::base64url_decode(secret);
|
||||
if (r_decoded_secret.is_error()) {
|
||||
td::TsCerr() << "Error: failed to find proxy port and secret in \"" << arg << "\"\n";
|
||||
usage();
|
||||
}
|
||||
}
|
||||
arg = arg.substr(0, secret_domain_pos) + td::base64url_encode(r_decoded_secret.ok() + domain);
|
||||
}
|
||||
|
||||
auto secret_pos = arg.rfind(':');
|
||||
if (secret_pos == td::string::npos) {
|
||||
td::TsCerr() << "Error: failed to find proxy port and secret in \"" << arg << "\"\n";
|
||||
usage();
|
||||
}
|
||||
auto secret = arg.substr(secret_pos + 1);
|
||||
auto port_pos = arg.substr(0, secret_pos).rfind(':');
|
||||
if (port_pos == td::string::npos) {
|
||||
td::TsCerr() << "Error: failed to find proxy secret in \"" << arg << "\"\n";
|
||||
usage();
|
||||
}
|
||||
auto r_port = td::to_integer_safe<td::int32>(arg.substr(port_pos + 1, secret_pos - port_pos - 1));
|
||||
if (r_port.is_error()) {
|
||||
td::TsCerr() << "Error: failed to parse proxy port in \"" << arg << "\"\n";
|
||||
usage();
|
||||
}
|
||||
auto port = r_port.move_as_ok();
|
||||
auto server = arg.substr(0, port_pos);
|
||||
if (server[0] == '[' && server.back() == ']') {
|
||||
server = server.substr(1, server.size() - 2);
|
||||
}
|
||||
|
||||
if (server.empty() || port <= 0 || port > 65536 || secret.empty()) {
|
||||
td::TsCerr() << "Error: proxy address to check is in wrong format: \"" << arg << "\"\n";
|
||||
usage();
|
||||
}
|
||||
|
||||
requests.emplace_back(arg,
|
||||
td::td_api::make_object<td::td_api::testProxy>(
|
||||
server, port, td::td_api::make_object<td::td_api::proxyTypeMtproto>(secret), -1, -1));
|
||||
};
|
||||
|
||||
td::int32 dc_id = 2;
|
||||
double timeout = 10.0;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
td::string arg(argv[i]);
|
||||
|
||||
auto get_next_arg = [&i, &arg, argc, argv](bool is_optional = false) {
|
||||
CHECK(arg.size() >= 2);
|
||||
if (arg.size() == 2 || arg[1] == '-') {
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
return td::string(argv[++i]);
|
||||
}
|
||||
} else {
|
||||
if (arg.size() > 2) {
|
||||
return arg.substr(2);
|
||||
}
|
||||
}
|
||||
if (!is_optional) {
|
||||
td::TsCerr() << "Error: value is required after " << arg << "\n";
|
||||
usage();
|
||||
}
|
||||
return td::string();
|
||||
};
|
||||
|
||||
if (td::begins_with(arg, "-v")) {
|
||||
arg = get_next_arg(true);
|
||||
int new_verbosity = 1;
|
||||
while (arg[0] == 'v') {
|
||||
new_verbosity++;
|
||||
arg = arg.substr(1);
|
||||
}
|
||||
if (!arg.empty()) {
|
||||
new_verbosity += td::to_integer<int>(arg) - (new_verbosity == 1);
|
||||
}
|
||||
new_verbosity_level = VERBOSITY_NAME(FATAL) + new_verbosity;
|
||||
} else if (td::begins_with(arg, "-t") || arg == "--timeout") {
|
||||
timeout = td::to_double(get_next_arg());
|
||||
} else if (td::begins_with(arg, "-d") || arg == "--dc-id") {
|
||||
dc_id = td::to_integer<td::int32>(get_next_arg());
|
||||
} else if (td::begins_with(arg, "-l") || arg == "--proxy-list") {
|
||||
auto r_proxies = td::read_file_str(get_next_arg());
|
||||
if (r_proxies.is_error()) {
|
||||
td::TsCerr() << "Error: wrong file name specified\n";
|
||||
usage();
|
||||
}
|
||||
for (auto &proxy : td::full_split(r_proxies.ok(), '\n')) {
|
||||
add_proxy(td::trim(proxy));
|
||||
}
|
||||
} else if (arg[0] == '-') {
|
||||
usage();
|
||||
} else {
|
||||
add_proxy(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (requests.empty()) {
|
||||
td::TsCerr() << "Error: proxy address to check is not specified\n";
|
||||
usage();
|
||||
}
|
||||
|
||||
SET_VERBOSITY_LEVEL(new_verbosity_level);
|
||||
|
||||
td::ClientManager client_manager;
|
||||
auto client_id = client_manager.create_client_id();
|
||||
for (size_t i = 0; i < requests.size(); i++) {
|
||||
auto &request = requests[i].second;
|
||||
request->dc_id_ = dc_id;
|
||||
request->timeout_ = timeout;
|
||||
client_manager.send(client_id, i + 1, std::move(request));
|
||||
}
|
||||
size_t successful_requests = 0;
|
||||
size_t failed_requests = 0;
|
||||
|
||||
while (successful_requests + failed_requests != requests.size()) {
|
||||
auto response = client_manager.receive(100.0);
|
||||
CHECK(client_id == response.client_id);
|
||||
if (1 <= response.request_id && response.request_id <= requests.size()) {
|
||||
auto &proxy = requests[static_cast<size_t>(response.request_id - 1)].first;
|
||||
if (response.object->get_id() == td::td_api::error::ID) {
|
||||
LOG(ERROR) << proxy << ": " << to_string(response.object);
|
||||
failed_requests++;
|
||||
} else {
|
||||
std::cout << proxy << std::endl;
|
||||
successful_requests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (successful_requests == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
336
third-party/td/td/benchmark/check_tls.cpp
vendored
@ -1,336 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/utils/BigNum.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/detail/Iocp.h"
|
||||
#include "td/utils/port/IPAddress.h"
|
||||
#include "td/utils/port/sleep.h"
|
||||
#include "td/utils/port/SocketFd.h"
|
||||
#include "td/utils/port/thread.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/Time.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
static td::BigNumContext context;
|
||||
|
||||
static bool is_quadratic_residue(const td::BigNum &a) {
|
||||
// 2^255 - 19
|
||||
td::BigNum mod =
|
||||
td::BigNum::from_hex("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed").move_as_ok();
|
||||
// (mod - 1) / 2 = 2^254 - 10
|
||||
td::BigNum pow =
|
||||
td::BigNum::from_hex("3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6").move_as_ok();
|
||||
|
||||
td::BigNum r;
|
||||
td::BigNum::mod_exp(r, a, pow, mod, context);
|
||||
td::BigNum one = td::BigNum::from_decimal("1").move_as_ok();
|
||||
td::BigNum::mod_add(r, r, one, mod, context);
|
||||
|
||||
td::string result = r.to_decimal();
|
||||
CHECK(result == "0" || result == "1" || result == "2");
|
||||
return result == "2";
|
||||
}
|
||||
|
||||
struct TlsInfo {
|
||||
td::vector<size_t> extension_list;
|
||||
td::vector<size_t> encrypted_application_data_length;
|
||||
};
|
||||
|
||||
td::Result<TlsInfo> test_tls(const td::string &url) {
|
||||
td::IPAddress address;
|
||||
TRY_STATUS(address.init_host_port(url, 443));
|
||||
TRY_RESULT(socket, td::SocketFd::open(address));
|
||||
|
||||
td::string request;
|
||||
|
||||
auto add_string = [&](td::Slice data) {
|
||||
request.append(data.data(), data.size());
|
||||
};
|
||||
auto add_random = [&](size_t length) {
|
||||
while (length-- > 0) {
|
||||
request += static_cast<char>(td::Random::secure_int32());
|
||||
}
|
||||
};
|
||||
auto add_length = [&](size_t length) {
|
||||
request += static_cast<char>(length / 256);
|
||||
request += static_cast<char>(length % 256);
|
||||
};
|
||||
auto add_key = [&] {
|
||||
td::string key(32, '\0');
|
||||
td::BigNum mod =
|
||||
td::BigNum::from_hex("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed").move_as_ok();
|
||||
while (true) {
|
||||
td::Random::secure_bytes(key);
|
||||
key[31] = static_cast<char>(key[31] & 127);
|
||||
td::BigNum x = td::BigNum::from_le_binary(key);
|
||||
if (!is_quadratic_residue(x)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
td::BigNum y = x.clone();
|
||||
td::BigNum coef = td::BigNum::from_decimal("486662").move_as_ok();
|
||||
td::BigNum::mod_add(y, y, coef, mod, context);
|
||||
td::BigNum::mod_mul(y, y, x, mod, context);
|
||||
td::BigNum one = td::BigNum::from_decimal("1").move_as_ok();
|
||||
td::BigNum::mod_add(y, y, one, mod, context);
|
||||
td::BigNum::mod_mul(y, y, x, mod, context);
|
||||
// y = x^3 + 486662 * x^2 + x
|
||||
if (is_quadratic_residue(y)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
request += key;
|
||||
};
|
||||
|
||||
const size_t MAX_GREASE = 7;
|
||||
char greases[MAX_GREASE];
|
||||
td::Random::secure_bytes(td::MutableSlice{greases, MAX_GREASE});
|
||||
for (auto &grease : greases) {
|
||||
grease = static_cast<char>((grease & 0xF0) + 0x0A);
|
||||
}
|
||||
for (size_t i = 1; i < MAX_GREASE; i += 2) {
|
||||
if (greases[i] == greases[i - 1]) {
|
||||
greases[i] = static_cast<char>(0x10 ^ greases[i]);
|
||||
}
|
||||
}
|
||||
auto add_grease = [&](size_t num) {
|
||||
auto c = greases[num];
|
||||
request += c;
|
||||
request += c;
|
||||
};
|
||||
|
||||
add_string("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03");
|
||||
add_random(32);
|
||||
add_string("\x20");
|
||||
add_random(32);
|
||||
add_string("\x00\x20");
|
||||
add_grease(0);
|
||||
add_string(
|
||||
"\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c\x00\x9d\x00"
|
||||
"\x2f\x00\x35\x01\x00\x01\x93");
|
||||
add_grease(2);
|
||||
add_string("\x00\x00\x00\x00");
|
||||
add_length(url.size() + 5);
|
||||
add_length(url.size() + 3);
|
||||
add_string("\x00");
|
||||
add_length(url.size());
|
||||
add_string(url);
|
||||
add_string("\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\x0a\x00\x0a\x00\x08");
|
||||
add_grease(4);
|
||||
add_string(
|
||||
"\x00\x1d\x00\x17\x00\x18\x00\x0b\x00\x02\x01\x00\x00\x23\x00\x00\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08\x68"
|
||||
"\x74\x74\x70\x2f\x31\x2e\x31\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x0d\x00\x12\x00\x10\x04\x03\x08\x04\x04"
|
||||
"\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01\x00\x12\x00\x00\x00\x33\x00\x2b\x00\x29");
|
||||
add_grease(4);
|
||||
add_string("\x00\x01\x00\x00\x1d\x00\x20");
|
||||
add_key();
|
||||
add_string("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x0b\x0a");
|
||||
add_grease(6);
|
||||
add_string("\x03\x04\x03\x03\x03\x02\x03\x01\x00\x1b\x00\x03\x02\x00\x02");
|
||||
add_grease(3);
|
||||
add_string("\x00\x01\x00\x00\x15");
|
||||
auto padding = 515 - static_cast<int>(request.size());
|
||||
CHECK(padding >= 0);
|
||||
add_length(padding);
|
||||
request.resize(517);
|
||||
|
||||
// LOG(ERROR) << td::format::as_hex_dump<0>(td::Slice(request));
|
||||
|
||||
TRY_STATUS(socket.write(request));
|
||||
|
||||
TlsInfo info;
|
||||
auto end_time = td::Time::now() + 3;
|
||||
td::string result;
|
||||
size_t pos = 0;
|
||||
size_t server_hello_length = 0;
|
||||
size_t encrypted_application_data_length_sum = 0;
|
||||
while (td::Time::now() < end_time) {
|
||||
static char buf[20000];
|
||||
TRY_RESULT(res, socket.read(td::MutableSlice{buf, sizeof(buf)}));
|
||||
if (res > 0) {
|
||||
auto read_length = [&]() -> size_t {
|
||||
CHECK(result.size() >= 2 + pos);
|
||||
pos += 2;
|
||||
return static_cast<unsigned char>(result[pos - 2]) * 256 + static_cast<unsigned char>(result[pos - 1]);
|
||||
};
|
||||
|
||||
result += td::Slice(buf, res).str();
|
||||
while (true) {
|
||||
#define CHECK_LENGTH(length) \
|
||||
if (pos + (length) > result.size()) { \
|
||||
break; \
|
||||
}
|
||||
#define EXPECT_STR(pos, str, error) \
|
||||
if (!begins_with(td::Slice(result).substr(pos), str)) { \
|
||||
return td::Status::Error(error); \
|
||||
}
|
||||
|
||||
if (pos == 0) {
|
||||
CHECK_LENGTH(3);
|
||||
EXPECT_STR(0, "\x16\x03\x03", "Non-TLS response or TLS <= 1.1");
|
||||
pos += 3;
|
||||
}
|
||||
if (pos == 3) {
|
||||
CHECK_LENGTH(2);
|
||||
server_hello_length = read_length();
|
||||
if (server_hello_length <= 39) {
|
||||
return td::Status::Error("Receive too short server hello");
|
||||
}
|
||||
}
|
||||
if (server_hello_length > 0) {
|
||||
if (pos == 5) {
|
||||
CHECK_LENGTH(server_hello_length);
|
||||
|
||||
EXPECT_STR(5, "\x02\x00", "Non-TLS response 2");
|
||||
EXPECT_STR(9, "\x03\x03", "Non-TLS response 3");
|
||||
|
||||
auto random_id = td::Slice(result.c_str() + 11, 32);
|
||||
if (random_id ==
|
||||
"\xcf\x21\xad\x74\xe5\x9a\x61\x11\xbe\x1d\x8c\x02\x1e\x65\xb8\x91\xc2\xa2\x11\x16\x7a\xbb\x8c\x5e\x07"
|
||||
"\x9e\x09\xe2\xc8\xa8\x33\x9c") {
|
||||
return td::Status::Error("TLS 1.3 servers returning HelloRetryRequest are not supported");
|
||||
}
|
||||
if (result[43] == '\x00') {
|
||||
return td::Status::Error("TLS <= 1.2: empty session_id");
|
||||
}
|
||||
EXPECT_STR(43, "\x20", "Non-TLS response 4");
|
||||
if (server_hello_length <= 75) {
|
||||
return td::Status::Error("Receive too short server hello 2");
|
||||
}
|
||||
EXPECT_STR(44, request.substr(44, 32), "TLS <= 1.2: expected mirrored session_id");
|
||||
EXPECT_STR(76, "\x13\x01\x00", "TLS <= 1.2: expected 0x1301 as a chosen cipher");
|
||||
pos += 74;
|
||||
size_t extensions_length = read_length();
|
||||
if (extensions_length + 76 != server_hello_length) {
|
||||
return td::Status::Error("Receive wrong extensions length");
|
||||
}
|
||||
while (pos < 5 + server_hello_length - 4) {
|
||||
info.extension_list.push_back(read_length());
|
||||
size_t extension_length = read_length();
|
||||
if (pos + extension_length > 5 + server_hello_length) {
|
||||
return td::Status::Error("Receive wrong extension length");
|
||||
}
|
||||
pos += extension_length;
|
||||
}
|
||||
if (pos != 5 + server_hello_length) {
|
||||
return td::Status::Error("Receive wrong extensions list");
|
||||
}
|
||||
}
|
||||
if (pos == 5 + server_hello_length) {
|
||||
CHECK_LENGTH(6);
|
||||
EXPECT_STR(pos, "\x14\x03\x03\x00\x01\x01", "Expected dummy ChangeCipherSpec");
|
||||
pos += 6;
|
||||
}
|
||||
if (pos == 11 + server_hello_length + encrypted_application_data_length_sum) {
|
||||
if (pos == result.size()) {
|
||||
return info;
|
||||
}
|
||||
|
||||
CHECK_LENGTH(3);
|
||||
EXPECT_STR(pos, "\x17\x03\x03", "Expected encrypted application data");
|
||||
pos += 3;
|
||||
}
|
||||
if (pos == 14 + server_hello_length + encrypted_application_data_length_sum) {
|
||||
CHECK_LENGTH(2);
|
||||
size_t encrypted_application_data_length = read_length();
|
||||
info.encrypted_application_data_length.push_back(encrypted_application_data_length);
|
||||
if (encrypted_application_data_length == 0) {
|
||||
return td::Status::Error("Receive empty encrypted application data");
|
||||
}
|
||||
}
|
||||
if (pos == 16 + server_hello_length + encrypted_application_data_length_sum) {
|
||||
CHECK_LENGTH(info.encrypted_application_data_length.back());
|
||||
pos += info.encrypted_application_data_length.back();
|
||||
encrypted_application_data_length_sum += info.encrypted_application_data_length.back() + 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
td::usleep_for(10000);
|
||||
}
|
||||
}
|
||||
|
||||
// LOG(ERROR) << url << ":" << td::format::as_hex_dump<0>(td::Slice(result));
|
||||
return td::Status::Error("Failed to get response in 3 seconds");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING));
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
auto iocp = td::make_unique<td::detail::Iocp>();
|
||||
iocp->init();
|
||||
auto iocp_thread = td::thread([&iocp] { iocp->loop(); });
|
||||
td::detail::Iocp::Guard iocp_guard(iocp.get());
|
||||
#endif
|
||||
|
||||
td::vector<td::string> urls;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
urls.emplace_back(argv[i]);
|
||||
}
|
||||
for (auto &url : urls) {
|
||||
const int MAX_TRIES = 100;
|
||||
td::vector<std::map<size_t, int>> length_count;
|
||||
td::vector<size_t> extension_list;
|
||||
for (int i = 0; i < MAX_TRIES; i++) {
|
||||
auto r_tls_info = test_tls(url);
|
||||
if (r_tls_info.is_error()) {
|
||||
LOG(ERROR) << url << ": " << r_tls_info.error();
|
||||
break;
|
||||
} else {
|
||||
auto tls_info = r_tls_info.move_as_ok();
|
||||
if (length_count.size() < tls_info.encrypted_application_data_length.size()) {
|
||||
length_count.resize(tls_info.encrypted_application_data_length.size());
|
||||
}
|
||||
for (size_t t = 0; t < tls_info.encrypted_application_data_length.size(); t++) {
|
||||
length_count[t][tls_info.encrypted_application_data_length[t]]++;
|
||||
}
|
||||
if (i == 0) {
|
||||
extension_list = tls_info.extension_list;
|
||||
} else {
|
||||
if (extension_list != tls_info.extension_list) {
|
||||
LOG(ERROR) << url << ": TLS 1.3.0 extension list has changed from " << extension_list << " to "
|
||||
<< tls_info.extension_list;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == MAX_TRIES - 1) {
|
||||
if (extension_list != td::vector<size_t>{51, 43} && extension_list != td::vector<size_t>{43, 51}) {
|
||||
LOG(ERROR) << url << ": TLS 1.3.0 unsupported extension list " << extension_list;
|
||||
} else {
|
||||
td::string length_distribution = "|";
|
||||
for (size_t t = 0; t < length_count.size(); t++) {
|
||||
for (auto it : length_count[t]) {
|
||||
length_distribution += PSTRING()
|
||||
<< it.first << " : " << static_cast<int>(it.second * 100.0 / MAX_TRIES) << "%|";
|
||||
}
|
||||
if (t + 1 != length_count.size()) {
|
||||
length_distribution += " + |";
|
||||
}
|
||||
}
|
||||
LOG(ERROR) << url << ": TLS 1.3.0 with extensions " << extension_list << " and "
|
||||
<< (length_count.size() != 1 ? "unsupported " : "")
|
||||
<< "encrypted application data length distribution " << length_distribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
iocp->interrupt_loop();
|
||||
iocp_thread.join();
|
||||
#endif
|
||||
}
|
545
third-party/td/td/benchmark/hashmap_build.cpp
vendored
@ -1,545 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/utils/FlatHashMap.h"
|
||||
|
||||
#ifdef SCOPE_EXIT
|
||||
#undef SCOPE_EXIT
|
||||
#endif
|
||||
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
#include <array>
|
||||
#include <folly/container/F14Map.h>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
#define test_map td::FlatHashMap
|
||||
//#define test_map folly::F14FastMap
|
||||
//#define test_map absl::flat_hash_map
|
||||
//#define test_map std::map
|
||||
//#define test_map std::unordered_map
|
||||
|
||||
//#define CREATE_MAP(num) CREATE_MAP_IMPL(num)
|
||||
#define CREATE_MAP(num)
|
||||
|
||||
#define CREATE_MAP_IMPL(num) \
|
||||
int f_##num() { \
|
||||
test_map<td::int32, std::array<char, num>> m; \
|
||||
m.emplace(1, std::array<char, num>{}); \
|
||||
int sum = 0; \
|
||||
for (auto &it : m) { \
|
||||
sum += it.first; \
|
||||
} \
|
||||
auto it = m.find(1); \
|
||||
sum += it->first; \
|
||||
m.erase(it); \
|
||||
return sum; \
|
||||
} \
|
||||
int x_##num = f_##num()
|
||||
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
CREATE_MAP(__LINE__);
|
||||
|
||||
int main() {
|
||||
}
|
193
third-party/td/td/benchmark/hashset_memory.cpp
vendored
@ -1,193 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
#if USE_MEMPROF
|
||||
#include "memprof/memprof_stat.h"
|
||||
#endif
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/FlatHashMapChunks.h"
|
||||
#include "td/utils/FlatHashTable.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/MapNode.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/Stat.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#ifdef SCOPE_EXIT
|
||||
#undef SCOPE_EXIT
|
||||
#endif
|
||||
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
#include <array>
|
||||
#include <folly/container/F14Map.h>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
static int mem_stat_i = -1;
|
||||
static int mem_stat_cur = 0;
|
||||
|
||||
static bool use_memprof() {
|
||||
#if USE_MEMPROF
|
||||
return mem_stat_i < 0 && is_memprof_on();
|
||||
#else
|
||||
return mem_stat_i < 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static td::uint64 get_memory() {
|
||||
#if USE_MEMPROF
|
||||
if (use_memprof()) {
|
||||
return get_used_memory_size();
|
||||
}
|
||||
#endif
|
||||
CHECK(!use_memprof());
|
||||
return td::mem_stat().ok().resident_size_;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class Generator {
|
||||
public:
|
||||
T next() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
static size_t dyn_size() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class IntGenerator {
|
||||
public:
|
||||
T next() {
|
||||
return ++value;
|
||||
}
|
||||
static size_t dyn_size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
T value{};
|
||||
};
|
||||
|
||||
template <>
|
||||
class Generator<td::int32> final : public IntGenerator<td::int32> {};
|
||||
template <>
|
||||
class Generator<td::int64> final : public IntGenerator<td::int64> {};
|
||||
|
||||
template <class T>
|
||||
class Generator<td::unique_ptr<T>> {
|
||||
public:
|
||||
td::unique_ptr<T> next() {
|
||||
return td::make_unique<T>();
|
||||
}
|
||||
static std::size_t dyn_size() {
|
||||
return sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class KeyT, class ValueT>
|
||||
static void measure(td::StringBuilder &sb, td::Slice name, td::Slice key_name, td::Slice value_name) {
|
||||
mem_stat_cur++;
|
||||
if (mem_stat_i >= 0 && mem_stat_cur != mem_stat_i) {
|
||||
return;
|
||||
}
|
||||
sb << name << "<" << key_name << "," << value_name << "> " << (use_memprof() ? "memprof" : "os") << "\n";
|
||||
std::size_t ideal_size = sizeof(KeyT) + sizeof(ValueT) + Generator<ValueT>::dyn_size();
|
||||
|
||||
sb << "\tempty:" << sizeof(T);
|
||||
struct Stat {
|
||||
int pi;
|
||||
double min_ratio;
|
||||
double max_ratio;
|
||||
};
|
||||
td::vector<Stat> stat;
|
||||
stat.reserve(1024);
|
||||
for (std::size_t size : {1000000u}) {
|
||||
Generator<KeyT> key_generator;
|
||||
Generator<ValueT> value_generator;
|
||||
auto start_mem = get_memory();
|
||||
T ht;
|
||||
auto ratio = [&] {
|
||||
auto end_mem = get_memory();
|
||||
auto used_mem = end_mem - start_mem;
|
||||
return static_cast<double>(used_mem) / (static_cast<double>(ideal_size) * static_cast<double>(ht.size()));
|
||||
};
|
||||
double min_ratio;
|
||||
double max_ratio;
|
||||
auto reset = [&] {
|
||||
min_ratio = 1e100;
|
||||
max_ratio = 0;
|
||||
};
|
||||
auto update = [&] {
|
||||
auto x = ratio();
|
||||
min_ratio = td::min(min_ratio, x);
|
||||
max_ratio = td::max(max_ratio, x);
|
||||
};
|
||||
reset();
|
||||
|
||||
int p = 10;
|
||||
int pi = 1;
|
||||
for (std::size_t i = 0; i < size; i++) {
|
||||
ht.emplace(key_generator.next(), value_generator.next());
|
||||
update();
|
||||
if ((i + 1) % p == 0) {
|
||||
stat.push_back(Stat{pi, min_ratio, max_ratio});
|
||||
reset();
|
||||
pi++;
|
||||
p *= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &s : stat) {
|
||||
sb << " 10^" << s.pi << ":" << s.min_ratio << "->" << s.max_ratio;
|
||||
}
|
||||
sb << '\n';
|
||||
}
|
||||
|
||||
template <std::size_t size>
|
||||
using Bytes = std::array<char, size>;
|
||||
|
||||
template <template <typename... Args> class T>
|
||||
void print_memory_stats(td::Slice name) {
|
||||
td::string big_buff(1 << 16, '\0');
|
||||
td::StringBuilder sb(big_buff, false);
|
||||
#define MEASURE(KeyT, ValueT) measure<T<KeyT, ValueT>, KeyT, ValueT>(sb, name, #KeyT, #ValueT);
|
||||
MEASURE(td::int32, td::int32);
|
||||
MEASURE(td::int64, td::unique_ptr<Bytes<360>>);
|
||||
if (!sb.as_cslice().empty()) {
|
||||
LOG(PLAIN) << '\n' << sb.as_cslice() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
template <class KeyT, class ValueT, class HashT = td::Hash<KeyT>, class EqT = std::equal_to<KeyT>>
|
||||
using FlatHashMapImpl = td::FlatHashTable<td::MapNode<KeyT, ValueT>, HashT, EqT>;
|
||||
|
||||
#define FOR_EACH_TABLE(F) \
|
||||
F(FlatHashMapImpl) \
|
||||
F(folly::F14FastMap) \
|
||||
F(absl::flat_hash_map) \
|
||||
F(std::unordered_map) \
|
||||
F(std::map)
|
||||
#define BENCHMARK_MEMORY(T) print_memory_stats<T>(#T);
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
// Usage:
|
||||
// % benchmark/memory-hashset-os 0
|
||||
// Number of benchmarks = 10
|
||||
// % for i in {1..10}; do ./benchmark/memory-hashset-os $i; done
|
||||
if (argc > 1) {
|
||||
mem_stat_i = td::to_integer<td::int32>(td::Slice(argv[1]));
|
||||
}
|
||||
FOR_EACH_TABLE(BENCHMARK_MEMORY);
|
||||
if (mem_stat_i <= 0) {
|
||||
LOG(PLAIN) << "Number of benchmarks = " << mem_stat_cur << "\n";
|
||||
}
|
||||
}
|
45
third-party/td/td/benchmark/rmdir.cpp
vendored
@ -1,45 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 1) {
|
||||
return 1;
|
||||
}
|
||||
td::CSlice dir(argv[1]);
|
||||
int cnt = 0;
|
||||
auto status = td::walk_path(dir, [&](td::CSlice path, auto type) {
|
||||
if (type != td::WalkPath::Type::EnterDir) {
|
||||
cnt++;
|
||||
}
|
||||
auto type_name = [&] {
|
||||
switch (type) {
|
||||
case td::WalkPath::Type::EnterDir:
|
||||
return td::CSlice("Open");
|
||||
case td::WalkPath::Type::ExitDir:
|
||||
return td::CSlice("Exit");
|
||||
case td::WalkPath::Type::RegularFile:
|
||||
return td::CSlice("File");
|
||||
case td::WalkPath::Type::Symlink:
|
||||
return td::CSlice("Link");
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return td::CSlice();
|
||||
}
|
||||
}();
|
||||
LOG(INFO) << type_name << ' ' << path;
|
||||
//if (is_dir) {
|
||||
// td::rmdir(path);
|
||||
//} else {
|
||||
// td::unlink(path);
|
||||
//}
|
||||
});
|
||||
LOG(INFO) << status << ": " << cnt;
|
||||
}
|
43
third-party/td/td/benchmark/wget.cpp
vendored
@ -1,43 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/net/HttpQuery.h"
|
||||
#include "td/net/Wget.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/ConcurrentScheduler.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(DEBUG));
|
||||
td::VERBOSITY_NAME(fd) = VERBOSITY_NAME(INFO);
|
||||
|
||||
td::string url = (argc > 1 ? argv[1] : "https://telegram.org");
|
||||
auto timeout = 10;
|
||||
auto ttl = 3;
|
||||
auto prefer_ipv6 = (argc > 2 && td::string(argv[2]) == "-6");
|
||||
auto scheduler = td::make_unique<td::ConcurrentScheduler>(0, 0);
|
||||
scheduler
|
||||
->create_actor_unsafe<td::Wget>(0, "Client",
|
||||
td::PromiseCreator::lambda([](td::Result<td::unique_ptr<td::HttpQuery>> res) {
|
||||
if (res.is_error()) {
|
||||
LOG(FATAL) << res.error();
|
||||
}
|
||||
LOG(ERROR) << *res.ok();
|
||||
td::Scheduler::instance()->finish();
|
||||
}),
|
||||
url, td::Auto(), timeout, ttl, prefer_ipv6)
|
||||
.release();
|
||||
scheduler->start();
|
||||
while (scheduler->run_main(10)) {
|
||||
// empty
|
||||
}
|
||||
scheduler->finish();
|
||||
}
|
1139
third-party/td/td/build.html
vendored
321
third-party/td/td/example/README.md
vendored
@ -1,321 +0,0 @@
|
||||
# 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
|
||||
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.
|
||||
|
||||
TDLib can be easily used from almost any programming language on any platform. See a [TDLib build instructions generator](https://tdlib.github.io/td/build.html) for detailed instructions on how to build TDLib.
|
||||
Choose your preferred programming language to see examples of usage and a detailed description:
|
||||
|
||||
- [Python](#python)
|
||||
- [JavaScript](#javascript)
|
||||
- [Go](#go)
|
||||
- [Java](#java)
|
||||
- [Kotlin](#kotlin)
|
||||
- [C#](#csharp)
|
||||
- [C++](#cxx)
|
||||
- [Swift](#swift)
|
||||
- [Objective-C](#objective-c)
|
||||
- [Object Pascal](#object-pascal)
|
||||
- [Dart](#dart)
|
||||
- [Rust](#rust)
|
||||
- [Erlang](#erlang)
|
||||
- [PHP](#php)
|
||||
- [Lua](#lua)
|
||||
- [Ruby](#ruby)
|
||||
- [Crystal](#crystal)
|
||||
- [Haskell](#haskell)
|
||||
- [Nim](#nim)
|
||||
- [Clojure](#clojure)
|
||||
- [Emacs Lisp](#emacslisp)
|
||||
- [D](#d)
|
||||
- [Elixir](#elixir)
|
||||
- [Vala](#vala)
|
||||
- [1С](#1s)
|
||||
- [C](#c)
|
||||
- [G](#g)
|
||||
- [Other](#other)
|
||||
|
||||
<a name="python"></a>
|
||||
## Using TDLib in Python projects
|
||||
|
||||
TDLib can be used from Python through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
Convenient Python wrappers already exist for our JSON interface.
|
||||
|
||||
If you use Python >= 3.6, take a look at [python-telegram](https://github.com/alexander-akhmetov/python-telegram).
|
||||
The wrapper uses the full power of asyncio, has a good documentation and has several examples. It can be installed through pip or used in a Docker container.
|
||||
You can also try a fork [python-telegram](https://github.com/iTeam-co/pytglib) of this library.
|
||||
|
||||
If you want to use TDLib with asyncio and Python >= 3.9, take a look at [aiotdlib](https://github.com/pylakey/aiotdlib) or [Pytdbot](https://github.com/pytdbot/client).
|
||||
|
||||
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),
|
||||
[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 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
|
||||
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.
|
||||
|
||||
TDLib can be used from Node.js through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
Convenient Node.js wrappers already exist for our JSON interface.
|
||||
For example, take a look at [Airgram](https://github.com/airgram/airgram) – modern TDLib framework for TypeScript/JavaScript, or
|
||||
at [tdl](https://github.com/eilvelia/tdl), which provides a convenient, fully-asynchronous interface for interaction with TDLib and contains a bunch of examples.
|
||||
|
||||
You can also see [TdNode](https://github.com/puppy0cam/TdNode), [tglib](https://github.com/nodegin/tglib), [node-tdlib](https://github.com/wfjsw/node-tdlib), [tdlnode](https://github.com/fonbah/tdlnode),
|
||||
[Paper Plane](https://github.com/par6n/paper-plane), or [node-tlg](https://github.com/dilongfa/node-tlg) for other examples of TDLib JSON interface integration with Node.js.
|
||||
|
||||
See also the source code of [DIBgram](https://github.com/DIBgram/DIBgram) - an unofficial Telegram web application which looks like Telegram Desktop.
|
||||
|
||||
TDLib can be used also from NativeScript through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
See [nativescript-tglib](https://github.com/arpit2438735/nativescript-tglib) as an example of a NativeScript library for building Telegram clients.
|
||||
|
||||
<a name="go"></a>
|
||||
## Using TDLib in Go projects
|
||||
|
||||
TDLib can be used from the Go programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and Cgo, and can be linked either statically or dynamically.
|
||||
|
||||
Convenient Go wrappers already exist for our JSON interface.
|
||||
For example, take a look at [github.com/zelenin/go-tdlib](https://github.com/zelenin/go-tdlib) or [github.com/Arman92/go-tdlib](https://github.com/Arman92/go-tdlib), which provide a convenient TDLib client, a generator for TDLib API classes and contain many examples.
|
||||
|
||||
You can also see [github.com/aliforever/go-tdlib](https://github.com/aliforever/go-tdlib) for another examples of TDLib JSON interface integration with Go.
|
||||
|
||||
<a name="java"></a>
|
||||
## Using TDLib in Java projects
|
||||
|
||||
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/android](https://github.com/tdlib/td/tree/master/example/android) for detailed build instructions for Android.
|
||||
|
||||
<a name="kotlin"></a>
|
||||
## Using TDLib in Kotlin projects
|
||||
|
||||
TDLib can be used from the Kotlin/JVM programming language through same way as in [Java](#java).
|
||||
|
||||
You can also use [ktd](https://github.com/whyoleg/ktd) library with Kotlin-specific bindings.
|
||||
|
||||
See also [td-ktx](https://github.com/tdlibx/td-ktx) - Kotlin coroutines wrapper for TDLib.
|
||||
|
||||
<a name="csharp"></a>
|
||||
## Using TDLib in C# projects
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Also, see [Unigram](https://github.com/UnigramDev/Unigram), which is a full-featured client rewritten from scratch in C# using TDLib SDK for Universal Windows Platform in less than 2 months,
|
||||
[egram.tel](https://github.com/egramtel/egram.tel) – a cross-platform Telegram client written in C#, .NET Core, ReactiveUI and Avalonia, or
|
||||
[telewear](https://github.com/telewear/telewear) - a Telegram client for Samsung watches.
|
||||
|
||||
<a name="cxx"></a>
|
||||
## Using TDLib in C++ projects
|
||||
|
||||
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 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,
|
||||
or [MeeGram](https://github.com/qtinsider/meegram2) - a Telegram client for Nokia N9,
|
||||
[TDLib Native Sciter Extension](https://github.com/EricKotato/TDLibNSE) - a Sciter native extension for TDLib's JSON interface, all of which are based on TDLib.
|
||||
|
||||
<a name="swift"></a>
|
||||
## Using TDLib in Swift projects
|
||||
|
||||
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, visionOS, 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.
|
||||
|
||||
<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, visionOS, and macOS.
|
||||
|
||||
<a name="object-pascal"></a>
|
||||
## Using TDLib in Object Pascal projects with Delphi and Lazarus
|
||||
|
||||
TDLib can be used from the Object Pascal programming language through the [JSON](https://github.com/tdlib/td#using-json).
|
||||
|
||||
See [tdlib-delphi](https://github.com/dieletro/tdlib-delphi) for an example of TDLib usage from Delphi.
|
||||
|
||||
See [tdlib-lazarus](https://github.com/dieletro/tdlib-lazarus) for an example of TDLib usage from Lazarus.
|
||||
|
||||
<a name="dart"></a>
|
||||
## Using TDLib in Dart projects
|
||||
|
||||
TDLib can be used from the Dart programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and a Dart Native Extension or Dart FFI.
|
||||
|
||||
See [tdlib-dart](https://github.com/ivk1800/tdlib-dart), which provide convenient TDLib client with automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
|
||||
See also [dart_tdlib](https://github.com/periodicaidan/dart_tdlib), [flutter_libtdjson](https://github.com/up9cloud/flutter_libtdjson), [Dart wrapper for TDLib](https://github.com/tdlib/td/pull/708/commits/237060abd4c205768153180e9f814298d1aa9d49), or [tdlib_bindings](https://github.com/lesnitsky/tdlib_bindings) for an example of a TDLib Dart bindings through FFI.
|
||||
|
||||
See [Telegram Client library](https://github.com/azkadev/telegram_client), [project.scarlet](https://github.com/aaugmentum/project.scarlet), [tdlib](https://github.com/i-Naji/tdlib),
|
||||
[tdlib-dart](https://github.com/drewpayment/tdlib-dart), [FluGram](https://github.com/triedcatched/tdlib-dart), or [telegram-service](https://github.com/igorder-dev/telegram-service) for examples of using TDLib from Dart.
|
||||
|
||||
See also [telegram-flutter](https://github.com/ivk1800/telegram-flutter) - Telegram client written in Dart, and [f-Telegram](https://github.com/evgfilim1/ftg) - Flutter Telegram client.
|
||||
|
||||
<a name="rust"></a>
|
||||
## Using TDLib in Rust projects
|
||||
|
||||
TDLib can be used from the Rust programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [rust-tdlib](https://github.com/antonio-antuan/rust-tdlib), or [tdlib](https://github.com/paper-plane-developers/tdlib-rs), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
|
||||
See [rtdlib](https://github.com/fewensa/rtdlib), [tdlib-rs](https://github.com/d653/tdlib-rs), [tdlib-futures](https://github.com/yuri91/tdlib-futures),
|
||||
[tdlib-sys](https://github.com/nuxeh/tdlib-sys), [tdjson-rs](https://github.com/mersinvald/tdjson-rs), [rust-tdlib](https://github.com/vhaoran/rust-tdlib), or [tdlib-json-sys](https://github.com/aykxt/tdlib-json-sys) for examples of TDLib Rust bindings.
|
||||
|
||||
Also, see [Paper Plane](https://github.com/paper-plane-developers/paper-plane) – a Telegram client written in Rust and GTK.
|
||||
|
||||
<a name="erlang"></a>
|
||||
## Using TDLib in Erlang projects
|
||||
|
||||
TDLib can be used from the Erlang programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [erl-tdlib](https://github.com/lattenwald/erl-tdlib) for an example of TDLib Erlang bindings.
|
||||
|
||||
<a name="php"></a>
|
||||
## Using TDLib in PHP projects
|
||||
|
||||
If you use modern PHP >= 7.4, you can use TDLib via a PHP FFI extension. For example, take a look at [ffi-tdlib](https://github.com/aurimasniekis/php-ffi-tdlib), or [tdlib-php-ffi](https://github.com/thisismzm/tdlib-php-ffi) - FFI-based TDLib wrappers.
|
||||
|
||||
See also [tdlib-schema](https://github.com/aurimasniekis/php-tdlib-schema) - a generator for TDLib API classes.
|
||||
|
||||
For older PHP versions you can use TDLib by wrapping its functionality in a PHP extension.
|
||||
|
||||
See [phptdlib](https://github.com/yaroslavche/phptdlib), [tdlib](https://github.com/aurimasniekis/php-ext-tdlib), or [PIF-TDPony](https://github.com/danog/pif-tdpony)
|
||||
for examples of such extensions which provide access to TDLib from PHP.
|
||||
|
||||
See [tdlib-bundle](https://github.com/yaroslavche/tdlib-bundle) – a Symfony bundle based on [phptdlib](https://github.com/yaroslavche/phptdlib).
|
||||
|
||||
<a name="lua"></a>
|
||||
## Using TDLib in Lua projects
|
||||
|
||||
TDLib can be used from the Lua programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [luajit-tdlib](https://github.com/Rami-Sabbagh/luajit-tdlib), [tdlua](https://github.com/giuseppeM99/tdlua), or
|
||||
[luajit-tdlib](https://github.com/Playermet/luajit-tdlib) for examples of TDLib Lua bindings and basic usage examples.
|
||||
|
||||
See also [tdbot](https://github.com/vysheng/tdbot), which makes all TDLib features available from Lua scripts.
|
||||
|
||||
<a name="d"></a>
|
||||
## Using TDLib in D projects
|
||||
|
||||
TDLib can be used from the D programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [d-tdlib-service](https://github.com/Lord-Evil/d-tdlib-service) for an example of TDLib D bindings.
|
||||
|
||||
<a name="ruby"></a>
|
||||
## Using TDLib in Ruby projects
|
||||
|
||||
TDLib can be used from the Ruby programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [tdlib-ruby](https://github.com/southbridgeio/tdlib-ruby) for examples of Ruby bindings and a client for TDLib.
|
||||
|
||||
<a name="Crystal"></a>
|
||||
## Using TDLib in Crystal projects
|
||||
|
||||
TDLib can be used from the Crystal programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [Proton](https://github.com/protoncr/proton) for examples of Crystal bindings with automatically generated types for all TDLib API methods and objects.
|
||||
|
||||
<a name="haskell"></a>
|
||||
## Using TDLib in Haskell projects
|
||||
|
||||
TDLib can be used from the Haskell programming language.
|
||||
|
||||
See [haskell-tdlib](https://github.com/mejgun/haskell-tdlib) or [tdlib](https://github.com/poscat0x04/tdlib) for examples of such usage and Haskell wrappers for TDLib.
|
||||
This library contains automatically generated Haskell types for all TDLib API methods and objects.
|
||||
|
||||
<a name="nim"></a>
|
||||
## Using TDLib in Nim projects
|
||||
|
||||
TDLib can be used from the Nim programming language.
|
||||
|
||||
See [telenim](https://github.com/Ethosa/telenim) for example of such usage and a Nim wrapper for TDLib.
|
||||
|
||||
<a name="clojure"></a>
|
||||
## Using TDLib in Clojure projects
|
||||
|
||||
TDLib can be used from the Clojure programming language through the [JSON](https://github.com/tdlib/td#using-json) interface.
|
||||
|
||||
See [clojure-tdlib-json-wrapper](https://github.com/MityaSaray/clojure-tdlib-json) for an example of TDLib Clojure bindings.
|
||||
|
||||
<a name="emacslisp"></a>
|
||||
## Using TDLib in Emacs Lisp projects
|
||||
|
||||
TDLib can be used from the Emacs Lisp programming language.
|
||||
|
||||
See [telega.el](https://github.com/zevlg/telega.el) for an example of a GNU Emacs Telegram client.
|
||||
|
||||
<a name="elixir"></a>
|
||||
## Using TDLib in Elixir projects
|
||||
|
||||
TDLib can be used from the Elixir programming language.
|
||||
|
||||
See [Elixir TDLib](https://github.com/QuantLayer/elixir-tdlib) for an example of such usage and an Elixir client for TDLib.
|
||||
The library contains automatically generated and fully-documented classes for all TDLib API methods and objects.
|
||||
|
||||
<a name="vala"></a>
|
||||
## Using TDLib in Vala projects
|
||||
|
||||
TDLib can be used from the Vala programming language.
|
||||
|
||||
See [TDLib Vala](https://github.com/AYMENJD/td-vala) for an example of such usage.
|
||||
|
||||
<a name="1s"></a>
|
||||
## Using TDLib from 1С:Enterprise
|
||||
|
||||
TDLib can be used from the 1С programming language.
|
||||
|
||||
See [TDLib bindings for 1С:Enterprise](https://github.com/Infactum/telegram-native) and [e1c.tAgents](https://github.com/fedbka/e1c.tAgents) for examples of such usage.
|
||||
|
||||
<a name="c"></a>
|
||||
## Using TDLib in C projects
|
||||
|
||||
TDLib can be used from the C programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
|
||||
|
||||
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).
|
||||
|
||||
<a name="g"></a>
|
||||
## Using TDLib from G projects
|
||||
|
||||
TDLib can be used from the G graphical programming language in LabVIEW development environment.
|
||||
|
||||
See [TDLib bindings for LabVIEW](https://github.com/IvanLisRus/Telegram-Client_TDLib) for examples of such usage.
|
||||
|
||||
<a name="other"></a>
|
||||
## Using TDLib from other programming languages
|
||||
|
||||
You can use TDLib from any other programming language using [tdbot](https://github.com/vysheng/tdbot) or [TDLib JSON CLI](https://github.com/oott123/tdlib-json-cli),
|
||||
which provide a command line tool for interaction with TDLIb using the [JSON](https://github.com/tdlib/td#using-json) interface through stdin and stdout.
|
||||
You can use this method to use TDLib, for example, from Brainfuck (unfortunately, we haven't seen examples of sending a Telegram message through TDLib on Brainfuck yet).
|
||||
|
||||
Alternatively, you can use the TDLib [JSON](https://github.com/tdlib/td#using-json) interface directly from your programming language.
|
||||
|
||||
Feel free to create an issue, if you have created a valuable TDLib binding or a TDLib client in some programming language and want it to be added to this list of examples.
|
3
third-party/td/td/example/android/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/SDK*
|
||||
/tdlib*
|
||||
/third-party*
|
51
third-party/td/td/example/android/AddIntDef.php
vendored
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
if ($argc !== 2) {
|
||||
exit();
|
||||
}
|
||||
$file = file_get_contents($argv[1]);
|
||||
|
||||
if (strpos($file, 'androidx.annotation.IntDef') !== false) {
|
||||
exit();
|
||||
}
|
||||
|
||||
$file = str_replace('import androidx.annotation.Nullable;', 'import androidx.annotation.IntDef;'.PHP_EOL.
|
||||
'import androidx.annotation.Nullable;'.PHP_EOL.
|
||||
PHP_EOL.
|
||||
'import java.lang.annotation.Retention;'.PHP_EOL.
|
||||
'import java.lang.annotation.RetentionPolicy;'.PHP_EOL, $file);
|
||||
|
||||
preg_match_all('/public static class ([A-Za-z0-9]+) extends ([A-Za-z0-9]+)/', $file, $matches, PREG_SET_ORDER);
|
||||
$children = [];
|
||||
foreach ($matches as $val) {
|
||||
if ($val[2] === 'Object') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$children[$val[2]][] = ' '.$val[1].'.CONSTRUCTOR';
|
||||
}
|
||||
|
||||
$file = preg_replace_callback('/public abstract static class ([A-Za-z0-9]+)(<R extends Object>)? extends Object [{]/',
|
||||
function ($val) use ($children) {
|
||||
$values = implode(','.PHP_EOL, $children[$val[1]]);
|
||||
return $val[0].<<<EOL
|
||||
|
||||
/**
|
||||
* Describes possible values returned by getConstructor().
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
$values
|
||||
})
|
||||
public @interface Constructors {}
|
||||
|
||||
/**
|
||||
* @return identifier uniquely determining type of the object.
|
||||
*/
|
||||
@Constructors
|
||||
@Override
|
||||
public abstract int getConstructor();
|
||||
EOL;
|
||||
},
|
||||
$file);
|
||||
|
||||
file_put_contents($argv[1], $file);
|
72
third-party/td/td/example/android/CMakeLists.txt
vendored
@ -1,72 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
|
||||
project(TdAndroid VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
set(TD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
|
||||
|
||||
option(TD_ANDROID_JSON "Use \"ON\" to build JSON interface.")
|
||||
option(TD_ANDROID_JSON_JAVA "Use \"ON\" to build Java wrapper for JSON API.")
|
||||
|
||||
if (TD_ANDROID_JSON)
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -flto=thin -Oz")
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH "${OPENSSL_ROOT_DIR}")
|
||||
endif()
|
||||
add_subdirectory(${TD_DIR} td)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT TD_ANDROID_JSON_JAVA)
|
||||
option(TD_ENABLE_JNI "Enable JNI-compatible TDLib API" ON)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_MODULE_PATH "${TD_DIR}/CMake")
|
||||
|
||||
include(TdSetUpCompiler)
|
||||
td_set_up_compiler()
|
||||
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -flto=thin -Oz")
|
||||
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH "${OPENSSL_ROOT_DIR}")
|
||||
add_subdirectory(${TD_DIR} td)
|
||||
|
||||
add_library(tdjni SHARED "${TD_DIR}/example/java/td_jni.cpp")
|
||||
|
||||
if (TD_ANDROID_JSON_JAVA)
|
||||
target_link_libraries(tdjni PRIVATE Td::TdJsonStatic)
|
||||
target_compile_definitions(tdjni PRIVATE TD_JSON_JAVA=1)
|
||||
set_target_properties(tdjni PROPERTIES OUTPUT_NAME "tdjsonjava")
|
||||
else()
|
||||
target_link_libraries(tdjni PRIVATE Td::TdStatic)
|
||||
endif()
|
||||
target_compile_definitions(tdjni PRIVATE PACKAGE_NAME="org/drinkless/tdlib")
|
||||
|
||||
add_custom_command(TARGET tdjni POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E rename $<TARGET_FILE:tdjni> $<TARGET_FILE:tdjni>.debug
|
||||
COMMAND ${CMAKE_STRIP} --strip-debug --strip-unneeded $<TARGET_FILE:tdjni>.debug -o $<TARGET_FILE:tdjni>)
|
||||
else()
|
||||
add_subdirectory(${TD_DIR} td)
|
||||
|
||||
if (TD_ANDROID_JSON_JAVA)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(TD_API_JAVA_PACKAGE "org/drinkless/tdlib")
|
||||
set(TD_API_JAVA_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${TD_API_JAVA_PACKAGE}/TdApi.java")
|
||||
set(TD_API_TLO_PATH "${TD_DIR}/td/generate/auto/tlo/td_api.tlo")
|
||||
set(TD_API_TL_PATH "${TD_DIR}/td/generate/scheme/td_api.tl")
|
||||
set(JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH "${TD_DIR}/td/generate/JavadocTlDocumentationGenerator.php")
|
||||
set(GENERATE_JAVA_CMD td_generate_java_api TdApi ${TD_API_TLO_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${TD_API_JAVA_PACKAGE})
|
||||
if (PHP_EXECUTABLE)
|
||||
set(GENERATE_JAVA_CMD ${GENERATE_JAVA_CMD} &&
|
||||
${PHP_EXECUTABLE} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH} ${TD_API_TL_PATH} ${TD_API_JAVA_PATH} androidx.annotation.Nullable @Nullable &&
|
||||
${PHP_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/AddIntDef.php ${TD_API_JAVA_PATH})
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${TD_API_JAVA_PACKAGE})
|
||||
add_custom_target(tl_generate_java
|
||||
COMMAND ${GENERATE_JAVA_CMD}
|
||||
COMMENT "Generate Java TL source files"
|
||||
DEPENDS td_generate_java_api tl_generate_tlo ${TD_API_TLO_PATH} ${TD_API_TL_PATH}
|
||||
)
|
||||
endif()
|
28
third-party/td/td/example/android/Dockerfile
vendored
@ -1,28 +0,0 @@
|
||||
FROM --platform=linux/amd64 ubuntu:24.04 AS build
|
||||
|
||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq default-jdk g++ git gperf make perl php-cli unzip wget && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /home
|
||||
|
||||
ARG ANDROID_NDK_VERSION=23.2.8568313
|
||||
COPY ./check-environment.sh ./fetch-sdk.sh ./
|
||||
RUN ./fetch-sdk.sh SDK "$ANDROID_NDK_VERSION"
|
||||
|
||||
ARG OPENSSL_VERSION=OpenSSL_1_1_1w
|
||||
ARG BUILD_SHARED_OPENSSL_LIBS=
|
||||
COPY ./build-openssl.sh ./
|
||||
RUN ./build-openssl.sh SDK "$ANDROID_NDK_VERSION" openssl "$OPENSSL_VERSION" "$BUILD_SHARED_OPENSSL_LIBS"
|
||||
|
||||
ADD "https://api.github.com/repos/tdlib/td/git/refs/heads/master" version.json
|
||||
ARG COMMIT_HASH=master
|
||||
RUN git clone https://github.com/tdlib/td.git && cd td && git checkout "$COMMIT_HASH"
|
||||
RUN cd td && git merge-base --is-ancestor 872d8ebd3ba9d922169839e6a24cee08b02b328a "$COMMIT_HASH"
|
||||
|
||||
ARG ANDROID_STL=c++_static
|
||||
ARG TDLIB_INTERFACE=Java
|
||||
RUN td/example/android/build-tdlib.sh SDK "$ANDROID_NDK_VERSION" openssl "$ANDROID_STL" "$TDLIB_INTERFACE" && rm -rf td/example/android/build-*
|
||||
|
||||
|
||||
FROM scratch
|
||||
|
||||
COPY --from=build /home/td/example/android/tdlib/tdlib* /
|
32
third-party/td/td/example/android/README.md
vendored
@ -1,32 +0,0 @@
|
||||
# TDLib Android example
|
||||
|
||||
This is an example of building `TDLib` for Android.
|
||||
You need a Bash shell on Linux, macOS, or Windows with some common tools, a C++ compiler, JDK, PHP, perl, and gperf pre-installed.
|
||||
|
||||
## Building TDLib for Android
|
||||
|
||||
* Run the script `./check-environment.sh` to check that you have all required Unix tools and Java utilities. If the script exits with an error message, install the missing tool.
|
||||
* Run the script `./fetch-sdk.sh` to download Android SDK to a local directory.
|
||||
* Run the script `./build-openssl.sh` to download and build OpenSSL for Android.
|
||||
* Run the script `./build-tdlib.sh` to build TDLib for Android.
|
||||
* The built libraries are now located in the `tdlib/libs` directory. If [Java](https://github.com/tdlib/td#using-java) interface was built, then corresponding Java code is located in the `tdlib/java` directory, and standalone Java documentation can be found in the `tdlib/javadoc` directory. You can also use archives `tdlib/tdlib.zip` and `tdlib/tdlib-debug.zip`, which contain all aforementioned data.
|
||||
|
||||
If you already have installed Android SDK and NDK, you can skip the second step and specify existing Android SDK root path and Android NDK version as the first and the second parameters to the subsequent scripts. Make sure that the SDK includes android-34 platform and CMake 3.22.1.
|
||||
|
||||
If you already have prebuilt OpenSSL, you can skip the third step and specify path to the prebuild OpenSSL as the third parameter to the script `./build-tdlib.sh`.
|
||||
|
||||
If you want to update TDLib to a newer version, you need to run only the script `./build-tdlib.sh`.
|
||||
|
||||
You can specify different OpenSSL version as the fourth parameter to the script `./build-openssl.sh`. By default OpenSSL 1.1.1 is used because of much smaller binary footprint and better performance than newer OpenSSL versions.
|
||||
|
||||
You can build shared OpenSSL libraries instead of static ones by passing any non-empty string as the fifth parameter to the script `./build-openssl.sh`. This can reduce total application size if you have a lot of other code that uses OpenSSL and want it to use the same shared library.
|
||||
|
||||
You can build TDLib against shared standard C++ library by specifying "c++_shared" as the fourth parameter to the script `./build-tdlib.sh`. This can reduce total application size if you have a lot of other C++ code and want it to use the same shared library.
|
||||
|
||||
You can also build TDLib with [JSON interface](https://github.com/tdlib/td#using-json) instead of [Java](https://github.com/tdlib/td#using-java) interface by passing "JSON" as the fifth parameter to the script `./build-tdlib.sh`.
|
||||
|
||||
You can also build TDLib with [JSON interface](https://github.com/tdlib/td#using-json) that can be called from Java by passing "JSONJava" as the fifth parameter to the script `./build-tdlib.sh`.
|
||||
|
||||
You can pass an empty string instead of any script parameter to use its default value. For example, you can use the command `./build-tdlib.sh '' '' '' '' 'JSON'` to build TDLib with [JSON interface](https://github.com/tdlib/td#using-json) using default values for other parameters.
|
||||
|
||||
Alternatively, you can use Docker to build TDLib for Android. Use `docker build --output tdlib .` to build the latest TDLib commit from Github, or `docker build --build-arg COMMIT_HASH=<commit-hash> --output tdlib .` to build specific commit. The output archives will be placed in the directory "tdlib" as specified. Additionally, you can specify build arguments "TDLIB_INTERFACE", "ANDROID_NDK_VERSION", "OPENSSL_VERSION", "BUILD_SHARED_OPENSSL_LIBS", and "ANDROID_STL" to the provided Dockerfile. For example, use `docker build --build-arg TDLIB_INTERFACE=JSON --output tdlib .` to build the latest TDLib with JSON interface.
|
@ -1,93 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ANDROID_SDK_ROOT=${1:-SDK}
|
||||
ANDROID_NDK_VERSION=${2:-23.2.8568313}
|
||||
OPENSSL_INSTALL_DIR=${3:-third-party/openssl}
|
||||
OPENSSL_VERSION=${4:-OpenSSL_1_1_1w} # openssl-3.3.0
|
||||
BUILD_SHARED_LIBS=$5
|
||||
|
||||
if [ ! -d "$ANDROID_SDK_ROOT" ] ; then
|
||||
echo "Error: directory \"$ANDROID_SDK_ROOT\" doesn't exist. Run ./fetch-sdk.sh first, or provide a valid path to Android SDK."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -e "$OPENSSL_INSTALL_DIR" ] ; then
|
||||
echo "Error: file or directory \"$OPENSSL_INSTALL_DIR\" already exists. Delete it manually to proceed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source ./check-environment.sh || exit 1
|
||||
|
||||
if [[ "$OS_NAME" == "win" ]] && [[ "$BUILD_SHARED_LIBS" ]] ; then
|
||||
echo "Error: OpenSSL shared libraries can't be built on Windows because of 'The command line is too long.' error during build. You can run the script in WSL instead."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p $OPENSSL_INSTALL_DIR || exit 1
|
||||
|
||||
ANDROID_SDK_ROOT="$(cd "$(dirname -- "$ANDROID_SDK_ROOT")" >/dev/null; pwd -P)/$(basename -- "$ANDROID_SDK_ROOT")"
|
||||
OPENSSL_INSTALL_DIR="$(cd "$(dirname -- "$OPENSSL_INSTALL_DIR")" >/dev/null; pwd -P)/$(basename -- "$OPENSSL_INSTALL_DIR")"
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
echo "Downloading OpenSSL sources..."
|
||||
rm -f $OPENSSL_VERSION.tar.gz || exit 1
|
||||
$WGET https://github.com/openssl/openssl/archive/refs/tags/$OPENSSL_VERSION.tar.gz || exit 1
|
||||
rm -rf ./openssl-$OPENSSL_VERSION || exit 1
|
||||
tar xzf $OPENSSL_VERSION.tar.gz || exit 1
|
||||
rm $OPENSSL_VERSION.tar.gz || exit 1
|
||||
cd openssl-$OPENSSL_VERSION
|
||||
|
||||
export ANDROID_NDK_ROOT=$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION # for OpenSSL 3.*.*
|
||||
export ANDROID_NDK_HOME=$ANDROID_NDK_ROOT # for OpenSSL 1.1.1
|
||||
PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin:$PATH
|
||||
|
||||
if ! clang --help >/dev/null 2>&1 ; then
|
||||
echo "Error: failed to run clang from Android NDK."
|
||||
if [[ "$OS_NAME" == "linux" ]] ; then
|
||||
echo "Prebuilt Android NDK binaries are linked against glibc, so glibc must be installed."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ANDROID_API32=16
|
||||
ANDROID_API64=21
|
||||
if [[ ${ANDROID_NDK_VERSION%%.*} -ge 24 ]] ; then
|
||||
ANDROID_API32=19
|
||||
fi
|
||||
if [[ ${ANDROID_NDK_VERSION%%.*} -ge 26 ]] ; then
|
||||
ANDROID_API32=21
|
||||
fi
|
||||
|
||||
SHARED_BUILD_OPTION=$([ "$BUILD_SHARED_LIBS" ] && echo "shared" || echo "no-shared")
|
||||
|
||||
for ABI in arm64-v8a armeabi-v7a x86_64 x86 ; do
|
||||
if [[ $ABI == "x86" ]] ; then
|
||||
./Configure android-x86 ${SHARED_BUILD_OPTION} -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API32 || exit 1
|
||||
elif [[ $ABI == "x86_64" ]] ; then
|
||||
./Configure android-x86_64 ${SHARED_BUILD_OPTION} -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API64 || exit 1
|
||||
elif [[ $ABI == "armeabi-v7a" ]] ; then
|
||||
./Configure android-arm ${SHARED_BUILD_OPTION} -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API32 -D__ARM_MAX_ARCH__=8 || exit 1
|
||||
elif [[ $ABI == "arm64-v8a" ]] ; then
|
||||
./Configure android-arm64 ${SHARED_BUILD_OPTION} -U__ANDROID_API__ -D__ANDROID_API__=$ANDROID_API64 || exit 1
|
||||
fi
|
||||
|
||||
sed -i.bak 's/-O3/-O3 -ffunction-sections -fdata-sections/g' Makefile || exit 1
|
||||
|
||||
make depend -s || exit 1
|
||||
make -j4 -s || exit 1
|
||||
|
||||
mkdir -p $OPENSSL_INSTALL_DIR/$ABI/lib/ || exit 1
|
||||
if [ "$BUILD_SHARED_LIBS" ] ; then
|
||||
cp libcrypto.so libssl.so $OPENSSL_INSTALL_DIR/$ABI/lib/ || exit 1
|
||||
else
|
||||
cp libcrypto.a libssl.a $OPENSSL_INSTALL_DIR/$ABI/lib/ || exit 1
|
||||
fi
|
||||
cp -r include $OPENSSL_INSTALL_DIR/$ABI/ || exit 1
|
||||
|
||||
make distclean || exit 1
|
||||
done
|
||||
|
||||
cd ..
|
||||
|
||||
rm -rf ./openssl-$OPENSSL_VERSION || exit 1
|
117
third-party/td/td/example/android/build-tdlib.sh
vendored
@ -1,117 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ANDROID_SDK_ROOT=${1:-SDK}
|
||||
ANDROID_NDK_VERSION=${2:-23.2.8568313}
|
||||
OPENSSL_INSTALL_DIR=${3:-third-party/openssl}
|
||||
ANDROID_STL=${4:-c++_static}
|
||||
TDLIB_INTERFACE=${5:-Java}
|
||||
|
||||
if [ "$ANDROID_STL" != "c++_static" ] && [ "$ANDROID_STL" != "c++_shared" ] ; then
|
||||
echo 'Error: ANDROID_STL must be either "c++_static" or "c++_shared".'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$TDLIB_INTERFACE" != "Java" ] && [ "$TDLIB_INTERFACE" != "JSON" ] && [ "$TDLIB_INTERFACE" != "JSONJava" ] ; then
|
||||
echo 'Error: TDLIB_INTERFACE must be either "Java", "JSON", or "JSONJava".'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source ./check-environment.sh || exit 1
|
||||
|
||||
if [ ! -d "$ANDROID_SDK_ROOT" ] ; then
|
||||
echo "Error: directory \"$ANDROID_SDK_ROOT\" doesn't exist. Run ./fetch-sdk.sh first, or provide a valid path to Android SDK."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$OPENSSL_INSTALL_DIR" ] ; then
|
||||
echo "Error: directory \"$OPENSSL_INSTALL_DIR\" doesn't exists. Run ./build-openssl.sh first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ANDROID_SDK_ROOT="$(cd "$(dirname -- "$ANDROID_SDK_ROOT")" >/dev/null; pwd -P)/$(basename -- "$ANDROID_SDK_ROOT")"
|
||||
ANDROID_NDK_ROOT="$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION"
|
||||
OPENSSL_INSTALL_DIR="$(cd "$(dirname -- "$OPENSSL_INSTALL_DIR")" >/dev/null; pwd -P)/$(basename -- "$OPENSSL_INSTALL_DIR")"
|
||||
PATH=$ANDROID_SDK_ROOT/cmake/3.22.1/bin:$PATH
|
||||
TDLIB_INTERFACE_OPTION=$([ "$TDLIB_INTERFACE" == "JSON" ] && echo "-DTD_ANDROID_JSON=ON" || [ "$TDLIB_INTERFACE" == "JSONJava" ] && echo "-DTD_ANDROID_JSON_JAVA=ON" || echo "")
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
echo "Generating TDLib source files..."
|
||||
mkdir -p build-native-$TDLIB_INTERFACE || exit 1
|
||||
cd build-native-$TDLIB_INTERFACE
|
||||
cmake $TDLIB_INTERFACE_OPTION -DTD_GENERATE_SOURCE_FILES=ON .. || exit 1
|
||||
cmake --build . || exit 1
|
||||
cd ..
|
||||
|
||||
rm -rf tdlib || exit 1
|
||||
|
||||
if [ "$TDLIB_INTERFACE" == "Java" ] ; then
|
||||
echo "Downloading annotation Java package..."
|
||||
rm -f android.jar annotation-1.4.0.jar || exit 1
|
||||
$WGET https://maven.google.com/androidx/annotation/annotation/1.4.0/annotation-1.4.0.jar || exit 1
|
||||
|
||||
echo "Generating Java source files..."
|
||||
cmake --build build-native-$TDLIB_INTERFACE --target tl_generate_java || exit 1
|
||||
php AddIntDef.php org/drinkless/tdlib/TdApi.java || exit 1
|
||||
mkdir -p tdlib/java/org/drinkless/tdlib || exit 1
|
||||
cp -p {..,tdlib}/java/org/drinkless/tdlib/Client.java || exit 1
|
||||
mv {,tdlib/java/}org/drinkless/tdlib/TdApi.java || exit 1
|
||||
rm -rf org || exit 1
|
||||
|
||||
echo "Generating Javadoc documentation..."
|
||||
cp "$ANDROID_SDK_ROOT/platforms/android-34/android.jar" . || exit 1
|
||||
JAVADOC_SEPARATOR=$([ "$OS_NAME" == "win" ] && echo ";" || echo ":")
|
||||
javadoc -d tdlib/javadoc -encoding UTF-8 -charset UTF-8 -classpath "android.jar${JAVADOC_SEPARATOR}annotation-1.4.0.jar" -quiet -sourcepath tdlib/java org.drinkless.tdlib || exit 1
|
||||
rm android.jar annotation-1.4.0.jar || exit 1
|
||||
fi
|
||||
if [ "$TDLIB_INTERFACE" == "JSONJava" ] ; then
|
||||
mkdir -p tdlib/java/org/drinkless/tdlib || exit 1
|
||||
cp -p {..,tdlib}/java/org/drinkless/tdlib/JsonClient.java || exit 1
|
||||
fi
|
||||
|
||||
echo "Building TDLib..."
|
||||
for ABI in arm64-v8a armeabi-v7a x86_64 x86 ; do
|
||||
mkdir -p tdlib/libs/$ABI/ || exit 1
|
||||
|
||||
mkdir -p build-$ABI-$TDLIB_INTERFACE || exit 1
|
||||
cd build-$ABI-$TDLIB_INTERFACE
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake" -DOPENSSL_ROOT_DIR="$OPENSSL_INSTALL_DIR/$ABI" -DCMAKE_BUILD_TYPE=RelWithDebInfo -GNinja -DANDROID_ABI=$ABI -DANDROID_STL=$ANDROID_STL -DANDROID_PLATFORM=android-16 $TDLIB_INTERFACE_OPTION .. || exit 1
|
||||
if [ "$TDLIB_INTERFACE" == "Java" ] || [ "$TDLIB_INTERFACE" == "JSONJava" ] ; then
|
||||
cmake --build . --target tdjni || exit 1
|
||||
cp -p libtd*.so* ../tdlib/libs/$ABI/ || exit 1
|
||||
fi
|
||||
if [ "$TDLIB_INTERFACE" == "JSON" ] ; then
|
||||
cmake --build . --target tdjson || exit 1
|
||||
cp -p td/libtdjson.so ../tdlib/libs/$ABI/libtdjson.so.debug || exit 1
|
||||
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin/llvm-strip" --strip-debug --strip-unneeded ../tdlib/libs/$ABI/libtdjson.so.debug -o ../tdlib/libs/$ABI/libtdjson.so || exit 1
|
||||
fi
|
||||
cd ..
|
||||
|
||||
if [[ "$ANDROID_STL" == "c++_shared" ]] ; then
|
||||
if [[ "$ABI" == "arm64-v8a" ]] ; then
|
||||
FULL_ABI="aarch64-linux-android"
|
||||
elif [[ "$ABI" == "armeabi-v7a" ]] ; then
|
||||
FULL_ABI="arm-linux-androideabi"
|
||||
elif [[ "$ABI" == "x86_64" ]] ; then
|
||||
FULL_ABI="x86_64-linux-android"
|
||||
elif [[ "$ABI" == "x86" ]] ; then
|
||||
FULL_ABI="i686-linux-android"
|
||||
fi
|
||||
cp "$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/sysroot/usr/lib/$FULL_ABI/libc++_shared.so" tdlib/libs/$ABI/ || exit 1
|
||||
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin/llvm-strip" tdlib/libs/$ABI/libc++_shared.so || exit 1
|
||||
fi
|
||||
if [ -e "$OPENSSL_INSTALL_DIR/$ABI/lib/libcrypto.so" ] ; then
|
||||
cp "$OPENSSL_INSTALL_DIR/$ABI/lib/libcrypto.so" "$OPENSSL_INSTALL_DIR/$ABI/lib/libssl.so" tdlib/libs/$ABI/ || exit 1
|
||||
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin/llvm-strip" tdlib/libs/$ABI/libcrypto.so || exit 1
|
||||
"$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$HOST_ARCH/bin/llvm-strip" tdlib/libs/$ABI/libssl.so || exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Compressing..."
|
||||
rm -f tdlib.zip tdlib-debug.zip || exit 1
|
||||
jar -cMf tdlib-debug.zip tdlib || exit 1
|
||||
rm tdlib/libs/*/*.debug || exit 1
|
||||
jar -cMf tdlib.zip tdlib || exit 1
|
||||
mv tdlib.zip tdlib-debug.zip tdlib || exit 1
|
||||
|
||||
echo "Done."
|
@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# The script checks that all needed tools are installed and sets OS_NAME, HOST_ARCH, and WGET variables
|
||||
|
||||
if [[ "$OSTYPE" == "linux"* ]] ; then
|
||||
OS_NAME="linux"
|
||||
HOST_ARCH="linux-x86_64"
|
||||
elif [[ "$OSTYPE" == "darwin"* ]] ; then
|
||||
OS_NAME="mac"
|
||||
HOST_ARCH="darwin-x86_64"
|
||||
elif [[ "$OSTYPE" == "msys" ]] ; then
|
||||
OS_NAME="win"
|
||||
HOST_ARCH="windows-x86_64"
|
||||
else
|
||||
echo "Error: this script supports only Bash shell on Linux, macOS, or Windows."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if which wget >/dev/null 2>&1 ; then
|
||||
WGET="wget -q"
|
||||
elif which curl >/dev/null 2>&1 ; then
|
||||
WGET="curl -sfLO"
|
||||
else
|
||||
echo "Error: this script requires either curl or wget tool installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for TOOL_NAME in gperf jar java javadoc make perl php sed tar yes unzip ; do
|
||||
if ! which "$TOOL_NAME" >/dev/null 2>&1 ; then
|
||||
echo "Error: this script requires $TOOL_NAME tool installed."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $(which make) = *" "* ]] ; then
|
||||
echo "Error: OpenSSL expects that full path to make tool doesn't contain spaces. Move it to some other place."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! perl -MExtUtils::MakeMaker -MLocale::Maketext::Simple -MPod::Usage -e '' >/dev/null 2>&1 ; then
|
||||
echo "Error: Perl installation is broken."
|
||||
if [[ "$OSTYPE" == "msys" ]] ; then
|
||||
echo "For Git Bash you need to manually copy ExtUtils, Locale and Pod modules to /usr/share/perl5/core_perl from any compatible Perl installation."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! java --help >/dev/null 2>&1 ; then
|
||||
echo "Error: Java installation is broken. Install JDK from https://www.oracle.com/java/technologies/downloads/ or via the package manager."
|
||||
exit 1
|
||||
fi
|
30
third-party/td/td/example/android/fetch-sdk.sh
vendored
@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ANDROID_SDK_ROOT=${1:-SDK}
|
||||
ANDROID_NDK_VERSION=${2:-23.2.8568313}
|
||||
|
||||
if [ -e "$ANDROID_SDK_ROOT" ] ; then
|
||||
echo "Error: file or directory \"$ANDROID_SDK_ROOT\" already exists. Delete it manually to proceed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source ./check-environment.sh || exit 1
|
||||
|
||||
SDKMANAGER="./sdkmanager"
|
||||
if [[ "$OS_NAME" == "win" ]] ; then
|
||||
SDKMANAGER="./sdkmanager.bat"
|
||||
fi
|
||||
|
||||
echo "Downloading SDK Manager..."
|
||||
mkdir -p "$ANDROID_SDK_ROOT" || exit 1
|
||||
cd "$ANDROID_SDK_ROOT" || exit 1
|
||||
$WGET "https://dl.google.com/android/repository/commandlinetools-$OS_NAME-11076708_latest.zip" || exit 1
|
||||
mkdir -p cmdline-tools || exit 1
|
||||
unzip -qq "commandlinetools-$OS_NAME-11076708_latest.zip" -d cmdline-tools || exit 1
|
||||
rm "commandlinetools-$OS_NAME-11076708_latest.zip" || exit 1
|
||||
mv cmdline-tools/* cmdline-tools/latest/ || exit 1
|
||||
|
||||
echo "Installing required SDK tools..."
|
||||
cd cmdline-tools/latest/bin/ || exit 1
|
||||
yes | $SDKMANAGER --licenses >/dev/null || exit 1
|
||||
$SDKMANAGER --install "ndk;$ANDROID_NDK_VERSION" "cmake;3.22.1" "build-tools;34.0.0" "platforms;android-34" > /dev/null || exit 1
|
1
third-party/td/td/example/cpp/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/td/
|
13
third-party/td/td/example/cpp/CMakeLists.txt
vendored
@ -1,13 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
|
||||
project(TdExample VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
find_package(Td 1.8.46 REQUIRED)
|
||||
|
||||
add_executable(tdjson_example tdjson_example.cpp)
|
||||
target_link_libraries(tdjson_example PRIVATE Td::TdJson)
|
||||
set_property(TARGET tdjson_example PROPERTY CXX_STANDARD 11)
|
||||
|
||||
add_executable(td_example td_example.cpp)
|
||||
target_link_libraries(td_example PRIVATE Td::TdStatic)
|
||||
set_property(TARGET td_example PROPERTY CXX_STANDARD 14)
|
24
third-party/td/td/example/cpp/README.md
vendored
@ -1,24 +0,0 @@
|
||||
# TDLib C++ basic usage examples
|
||||
|
||||
TDLib should be prebuilt and installed to local subdirectory `td/`:
|
||||
```
|
||||
cd <path to TDLib sources>
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../example/cpp/td ..
|
||||
cmake --build . --target install
|
||||
```
|
||||
Also, see [building](https://github.com/tdlib/td#building) for additional details on TDLib building.
|
||||
|
||||
After this you can build the examples:
|
||||
```
|
||||
cd <path to TDLib sources>/example/cpp
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DTd_DIR=<full path to TDLib sources>/example/cpp/td/lib/cmake/Td ..
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
Documentation for all available classes and methods can be found at https://core.telegram.org/tdlib/docs.
|
||||
|
||||
To run the examples you may need to manually copy needed shared libraries from `td/bin` to a directory containing built binaries.
|
337
third-party/td/td/example/cpp/td_example.cpp
vendored
@ -1,337 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/Client.h>
|
||||
#include <td/telegram/td_api.h>
|
||||
#include <td/telegram/td_api.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Simple single-threaded example of TDLib usage.
|
||||
// Real world programs should use separate thread for the user input.
|
||||
// Example includes user authentication, receiving updates, getting chat list and sending text messages.
|
||||
|
||||
// overloaded
|
||||
namespace detail {
|
||||
template <class... Fs>
|
||||
struct overload;
|
||||
|
||||
template <class F>
|
||||
struct overload<F> : public F {
|
||||
explicit overload(F f) : F(f) {
|
||||
}
|
||||
};
|
||||
template <class F, class... Fs>
|
||||
struct overload<F, Fs...>
|
||||
: public overload<F>
|
||||
, public overload<Fs...> {
|
||||
overload(F f, Fs... fs) : overload<F>(f), overload<Fs...>(fs...) {
|
||||
}
|
||||
using overload<F>::operator();
|
||||
using overload<Fs...>::operator();
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <class... F>
|
||||
auto overloaded(F... f) {
|
||||
return detail::overload<F...>(f...);
|
||||
}
|
||||
|
||||
namespace td_api = td::td_api;
|
||||
|
||||
class TdExample {
|
||||
public:
|
||||
TdExample() {
|
||||
td::ClientManager::execute(td_api::make_object<td_api::setLogVerbosityLevel>(1));
|
||||
client_manager_ = std::make_unique<td::ClientManager>();
|
||||
client_id_ = client_manager_->create_client_id();
|
||||
send_query(td_api::make_object<td_api::getOption>("version"), {});
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (true) {
|
||||
if (need_restart_) {
|
||||
restart();
|
||||
} else if (!are_authorized_) {
|
||||
process_response(client_manager_->receive(10));
|
||||
} else {
|
||||
std::cout << "Enter action [q] quit [u] check for updates and request results [c] show chats [m <chat_id> "
|
||||
"<text>] send message [me] show self [l] logout: "
|
||||
<< std::endl;
|
||||
std::string line;
|
||||
std::getline(std::cin, line);
|
||||
std::istringstream ss(line);
|
||||
std::string action;
|
||||
if (!(ss >> action)) {
|
||||
continue;
|
||||
}
|
||||
if (action == "q") {
|
||||
return;
|
||||
}
|
||||
if (action == "u") {
|
||||
std::cout << "Checking for updates..." << std::endl;
|
||||
while (true) {
|
||||
auto response = client_manager_->receive(0);
|
||||
if (response.object) {
|
||||
process_response(std::move(response));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (action == "close") {
|
||||
std::cout << "Closing..." << std::endl;
|
||||
send_query(td_api::make_object<td_api::close>(), {});
|
||||
} else if (action == "me") {
|
||||
send_query(td_api::make_object<td_api::getMe>(),
|
||||
[this](Object object) { std::cout << to_string(object) << std::endl; });
|
||||
} else if (action == "l") {
|
||||
std::cout << "Logging out..." << std::endl;
|
||||
send_query(td_api::make_object<td_api::logOut>(), {});
|
||||
} else if (action == "m") {
|
||||
std::int64_t chat_id;
|
||||
ss >> chat_id;
|
||||
ss.get();
|
||||
std::string text;
|
||||
std::getline(ss, text);
|
||||
|
||||
std::cout << "Sending message to chat " << chat_id << "..." << std::endl;
|
||||
auto send_message = td_api::make_object<td_api::sendMessage>();
|
||||
send_message->chat_id_ = chat_id;
|
||||
auto message_content = td_api::make_object<td_api::inputMessageText>();
|
||||
message_content->text_ = td_api::make_object<td_api::formattedText>();
|
||||
message_content->text_->text_ = std::move(text);
|
||||
send_message->input_message_content_ = std::move(message_content);
|
||||
|
||||
send_query(std::move(send_message), {});
|
||||
} else if (action == "c") {
|
||||
std::cout << "Loading chat list..." << std::endl;
|
||||
send_query(td_api::make_object<td_api::getChats>(nullptr, 20), [this](Object object) {
|
||||
if (object->get_id() == td_api::error::ID) {
|
||||
return;
|
||||
}
|
||||
auto chats = td::move_tl_object_as<td_api::chats>(object);
|
||||
for (auto chat_id : chats->chat_ids_) {
|
||||
std::cout << "[chat_id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using Object = td_api::object_ptr<td_api::Object>;
|
||||
std::unique_ptr<td::ClientManager> client_manager_;
|
||||
std::int32_t client_id_{0};
|
||||
|
||||
td_api::object_ptr<td_api::AuthorizationState> authorization_state_;
|
||||
bool are_authorized_{false};
|
||||
bool need_restart_{false};
|
||||
std::uint64_t current_query_id_{0};
|
||||
std::uint64_t authentication_query_id_{0};
|
||||
|
||||
std::map<std::uint64_t, std::function<void(Object)>> handlers_;
|
||||
|
||||
std::map<std::int64_t, td_api::object_ptr<td_api::user>> users_;
|
||||
|
||||
std::map<std::int64_t, std::string> chat_title_;
|
||||
|
||||
void restart() {
|
||||
client_manager_.reset();
|
||||
*this = TdExample();
|
||||
}
|
||||
|
||||
void send_query(td_api::object_ptr<td_api::Function> f, std::function<void(Object)> handler) {
|
||||
auto query_id = next_query_id();
|
||||
if (handler) {
|
||||
handlers_.emplace(query_id, std::move(handler));
|
||||
}
|
||||
client_manager_->send(client_id_, query_id, std::move(f));
|
||||
}
|
||||
|
||||
void process_response(td::ClientManager::Response response) {
|
||||
if (!response.object) {
|
||||
return;
|
||||
}
|
||||
//std::cout << response.request_id << " " << to_string(response.object) << std::endl;
|
||||
if (response.request_id == 0) {
|
||||
return process_update(std::move(response.object));
|
||||
}
|
||||
auto it = handlers_.find(response.request_id);
|
||||
if (it != handlers_.end()) {
|
||||
it->second(std::move(response.object));
|
||||
handlers_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_user_name(std::int64_t user_id) const {
|
||||
auto it = users_.find(user_id);
|
||||
if (it == users_.end()) {
|
||||
return "unknown user";
|
||||
}
|
||||
return it->second->first_name_ + " " + it->second->last_name_;
|
||||
}
|
||||
|
||||
std::string get_chat_title(std::int64_t chat_id) const {
|
||||
auto it = chat_title_.find(chat_id);
|
||||
if (it == chat_title_.end()) {
|
||||
return "unknown chat";
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void process_update(td_api::object_ptr<td_api::Object> update) {
|
||||
td_api::downcast_call(
|
||||
*update, overloaded(
|
||||
[this](td_api::updateAuthorizationState &update_authorization_state) {
|
||||
authorization_state_ = std::move(update_authorization_state.authorization_state_);
|
||||
on_authorization_state_update();
|
||||
},
|
||||
[this](td_api::updateNewChat &update_new_chat) {
|
||||
chat_title_[update_new_chat.chat_->id_] = update_new_chat.chat_->title_;
|
||||
},
|
||||
[this](td_api::updateChatTitle &update_chat_title) {
|
||||
chat_title_[update_chat_title.chat_id_] = update_chat_title.title_;
|
||||
},
|
||||
[this](td_api::updateUser &update_user) {
|
||||
auto user_id = update_user.user_->id_;
|
||||
users_[user_id] = std::move(update_user.user_);
|
||||
},
|
||||
[this](td_api::updateNewMessage &update_new_message) {
|
||||
auto chat_id = update_new_message.message_->chat_id_;
|
||||
std::string sender_name;
|
||||
td_api::downcast_call(*update_new_message.message_->sender_id_,
|
||||
overloaded(
|
||||
[this, &sender_name](td_api::messageSenderUser &user) {
|
||||
sender_name = get_user_name(user.user_id_);
|
||||
},
|
||||
[this, &sender_name](td_api::messageSenderChat &chat) {
|
||||
sender_name = get_chat_title(chat.chat_id_);
|
||||
}));
|
||||
std::string text;
|
||||
if (update_new_message.message_->content_->get_id() == td_api::messageText::ID) {
|
||||
text = static_cast<td_api::messageText &>(*update_new_message.message_->content_).text_->text_;
|
||||
}
|
||||
std::cout << "Receive message: [chat_id:" << chat_id << "] [from:" << sender_name << "] ["
|
||||
<< text << "]" << std::endl;
|
||||
},
|
||||
[](auto &update) {}));
|
||||
}
|
||||
|
||||
auto create_authentication_query_handler() {
|
||||
return [this, id = authentication_query_id_](Object object) {
|
||||
if (id == authentication_query_id_) {
|
||||
check_authentication_error(std::move(object));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void on_authorization_state_update() {
|
||||
authentication_query_id_++;
|
||||
td_api::downcast_call(*authorization_state_,
|
||||
overloaded(
|
||||
[this](td_api::authorizationStateReady &) {
|
||||
are_authorized_ = true;
|
||||
std::cout << "Authorization is completed" << std::endl;
|
||||
},
|
||||
[this](td_api::authorizationStateLoggingOut &) {
|
||||
are_authorized_ = false;
|
||||
std::cout << "Logging out" << std::endl;
|
||||
},
|
||||
[this](td_api::authorizationStateClosing &) { std::cout << "Closing" << std::endl; },
|
||||
[this](td_api::authorizationStateClosed &) {
|
||||
are_authorized_ = false;
|
||||
need_restart_ = true;
|
||||
std::cout << "Terminated" << std::endl;
|
||||
},
|
||||
[this](td_api::authorizationStateWaitPhoneNumber &) {
|
||||
std::cout << "Enter phone number: " << std::flush;
|
||||
std::string phone_number;
|
||||
std::cin >> phone_number;
|
||||
send_query(
|
||||
td_api::make_object<td_api::setAuthenticationPhoneNumber>(phone_number, nullptr),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td_api::authorizationStateWaitEmailAddress &) {
|
||||
std::cout << "Enter email address: " << std::flush;
|
||||
std::string email_address;
|
||||
std::cin >> email_address;
|
||||
send_query(td_api::make_object<td_api::setAuthenticationEmailAddress>(email_address),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td_api::authorizationStateWaitEmailCode &) {
|
||||
std::cout << "Enter email authentication code: " << std::flush;
|
||||
std::string code;
|
||||
std::cin >> code;
|
||||
send_query(td_api::make_object<td_api::checkAuthenticationEmailCode>(
|
||||
td_api::make_object<td_api::emailAddressAuthenticationCode>(code)),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td_api::authorizationStateWaitCode &) {
|
||||
std::cout << "Enter authentication code: " << std::flush;
|
||||
std::string code;
|
||||
std::cin >> code;
|
||||
send_query(td_api::make_object<td_api::checkAuthenticationCode>(code),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td_api::authorizationStateWaitRegistration &) {
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
std::cout << "Enter your first name: " << std::flush;
|
||||
std::cin >> first_name;
|
||||
std::cout << "Enter your last name: " << std::flush;
|
||||
std::cin >> last_name;
|
||||
send_query(td_api::make_object<td_api::registerUser>(first_name, last_name, false),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td_api::authorizationStateWaitPassword &) {
|
||||
std::cout << "Enter authentication password: " << std::flush;
|
||||
std::string password;
|
||||
std::getline(std::cin, password);
|
||||
send_query(td_api::make_object<td_api::checkAuthenticationPassword>(password),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td_api::authorizationStateWaitOtherDeviceConfirmation &state) {
|
||||
std::cout << "Confirm this login link on another device: " << state.link_ << std::endl;
|
||||
},
|
||||
[this](td_api::authorizationStateWaitTdlibParameters &) {
|
||||
auto request = td_api::make_object<td_api::setTdlibParameters>();
|
||||
request->database_directory_ = "tdlib";
|
||||
request->use_message_database_ = true;
|
||||
request->use_secret_chats_ = true;
|
||||
request->api_id_ = 94575;
|
||||
request->api_hash_ = "a3406de8d171bb422bb6ddf3bbd800e2";
|
||||
request->system_language_code_ = "en";
|
||||
request->device_model_ = "Desktop";
|
||||
request->application_version_ = "1.0";
|
||||
send_query(std::move(request), create_authentication_query_handler());
|
||||
}));
|
||||
}
|
||||
|
||||
void check_authentication_error(Object object) {
|
||||
if (object->get_id() == td_api::error::ID) {
|
||||
auto error = td::move_tl_object_as<td_api::error>(object);
|
||||
std::cout << "Error: " << to_string(error) << std::flush;
|
||||
on_authorization_state_update();
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t next_query_id() {
|
||||
return ++current_query_id_;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
TdExample example;
|
||||
example.loop();
|
||||
}
|
55
third-party/td/td/example/cpp/tdjson_example.cpp
vendored
@ -1,55 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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 <iostream>
|
||||
#include <td/telegram/td_json_client.h>
|
||||
|
||||
// Basic example of TDLib JSON interface usage.
|
||||
// Native interface should be preferred instead in C++, so here is only an example of
|
||||
// the main event cycle, which should be essentially the same for all languages.
|
||||
|
||||
int main() {
|
||||
// disable TDLib logging
|
||||
td_execute("{\"@type\":\"setLogVerbosityLevel\", \"new_verbosity_level\":0}");
|
||||
|
||||
int client_id = td_create_client_id();
|
||||
// somehow share the client_id with other threads, which will be able to send requests via td_send
|
||||
|
||||
// start the client by sending request to it
|
||||
td_send(client_id, "{\"@type\":\"getOption\", \"name\":\"version\"}");
|
||||
|
||||
const bool test_incorrect_queries = false;
|
||||
if (test_incorrect_queries) {
|
||||
td_execute("{\"@type\":\"setLogVerbosityLevel\", \"new_verbosity_level\":1}");
|
||||
td_execute("");
|
||||
td_execute("test");
|
||||
td_execute("\"test\"");
|
||||
td_execute("{\"@type\":\"test\", \"@extra\":1}");
|
||||
|
||||
td_send(client_id, "{\"@type\":\"getFileMimeType\"}");
|
||||
td_send(client_id, "{\"@type\":\"getFileMimeType\", \"@extra\":1}");
|
||||
td_send(client_id, "{\"@type\":\"getFileMimeType\", \"@extra\":null}");
|
||||
td_send(client_id, "{\"@type\":\"test\"}");
|
||||
td_send(client_id, "[]");
|
||||
td_send(client_id, "{\"@type\":\"test\", \"@extra\":1}");
|
||||
td_send(client_id, "{\"@type\":\"sendMessage\", \"chat_id\":true, \"@extra\":1}");
|
||||
td_send(client_id, "test");
|
||||
}
|
||||
|
||||
const double WAIT_TIMEOUT = 10.0; // seconds
|
||||
while (true) {
|
||||
const char *result = td_receive(WAIT_TIMEOUT);
|
||||
if (result != nullptr) {
|
||||
// parse the result as a JSON object and process it as an incoming update or an answer to a previously sent request
|
||||
|
||||
// if (result is UpdateAuthorizationState with authorizationStateClosed) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
std::cout << result << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
5
third-party/td/td/example/csharp/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
/.vs/
|
||||
/bin/
|
||||
/obj/
|
||||
/project.lock.json
|
||||
/TdExample.csproj.user
|
40
third-party/td/td/example/csharp/README.md
vendored
@ -1,40 +0,0 @@
|
||||
# TDLib C# example
|
||||
|
||||
This is an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C#.
|
||||
|
||||
## Building TDLib
|
||||
|
||||
* Download and install Microsoft Visual Studio 2015 or later.
|
||||
* Download and install [CMake](https://cmake.org/download/); choose "Add CMake to the system PATH" option while installing.
|
||||
* Install `gperf`, `zlib`, and `openssl` using [vcpkg](https://github.com/Microsoft/vcpkg#quick-start):
|
||||
```
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
git checkout 07b30b49e5136a36100a2ce644476e60d7f3ddc1
|
||||
.\bootstrap-vcpkg.bat
|
||||
.\vcpkg.exe install gperf:x64-windows gperf:x86-windows openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows
|
||||
```
|
||||
* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download). Add the path to php.exe to the PATH environment variable.
|
||||
* Build `TDLib` with CMake enabling `.NET` support and specifying correct path to `vcpkg` toolchain file:
|
||||
```
|
||||
cd <path to TDLib sources>/example/csharp
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -A Win32 -DTD_ENABLE_DOTNET=ON -DCMAKE_TOOLCHAIN_FILE=<path to vcpkg>/scripts/buildsystems/vcpkg.cmake ../../..
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Debug
|
||||
cd ..
|
||||
mkdir build64
|
||||
cd build64
|
||||
cmake -A x64 -DTD_ENABLE_DOTNET=ON -DCMAKE_TOOLCHAIN_FILE=<path to vcpkg>/scripts/buildsystems/vcpkg.cmake ../../..
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Debug
|
||||
```
|
||||
|
||||
## Example of usage
|
||||
|
||||
After `TDLib` is built you can open and run TdExample project.
|
||||
It contains a simple console C# application with implementation of authorization and message sending.
|
||||
Just open it with Visual Studio 2015 or later and run.
|
||||
|
||||
Also, see TdExample.csproj for example of including TDLib in C# project with all native shared library dependencies.
|
293
third-party/td/td/example/csharp/TdExample.cs
vendored
@ -1,293 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
using Td = Telegram.Td;
|
||||
using TdApi = Telegram.Td.Api;
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace TdExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Example class for TDLib usage from C#.
|
||||
/// </summary>
|
||||
class Example
|
||||
{
|
||||
private static Td.Client _client = null;
|
||||
private readonly static Td.ClientResultHandler _defaultHandler = new DefaultHandler();
|
||||
|
||||
private static TdApi.AuthorizationState _authorizationState = null;
|
||||
private static volatile bool _haveAuthorization = false;
|
||||
private static volatile bool _needQuit = false;
|
||||
private static volatile bool _canQuit = false;
|
||||
|
||||
private static volatile AutoResetEvent _gotAuthorization = new AutoResetEvent(false);
|
||||
|
||||
private static readonly string _newLine = Environment.NewLine;
|
||||
private static readonly string _commandsLine = "Enter command (gc <chatId> - GetChat, me - GetMe, sm <chatId> <message> - SendMessage, lo - LogOut, r - Restart, q - Quit): ";
|
||||
private static volatile string _currentPrompt = null;
|
||||
|
||||
private static Td.Client CreateTdClient()
|
||||
{
|
||||
return Td.Client.Create(new UpdateHandler());
|
||||
}
|
||||
|
||||
private static void Print(string str)
|
||||
{
|
||||
if (_currentPrompt != null)
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
Console.WriteLine(str);
|
||||
if (_currentPrompt != null)
|
||||
{
|
||||
Console.Write(_currentPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReadLine(string str)
|
||||
{
|
||||
Console.Write(str);
|
||||
_currentPrompt = str;
|
||||
var result = Console.ReadLine();
|
||||
_currentPrompt = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void OnAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState)
|
||||
{
|
||||
if (authorizationState != null)
|
||||
{
|
||||
_authorizationState = authorizationState;
|
||||
}
|
||||
if (_authorizationState is TdApi.AuthorizationStateWaitTdlibParameters)
|
||||
{
|
||||
TdApi.SetTdlibParameters request = new TdApi.SetTdlibParameters();
|
||||
request.DatabaseDirectory = "tdlib";
|
||||
request.UseMessageDatabase = true;
|
||||
request.UseSecretChats = true;
|
||||
request.ApiId = 94575;
|
||||
request.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
|
||||
request.SystemLanguageCode = "en";
|
||||
request.DeviceModel = "Desktop";
|
||||
request.ApplicationVersion = "1.0";
|
||||
|
||||
_client.Send(request, new AuthorizationRequestHandler());
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateWaitPhoneNumber)
|
||||
{
|
||||
string phoneNumber = ReadLine("Please enter phone number: ");
|
||||
_client.Send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, null), new AuthorizationRequestHandler());
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateWaitEmailAddress)
|
||||
{
|
||||
string emailAddress = ReadLine("Please enter email address: ");
|
||||
_client.Send(new TdApi.SetAuthenticationEmailAddress(emailAddress), new AuthorizationRequestHandler());
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateWaitEmailCode)
|
||||
{
|
||||
string code = ReadLine("Please enter email authentication code: ");
|
||||
_client.Send(new TdApi.CheckAuthenticationEmailCode(new TdApi.EmailAddressAuthenticationCode(code)), new AuthorizationRequestHandler());
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateWaitOtherDeviceConfirmation state)
|
||||
{
|
||||
Console.WriteLine("Please confirm this login link on another device: " + state.Link);
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateWaitCode)
|
||||
{
|
||||
string code = ReadLine("Please enter authentication code: ");
|
||||
_client.Send(new TdApi.CheckAuthenticationCode(code), new AuthorizationRequestHandler());
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateWaitRegistration)
|
||||
{
|
||||
string firstName = ReadLine("Please enter your first name: ");
|
||||
string lastName = ReadLine("Please enter your last name: ");
|
||||
_client.Send(new TdApi.RegisterUser(firstName, lastName, false), new AuthorizationRequestHandler());
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateWaitPassword)
|
||||
{
|
||||
string password = ReadLine("Please enter password: ");
|
||||
_client.Send(new TdApi.CheckAuthenticationPassword(password), new AuthorizationRequestHandler());
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateReady)
|
||||
{
|
||||
_haveAuthorization = true;
|
||||
_gotAuthorization.Set();
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateLoggingOut)
|
||||
{
|
||||
_haveAuthorization = false;
|
||||
Print("Logging out");
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateClosing)
|
||||
{
|
||||
_haveAuthorization = false;
|
||||
Print("Closing");
|
||||
}
|
||||
else if (_authorizationState is TdApi.AuthorizationStateClosed)
|
||||
{
|
||||
Print("Closed");
|
||||
if (!_needQuit)
|
||||
{
|
||||
_client = CreateTdClient(); // recreate _client after previous has closed
|
||||
} else {
|
||||
_canQuit = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Unsupported authorization state:" + _newLine + _authorizationState);
|
||||
}
|
||||
}
|
||||
|
||||
private static long GetChatId(string arg)
|
||||
{
|
||||
long chatId = 0;
|
||||
try
|
||||
{
|
||||
chatId = Convert.ToInt64(arg);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
}
|
||||
return chatId;
|
||||
}
|
||||
|
||||
private static void GetCommand()
|
||||
{
|
||||
string command = ReadLine(_commandsLine);
|
||||
string[] commands = command.Split(new char[] { ' ' }, 2);
|
||||
try
|
||||
{
|
||||
switch (commands[0])
|
||||
{
|
||||
case "gc":
|
||||
_client.Send(new TdApi.GetChat(GetChatId(commands[1])), _defaultHandler);
|
||||
break;
|
||||
case "me":
|
||||
_client.Send(new TdApi.GetMe(), _defaultHandler);
|
||||
break;
|
||||
case "sm":
|
||||
string[] args = commands[1].Split(new char[] { ' ' }, 2);
|
||||
sendMessage(GetChatId(args[0]), args[1]);
|
||||
break;
|
||||
case "lo":
|
||||
_haveAuthorization = false;
|
||||
_client.Send(new TdApi.LogOut(), _defaultHandler);
|
||||
break;
|
||||
case "r":
|
||||
_haveAuthorization = false;
|
||||
_client.Send(new TdApi.Close(), _defaultHandler);
|
||||
break;
|
||||
case "q":
|
||||
_needQuit = true;
|
||||
_haveAuthorization = false;
|
||||
_client.Send(new TdApi.Close(), _defaultHandler);
|
||||
break;
|
||||
default:
|
||||
Print("Unsupported command: " + command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
Print("Not enough arguments");
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendMessage(long chatId, string message)
|
||||
{
|
||||
// initialize reply markup just for testing
|
||||
TdApi.InlineKeyboardButton[] row = { new TdApi.InlineKeyboardButton("https://telegram.org?1", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?2", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?3", new TdApi.InlineKeyboardButtonTypeUrl()) };
|
||||
TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][] { row, row, row });
|
||||
|
||||
TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), null, true);
|
||||
_client.Send(new TdApi.SendMessage(chatId, 0, null, null, replyMarkup, content), _defaultHandler);
|
||||
}
|
||||
|
||||
static void Main()
|
||||
{
|
||||
// disable TDLib log
|
||||
Td.Client.Execute(new TdApi.SetLogVerbosityLevel(0));
|
||||
if (Td.Client.Execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false))) is TdApi.Error)
|
||||
{
|
||||
throw new System.IO.IOException("Write access to the current directory is required");
|
||||
}
|
||||
new Thread(() =>
|
||||
{
|
||||
Thread.CurrentThread.IsBackground = true;
|
||||
Td.Client.Run();
|
||||
}).Start();
|
||||
|
||||
// create Td.Client
|
||||
_client = CreateTdClient();
|
||||
|
||||
// test Client.Execute
|
||||
_defaultHandler.OnResult(Td.Client.Execute(new TdApi.GetTextEntities("@telegram /test_command https://telegram.org telegram.me @gif @test")));
|
||||
|
||||
// main loop
|
||||
while (!_needQuit)
|
||||
{
|
||||
// await authorization
|
||||
_gotAuthorization.Reset();
|
||||
_gotAuthorization.WaitOne();
|
||||
|
||||
_client.Send(new TdApi.LoadChats(null, 100), _defaultHandler); // preload main chat list
|
||||
while (_haveAuthorization)
|
||||
{
|
||||
GetCommand();
|
||||
}
|
||||
}
|
||||
while (!_canQuit) {
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultHandler : Td.ClientResultHandler
|
||||
{
|
||||
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
|
||||
{
|
||||
Print(@object.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateHandler : Td.ClientResultHandler
|
||||
{
|
||||
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
|
||||
{
|
||||
if (@object is TdApi.UpdateAuthorizationState)
|
||||
{
|
||||
OnAuthorizationStateUpdated((@object as TdApi.UpdateAuthorizationState).AuthorizationState);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print("Unsupported update: " + @object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AuthorizationRequestHandler : Td.ClientResultHandler
|
||||
{
|
||||
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
|
||||
{
|
||||
if (@object is TdApi.Error)
|
||||
{
|
||||
Print("Receive an error:" + _newLine + @object);
|
||||
OnAuthorizationStateUpdated(null); // repeat last action
|
||||
}
|
||||
else
|
||||
{
|
||||
// result is already received through UpdateAuthorizationState, nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
119
third-party/td/td/example/csharp/TdExample.csproj
vendored
@ -1,119 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<NoStandardLibraries>false</NoStandardLibraries>
|
||||
<AssemblyName>ConsoleApplication</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RootNamespace>TdExample</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Telegram.Td, Version=0.0.0.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath Condition=" '$(Platform)' == 'x86' ">build\$(Configuration)\Telegram.Td.dll</HintPath>
|
||||
<HintPath Condition=" '$(Platform)' == 'x64' ">build64\$(Configuration)\Telegram.Td.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="TdExample.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<Content Include="build\Debug\zlibd1.dll">
|
||||
<Link>zlibd1.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<Content Include="build\Release\zlib1.dll">
|
||||
<Link>zlib1.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
|
||||
<Content Include="build64\Debug\zlibd1.dll">
|
||||
<Link>zlibd1.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
||||
<Content Include="build64\Release\zlib1.dll">
|
||||
<Link>zlib1.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(Platform)' == 'x86' ">
|
||||
<Content Include="build\$(Configuration)\libcrypto-3.dll">
|
||||
<Link>libcrypto-3.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="build\$(Configuration)\libssl-3.dll">
|
||||
<Link>libssl-3.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
|
||||
<Content Include="build64\$(Configuration)\libcrypto-3-x64.dll">
|
||||
<Link>libcrypto-3-x64.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="build64\$(Configuration)\libssl-3-x64.dll">
|
||||
<Link>libssl-3-x64.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSHARP.Targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio AllowExistingFolder="true" />
|
||||
</ProjectExtensions>
|
||||
</Project>
|
31
third-party/td/td/example/csharp/TdExample.sln
vendored
@ -1,31 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28010.2046
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TdExample", "TdExample.csproj", "{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Debug|x64.Build.0 = Debug|x64
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Debug|x86.Build.0 = Debug|x86
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Release|x64.ActiveCfg = Release|x64
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Release|x64.Build.0 = Release|x64
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Release|x86.ActiveCfg = Release|x86
|
||||
{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {865856BA-F733-45DF-B35F-12607605B023}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,118 +0,0 @@
|
||||
diff --git a/Makefile b/Makefile
|
||||
index a1d13e9..8efcf20 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -18,8 +18,13 @@
|
||||
# - OpenSSL - build OpenSSL for all platforms
|
||||
# - OpenSSL-macOS - build OpenSSL for macOS
|
||||
# - OpenSSL-iOS - build OpenSSL for iOS
|
||||
+# - OpenSSL-iOS-simulator - build OpenSSL for iOS-simulator
|
||||
# - OpenSSL-tvOS - build OpenSSL for tvOS
|
||||
+# - OpenSSL-tvOS-simulator - build OpenSSL for tvOS-simulator
|
||||
# - OpenSSL-watchOS - build OpenSSL for watchOS
|
||||
+# - OpenSSL-watchOS-simulator - build OpenSSL for watchOS-simulator
|
||||
+# - OpenSSL-visionOS - build OpenSSL for visionOS
|
||||
+# - OpenSSL-visionOS-simulator - build OpenSSL for visionOS-simulator
|
||||
# - libFFI - build libFFI for all platforms (except macOS)
|
||||
# - libFFI-iOS - build libFFI for iOS
|
||||
# - libFFI-tvOS - build libFFI for tvOS
|
||||
@@ -50,7 +55,7 @@ XZ_VERSION=5.4.2
|
||||
# Preference is to use OpenSSL 3; however, Cryptography 3.4.8 (and
|
||||
# probably some other packages as well) only works with 1.1.1, so
|
||||
# we need to preserve the ability to build the older OpenSSL (for now...)
|
||||
-OPENSSL_VERSION=3.1.0
|
||||
+OPENSSL_VERSION=3.1.5
|
||||
# OPENSSL_VERSION_NUMBER=1.1.1
|
||||
# OPENSSL_REVISION=q
|
||||
# OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION)
|
||||
@@ -59,7 +64,7 @@ LIBFFI_VERSION=3.4.2
|
||||
|
||||
# Supported OS and dependencies
|
||||
DEPENDENCIES=BZip2 XZ OpenSSL libFFI
|
||||
-OS_LIST=macOS iOS tvOS watchOS
|
||||
+OS_LIST=macOS iOS iOS-simulator tvOS tvOS-simulator watchOS watchOS-simulator visionOS visionOS-simulator
|
||||
|
||||
CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar
|
||||
|
||||
@@ -69,22 +74,41 @@ VERSION_MIN-macOS=10.15
|
||||
CFLAGS-macOS=-mmacosx-version-min=$(VERSION_MIN-macOS)
|
||||
|
||||
# iOS targets
|
||||
-TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64
|
||||
+TARGETS-iOS=iphoneos.arm64
|
||||
VERSION_MIN-iOS=12.0
|
||||
CFLAGS-iOS=-mios-version-min=$(VERSION_MIN-iOS)
|
||||
|
||||
+# iOS-simulator targets
|
||||
+TARGETS-iOS-simulator=iphonesimulator.x86_64 iphonesimulator.arm64
|
||||
+CFLAGS-iOS-simulator=-mios-simulator-version-min=$(VERSION_MIN-iOS)
|
||||
+
|
||||
# tvOS targets
|
||||
-TARGETS-tvOS=appletvsimulator.x86_64 appletvsimulator.arm64 appletvos.arm64
|
||||
+TARGETS-tvOS=appletvos.arm64
|
||||
VERSION_MIN-tvOS=9.0
|
||||
CFLAGS-tvOS=-mtvos-version-min=$(VERSION_MIN-tvOS)
|
||||
PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no
|
||||
|
||||
+# tvOS-simulator targets
|
||||
+TARGETS-tvOS-simulator=appletvsimulator.x86_64 appletvsimulator.arm64
|
||||
+CFLAGS-tvOS-simulator=-mtvos-simulator-version-min=$(VERSION_MIN-tvOS)
|
||||
+
|
||||
# watchOS targets
|
||||
-TARGETS-watchOS=watchsimulator.x86_64 watchsimulator.arm64 watchos.arm64_32
|
||||
+TARGETS-watchOS=watchos.armv7k watchos.arm64_32 watchos.arm64
|
||||
VERSION_MIN-watchOS=4.0
|
||||
CFLAGS-watchOS=-mwatchos-version-min=$(VERSION_MIN-watchOS)
|
||||
PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no
|
||||
|
||||
+# watchOS-simulator targets
|
||||
+TARGETS-watchOS-simulator=watchsimulator.i386 watchsimulator.x86_64 watchsimulator.arm64
|
||||
+CFLAGS-watchOS-simulator=-mwatchos-simulator-version-min=$(VERSION_MIN-watchOS)
|
||||
+
|
||||
+# visionOS targets
|
||||
+TARGETS-visionOS=xros.arm64
|
||||
+PYTHON_CONFIGURE-visionOS=ac_cv_func_sigaltstack=no
|
||||
+
|
||||
+# visionOS-simulator targets
|
||||
+TARGETS-visionOS-simulator=xrsimulator.x86_64 xrsimulator.arm64
|
||||
+
|
||||
# The architecture of the machine doing the build
|
||||
HOST_ARCH=$(shell uname -m)
|
||||
HOST_PYTHON=install/macOS/macosx/python-$(PYTHON_VERSION)
|
||||
@@ -212,6 +236,10 @@ ARCH-$(target)=$$(subst .,,$$(suffix $(target)))
|
||||
|
||||
ifeq ($(os),macOS)
|
||||
TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-darwin
|
||||
+else ifeq ($(os),visionOS)
|
||||
+TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-xros
|
||||
+else ifeq ($(os),visionOS-simulator)
|
||||
+TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-xros-simulator
|
||||
else
|
||||
ifeq ($$(findstring simulator,$$(SDK-$(target))),)
|
||||
TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))
|
||||
@@ -662,7 +690,7 @@ BZIP2_FATLIB-$(sdk)=$$(BZIP2_MERGE-$(sdk))/lib/libbz2.a
|
||||
XZ_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/xz-$(XZ_VERSION)
|
||||
XZ_FATLIB-$(sdk)=$$(XZ_MERGE-$(sdk))/lib/liblzma.a
|
||||
|
||||
-OPENSSL_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/openssl-$(OPENSSL_VERSION)
|
||||
+OPENSSL_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/openssl
|
||||
OPENSSL_FATINCLUDE-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/include
|
||||
OPENSSL_SSL_FATLIB-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/lib/libssl.a
|
||||
OPENSSL_CRYPTO_FATLIB-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/lib/libcrypto.a
|
||||
@@ -716,14 +744,14 @@ $$(OPENSSL_SSL_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENS
|
||||
mkdir -p $$(OPENSSL_MERGE-$(sdk))/lib
|
||||
lipo -create -output $$@ \
|
||||
$$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_SSL_LIB-$$(target))) \
|
||||
- 2>&1 | tee -a merge/$(os)/$(sdk)/openssl-$(OPENSSL_VERSION).ssl.lipo.log
|
||||
+ 2>&1 | tee -a merge/$(os)/openssl-$(OPENSSL_VERSION).ssl.lipo.log
|
||||
|
||||
$$(OPENSSL_CRYPTO_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_CRYPTO_LIB-$$(target)))
|
||||
@echo ">>> Build OpenSSL crypto fat library for $(sdk)"
|
||||
mkdir -p $$(OPENSSL_MERGE-$(sdk))/lib
|
||||
lipo -create -output $$@ \
|
||||
$$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_CRYPTO_LIB-$$(target))) \
|
||||
- 2>&1 | tee -a merge/$(os)/$(sdk)/openssl-$(OPENSSL_VERSION).crypto.lipo.log
|
||||
+ 2>&1 | tee -a merge/$(os)/openssl-$(OPENSSL_VERSION).crypto.lipo.log
|
||||
|
||||
###########################################################################
|
||||
# SDK: libFFI
|
46
third-party/td/td/example/ios/README.md
vendored
@ -1,46 +0,0 @@
|
||||
# Universal XCFramework build example
|
||||
|
||||
Below are instructions for building TDLib for iOS, watchOS, tvOS, visionOS, 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).
|
||||
|
||||
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/).
|
||||
It is not enough to install only command line developer tools to build `TDLib` for iOS. Xcode >= 14.0 is required to build TDLib for watchOS.
|
||||
* Install other build dependencies using [Homebrew](https://brew.sh):
|
||||
```
|
||||
brew install gperf cmake coreutils
|
||||
```
|
||||
* If you don't want to build `TDLib` for macOS first, you **must** pregenerate required source code files in the following way:
|
||||
```
|
||||
cd <path to TDLib sources>
|
||||
mkdir native-build
|
||||
cd native-build
|
||||
cmake -DTD_GENERATE_SOURCE_FILES=ON ..
|
||||
cmake --build .
|
||||
```
|
||||
* Build OpenSSL for iOS, watchOS, tvOS, visionOS, and macOS:
|
||||
```
|
||||
cd <path to TDLib sources>/example/ios
|
||||
./build-openssl.sh
|
||||
```
|
||||
Here we use scripts from [Python Apple support](https://github.com/beeware/Python-Apple-support), but any other OpenSSL build should work too.
|
||||
[Python Apple support](https://github.com/beeware/Python-Apple-support) has known problems with spaces in the path to the current directory, so
|
||||
you need to ensure that there are no spaces in the path.
|
||||
Built OpenSSL libraries should be stored in the directory `third_party/openssl/<platform>`, because the next script will rely on this location.
|
||||
* Build TDLib for iOS, watchOS, tvOS, visionOS, and macOS:
|
||||
```
|
||||
cd <path to TDLib sources>/example/ios
|
||||
./build.sh
|
||||
```
|
||||
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.
|
||||
|
||||
Built libraries and XCFramework will be stored in `tdjson` directory.
|
||||
|
||||
Documentation for all available classes and methods can be found at https://core.telegram.org/tdlib/docs.
|
||||
|
||||
If you receive an "error: SDK "appletvsimulator" cannot be located", you need to run the command "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" before running ./build.sh.
|
37
third-party/td/td/example/ios/build-openssl.sh
vendored
@ -1,37 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $(dirname $0)
|
||||
|
||||
git clone https://github.com/beeware/Python-Apple-support
|
||||
cd Python-Apple-support
|
||||
git checkout 6f43aba0ddd5a9f52f39775d0141bd4363614020 || exit 1
|
||||
git reset --hard || exit 1
|
||||
git apply ../Python-Apple-support.patch || exit 1
|
||||
cd ..
|
||||
|
||||
platforms="macOS iOS watchOS tvOS visionOS"
|
||||
|
||||
for platform in $platforms;
|
||||
do
|
||||
if [[ $platform = "macOS" ]]; then
|
||||
simulators="0"
|
||||
else
|
||||
simulators="0 1"
|
||||
fi
|
||||
|
||||
for simulator in $simulators;
|
||||
do
|
||||
if [[ $simulator = "1" ]]; then
|
||||
platform="${platform}-simulator"
|
||||
fi
|
||||
echo $platform
|
||||
cd Python-Apple-support
|
||||
#NB: -j will fail
|
||||
make OpenSSL-$platform || exit 1
|
||||
cd ..
|
||||
rm -rf third_party/openssl/$platform || exit 1
|
||||
mkdir -p third_party/openssl/$platform/lib || exit 1
|
||||
cp ./Python-Apple-support/merge/$platform/openssl/lib/libcrypto.a third_party/openssl/$platform/lib/ || exit 1
|
||||
cp ./Python-Apple-support/merge/$platform/openssl/lib/libssl.a third_party/openssl/$platform/lib/ || exit 1
|
||||
cp -r ./Python-Apple-support/merge/$platform/openssl/include/ third_party/openssl/$platform/include || exit 1
|
||||
done
|
||||
done
|
92
third-party/td/td/example/ios/build.sh
vendored
@ -1,92 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $(dirname $0)
|
||||
td_path=$(grealpath ../..)
|
||||
|
||||
rm -rf build
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
set_cmake_options () {
|
||||
# Set CMAKE options depending on platform passed $1
|
||||
openssl_path=$(grealpath ../third_party/openssl/$1)
|
||||
echo "OpenSSL path = ${openssl_path}"
|
||||
openssl_crypto_library="${openssl_path}/lib/libcrypto.a"
|
||||
openssl_ssl_library="${openssl_path}/lib/libssl.a"
|
||||
options=""
|
||||
options="$options -DOPENSSL_FOUND=1"
|
||||
options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}"
|
||||
options="$options -DOPENSSL_SSL_LIBRARY=${openssl_ssl_library}"
|
||||
options="$options -DOPENSSL_INCLUDE_DIR=${openssl_path}/include"
|
||||
options="$options -DOPENSSL_LIBRARIES=${openssl_crypto_library};${openssl_ssl_library}"
|
||||
options="$options -DCMAKE_BUILD_TYPE=Release"
|
||||
}
|
||||
|
||||
platforms="macOS iOS watchOS tvOS visionOS"
|
||||
#platforms="watchOS"
|
||||
for platform in $platforms;
|
||||
do
|
||||
echo "Platform = ${platform}"
|
||||
if [[ $platform = "macOS" ]]; then
|
||||
simulators="0"
|
||||
else
|
||||
simulators="0 1"
|
||||
fi
|
||||
|
||||
for simulator in $simulators;
|
||||
do
|
||||
if [[ $platform = "macOS" ]]; then
|
||||
other_options="-DCMAKE_OSX_ARCHITECTURES='x86_64;arm64'"
|
||||
else
|
||||
if [[ $platform = "watchOS" ]]; then
|
||||
ios_platform="WATCH"
|
||||
elif [[ $platform = "tvOS" ]]; then
|
||||
ios_platform="TV"
|
||||
elif [[ $platform = "visionOS" ]]; then
|
||||
ios_platform="VISION"
|
||||
else
|
||||
ios_platform=""
|
||||
fi
|
||||
|
||||
if [[ $simulator = "1" ]]; then
|
||||
platform="${platform}-simulator"
|
||||
ios_platform="${ios_platform}SIMULATOR"
|
||||
else
|
||||
ios_platform="${ios_platform}OS"
|
||||
fi
|
||||
|
||||
echo "iOS platform = ${ios_platform}"
|
||||
other_options="-DIOS_PLATFORM=${ios_platform} -DCMAKE_TOOLCHAIN_FILE=${td_path}/CMake/iOS.cmake"
|
||||
fi
|
||||
|
||||
set_cmake_options $platform
|
||||
build="build-${platform}"
|
||||
install="install-${platform}"
|
||||
rm -rf $build
|
||||
mkdir -p $build
|
||||
mkdir -p $install
|
||||
cd $build
|
||||
cmake $td_path $options $other_options -DCMAKE_INSTALL_PREFIX=../${install}
|
||||
make -j3 install || exit
|
||||
cd ..
|
||||
install_name_tool -id @rpath/libtdjson.dylib ${install}/lib/libtdjson.dylib
|
||||
mkdir -p ../tdjson/${platform}/include
|
||||
rsync --recursive ${install}/include/ ../tdjson/${platform}/include/
|
||||
mkdir -p ../tdjson/${platform}/lib
|
||||
cp ${install}/lib/libtdjson.dylib ../tdjson/${platform}/lib/
|
||||
done
|
||||
done
|
||||
|
||||
produced_dylibs=(install-*/lib/libtdjson.dylib)
|
||||
xcodebuild_frameworks=()
|
||||
|
||||
for dylib in "${produced_dylibs[@]}";
|
||||
do
|
||||
xcodebuild_frameworks+=(-library $(grealpath "${dylib}"))
|
||||
done
|
||||
|
||||
# Make xcframework
|
||||
xcodebuild -create-xcframework \
|
||||
"${xcodebuild_frameworks[@]}" \
|
||||
-output "libtdjson.xcframework"
|
||||
|
||||
rsync --recursive libtdjson.xcframework ../tdjson/
|
5
third-party/td/td/example/java/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
**/*build/
|
||||
/bin/
|
||||
/docs/
|
||||
/org/drinkless/tdlib/TdApi.java
|
||||
/td/
|
141
third-party/td/td/example/java/CMakeLists.txt
vendored
@ -1,141 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
|
||||
project(TdJavaExample VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
option(TD_JSON_JAVA "Use \"ON\" to build Java wrapper for JSON API.")
|
||||
|
||||
if (POLICY CMP0074)
|
||||
# use environment variables to find libraries
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
endif()
|
||||
|
||||
find_package(Td REQUIRED)
|
||||
|
||||
if (NOT JNI_FOUND)
|
||||
find_package(JNI REQUIRED COMPONENTS JVM)
|
||||
endif()
|
||||
message(STATUS "Found JNI: ${JNI_INCLUDE_DIRS} ${JNI_LIBRARIES}")
|
||||
|
||||
if (NOT Java_FOUND)
|
||||
find_package(Java REQUIRED)
|
||||
endif()
|
||||
message(STATUS "Found Java: ${Java_JAVAC_EXECUTABLE} ${Java_JAVADOC_EXECUTABLE}")
|
||||
|
||||
# Generating TdApi.java
|
||||
set(TD_API_JAVA_PACKAGE "org/drinkless/tdlib")
|
||||
set(TD_API_JAVA_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(JAVA_SOURCE_PATH "${TD_API_JAVA_PATH}/${TD_API_JAVA_PACKAGE}")
|
||||
if (TD_JSON_JAVA)
|
||||
add_custom_target(td_generate_java_api
|
||||
COMMAND cmake -E echo ""
|
||||
COMMENT "Skip generation of Java TDLib API source files"
|
||||
)
|
||||
|
||||
set(JAVA_EXAMPLE_FILES "${JAVA_SOURCE_PATH}/example/JsonExample.java")
|
||||
set(JAVA_SOURCE_FILES "${JAVA_SOURCE_PATH}/JsonClient.java")
|
||||
else()
|
||||
find_program(PHP_EXECUTABLE php)
|
||||
if ((CMAKE_SYSTEM_NAME MATCHES "FreeBSD") AND (CMAKE_SYSTEM_VERSION MATCHES "HBSD"))
|
||||
set(PHP_EXECUTABLE "PHP_EXECUTABLE-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(TD_API_TLO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tlo)
|
||||
set(TD_API_TL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tl)
|
||||
set(JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/JavadocTlDocumentationGenerator.php)
|
||||
set(GENERATE_JAVA_API_CMD ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api TdApi "${TD_API_TLO_PATH}" "${TD_API_JAVA_PATH}" "${TD_API_JAVA_PACKAGE}")
|
||||
if (PHP_EXECUTABLE)
|
||||
set(GENERATE_JAVA_API_CMD ${GENERATE_JAVA_API_CMD} && ${PHP_EXECUTABLE} "${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH}" "${TD_API_TL_PATH}" "${JAVA_SOURCE_PATH}/TdApi.java")
|
||||
endif()
|
||||
|
||||
add_custom_target(td_generate_java_api
|
||||
COMMAND ${GENERATE_JAVA_API_CMD}
|
||||
COMMENT "Generating Java TDLib API source files"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api ${TD_API_TLO_PATH} ${TD_API_TL_PATH} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH}
|
||||
)
|
||||
|
||||
set(JAVA_EXAMPLE_FILES "${JAVA_SOURCE_PATH}/example/Example.java")
|
||||
set(JAVA_SOURCE_FILES "${JAVA_SOURCE_PATH}/Client.java" "${JAVA_SOURCE_PATH}/TdApi.java")
|
||||
endif()
|
||||
|
||||
if (CMAKE_VERSION VERSION_LESS "3.17")
|
||||
set(CMAKE_RM_COMMAND remove_directory)
|
||||
else()
|
||||
set(CMAKE_RM_COMMAND rm -rf --)
|
||||
endif()
|
||||
|
||||
get_filename_component(JAVA_OUTPUT_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin REALPATH BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(MAKE_DIRECTORY ${JAVA_OUTPUT_DIRECTORY})
|
||||
add_custom_target(build_java
|
||||
COMMAND ${CMAKE_COMMAND} -E ${CMAKE_RM_COMMAND} "${JAVA_OUTPUT_DIRECTORY}/${TD_API_JAVA_PACKAGE}"
|
||||
COMMAND ${Java_JAVAC_EXECUTABLE} -encoding UTF-8 -d "${JAVA_OUTPUT_DIRECTORY}" ${JAVA_EXAMPLE_FILES} ${JAVA_SOURCE_FILES}
|
||||
COMMENT "Building Java code"
|
||||
DEPENDS td_generate_java_api
|
||||
)
|
||||
|
||||
add_custom_target(generate_javadoc
|
||||
COMMAND ${CMAKE_COMMAND} -E ${CMAKE_RM_COMMAND} "${JAVA_OUTPUT_DIRECTORY}/../docs"
|
||||
COMMAND ${Java_JAVADOC_EXECUTABLE} -encoding UTF-8 -charset UTF-8 -d "${JAVA_OUTPUT_DIRECTORY}/../docs" ${JAVA_SOURCE_FILES}
|
||||
WORKING_DIRECTORY ${TD_API_JAVA_PATH}
|
||||
COMMENT "Generating Javadoc documentation"
|
||||
DEPENDS td_generate_java_api
|
||||
)
|
||||
|
||||
# Building shared library
|
||||
add_library(tdjni SHARED
|
||||
td_jni.cpp
|
||||
)
|
||||
target_include_directories(tdjni PRIVATE ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
|
||||
target_link_libraries(tdjni PRIVATE ${JAVA_JVM_LIBRARY})
|
||||
target_compile_definitions(tdjni PRIVATE PACKAGE_NAME="${TD_API_JAVA_PACKAGE}")
|
||||
|
||||
if (TD_JSON_JAVA)
|
||||
target_link_libraries(tdjni PRIVATE Td::TdJsonStatic)
|
||||
target_compile_definitions(tdjni PRIVATE TD_JSON_JAVA=1)
|
||||
set_target_properties(tdjni PROPERTIES OUTPUT_NAME "tdjsonjava")
|
||||
else()
|
||||
target_link_libraries(tdjni PRIVATE Td::TdStatic)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(GCC 1)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CLANG 1)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
set(INTEL 1)
|
||||
elseif (NOT MSVC)
|
||||
message(FATAL_ERROR "Compiler isn't supported")
|
||||
endif()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if (GCC OR CLANG OR INTEL)
|
||||
if (WIN32 AND INTEL)
|
||||
set(STD14_FLAG /Qstd=c++14)
|
||||
else()
|
||||
set(STD14_FLAG -std=c++14)
|
||||
endif()
|
||||
check_cxx_compiler_flag(${STD14_FLAG} HAVE_STD14)
|
||||
if (NOT HAVE_STD14)
|
||||
string(REPLACE "c++14" "c++1y" STD14_FLAG "${STD14_FLAG}")
|
||||
check_cxx_compiler_flag(${STD14_FLAG} HAVE_STD1Y)
|
||||
set(HAVE_STD14 ${HAVE_STD1Y})
|
||||
endif()
|
||||
|
||||
target_compile_options(tdjni PRIVATE "${STD14_FLAG}")
|
||||
elseif (MSVC)
|
||||
set(HAVE_STD14 MSVC_VERSION>=1900)
|
||||
endif()
|
||||
|
||||
if (NOT HAVE_STD14)
|
||||
message(FATAL_ERROR "No C++14 support in the compiler. Please upgrade the compiler.")
|
||||
endif()
|
||||
|
||||
add_dependencies(tdjni td_generate_java_api build_java generate_javadoc)
|
||||
|
||||
install(TARGETS tdjni
|
||||
LIBRARY DESTINATION bin
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
if (MSVC AND VCPKG_TOOLCHAIN)
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/" DESTINATION bin FILES_MATCHING PATTERN "*.dll" PATTERN "*.pdb")
|
||||
endif()
|
47
third-party/td/td/example/java/README.md
vendored
@ -1,47 +0,0 @@
|
||||
# TDLib Java example
|
||||
|
||||
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.
|
||||
|
||||
In general, the build process looks as follows.
|
||||
|
||||
TDLib should be prebuilt with JNI bindings and installed to local subdirectory `td/` as follows:
|
||||
```
|
||||
cd <path to TDLib sources>
|
||||
mkdir jnibuild
|
||||
cd jnibuild
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DTD_ENABLE_JNI=ON -DCMAKE_INSTALL_PREFIX:PATH=../example/java/td ..
|
||||
cmake --build . --target install
|
||||
```
|
||||
If you want to compile TDLib for 32-bit/64-bit Java on Windows using MSVC, you will also need to add `-A Win32`/`-A x64` option to CMake.
|
||||
|
||||
In Windows, use vcpkg toolchain file by adding parameter -DCMAKE_TOOLCHAIN_FILE=<VCPKG_DIR>/scripts/buildsystems/vcpkg.cmake
|
||||
|
||||
If you want to build JsonClient.java wrapper for JSON interface instead of the native JNI interface, add `-DTD_JSON_JAVA=ON` option to CMake.
|
||||
|
||||
After this you can compile the example source code:
|
||||
```
|
||||
cd <path to TDLib sources>/example/java
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DTd_DIR=<full path to TDLib sources>/example/java/td/lib/cmake/Td -DCMAKE_INSTALL_PREFIX:PATH=.. ..
|
||||
cmake --build . --target install
|
||||
```
|
||||
|
||||
Compiled TDLib shared library and Java example after that will be placed in `bin/` and Javadoc documentation in `docs/`.
|
||||
|
||||
After this you can run the Java example:
|
||||
```
|
||||
cd <path to TDLib sources>/example/java/bin
|
||||
java '-Djava.library.path=.' org/drinkless/tdlib/example/Example
|
||||
```
|
||||
|
||||
If you built JSON interface example using `-DTD_JSON_JAVA=ON` option, then use the command `java '-Djava.library.path=.' org/drinkless/tdlib/example/JsonExample` instead.
|
||||
|
||||
If you receive "Could NOT find JNI ..." error from CMake, you need to specify to CMake path to the installed JDK, for example, "-DJAVA_HOME=/usr/lib/jvm/java-8-oracle/".
|
||||
|
||||
If you receive java.lang.UnsatisfiedLinkError with "Can't find dependent libraries", you may also need to copy some dependent shared OpenSSL and zlib libraries to `bin/`.
|
||||
|
||||
Make sure that you compiled the example for the same architecture as your JVM.
|
@ -1,259 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
package org.drinkless.tdlib;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Main class for interaction with the TDLib.
|
||||
*/
|
||||
public final class Client {
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("tdjni");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for handler for results of queries to TDLib and incoming updates from TDLib.
|
||||
*/
|
||||
public interface ResultHandler {
|
||||
/**
|
||||
* Callback called on result of query to TDLib or incoming update from TDLib.
|
||||
*
|
||||
* @param object Result of query or update of type TdApi.Update about new events.
|
||||
*/
|
||||
void onResult(TdApi.Object object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for handler of exceptions thrown while invoking ResultHandler.
|
||||
* By default, all such exceptions are ignored.
|
||||
* All exceptions thrown from ExceptionHandler are ignored.
|
||||
*/
|
||||
public interface ExceptionHandler {
|
||||
/**
|
||||
* Callback called on exceptions thrown while invoking ResultHandler.
|
||||
*
|
||||
* @param e Exception thrown by ResultHandler.
|
||||
*/
|
||||
void onException(Throwable e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for handler of messages that are added to the internal TDLib log.
|
||||
*/
|
||||
public interface LogMessageHandler {
|
||||
/**
|
||||
* Callback called on messages that are added to the internal TDLib log.
|
||||
*
|
||||
* @param verbosityLevel Log verbosity level with which the message was added from -1 up to 1024.
|
||||
* If 0, then TDLib will crash as soon as the callback returns.
|
||||
* None of the TDLib methods can be called from the callback.
|
||||
* @param message The message added to the internal TDLib log.
|
||||
*/
|
||||
void onLogMessage(int verbosityLevel, String message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception class thrown when TDLib error occurred while performing {@link #execute(TdApi.Function)}.
|
||||
*/
|
||||
public static class ExecutionException extends Exception {
|
||||
/**
|
||||
* Original TDLib error occurred when performing one of the synchronous functions.
|
||||
*/
|
||||
public final TdApi.Error error;
|
||||
|
||||
/**
|
||||
* @param error TDLib error occurred while performing {@link #execute(TdApi.Function)}.
|
||||
*/
|
||||
ExecutionException (TdApi.Error error) {
|
||||
super(error.code + ": " + error.message);
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to the TDLib.
|
||||
*
|
||||
* @param query Object representing a query to the TDLib.
|
||||
* @param resultHandler Result handler with onResult method which will be called with result
|
||||
* of the query or with TdApi.Error as parameter. If it is null, nothing
|
||||
* will be called.
|
||||
* @param exceptionHandler Exception handler with onException method which will be called on
|
||||
* exception thrown from resultHandler. If it is null, then
|
||||
* defaultExceptionHandler will be called.
|
||||
*/
|
||||
public void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
long queryId = currentQueryId.incrementAndGet();
|
||||
if (resultHandler != null) {
|
||||
handlers.put(queryId, new Handler(resultHandler, exceptionHandler));
|
||||
}
|
||||
nativeClientSend(nativeClientId, queryId, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to the TDLib with an empty ExceptionHandler.
|
||||
*
|
||||
* @param query Object representing a query to the TDLib.
|
||||
* @param resultHandler Result handler with onResult method which will be called with result
|
||||
* of the query or with TdApi.Error as parameter. If it is null, then
|
||||
* defaultExceptionHandler will be called.
|
||||
*/
|
||||
public void send(TdApi.Function query, ResultHandler resultHandler) {
|
||||
send(query, resultHandler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously executes a TDLib request. Only a few marked accordingly requests can be executed synchronously.
|
||||
*
|
||||
* @param query Object representing a query to the TDLib.
|
||||
* @param <T> Automatically deduced return type of the query.
|
||||
* @return request result.
|
||||
* @throws ExecutionException if query execution fails.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends TdApi.Object> T execute(TdApi.Function<T> query) throws ExecutionException {
|
||||
TdApi.Object object = nativeClientExecute(query);
|
||||
if (object instanceof TdApi.Error) {
|
||||
throw new ExecutionException((TdApi.Error) object);
|
||||
}
|
||||
return (T) object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new Client.
|
||||
*
|
||||
* @param updateHandler Handler for incoming updates.
|
||||
* @param updateExceptionHandler Handler for exceptions thrown from updateHandler. If it is null, exceptions will be ignored.
|
||||
* @param defaultExceptionHandler Default handler for exceptions thrown from all ResultHandler. If it is null, exceptions will be ignored.
|
||||
* @return created Client
|
||||
*/
|
||||
public static Client create(ResultHandler updateHandler, ExceptionHandler updateExceptionHandler, ExceptionHandler defaultExceptionHandler) {
|
||||
Client client = new Client(updateHandler, updateExceptionHandler, defaultExceptionHandler);
|
||||
synchronized (responseReceiver) {
|
||||
if (!responseReceiver.isRun) {
|
||||
responseReceiver.isRun = true;
|
||||
|
||||
Thread receiverThread = new Thread(responseReceiver, "TDLib thread");
|
||||
receiverThread.setDaemon(true);
|
||||
receiverThread.start();
|
||||
}
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the handler for messages that are added to the internal TDLib log.
|
||||
* None of the TDLib methods can be called from the callback.
|
||||
*
|
||||
* @param maxVerbosityLevel The maximum verbosity level of messages for which the callback will be called.
|
||||
* @param logMessageHandler Handler for messages that are added to the internal TDLib log. Pass null to remove the handler.
|
||||
*/
|
||||
public static void setLogMessageHandler(int maxVerbosityLevel, Client.LogMessageHandler logMessageHandler) {
|
||||
nativeClientSetLogMessageHandler(maxVerbosityLevel, logMessageHandler);
|
||||
}
|
||||
|
||||
private static class ResponseReceiver implements Runnable {
|
||||
public boolean isRun = false;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
int resultN = nativeClientReceive(clientIds, eventIds, events, 100000.0 /*seconds*/);
|
||||
for (int i = 0; i < resultN; i++) {
|
||||
processResult(clientIds[i], eventIds[i], events[i]);
|
||||
events[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processResult(int clientId, long id, TdApi.Object object) {
|
||||
boolean isClosed = false;
|
||||
if (id == 0 && object instanceof TdApi.UpdateAuthorizationState) {
|
||||
TdApi.AuthorizationState authorizationState = ((TdApi.UpdateAuthorizationState) object).authorizationState;
|
||||
if (authorizationState instanceof TdApi.AuthorizationStateClosed) {
|
||||
isClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
Handler handler = id == 0 ? updateHandlers.get(clientId) : handlers.remove(id);
|
||||
if (handler != null) {
|
||||
try {
|
||||
handler.resultHandler.onResult(object);
|
||||
} catch (Throwable cause) {
|
||||
ExceptionHandler exceptionHandler = handler.exceptionHandler;
|
||||
if (exceptionHandler == null) {
|
||||
exceptionHandler = defaultExceptionHandlers.get(clientId);
|
||||
}
|
||||
if (exceptionHandler != null) {
|
||||
try {
|
||||
exceptionHandler.onException(cause);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isClosed) {
|
||||
updateHandlers.remove(clientId); // there will be no more updates
|
||||
defaultExceptionHandlers.remove(clientId); // ignore further exceptions
|
||||
clientCount.decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MAX_EVENTS = 1000;
|
||||
private final int[] clientIds = new int[MAX_EVENTS];
|
||||
private final long[] eventIds = new long[MAX_EVENTS];
|
||||
private final TdApi.Object[] events = new TdApi.Object[MAX_EVENTS];
|
||||
}
|
||||
|
||||
private final int nativeClientId;
|
||||
|
||||
private static final ConcurrentHashMap<Integer, ExceptionHandler> defaultExceptionHandlers = new ConcurrentHashMap<Integer, ExceptionHandler>();
|
||||
private static final ConcurrentHashMap<Integer, Handler> updateHandlers = new ConcurrentHashMap<Integer, Handler>();
|
||||
private static final ConcurrentHashMap<Long, Handler> handlers = new ConcurrentHashMap<Long, Handler>();
|
||||
private static final AtomicLong currentQueryId = new AtomicLong();
|
||||
private static final AtomicLong clientCount = new AtomicLong();
|
||||
|
||||
private static final ResponseReceiver responseReceiver = new ResponseReceiver();
|
||||
|
||||
private static class Handler {
|
||||
final ResultHandler resultHandler;
|
||||
final ExceptionHandler exceptionHandler;
|
||||
|
||||
Handler(ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
this.resultHandler = resultHandler;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
}
|
||||
|
||||
private Client(ResultHandler updateHandler, ExceptionHandler updateExceptionHandler, ExceptionHandler defaultExceptionHandler) {
|
||||
clientCount.incrementAndGet();
|
||||
nativeClientId = createNativeClient();
|
||||
if (updateHandler != null) {
|
||||
updateHandlers.put(nativeClientId, new Handler(updateHandler, updateExceptionHandler));
|
||||
}
|
||||
if (defaultExceptionHandler != null) {
|
||||
defaultExceptionHandlers.put(nativeClientId, defaultExceptionHandler);
|
||||
}
|
||||
send(new TdApi.GetOption("version"), null, null);
|
||||
}
|
||||
|
||||
private static native int createNativeClient();
|
||||
|
||||
private static native void nativeClientSend(int nativeClientId, long eventId, TdApi.Function function);
|
||||
|
||||
private static native int nativeClientReceive(int[] clientIds, long[] eventIds, TdApi.Object[] events, double timeout);
|
||||
|
||||
private static native TdApi.Object nativeClientExecute(TdApi.Function function);
|
||||
|
||||
private static native void nativeClientSetLogMessageHandler(int maxVerbosityLevel, LogMessageHandler logMessageHandler);
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
package org.drinkless.tdlib;
|
||||
|
||||
/**
|
||||
* Main class for interaction with the TDLib using JSON interface.
|
||||
*/
|
||||
public final class JsonClient {
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("tdjsonjava");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an opaque identifier of a new TDLib instance.
|
||||
* The TDLib instance will not send updates until the first request is sent to it.
|
||||
* @return Opaque identifier of a new TDLib instance.
|
||||
*/
|
||||
public static native int createClientId();
|
||||
|
||||
/**
|
||||
* Sends request to the TDLib client. May be called from any thread.
|
||||
* @param clientId TDLib client identifier.
|
||||
* @param request JSON-serialized request.
|
||||
*/
|
||||
public static native void send(int clientId, String request);
|
||||
|
||||
/**
|
||||
* Receives incoming updates and request responses. Must not be called simultaneously from two different threads.
|
||||
* @param timeout The maximum number of seconds allowed for this function to wait for new data.
|
||||
* @return JSON-serialized incoming update or request response. May be null if the timeout expired before new data received.
|
||||
*/
|
||||
public static native String receive(double timeout);
|
||||
|
||||
/**
|
||||
* Synchronously executes a TDLib request.
|
||||
* A request can be executed synchronously, only if it is documented with "Can be called synchronously".
|
||||
* @param request JSON-serialized request.
|
||||
* @return JSON-serialized request response. May be null if the request is invalid.
|
||||
*/
|
||||
public static native String execute(String request);
|
||||
|
||||
/**
|
||||
* Interface for handler of messages that are added to the internal TDLib log.
|
||||
*/
|
||||
public interface LogMessageHandler {
|
||||
/**
|
||||
* Callback called on messages that are added to the internal TDLib log.
|
||||
*
|
||||
* @param verbosityLevel Log verbosity level with which the message was added from -1 up to 1024.
|
||||
* If 0, then TDLib will crash as soon as the callback returns.
|
||||
* None of the TDLib methods can be called from the callback.
|
||||
* @param message The message added to the internal TDLib log.
|
||||
*/
|
||||
void onLogMessage(int verbosityLevel, String message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the handler for messages that are added to the internal TDLib log.
|
||||
* None of the TDLib methods can be called from the callback.
|
||||
*
|
||||
* @param maxVerbosityLevel The maximum verbosity level of messages for which the callback will be called.
|
||||
* @param logMessageHandler Handler for messages that are added to the internal TDLib log. Pass null to remove the handler.
|
||||
*/
|
||||
public static native void setLogMessageHandler(int maxVerbosityLevel, JsonClient.LogMessageHandler logMessageHandler);
|
||||
|
||||
/**
|
||||
* The class can't be instantiated.
|
||||
*/
|
||||
private JsonClient() {
|
||||
}
|
||||
}
|
@ -1,780 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
package org.drinkless.tdlib.example;
|
||||
|
||||
import org.drinkless.tdlib.Client;
|
||||
import org.drinkless.tdlib.TdApi;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Example class for TDLib usage from Java.
|
||||
*/
|
||||
public final class Example {
|
||||
private static Client client = null;
|
||||
|
||||
private static TdApi.AuthorizationState authorizationState = null;
|
||||
private static volatile boolean haveAuthorization = false;
|
||||
private static volatile boolean needQuit = false;
|
||||
private static volatile boolean canQuit = false;
|
||||
|
||||
private static final Client.ResultHandler defaultHandler = new DefaultHandler();
|
||||
|
||||
private static final Lock authorizationLock = new ReentrantLock();
|
||||
private static final Condition gotAuthorization = authorizationLock.newCondition();
|
||||
|
||||
private static final ConcurrentMap<Long, TdApi.User> users = new ConcurrentHashMap<Long, TdApi.User>();
|
||||
private static final ConcurrentMap<Long, TdApi.BasicGroup> basicGroups = new ConcurrentHashMap<Long, TdApi.BasicGroup>();
|
||||
private static final ConcurrentMap<Long, TdApi.Supergroup> supergroups = new ConcurrentHashMap<Long, TdApi.Supergroup>();
|
||||
private static final ConcurrentMap<Integer, TdApi.SecretChat> secretChats = new ConcurrentHashMap<Integer, TdApi.SecretChat>();
|
||||
|
||||
private static final ConcurrentMap<Long, TdApi.Chat> chats = new ConcurrentHashMap<Long, TdApi.Chat>();
|
||||
private static final NavigableSet<OrderedChat> mainChatList = new TreeSet<OrderedChat>();
|
||||
private static boolean haveFullMainChatList = false;
|
||||
|
||||
private static final ConcurrentMap<Long, TdApi.UserFullInfo> usersFullInfo = new ConcurrentHashMap<Long, TdApi.UserFullInfo>();
|
||||
private static final ConcurrentMap<Long, TdApi.BasicGroupFullInfo> basicGroupsFullInfo = new ConcurrentHashMap<Long, TdApi.BasicGroupFullInfo>();
|
||||
private static final ConcurrentMap<Long, TdApi.SupergroupFullInfo> supergroupsFullInfo = new ConcurrentHashMap<Long, TdApi.SupergroupFullInfo>();
|
||||
|
||||
private static final String newLine = System.getProperty("line.separator");
|
||||
private static final String commandsLine = "Enter command (gcs - GetChats, gc <chatId> - GetChat, me - GetMe, sm <chatId> <message> - SendMessage, lo - LogOut, q - Quit): ";
|
||||
private static volatile String currentPrompt = null;
|
||||
|
||||
private static void print(String str) {
|
||||
if (currentPrompt != null) {
|
||||
System.out.println("");
|
||||
}
|
||||
System.out.println(str);
|
||||
if (currentPrompt != null) {
|
||||
System.out.print(currentPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setChatPositions(TdApi.Chat chat, TdApi.ChatPosition[] positions) {
|
||||
synchronized (mainChatList) {
|
||||
synchronized (chat) {
|
||||
for (TdApi.ChatPosition position : chat.positions) {
|
||||
if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
boolean isRemoved = mainChatList.remove(new OrderedChat(chat.id, position));
|
||||
assert isRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
chat.positions = positions;
|
||||
|
||||
for (TdApi.ChatPosition position : chat.positions) {
|
||||
if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
boolean isAdded = mainChatList.add(new OrderedChat(chat.id, position));
|
||||
assert isAdded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void onAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState) {
|
||||
if (authorizationState != null) {
|
||||
Example.authorizationState = authorizationState;
|
||||
}
|
||||
switch (Example.authorizationState.getConstructor()) {
|
||||
case TdApi.AuthorizationStateWaitTdlibParameters.CONSTRUCTOR:
|
||||
TdApi.SetTdlibParameters request = new TdApi.SetTdlibParameters();
|
||||
request.databaseDirectory = "tdlib";
|
||||
request.useMessageDatabase = true;
|
||||
request.useSecretChats = true;
|
||||
request.apiId = 94575;
|
||||
request.apiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
|
||||
request.systemLanguageCode = "en";
|
||||
request.deviceModel = "Desktop";
|
||||
request.applicationVersion = "1.0";
|
||||
|
||||
client.send(request, new AuthorizationRequestHandler());
|
||||
break;
|
||||
case TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR: {
|
||||
String phoneNumber = promptString("Please enter phone number: ");
|
||||
client.send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, null), new AuthorizationRequestHandler());
|
||||
break;
|
||||
}
|
||||
case TdApi.AuthorizationStateWaitOtherDeviceConfirmation.CONSTRUCTOR: {
|
||||
String link = ((TdApi.AuthorizationStateWaitOtherDeviceConfirmation) Example.authorizationState).link;
|
||||
System.out.println("Please confirm this login link on another device: " + link);
|
||||
break;
|
||||
}
|
||||
case TdApi.AuthorizationStateWaitEmailAddress.CONSTRUCTOR: {
|
||||
String emailAddress = promptString("Please enter email address: ");
|
||||
client.send(new TdApi.SetAuthenticationEmailAddress(emailAddress), new AuthorizationRequestHandler());
|
||||
break;
|
||||
}
|
||||
case TdApi.AuthorizationStateWaitEmailCode.CONSTRUCTOR: {
|
||||
String code = promptString("Please enter email authentication code: ");
|
||||
client.send(new TdApi.CheckAuthenticationEmailCode(new TdApi.EmailAddressAuthenticationCode(code)), new AuthorizationRequestHandler());
|
||||
break;
|
||||
}
|
||||
case TdApi.AuthorizationStateWaitCode.CONSTRUCTOR: {
|
||||
String code = promptString("Please enter authentication code: ");
|
||||
client.send(new TdApi.CheckAuthenticationCode(code), new AuthorizationRequestHandler());
|
||||
break;
|
||||
}
|
||||
case TdApi.AuthorizationStateWaitRegistration.CONSTRUCTOR: {
|
||||
String firstName = promptString("Please enter your first name: ");
|
||||
String lastName = promptString("Please enter your last name: ");
|
||||
client.send(new TdApi.RegisterUser(firstName, lastName, false), new AuthorizationRequestHandler());
|
||||
break;
|
||||
}
|
||||
case TdApi.AuthorizationStateWaitPassword.CONSTRUCTOR: {
|
||||
String password = promptString("Please enter password: ");
|
||||
client.send(new TdApi.CheckAuthenticationPassword(password), new AuthorizationRequestHandler());
|
||||
break;
|
||||
}
|
||||
case TdApi.AuthorizationStateReady.CONSTRUCTOR:
|
||||
haveAuthorization = true;
|
||||
authorizationLock.lock();
|
||||
try {
|
||||
gotAuthorization.signal();
|
||||
} finally {
|
||||
authorizationLock.unlock();
|
||||
}
|
||||
break;
|
||||
case TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR:
|
||||
haveAuthorization = false;
|
||||
print("Logging out");
|
||||
break;
|
||||
case TdApi.AuthorizationStateClosing.CONSTRUCTOR:
|
||||
haveAuthorization = false;
|
||||
print("Closing");
|
||||
break;
|
||||
case TdApi.AuthorizationStateClosed.CONSTRUCTOR:
|
||||
print("Closed");
|
||||
if (!needQuit) {
|
||||
client = Client.create(new UpdateHandler(), null, null); // recreate client after previous has closed
|
||||
} else {
|
||||
canQuit = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unsupported authorization state:" + newLine + Example.authorizationState);
|
||||
}
|
||||
}
|
||||
|
||||
private static int toInt(String arg) {
|
||||
int result = 0;
|
||||
try {
|
||||
result = Integer.parseInt(arg);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static long getChatId(String arg) {
|
||||
long chatId = 0;
|
||||
try {
|
||||
chatId = Long.parseLong(arg);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
return chatId;
|
||||
}
|
||||
|
||||
private static String promptString(String prompt) {
|
||||
System.out.print(prompt);
|
||||
currentPrompt = prompt;
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
String str = "";
|
||||
try {
|
||||
str = reader.readLine();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
currentPrompt = null;
|
||||
return str;
|
||||
}
|
||||
|
||||
private static void getCommand() {
|
||||
String command = promptString(commandsLine);
|
||||
String[] commands = command.split(" ", 2);
|
||||
try {
|
||||
switch (commands[0]) {
|
||||
case "gcs": {
|
||||
int limit = 20;
|
||||
if (commands.length > 1) {
|
||||
limit = toInt(commands[1]);
|
||||
}
|
||||
getMainChatList(limit);
|
||||
break;
|
||||
}
|
||||
case "gc":
|
||||
client.send(new TdApi.GetChat(getChatId(commands[1])), defaultHandler);
|
||||
break;
|
||||
case "me":
|
||||
client.send(new TdApi.GetMe(), defaultHandler);
|
||||
break;
|
||||
case "sm": {
|
||||
String[] args = commands[1].split(" ", 2);
|
||||
sendMessage(getChatId(args[0]), args[1]);
|
||||
break;
|
||||
}
|
||||
case "lo":
|
||||
haveAuthorization = false;
|
||||
client.send(new TdApi.LogOut(), defaultHandler);
|
||||
break;
|
||||
case "q":
|
||||
needQuit = true;
|
||||
haveAuthorization = false;
|
||||
client.send(new TdApi.Close(), defaultHandler);
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unsupported command: " + command);
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
print("Not enough arguments");
|
||||
}
|
||||
}
|
||||
|
||||
private static void getMainChatList(final int limit) {
|
||||
synchronized (mainChatList) {
|
||||
if (!haveFullMainChatList && limit > mainChatList.size()) {
|
||||
// send LoadChats request if there are some unknown chats and have not enough known chats
|
||||
client.send(new TdApi.LoadChats(new TdApi.ChatListMain(), limit - mainChatList.size()), new Client.ResultHandler() {
|
||||
@Override
|
||||
public void onResult(TdApi.Object object) {
|
||||
switch (object.getConstructor()) {
|
||||
case TdApi.Error.CONSTRUCTOR:
|
||||
if (((TdApi.Error) object).code == 404) {
|
||||
synchronized (mainChatList) {
|
||||
haveFullMainChatList = true;
|
||||
}
|
||||
} else {
|
||||
System.err.println("Receive an error for LoadChats:" + newLine + object);
|
||||
}
|
||||
break;
|
||||
case TdApi.Ok.CONSTRUCTOR:
|
||||
// chats had already been received through updates, let's retry request
|
||||
getMainChatList(limit);
|
||||
break;
|
||||
default:
|
||||
System.err.println("Receive wrong response from TDLib:" + newLine + object);
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
java.util.Iterator<OrderedChat> iter = mainChatList.iterator();
|
||||
System.out.println();
|
||||
System.out.println("First " + limit + " chat(s) out of " + mainChatList.size() + " known chat(s):");
|
||||
for (int i = 0; i < limit && i < mainChatList.size(); i++) {
|
||||
long chatId = iter.next().chatId;
|
||||
TdApi.Chat chat = chats.get(chatId);
|
||||
synchronized (chat) {
|
||||
System.out.println(chatId + ": " + chat.title);
|
||||
}
|
||||
}
|
||||
print("");
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendMessage(long chatId, String message) {
|
||||
// initialize reply markup just for testing
|
||||
TdApi.InlineKeyboardButton[] row = {new TdApi.InlineKeyboardButton("https://telegram.org?1", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?2", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?3", new TdApi.InlineKeyboardButtonTypeUrl())};
|
||||
TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][]{row, row, row});
|
||||
|
||||
TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), null, true);
|
||||
client.send(new TdApi.SendMessage(chatId, 0, null, null, replyMarkup, content), defaultHandler);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
// set log message handler to handle only fatal errors (0) and plain log messages (-1)
|
||||
Client.setLogMessageHandler(0, new LogMessageHandler());
|
||||
|
||||
// disable TDLib log and redirect fatal errors and plain log messages to a file
|
||||
try {
|
||||
Client.execute(new TdApi.SetLogVerbosityLevel(0));
|
||||
Client.execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false)));
|
||||
} catch (Client.ExecutionException error) {
|
||||
throw new IOError(new IOException("Write access to the current directory is required"));
|
||||
}
|
||||
|
||||
// create client
|
||||
client = Client.create(new UpdateHandler(), null, null);
|
||||
|
||||
// main loop
|
||||
while (!needQuit) {
|
||||
// await authorization
|
||||
authorizationLock.lock();
|
||||
try {
|
||||
while (!haveAuthorization) {
|
||||
gotAuthorization.await();
|
||||
}
|
||||
} finally {
|
||||
authorizationLock.unlock();
|
||||
}
|
||||
|
||||
while (haveAuthorization) {
|
||||
getCommand();
|
||||
}
|
||||
}
|
||||
while (!canQuit) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static class OrderedChat implements Comparable<OrderedChat> {
|
||||
final long chatId;
|
||||
final TdApi.ChatPosition position;
|
||||
|
||||
OrderedChat(long chatId, TdApi.ChatPosition position) {
|
||||
this.chatId = chatId;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(OrderedChat o) {
|
||||
if (this.position.order != o.position.order) {
|
||||
return o.position.order < this.position.order ? -1 : 1;
|
||||
}
|
||||
if (this.chatId != o.chatId) {
|
||||
return o.chatId < this.chatId ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
OrderedChat o = (OrderedChat) obj;
|
||||
return this.chatId == o.chatId && this.position.order == o.position.order;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultHandler implements Client.ResultHandler {
|
||||
@Override
|
||||
public void onResult(TdApi.Object object) {
|
||||
print(object.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static class UpdateHandler implements Client.ResultHandler {
|
||||
@Override
|
||||
public void onResult(TdApi.Object object) {
|
||||
switch (object.getConstructor()) {
|
||||
case TdApi.UpdateAuthorizationState.CONSTRUCTOR:
|
||||
onAuthorizationStateUpdated(((TdApi.UpdateAuthorizationState) object).authorizationState);
|
||||
break;
|
||||
|
||||
case TdApi.UpdateUser.CONSTRUCTOR:
|
||||
TdApi.UpdateUser updateUser = (TdApi.UpdateUser) object;
|
||||
users.put(updateUser.user.id, updateUser.user);
|
||||
break;
|
||||
case TdApi.UpdateUserStatus.CONSTRUCTOR: {
|
||||
TdApi.UpdateUserStatus updateUserStatus = (TdApi.UpdateUserStatus) object;
|
||||
TdApi.User user = users.get(updateUserStatus.userId);
|
||||
synchronized (user) {
|
||||
user.status = updateUserStatus.status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateBasicGroup.CONSTRUCTOR:
|
||||
TdApi.UpdateBasicGroup updateBasicGroup = (TdApi.UpdateBasicGroup) object;
|
||||
basicGroups.put(updateBasicGroup.basicGroup.id, updateBasicGroup.basicGroup);
|
||||
break;
|
||||
case TdApi.UpdateSupergroup.CONSTRUCTOR:
|
||||
TdApi.UpdateSupergroup updateSupergroup = (TdApi.UpdateSupergroup) object;
|
||||
supergroups.put(updateSupergroup.supergroup.id, updateSupergroup.supergroup);
|
||||
break;
|
||||
case TdApi.UpdateSecretChat.CONSTRUCTOR:
|
||||
TdApi.UpdateSecretChat updateSecretChat = (TdApi.UpdateSecretChat) object;
|
||||
secretChats.put(updateSecretChat.secretChat.id, updateSecretChat.secretChat);
|
||||
break;
|
||||
|
||||
case TdApi.UpdateNewChat.CONSTRUCTOR: {
|
||||
TdApi.UpdateNewChat updateNewChat = (TdApi.UpdateNewChat) object;
|
||||
TdApi.Chat chat = updateNewChat.chat;
|
||||
synchronized (chat) {
|
||||
chats.put(chat.id, chat);
|
||||
|
||||
TdApi.ChatPosition[] positions = chat.positions;
|
||||
chat.positions = new TdApi.ChatPosition[0];
|
||||
setChatPositions(chat, positions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatTitle.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatTitle updateChat = (TdApi.UpdateChatTitle) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.title = updateChat.title;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatPhoto.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatPhoto updateChat = (TdApi.UpdateChatPhoto) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.photo = updateChat.photo;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatPermissions.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatPermissions update = (TdApi.UpdateChatPermissions) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.permissions = update.permissions;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatLastMessage.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatLastMessage updateChat = (TdApi.UpdateChatLastMessage) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.lastMessage = updateChat.lastMessage;
|
||||
setChatPositions(chat, updateChat.positions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatPosition.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatPosition updateChat = (TdApi.UpdateChatPosition) object;
|
||||
if (updateChat.position.list.getConstructor() != TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
break;
|
||||
}
|
||||
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
int i;
|
||||
for (i = 0; i < chat.positions.length; i++) {
|
||||
if (chat.positions[i].list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TdApi.ChatPosition[] new_positions = new TdApi.ChatPosition[chat.positions.length + (updateChat.position.order == 0 ? 0 : 1) - (i < chat.positions.length ? 1 : 0)];
|
||||
int pos = 0;
|
||||
if (updateChat.position.order != 0) {
|
||||
new_positions[pos++] = updateChat.position;
|
||||
}
|
||||
for (int j = 0; j < chat.positions.length; j++) {
|
||||
if (j != i) {
|
||||
new_positions[pos++] = chat.positions[j];
|
||||
}
|
||||
}
|
||||
assert pos == new_positions.length;
|
||||
|
||||
setChatPositions(chat, new_positions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatReadInbox.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatReadInbox updateChat = (TdApi.UpdateChatReadInbox) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.lastReadInboxMessageId = updateChat.lastReadInboxMessageId;
|
||||
chat.unreadCount = updateChat.unreadCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatReadOutbox.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatReadOutbox updateChat = (TdApi.UpdateChatReadOutbox) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.lastReadOutboxMessageId = updateChat.lastReadOutboxMessageId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatActionBar.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatActionBar updateChat = (TdApi.UpdateChatActionBar) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.actionBar = updateChat.actionBar;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatAvailableReactions.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatAvailableReactions updateChat = (TdApi.UpdateChatAvailableReactions) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.availableReactions = updateChat.availableReactions;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatDraftMessage.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatDraftMessage updateChat = (TdApi.UpdateChatDraftMessage) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.draftMessage = updateChat.draftMessage;
|
||||
setChatPositions(chat, updateChat.positions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatMessageSender.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatMessageSender updateChat = (TdApi.UpdateChatMessageSender) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.messageSenderId = updateChat.messageSenderId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatMessageAutoDeleteTime.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatMessageAutoDeleteTime updateChat = (TdApi.UpdateChatMessageAutoDeleteTime) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.messageAutoDeleteTime = updateChat.messageAutoDeleteTime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatNotificationSettings.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatNotificationSettings update = (TdApi.UpdateChatNotificationSettings) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.notificationSettings = update.notificationSettings;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatPendingJoinRequests.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatPendingJoinRequests update = (TdApi.UpdateChatPendingJoinRequests) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.pendingJoinRequests = update.pendingJoinRequests;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatReplyMarkup.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatReplyMarkup updateChat = (TdApi.UpdateChatReplyMarkup) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.replyMarkupMessageId = updateChat.replyMarkupMessageId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatBackground.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatBackground updateChat = (TdApi.UpdateChatBackground) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.background = updateChat.background;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatTheme.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatTheme updateChat = (TdApi.UpdateChatTheme) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.themeName = updateChat.themeName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatUnreadMentionCount.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatUnreadMentionCount updateChat = (TdApi.UpdateChatUnreadMentionCount) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.unreadMentionCount = updateChat.unreadMentionCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatUnreadReactionCount.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatUnreadReactionCount updateChat = (TdApi.UpdateChatUnreadReactionCount) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.unreadReactionCount = updateChat.unreadReactionCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatVideoChat.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatVideoChat updateChat = (TdApi.UpdateChatVideoChat) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.videoChat = updateChat.videoChat;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatDefaultDisableNotification.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatDefaultDisableNotification update = (TdApi.UpdateChatDefaultDisableNotification) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.defaultDisableNotification = update.defaultDisableNotification;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatHasProtectedContent.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatHasProtectedContent updateChat = (TdApi.UpdateChatHasProtectedContent) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.hasProtectedContent = updateChat.hasProtectedContent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatIsTranslatable.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatIsTranslatable update = (TdApi.UpdateChatIsTranslatable) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.isTranslatable = update.isTranslatable;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatIsMarkedAsUnread.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatIsMarkedAsUnread update = (TdApi.UpdateChatIsMarkedAsUnread) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.isMarkedAsUnread = update.isMarkedAsUnread;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatBlockList.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatBlockList update = (TdApi.UpdateChatBlockList) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.blockList = update.blockList;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatHasScheduledMessages.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatHasScheduledMessages update = (TdApi.UpdateChatHasScheduledMessages) object;
|
||||
TdApi.Chat chat = chats.get(update.chatId);
|
||||
synchronized (chat) {
|
||||
chat.hasScheduledMessages = update.hasScheduledMessages;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TdApi.UpdateMessageMentionRead.CONSTRUCTOR: {
|
||||
TdApi.UpdateMessageMentionRead updateChat = (TdApi.UpdateMessageMentionRead) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.unreadMentionCount = updateChat.unreadMentionCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateMessageUnreadReactions.CONSTRUCTOR: {
|
||||
TdApi.UpdateMessageUnreadReactions updateChat = (TdApi.UpdateMessageUnreadReactions) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.unreadReactionCount = updateChat.unreadReactionCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TdApi.UpdateUserFullInfo.CONSTRUCTOR:
|
||||
TdApi.UpdateUserFullInfo updateUserFullInfo = (TdApi.UpdateUserFullInfo) object;
|
||||
usersFullInfo.put(updateUserFullInfo.userId, updateUserFullInfo.userFullInfo);
|
||||
break;
|
||||
case TdApi.UpdateBasicGroupFullInfo.CONSTRUCTOR:
|
||||
TdApi.UpdateBasicGroupFullInfo updateBasicGroupFullInfo = (TdApi.UpdateBasicGroupFullInfo) object;
|
||||
basicGroupsFullInfo.put(updateBasicGroupFullInfo.basicGroupId, updateBasicGroupFullInfo.basicGroupFullInfo);
|
||||
break;
|
||||
case TdApi.UpdateSupergroupFullInfo.CONSTRUCTOR:
|
||||
TdApi.UpdateSupergroupFullInfo updateSupergroupFullInfo = (TdApi.UpdateSupergroupFullInfo) object;
|
||||
supergroupsFullInfo.put(updateSupergroupFullInfo.supergroupId, updateSupergroupFullInfo.supergroupFullInfo);
|
||||
break;
|
||||
default:
|
||||
// print("Unsupported update:" + newLine + object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class AuthorizationRequestHandler implements Client.ResultHandler {
|
||||
@Override
|
||||
public void onResult(TdApi.Object object) {
|
||||
switch (object.getConstructor()) {
|
||||
case TdApi.Error.CONSTRUCTOR:
|
||||
System.err.println("Receive an error:" + newLine + object);
|
||||
onAuthorizationStateUpdated(null); // repeat last action
|
||||
break;
|
||||
case TdApi.Ok.CONSTRUCTOR:
|
||||
// result is already received through UpdateAuthorizationState, nothing to do
|
||||
break;
|
||||
default:
|
||||
System.err.println("Receive wrong response from TDLib:" + newLine + object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LogMessageHandler implements Client.LogMessageHandler {
|
||||
@Override
|
||||
public void onLogMessage(int verbosityLevel, String message) {
|
||||
if (verbosityLevel == 0) {
|
||||
onFatalError(message);
|
||||
return;
|
||||
}
|
||||
System.err.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void onFatalError(String errorMessage) {
|
||||
final class ThrowError implements Runnable {
|
||||
private final String errorMessage;
|
||||
private final AtomicLong errorThrowTime;
|
||||
|
||||
private ThrowError(String errorMessage, AtomicLong errorThrowTime) {
|
||||
this.errorMessage = errorMessage;
|
||||
this.errorThrowTime = errorThrowTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (isDatabaseBrokenError(errorMessage) || isDiskFullError(errorMessage) || isDiskError(errorMessage)) {
|
||||
processExternalError();
|
||||
return;
|
||||
}
|
||||
|
||||
errorThrowTime.set(System.currentTimeMillis());
|
||||
throw new ClientError("TDLib fatal error: " + errorMessage);
|
||||
}
|
||||
|
||||
private void processExternalError() {
|
||||
errorThrowTime.set(System.currentTimeMillis());
|
||||
throw new ExternalClientError("Fatal error: " + errorMessage);
|
||||
}
|
||||
|
||||
final class ClientError extends Error {
|
||||
private ClientError(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
final class ExternalClientError extends Error {
|
||||
public ExternalClientError(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDatabaseBrokenError(String message) {
|
||||
return message.contains("Wrong key or database is corrupted") ||
|
||||
message.contains("SQL logic error or missing database") ||
|
||||
message.contains("database disk image is malformed") ||
|
||||
message.contains("file is encrypted or is not a database") ||
|
||||
message.contains("unsupported file format") ||
|
||||
message.contains("Database was corrupted and deleted during execution and can't be recreated");
|
||||
}
|
||||
|
||||
private boolean isDiskFullError(String message) {
|
||||
return message.contains("PosixError : No space left on device") ||
|
||||
message.contains("database or disk is full");
|
||||
}
|
||||
|
||||
private boolean isDiskError(String message) {
|
||||
return message.contains("I/O error") || message.contains("Structure needs cleaning");
|
||||
}
|
||||
}
|
||||
|
||||
final AtomicLong errorThrowTime = new AtomicLong(Long.MAX_VALUE);
|
||||
new Thread(new ThrowError(errorMessage, errorThrowTime), "TDLib fatal error thread").start();
|
||||
|
||||
// wait at least 10 seconds after the error is thrown
|
||||
while (errorThrowTime.get() >= System.currentTimeMillis() - 10000) {
|
||||
try {
|
||||
Thread.sleep(1000 /* milliseconds */);
|
||||
} catch (InterruptedException ignore) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
package org.drinkless.tdlib.example;
|
||||
|
||||
import org.drinkless.tdlib.JsonClient;
|
||||
|
||||
/**
|
||||
* Example class for TDLib usage from Java using JSON interface.
|
||||
*/
|
||||
public final class JsonExample {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
// set log message handler to handle only fatal errors (0) and plain log messages (-1)
|
||||
JsonClient.setLogMessageHandler(0, new LogMessageHandler());
|
||||
|
||||
// disable TDLib log and redirect fatal errors and plain log messages to a file
|
||||
JsonClient.execute("{\"@type\":\"setLogVerbosityLevel\",\"new_verbosity_level\":0}");
|
||||
JsonClient.execute("{\"@type\":\"setLogStream\",\"log_stream\":{\"@type\":\"logStreamFile\",\"path\":\"tdlib.log\",\"max_file_size\":128000000}}");
|
||||
|
||||
// create client identifier
|
||||
int clientId = JsonClient.createClientId();
|
||||
|
||||
// send first request to activate the client
|
||||
JsonClient.send(clientId, "{\"@type\":\"getOption\",\"name\":\"version\"}");
|
||||
|
||||
// main loop
|
||||
while (true) {
|
||||
String result = JsonClient.receive(100.0);
|
||||
if (result != null) {
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LogMessageHandler implements JsonClient.LogMessageHandler {
|
||||
@Override
|
||||
public void onLogMessage(int verbosityLevel, String message) {
|
||||
System.err.print(message);
|
||||
if (verbosityLevel == 0) {
|
||||
System.err.println("Receive fatal error; the process will crash now");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
241
third-party/td/td/example/java/td_jni.cpp
vendored
@ -1,241 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
#ifdef TD_JSON_JAVA
|
||||
#include <td/telegram/td_json_client.h>
|
||||
#else
|
||||
#include <td/telegram/Client.h>
|
||||
#include <td/telegram/td_api.h>
|
||||
#endif
|
||||
|
||||
#include <td/tl/tl_jni_object.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace td_jni {
|
||||
|
||||
#ifdef TD_JSON_JAVA
|
||||
static jint JsonClient_createClientId(JNIEnv *env, jclass clazz) {
|
||||
return static_cast<jint>(td_create_client_id());
|
||||
}
|
||||
|
||||
static void JsonClient_send(JNIEnv *env, jclass clazz, jint client_id, jstring request) {
|
||||
td_send(static_cast<int>(client_id), td::jni::from_jstring(env, request).c_str());
|
||||
}
|
||||
|
||||
static jstring JsonClient_receive(JNIEnv *env, jclass clazz, jdouble timeout) {
|
||||
auto result = td_receive(timeout);
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::jni::to_jstring(env, result);
|
||||
}
|
||||
|
||||
static jstring JsonClient_execute(JNIEnv *env, jclass clazz, jstring request) {
|
||||
auto result = td_execute(td::jni::from_jstring(env, request).c_str());
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::jni::to_jstring(env, result);
|
||||
}
|
||||
#else
|
||||
static td::td_api::object_ptr<td::td_api::Function> fetch_function(JNIEnv *env, jobject function) {
|
||||
td::jni::reset_parse_error();
|
||||
auto result = td::td_api::Function::fetch(env, function);
|
||||
if (td::jni::have_parse_error()) {
|
||||
std::abort();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static td::ClientManager *get_manager() {
|
||||
return td::ClientManager::get_manager_singleton();
|
||||
}
|
||||
|
||||
static jint Client_createNativeClient(JNIEnv *env, jclass clazz) {
|
||||
return static_cast<jint>(get_manager()->create_client_id());
|
||||
}
|
||||
|
||||
static void Client_nativeClientSend(JNIEnv *env, jclass clazz, jint client_id, jlong id, jobject function) {
|
||||
get_manager()->send(static_cast<std::int32_t>(client_id), static_cast<std::uint64_t>(id),
|
||||
fetch_function(env, function));
|
||||
}
|
||||
|
||||
static jint Client_nativeClientReceive(JNIEnv *env, jclass clazz, jintArray client_ids, jlongArray ids,
|
||||
jobjectArray events, jdouble timeout) {
|
||||
jsize events_size = env->GetArrayLength(ids); // client_ids, ids and events must be of equal size
|
||||
if (events_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
jsize result_size = 0;
|
||||
|
||||
auto *manager = get_manager();
|
||||
auto response = manager->receive(timeout);
|
||||
while (response.object) {
|
||||
auto client_id = static_cast<jint>(response.client_id);
|
||||
env->SetIntArrayRegion(client_ids, result_size, 1, &client_id);
|
||||
|
||||
auto request_id = static_cast<jlong>(response.request_id);
|
||||
env->SetLongArrayRegion(ids, result_size, 1, &request_id);
|
||||
|
||||
jobject object;
|
||||
response.object->store(env, object);
|
||||
env->SetObjectArrayElement(events, result_size, object);
|
||||
env->DeleteLocalRef(object);
|
||||
|
||||
result_size++;
|
||||
if (result_size == events_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
response = manager->receive(0);
|
||||
}
|
||||
return result_size;
|
||||
}
|
||||
|
||||
static jobject Client_nativeClientExecute(JNIEnv *env, jclass clazz, jobject function) {
|
||||
jobject result;
|
||||
td::ClientManager::execute(fetch_function(env, function))->store(env, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static jstring Object_toString(JNIEnv *env, jobject object) {
|
||||
return td::jni::to_jstring(env, to_string(td::td_api::Object::fetch(env, object)));
|
||||
}
|
||||
|
||||
static jstring Function_toString(JNIEnv *env, jobject object) {
|
||||
return td::jni::to_jstring(env, to_string(td::td_api::Function::fetch(env, object)));
|
||||
}
|
||||
#endif
|
||||
|
||||
static constexpr jint JAVA_VERSION = JNI_VERSION_1_6;
|
||||
static JavaVM *java_vm;
|
||||
static jobject log_message_handler;
|
||||
|
||||
static void on_log_message(int verbosity_level, const char *log_message) {
|
||||
auto env = td::jni::get_jni_env(java_vm, JAVA_VERSION);
|
||||
if (env == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
jobject handler = env->NewLocalRef(log_message_handler);
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
jclass handler_class = env->GetObjectClass(handler);
|
||||
if (handler_class) {
|
||||
jmethodID on_log_message_method = env->GetMethodID(handler_class, "onLogMessage", "(ILjava/lang/String;)V");
|
||||
if (on_log_message_method) {
|
||||
jstring log_message_str = td::jni::to_jstring(env.get(), log_message);
|
||||
if (log_message_str) {
|
||||
env->CallVoidMethod(handler, on_log_message_method, static_cast<jint>(verbosity_level), log_message_str);
|
||||
env->DeleteLocalRef((jobject)log_message_str);
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef((jobject)handler_class);
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(handler);
|
||||
}
|
||||
|
||||
static void Client_nativeClientSetLogMessageHandler(JNIEnv *env, jclass clazz, jint max_verbosity_level,
|
||||
jobject new_log_message_handler) {
|
||||
if (log_message_handler) {
|
||||
#ifdef TD_JSON_JAVA
|
||||
td_set_log_message_callback(0, nullptr);
|
||||
#else
|
||||
td::ClientManager::set_log_message_callback(0, nullptr);
|
||||
#endif
|
||||
jobject old_log_message_handler = log_message_handler;
|
||||
log_message_handler = jobject();
|
||||
env->DeleteGlobalRef(old_log_message_handler);
|
||||
}
|
||||
|
||||
if (new_log_message_handler) {
|
||||
log_message_handler = env->NewGlobalRef(new_log_message_handler);
|
||||
if (!log_message_handler) {
|
||||
// out of memory
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TD_JSON_JAVA
|
||||
td_set_log_message_callback(static_cast<int>(max_verbosity_level), on_log_message);
|
||||
#else
|
||||
td::ClientManager::set_log_message_callback(static_cast<int>(max_verbosity_level), on_log_message);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static jint register_native(JavaVM *vm) {
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JAVA_VERSION) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
java_vm = vm;
|
||||
|
||||
auto register_method = [env](jclass clazz, std::string name, std::string signature, auto function_ptr) {
|
||||
td::jni::register_native_method(env, clazz, std::move(name), std::move(signature),
|
||||
reinterpret_cast<void *>(function_ptr));
|
||||
};
|
||||
|
||||
#ifdef TD_JSON_JAVA
|
||||
auto client_class = td::jni::get_jclass(env, PACKAGE_NAME "/JsonClient");
|
||||
|
||||
register_method(client_class, "createClientId", "()I", JsonClient_createClientId);
|
||||
register_method(client_class, "send", "(ILjava/lang/String;)V", JsonClient_send);
|
||||
register_method(client_class, "receive", "(D)Ljava/lang/String;", JsonClient_receive);
|
||||
register_method(client_class, "execute", "(Ljava/lang/String;)Ljava/lang/String;", JsonClient_execute);
|
||||
register_method(client_class, "setLogMessageHandler", "(IL" PACKAGE_NAME "/JsonClient$LogMessageHandler;)V",
|
||||
Client_nativeClientSetLogMessageHandler);
|
||||
#else
|
||||
auto td_api_class = td::jni::get_jclass(env, PACKAGE_NAME "/TdApi");
|
||||
jfieldID commit_hash_field_id =
|
||||
td::jni::get_static_field_id(env, td_api_class, "GIT_COMMIT_HASH", "Ljava/lang/String;");
|
||||
std::string td_api_version = td::jni::fetch_static_string(env, td_api_class, commit_hash_field_id);
|
||||
std::string tdjni_version = td::td_api::get_git_commit_hash();
|
||||
if (tdjni_version != td_api_version) {
|
||||
td::jni::set_fatal_error(env, "Mismatched TdApi.java (" + td_api_version + ") and tdjni shared library (" +
|
||||
tdjni_version + ") versions");
|
||||
return JAVA_VERSION;
|
||||
}
|
||||
|
||||
auto client_class = td::jni::get_jclass(env, PACKAGE_NAME "/Client");
|
||||
auto object_class = td::jni::get_jclass(env, PACKAGE_NAME "/TdApi$Object");
|
||||
auto function_class = td::jni::get_jclass(env, PACKAGE_NAME "/TdApi$Function");
|
||||
|
||||
#define TD_OBJECT "L" PACKAGE_NAME "/TdApi$Object;"
|
||||
#define TD_FUNCTION "L" PACKAGE_NAME "/TdApi$Function;"
|
||||
register_method(client_class, "createNativeClient", "()I", Client_createNativeClient);
|
||||
register_method(client_class, "nativeClientSend", "(IJ" TD_FUNCTION ")V", Client_nativeClientSend);
|
||||
register_method(client_class, "nativeClientReceive", "([I[J[" TD_OBJECT "D)I", Client_nativeClientReceive);
|
||||
register_method(client_class, "nativeClientExecute", "(" TD_FUNCTION ")" TD_OBJECT, Client_nativeClientExecute);
|
||||
register_method(client_class, "nativeClientSetLogMessageHandler", "(IL" PACKAGE_NAME "/Client$LogMessageHandler;)V",
|
||||
Client_nativeClientSetLogMessageHandler);
|
||||
|
||||
register_method(object_class, "toString", "()Ljava/lang/String;", Object_toString);
|
||||
|
||||
register_method(function_class, "toString", "()Ljava/lang/String;", Function_toString);
|
||||
#undef TD_FUNCTION
|
||||
#undef TD_OBJECT
|
||||
|
||||
td::jni::init_vars(env, PACKAGE_NAME);
|
||||
td::td_api::get_package_name_ref() = PACKAGE_NAME;
|
||||
#endif
|
||||
|
||||
return JAVA_VERSION;
|
||||
}
|
||||
|
||||
} // namespace td_jni
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
static jint jni_version = td_jni::register_native(vm); // call_once
|
||||
return jni_version;
|
||||
}
|
3
third-party/td/td/example/python/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/td/
|
||||
/tdlib/
|
||||
/*.dll
|
11
third-party/td/td/example/python/README.md
vendored
@ -1,11 +0,0 @@
|
||||
# TDLib Python example
|
||||
|
||||
To run this example you need to [build](https://github.com/tdlib/td#building) TDLib and copy built tdjson shared library to this directory.
|
||||
|
||||
After this you can run the example:
|
||||
```
|
||||
python tdjson_example.py
|
||||
```
|
||||
|
||||
Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html)
|
||||
and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation.
|
145
third-party/td/td/example/python/tdjson_example.py
vendored
@ -1,145 +0,0 @@
|
||||
#
|
||||
# Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com),
|
||||
# Pellegrino Prevete (pellegrinoprevete@gmail.com) 2014-2025
|
||||
#
|
||||
# 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)
|
||||
#
|
||||
from ctypes.util import find_library
|
||||
from ctypes import *
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
# load shared library
|
||||
tdjson_path = find_library('tdjson')
|
||||
if tdjson_path is None:
|
||||
if os.name == 'nt':
|
||||
tdjson_path = os.path.join(os.path.dirname(__file__), 'tdjson.dll')
|
||||
else:
|
||||
sys.exit("Can't find 'tdjson' library")
|
||||
tdjson = CDLL(tdjson_path)
|
||||
|
||||
# load TDLib functions from shared library
|
||||
_td_create_client_id = tdjson.td_create_client_id
|
||||
_td_create_client_id.restype = c_int
|
||||
_td_create_client_id.argtypes = []
|
||||
|
||||
_td_receive = tdjson.td_receive
|
||||
_td_receive.restype = c_char_p
|
||||
_td_receive.argtypes = [c_double]
|
||||
|
||||
_td_send = tdjson.td_send
|
||||
_td_send.restype = None
|
||||
_td_send.argtypes = [c_int, c_char_p]
|
||||
|
||||
_td_execute = tdjson.td_execute
|
||||
_td_execute.restype = c_char_p
|
||||
_td_execute.argtypes = [c_char_p]
|
||||
|
||||
log_message_callback_type = CFUNCTYPE(None, c_int, c_char_p)
|
||||
|
||||
_td_set_log_message_callback = tdjson.td_set_log_message_callback
|
||||
_td_set_log_message_callback.restype = None
|
||||
_td_set_log_message_callback.argtypes = [c_int, log_message_callback_type]
|
||||
|
||||
# initialize TDLib log with desired parameters
|
||||
@log_message_callback_type
|
||||
def on_log_message_callback(verbosity_level, message):
|
||||
if verbosity_level == 0:
|
||||
sys.exit('TDLib fatal error: %r' % message)
|
||||
|
||||
def td_execute(query):
|
||||
query = json.dumps(query).encode('utf-8')
|
||||
result = _td_execute(query)
|
||||
if result:
|
||||
result = json.loads(result.decode('utf-8'))
|
||||
return result
|
||||
|
||||
_td_set_log_message_callback(2, on_log_message_callback)
|
||||
|
||||
# setting TDLib log verbosity level to 1 (errors)
|
||||
print(str(td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 1, '@extra': 1.01234})).encode('utf-8'))
|
||||
|
||||
|
||||
# create client
|
||||
client_id = _td_create_client_id()
|
||||
|
||||
# simple wrappers for client usage
|
||||
def td_send(query):
|
||||
query = json.dumps(query).encode('utf-8')
|
||||
_td_send(client_id, query)
|
||||
|
||||
def td_receive():
|
||||
result = _td_receive(1.0)
|
||||
if result:
|
||||
result = json.loads(result.decode('utf-8'))
|
||||
return result
|
||||
|
||||
# another test for TDLib execute method
|
||||
print(str(td_execute({'@type': 'getTextEntities', 'text': '@telegram /test_command https://telegram.org telegram.me', '@extra': ['5', 7.0, 'a']})).encode('utf-8'))
|
||||
|
||||
# start the client by sending a request to it
|
||||
td_send({'@type': 'getOption', 'name': 'version', '@extra': 1.01234})
|
||||
|
||||
# main events cycle
|
||||
while True:
|
||||
event = td_receive()
|
||||
if event:
|
||||
# process authorization states
|
||||
if event['@type'] == 'updateAuthorizationState':
|
||||
auth_state = event['authorization_state']
|
||||
|
||||
# if client is closed, we need to destroy it and create new client
|
||||
if auth_state['@type'] == 'authorizationStateClosed':
|
||||
break
|
||||
|
||||
# set TDLib parameters
|
||||
# you MUST obtain your own api_id and api_hash at https://my.telegram.org
|
||||
# and use them in the setTdlibParameters call
|
||||
if auth_state['@type'] == 'authorizationStateWaitTdlibParameters':
|
||||
td_send({'@type': 'setTdlibParameters',
|
||||
'database_directory': 'tdlib',
|
||||
'use_message_database': True,
|
||||
'use_secret_chats': True,
|
||||
'api_id': 94575,
|
||||
'api_hash': 'a3406de8d171bb422bb6ddf3bbd800e2',
|
||||
'system_language_code': 'en',
|
||||
'device_model': 'Desktop',
|
||||
'application_version': '1.0'})
|
||||
|
||||
# enter phone number to log in
|
||||
if auth_state['@type'] == 'authorizationStateWaitPhoneNumber':
|
||||
phone_number = input('Please enter your phone number: ')
|
||||
td_send({'@type': 'setAuthenticationPhoneNumber', 'phone_number': phone_number})
|
||||
|
||||
# enter email address to log in
|
||||
if auth_state['@type'] == 'authorizationStateWaitEmailAddress':
|
||||
email_address = input('Please enter your email address: ')
|
||||
td_send({'@type': 'setAuthenticationEmailAddress', 'email_address': email_address})
|
||||
|
||||
# wait for email authorization code
|
||||
if auth_state['@type'] == 'authorizationStateWaitEmailCode':
|
||||
code = input('Please enter the email authentication code you received: ')
|
||||
td_send({'@type': 'checkAuthenticationEmailCode',
|
||||
'code': {'@type': 'emailAddressAuthenticationCode', 'code' : code}})
|
||||
|
||||
# wait for authorization code
|
||||
if auth_state['@type'] == 'authorizationStateWaitCode':
|
||||
code = input('Please enter the authentication code you received: ')
|
||||
td_send({'@type': 'checkAuthenticationCode', 'code': code})
|
||||
|
||||
# wait for first and last name for new users
|
||||
if auth_state['@type'] == 'authorizationStateWaitRegistration':
|
||||
first_name = input('Please enter your first name: ')
|
||||
last_name = input('Please enter your last name: ')
|
||||
td_send({'@type': 'registerUser', 'first_name': first_name, 'last_name': last_name})
|
||||
|
||||
# wait for password if present
|
||||
if auth_state['@type'] == 'authorizationStateWaitPassword':
|
||||
password = input('Please enter your password: ')
|
||||
td_send({'@type': 'checkAuthenticationPassword', 'password': password})
|
||||
|
||||
# handle an incoming update or an answer to a previously sent request
|
||||
print(str(event).encode('utf-8'))
|
||||
sys.stdout.flush()
|
3
third-party/td/td/example/swift/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/xcuserdata/
|
||||
/*workspace/
|
||||
/td/
|
15
third-party/td/td/example/swift/README.md
vendored
@ -1,15 +0,0 @@
|
||||
# TDLib swift macOS example
|
||||
|
||||
TDLib should be prebuilt and installed to local subdirectory `td/`:
|
||||
```
|
||||
cd <path to TDLib sources>
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../example/swift/td ..
|
||||
cmake --build . --target install
|
||||
```
|
||||
|
||||
After this you can open and build the example with the latest Xcode.
|
||||
|
||||
Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html)
|
||||
and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation.
|
189
third-party/td/td/example/swift/src/main.swift
vendored
@ -1,189 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// TDLib Client Swift binding
|
||||
class TdClient {
|
||||
var client_id = td_create_client_id()
|
||||
let tdlibMainLoop = DispatchQueue(label: "TDLib")
|
||||
let tdlibQueryQueue = DispatchQueue(label: "TDLibQuery")
|
||||
var queryF = Dictionary<Int64, (Dictionary<String,Any>)->()>()
|
||||
var updateF: ((Dictionary<String,Any>)->())?
|
||||
var queryId: Int64 = 0
|
||||
|
||||
func queryAsync(query: [String: Any], f: ((Dictionary<String,Any>)->())? = nil) {
|
||||
tdlibQueryQueue.async {
|
||||
var newQuery = query
|
||||
|
||||
if f != nil {
|
||||
let nextQueryId = self.queryId + 1
|
||||
newQuery["@extra"] = nextQueryId
|
||||
self.queryF[nextQueryId] = f
|
||||
self.queryId = nextQueryId
|
||||
}
|
||||
td_send(self.client_id, to_json(newQuery))
|
||||
}
|
||||
}
|
||||
|
||||
func querySync(query: [String: Any]) -> Dictionary<String,Any> {
|
||||
let semaphore = DispatchSemaphore(value:0)
|
||||
var result = Dictionary<String,Any>()
|
||||
queryAsync(query: query) {
|
||||
result = $0
|
||||
semaphore.signal()
|
||||
}
|
||||
semaphore.wait()
|
||||
return result
|
||||
}
|
||||
|
||||
init() {
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
func run(updateHandler: @escaping (Dictionary<String,Any>)->()) {
|
||||
updateF = updateHandler
|
||||
tdlibMainLoop.async { [weak self] in
|
||||
while (true) {
|
||||
if let s = self {
|
||||
if let res = td_receive(10) {
|
||||
let event = String(cString: res)
|
||||
s.queryResultAsync(event)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func queryResultAsync(_ result: String) {
|
||||
tdlibQueryQueue.async {
|
||||
let json = try? JSONSerialization.jsonObject(with: result.data(using: .utf8)!, options:[])
|
||||
if let dictionary = json as? [String:Any] {
|
||||
if let extra = dictionary["@extra"] as? Int64 {
|
||||
let index = self.queryF.index(forKey: extra)!
|
||||
self.queryF[index].value(dictionary)
|
||||
self.queryF.remove(at: index)
|
||||
} else {
|
||||
self.updateF!(dictionary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func to_json(_ obj: Any) -> String {
|
||||
do {
|
||||
let obj = try JSONSerialization.data(withJSONObject: obj)
|
||||
return String(data: obj, encoding: .utf8)!
|
||||
} catch {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var client = TdClient()
|
||||
|
||||
// start the client by sending request to it
|
||||
client.queryAsync(query: ["@type":"getOption", "name":"version"])
|
||||
|
||||
func myReadLine() -> String {
|
||||
while (true) {
|
||||
if let line = readLine() {
|
||||
return line
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateAuthorizationState(authorizationState: Dictionary<String, Any>) {
|
||||
switch(authorizationState["@type"] as! String) {
|
||||
case "authorizationStateWaitTdlibParameters":
|
||||
client.queryAsync(query:[
|
||||
"@type":"setTdlibParameters",
|
||||
"database_directory":"tdlib",
|
||||
"use_message_database":true,
|
||||
"use_secret_chats":true,
|
||||
"api_id":94575,
|
||||
"api_hash":"a3406de8d171bb422bb6ddf3bbd800e2",
|
||||
"system_language_code":"en",
|
||||
"device_model":"Desktop",
|
||||
"application_version":"1.0"
|
||||
]);
|
||||
|
||||
case "authorizationStateWaitPhoneNumber":
|
||||
print("Enter your phone number: ")
|
||||
let phone_number = myReadLine()
|
||||
client.queryAsync(query:["@type":"setAuthenticationPhoneNumber", "phone_number":phone_number], f:checkAuthenticationError)
|
||||
|
||||
case "authorizationStateWaitEmailAddress":
|
||||
print("Enter your email address: ")
|
||||
let email_address = myReadLine()
|
||||
client.queryAsync(query:["@type":"setAuthenticationEmailAddress", "email_address":email_address], f:checkAuthenticationError)
|
||||
|
||||
case "authorizationStateWaitEmailCode":
|
||||
var code: String = ""
|
||||
print("Enter email code: ")
|
||||
code = myReadLine()
|
||||
client.queryAsync(query:["@type":"checkAuthenticationEmailCode", "code":["@type":"emailAddressAuthenticationCode", "code":code]], f:checkAuthenticationError)
|
||||
|
||||
case "authorizationStateWaitCode":
|
||||
var code: String = ""
|
||||
print("Enter (SMS) code: ")
|
||||
code = myReadLine()
|
||||
client.queryAsync(query:["@type":"checkAuthenticationCode", "code":code], f:checkAuthenticationError)
|
||||
|
||||
case "authorizationStateWaitRegistration":
|
||||
var first_name: String = ""
|
||||
var last_name: String = ""
|
||||
print("Enter your first name: ")
|
||||
first_name = myReadLine()
|
||||
print("Enter your last name: ")
|
||||
last_name = myReadLine()
|
||||
client.queryAsync(query:["@type":"registerUser", "first_name":first_name, "last_name":last_name], f:checkAuthenticationError)
|
||||
|
||||
case "authorizationStateWaitPassword":
|
||||
print("Enter password: ")
|
||||
let password = myReadLine()
|
||||
client.queryAsync(query:["@type":"checkAuthenticationPassword", "password":password], f:checkAuthenticationError)
|
||||
|
||||
case "authorizationStateReady":
|
||||
()
|
||||
|
||||
case "authorizationStateLoggingOut":
|
||||
print("Logging out...")
|
||||
|
||||
case "authorizationStateClosing":
|
||||
print("Closing...")
|
||||
|
||||
case "authorizationStateClosed":
|
||||
print("Closed.")
|
||||
|
||||
default:
|
||||
assert(false, "TODO: Unexpected authorization state");
|
||||
}
|
||||
}
|
||||
|
||||
func checkAuthenticationError(error: Dictionary<String, Any>) {
|
||||
if (error["@type"] as! String == "error") {
|
||||
client.queryAsync(query:["@type":"getAuthorizationState"], f:updateAuthorizationState)
|
||||
}
|
||||
}
|
||||
|
||||
client.run {
|
||||
let update = $0
|
||||
print(update)
|
||||
if update["@type"] as! String == "updateAuthorizationState" {
|
||||
updateAuthorizationState(authorizationState: update["authorization_state"] as! Dictionary<String, Any>)
|
||||
}
|
||||
}
|
||||
|
||||
while true {
|
||||
sleep(1)
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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/td_json_client.h"
|
||||
#include "td/telegram/td_log.h"
|
23
third-party/td/td/example/uwp/LICENSE_1_0.txt
vendored
@ -1,23 +0,0 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
33
third-party/td/td/example/uwp/README.md
vendored
@ -1,33 +0,0 @@
|
||||
# TDLib Universal Windows Platform example
|
||||
|
||||
This is an example of building TDLib SDK for Universal Windows Platform and an example of its usage from C#.
|
||||
|
||||
## Building SDK
|
||||
|
||||
* Download and install Microsoft Visual Studio 2017+ with Windows 10 SDK. We recommend to use the latest available versions of Microsoft Visual Studio and Windows 10 SDK.
|
||||
* Download and install [CMake](https://cmake.org/download/). CMake 3.13 or newer is required.
|
||||
* Install `zlib` and `openssl` for all UWP architectures and `gperf` for x86 using [vcpkg](https://github.com/Microsoft/vcpkg#quick-start):
|
||||
```
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
git checkout 07b30b49e5136a36100a2ce644476e60d7f3ddc1
|
||||
.\bootstrap-vcpkg.bat
|
||||
.\vcpkg.exe install gperf:x86-windows openssl:arm-uwp openssl:arm64-uwp openssl:x64-uwp openssl:x86-uwp zlib:arm-uwp zlib:arm64-uwp zlib:x64-uwp zlib:x86-uwp
|
||||
```
|
||||
* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download). Add the path to php.exe to the PATH environment variable.
|
||||
* Download and install [7-Zip](http://www.7-zip.org/download.html) archiver, which is used by the `build.ps1` script to create a Telegram.Td.UWP Visual Studio Extension. Add the path to 7z.exe to the PATH environment variable.
|
||||
Alternatively `build.ps1` supports compressing using [WinRAR](https://en.wikipedia.org/wiki/WinRAR) with option `-compress winrar` and compressing using [zip](http://gnuwin32.sourceforge.net/packages/zip.htm) with `-compress zip`.
|
||||
* Build `TDLib` using provided `build.ps1` script (TDLib should be built 6 times for multiple platforms in Debug and Release configurations, so it make take few hours). Pass path to vcpkg.exe as `-vcpkg-root` argument, for example:
|
||||
```
|
||||
powershell -ExecutionPolicy ByPass .\build.ps1 -vcpkg_root C:\vcpkg
|
||||
```
|
||||
If you need to restart the build from scratch, call `.\build.ps1 -vcpkg_root C:\vcpkg -mode clean` first.
|
||||
* Install Visual Studio Extension "TDLib for Universal Windows Platform" located at `build-uwp\vsix\tdlib.vsix`, which was created on the previous step by `build.ps1` script.
|
||||
|
||||
After this `TDLib` can be used from any UWP project, built in Visual Studio.
|
||||
|
||||
Alternatively, you can build `TDLib` as a NuGet package, adding the option `-nupkg` to the `.\build.ps1` script invocation. The resulting package will be placed in the directory `build-uwp\nupkg`.
|
||||
|
||||
## Example of usage
|
||||
|
||||
The `app/` directory contains a simple example of a C# application for Universal Windows Platform. Just open it with Visual Studio 2015 or later and run.
|
12
third-party/td/td/example/uwp/SDKManifest.xml
vendored
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<FileList
|
||||
DisplayName="TDLib for Universal Windows Platform"
|
||||
ProductFamilyName="Telegram.Td.UWP"
|
||||
MoreInfo="https://core.telegram.org/tdlib"
|
||||
MinVSVersion="14.0"
|
||||
AppliesTo="WindowsAppContainer"
|
||||
DependsOn="Microsoft.VCLibs, version=14.0"
|
||||
SupportsMultipleVersions="Error"
|
||||
SupportedArchitectures="x86;x64;ARM;ARM64">
|
||||
<File Reference="Telegram.Td.winmd" Implementation="Telegram.Td.dll" />
|
||||
</FileList>
|
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Telegram.Td.UWP</id>
|
||||
<version>1.8.46</version>
|
||||
<title>TDLib for Universal Windows Platform</title>
|
||||
<authors>Telegram</authors>
|
||||
<owners>Telegram</owners>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="file">LICENSE_1_0.txt</license>
|
||||
<projectUrl>https://core.telegram.org/tdlib</projectUrl>
|
||||
<releaseNotes>https://github.com/tdlib/td/blob/master/CHANGELOG.md</releaseNotes>
|
||||
<description>TDLib for Universal Windows Platform</description>
|
||||
<copyright>© Telegram FZ-LLC. All rights reserved.</copyright>
|
||||
<dependencies>
|
||||
<group targetFramework="UAP10.0" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
</package>
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup>
|
||||
<TelegramTdPlatform Condition="'$(Platform)' == 'Win32'">x86</TelegramTdPlatform>
|
||||
<TelegramTdPlatform Condition="'$(Platform)' != 'Win32'">$(Platform)</TelegramTdPlatform>
|
||||
<OpenSSLPlatform Condition="'$(Platform)' == 'Win32'"></OpenSSLPlatform>
|
||||
<OpenSSLPlatform Condition="'$(Platform)' != 'Win32'">-$(Platform)</OpenSSLPlatform>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'UAP'">
|
||||
<Reference Include="$(MSBuildThisFileDirectory)..\..\lib\uap10.0\Telegram.Td.winmd">
|
||||
<Implementation>Telegram.Td.dll</Implementation>
|
||||
</Reference>
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(TelegramTdPlatform)\native\Telegram.Td.dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(TelegramTdPlatform)\native\libcrypto-3$(OpenSSLPlatform).dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(TelegramTdPlatform)\native\libssl-3$(OpenSSLPlatform).dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(MSBuildThisFileDirectory)..\..\runtimes\win10-$(TelegramTdPlatform)\native\zlib1.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
||||
<Default Extension="winmd" ContentType="application/octet-stream" />
|
||||
<Default Extension="pri" ContentType="application/octet-stream" />
|
||||
<Default Extension="dll" ContentType="application/octet-stream" />
|
||||
<Default Extension="h" ContentType="application/octet-stream" />
|
||||
<Default Extension="lib" ContentType="application/octet-stream" />
|
||||
<Default Extension="pdb" ContentType="application/octet-stream" />
|
||||
<Default Extension="png" ContentType="application/octet-stream" />
|
||||
<Default Extension="props" ContentType="application/octet-stream" />
|
||||
<Default Extension="txt" ContentType="text/plain" />
|
||||
<Default Extension="vsixmanifest" ContentType="text/xml" />
|
||||
<Default Extension="xml" ContentType="text/xml" />
|
||||
</Types>
|
5
third-party/td/td/example/uwp/app/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
/.vs/
|
||||
/bin/
|
||||
/obj/
|
||||
/project.lock.json
|
||||
/TdApp.csproj.user
|
7
third-party/td/td/example/uwp/app/App.xaml
vendored
@ -1,7 +0,0 @@
|
||||
<Application
|
||||
x:Class="TdApp.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TdApp"
|
||||
RequestedTheme="Light">
|
||||
</Application>
|
104
third-party/td/td/example/uwp/app/App.xaml.cs
vendored
@ -1,104 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
using System;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace TdApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
|
||||
Microsoft.ApplicationInsights.WindowsCollectors.Metadata |
|
||||
Microsoft.ApplicationInsights.WindowsCollectors.Session);
|
||||
this.InitializeComponent();
|
||||
this.Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
|
||||
#if DEBUG
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
this.DebugSettings.EnableFrameRateCounter = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Frame rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (rootFrame == null)
|
||||
{
|
||||
// Create a Frame to act as the navigation context and navigate to the first page
|
||||
rootFrame = new Frame();
|
||||
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Place the frame in the current Window
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (rootFrame.Content == null)
|
||||
{
|
||||
// When the navigation stack isn't restored navigate to the first page,
|
||||
// configuring the new page by passing required information as a navigation
|
||||
// parameter
|
||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when Navigation to a certain page fails
|
||||
/// </summary>
|
||||
/// <param name="sender">The Frame which failed navigation</param>
|
||||
/// <param name="e">Details about the navigation failure</param>
|
||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application execution is being suspended. Application state is saved
|
||||
/// without knowing whether the application will be terminated or resumed with the contents
|
||||
/// of memory still intact.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the suspend request.</param>
|
||||
/// <param name="e">Details about the suspend request.</param>
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
//TODO: Save application state and stop any background activity
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ApplicationInsights xmlns = "http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
|
||||
</ApplicationInsights>
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.1 KiB |
29
third-party/td/td/example/uwp/app/MainPage.xaml
vendored
@ -1,29 +0,0 @@
|
||||
<Page
|
||||
x:Class="TdApp.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TdApp"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Name="Self">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="Input"/>
|
||||
<Button Grid.Column="1" x:Name="Send" Content="send" Click="Button_Click"/>
|
||||
</Grid>
|
||||
<ListBox Grid.Row="1" x:Name="ItemsControl" ItemsSource="{Binding Items, ElementName=Self}">
|
||||
|
||||
</ListBox>
|
||||
<!--<Button Content="Test" Click="Button_Click"/>-->
|
||||
</Grid>
|
||||
</Page>
|
186
third-party/td/td/example/uwp/app/MainPage.xaml.cs
vendored
@ -1,186 +0,0 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
using System;
|
||||
using System.IO;
|
||||
using Td = Telegram.Td;
|
||||
using TdApi = Telegram.Td.Api;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace TdApp
|
||||
{
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
public System.Collections.ObjectModel.ObservableCollection<string> Items { get; set; }
|
||||
|
||||
private MyClientResultHandler _handler;
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Items = new System.Collections.ObjectModel.ObservableCollection<string>();
|
||||
_handler = new MyClientResultHandler(this);
|
||||
|
||||
Td.Client.Execute(new TdApi.SetLogVerbosityLevel(0));
|
||||
Td.Client.Execute(new TdApi.SetLogStream(new TdApi.LogStreamFile(Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "log"), 1 << 27, false)));
|
||||
Td.Client.SetLogMessageCallback(100, LogMessageCallback);
|
||||
System.Threading.Tasks.Task.Run(() =>
|
||||
{
|
||||
Td.Client.Run();
|
||||
});
|
||||
|
||||
_client = Td.Client.Create(_handler);
|
||||
var request = new TdApi.SetTdlibParameters();
|
||||
request.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
|
||||
request.UseSecretChats = true;
|
||||
request.UseMessageDatabase = true;
|
||||
request.ApiId = 94575;
|
||||
request.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
|
||||
request.SystemLanguageCode = "en";
|
||||
request.DeviceModel = "Desktop";
|
||||
request.ApplicationVersion = "1.0.0";
|
||||
_client.Send(request, null);
|
||||
}
|
||||
|
||||
public void Print(String str)
|
||||
{
|
||||
var delayTask = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
Items.Insert(0, str.Substring(0, Math.Min(1024, str.Length)));
|
||||
});
|
||||
}
|
||||
|
||||
private void LogMessageCallback(int verbosity_level, String str)
|
||||
{
|
||||
if (verbosity_level < 0) {
|
||||
return;
|
||||
}
|
||||
Print(verbosity_level + ": " + str);
|
||||
}
|
||||
|
||||
private Td.Client _client;
|
||||
|
||||
private void AcceptCommand(String command)
|
||||
{
|
||||
Input.Text = string.Empty;
|
||||
Items.Insert(0, string.Format(">>{0}", command));
|
||||
}
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var command = Input.Text;
|
||||
|
||||
if (command.StartsWith("DESTROY"))
|
||||
{
|
||||
AcceptCommand("Destroy");
|
||||
_client.Send(new TdApi.Destroy(), _handler);
|
||||
}
|
||||
else if (command.StartsWith("lo"))
|
||||
{
|
||||
AcceptCommand("LogOut");
|
||||
_client.Send(new TdApi.LogOut(), _handler);
|
||||
}
|
||||
else if (command.StartsWith("sap"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.SetAuthenticationPhoneNumber(args[1], null), _handler);
|
||||
}
|
||||
else if (command.StartsWith("sae"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.SetAuthenticationEmailAddress(args[1]), _handler);
|
||||
}
|
||||
else if (command.StartsWith("caec"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.CheckAuthenticationEmailCode(new TdApi.EmailAddressAuthenticationCode(args[1])), _handler);
|
||||
}
|
||||
else if (command.StartsWith("cac"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.CheckAuthenticationCode(args[1]), _handler);
|
||||
}
|
||||
else if (command.StartsWith("cap"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.CheckAuthenticationPassword(args[1]), _handler);
|
||||
}
|
||||
else if (command.StartsWith("alm"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 3);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.AddLogMessage(Int32.Parse(args[1]), args[2]), _handler);
|
||||
}
|
||||
else if (command.StartsWith("gco"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.SearchContacts(), _handler);
|
||||
}
|
||||
else if (command.StartsWith("df"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
_client.Send(new TdApi.DownloadFile(Int32.Parse(args[1]), 1, 0, 0, false), _handler);
|
||||
}
|
||||
else if (command.StartsWith("bench"))
|
||||
{
|
||||
var args = command.Split(" ".ToCharArray(), 2);
|
||||
AcceptCommand(command);
|
||||
var cnt = Int32.Parse(args[1]);
|
||||
var handler = new BenchSimpleHandler(this, cnt);
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
_client.Send(new TdApi.TestSquareInt(123), handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyClientResultHandler : Td.ClientResultHandler
|
||||
{
|
||||
private MainPage _page;
|
||||
|
||||
public MyClientResultHandler(MainPage page)
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
public void OnResult(TdApi.BaseObject obj)
|
||||
{
|
||||
var str = obj.ToString();
|
||||
_page.Print(str);
|
||||
}
|
||||
}
|
||||
|
||||
class BenchSimpleHandler : Td.ClientResultHandler
|
||||
{
|
||||
private MainPage _page;
|
||||
private int _cnt;
|
||||
|
||||
public BenchSimpleHandler(MainPage page, int cnt)
|
||||
{
|
||||
_page = page;
|
||||
_cnt = cnt;
|
||||
}
|
||||
|
||||
public void OnResult(TdApi.BaseObject obj)
|
||||
{
|
||||
_cnt--;
|
||||
if (_cnt == 0)
|
||||
{
|
||||
_page.Print("DONE");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|