Wire local TDLib into iOS FFI build
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,4 +1,8 @@
|
|||||||
/target
|
/target
|
||||||
|
/.build
|
||||||
|
/build
|
||||||
|
/apps/ios/TeleTuiIOS/BinaryArtifacts
|
||||||
|
/apps/ios/TeleTuiIOS/Generated
|
||||||
|
|
||||||
# TDLib session data (contains auth tokens - NEVER commit!)
|
# TDLib session data (contains auth tokens - NEVER commit!)
|
||||||
/tdlib_data/
|
/tdlib_data/
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -4097,8 +4097,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "tdlib-rs"
|
name = "tdlib-rs"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c309480dcdd6d5dc2f37866d9063fed280780ddfeb51ae3a0adc2b52b0c0bc3"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs 6.0.0",
|
"dirs 6.0.0",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
|
|||||||
@@ -7,3 +7,6 @@ members = [
|
|||||||
]
|
]
|
||||||
default-members = ["crates/tele-tui"]
|
default-members = ["crates/tele-tui"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
tdlib-rs = { path = "crates/vendor/tdlib-rs" }
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
// swift-tools-version: 6.0
|
// swift-tools-version: 6.0
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
|
let useLocalFfi = ProcessInfo.processInfo.environment["TELE_IOS_USE_LOCAL_FFI"] == "1"
|
||||||
|
let localFfiTargets: [Target] = useLocalFfi ? [
|
||||||
|
.binaryTarget(
|
||||||
|
name: "tele_ios_ffiFFI",
|
||||||
|
path: "BinaryArtifacts/tele_ios_ffi.xcframework"
|
||||||
|
),
|
||||||
|
.binaryTarget(
|
||||||
|
name: "tdjson",
|
||||||
|
path: "BinaryArtifacts/tdjson.xcframework"
|
||||||
|
),
|
||||||
|
.target(
|
||||||
|
name: "tele_ios_ffi",
|
||||||
|
dependencies: ["tele_ios_ffiFFI", "tdjson"],
|
||||||
|
path: "Generated/tele_ios_ffi/Sources/tele_ios_ffi"
|
||||||
|
),
|
||||||
|
] : []
|
||||||
|
|
||||||
|
let coreDependencies: [Target.Dependency] = useLocalFfi ? [
|
||||||
|
"tele_ios_ffi",
|
||||||
|
] : []
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "TeleTuiIOS",
|
name: "TeleTuiIOS",
|
||||||
platforms: [
|
platforms: [
|
||||||
@@ -14,7 +36,10 @@ let package = Package(
|
|||||||
.executable(name: "TeleTuiIOSSmokeTests", targets: ["TeleTuiIOSSmokeTests"]),
|
.executable(name: "TeleTuiIOSSmokeTests", targets: ["TeleTuiIOSSmokeTests"]),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(name: "TeleTuiIOSCore"),
|
.target(
|
||||||
|
name: "TeleTuiIOSCore",
|
||||||
|
dependencies: coreDependencies
|
||||||
|
),
|
||||||
.executableTarget(
|
.executableTarget(
|
||||||
name: "TeleTuiIOSApp",
|
name: "TeleTuiIOSApp",
|
||||||
dependencies: ["TeleTuiIOSCore"]
|
dependencies: ["TeleTuiIOSCore"]
|
||||||
@@ -23,5 +48,5 @@ let package = Package(
|
|||||||
name: "TeleTuiIOSSmokeTests",
|
name: "TeleTuiIOSSmokeTests",
|
||||||
dependencies: ["TeleTuiIOSCore"]
|
dependencies: ["TeleTuiIOSCore"]
|
||||||
),
|
),
|
||||||
]
|
] + localFfiTargets
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,3 +38,10 @@ Run the simulator launch plus screenshot sanity check:
|
|||||||
```bash
|
```bash
|
||||||
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/smoke-ios-simulator-ui.sh
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/smoke-ios-simulator-ui.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Build the app against the local real Rust/TDLib FFI artifacts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/build-ios-real-ffi-xcframework.sh
|
||||||
|
TELE_IOS_USE_LOCAL_FFI=1 DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/build-ios-simulator-app.sh
|
||||||
|
```
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ public enum SessionBridgeFactory {
|
|||||||
account: Account,
|
account: Account,
|
||||||
useFakeTdlib: Bool = true
|
useFakeTdlib: Bool = true
|
||||||
) -> SessionBridge {
|
) -> SessionBridge {
|
||||||
#if canImport(tele_ios_ffiFFI)
|
#if canImport(tele_ios_ffi) || canImport(tele_ios_ffiFFI)
|
||||||
do {
|
do {
|
||||||
return try UniFfiSessionBridge(account: account, useFakeTdlib: useFakeTdlib)
|
return try UniFfiSessionBridge(account: account, useFakeTdlib: useFakeTdlib)
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
#if canImport(tele_ios_ffiFFI)
|
#if canImport(tele_ios_ffi)
|
||||||
|
import tele_ios_ffi
|
||||||
|
#elseif canImport(tele_ios_ffiFFI)
|
||||||
import tele_ios_ffiFFI
|
import tele_ios_ffiFFI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if canImport(tele_ios_ffi) || canImport(tele_ios_ffiFFI)
|
||||||
public actor UniFfiSessionBridge: SessionBridge {
|
public actor UniFfiSessionBridge: SessionBridge {
|
||||||
private let handle: SessionHandle
|
private let handle: SessionHandle
|
||||||
private let defaultLimit: Int32
|
private let defaultLimit: Int32
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ keywords = ["telegram", "tdlib"]
|
|||||||
categories = ["api-bindings"]
|
categories = ["api-bindings"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = ["tdlib-download"]
|
||||||
images = []
|
images = []
|
||||||
test-support = []
|
test-support = []
|
||||||
|
tdlib-download = ["tdlib-rs/download-tdlib"]
|
||||||
|
tdlib-local = ["tdlib-rs/local-tdlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tdlib-rs = { version = "1.2.0", features = ["download-tdlib"] }
|
tdlib-rs = { version = "1.2.0", default-features = false }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|||||||
@@ -11,15 +11,17 @@ repository = "https://github.com/your-username/tele-tui"
|
|||||||
crate-type = ["cdylib", "staticlib", "rlib"]
|
crate-type = ["cdylib", "staticlib", "rlib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["core-session"]
|
default = ["core-session-download"]
|
||||||
core-session = ["dep:tele-core"]
|
core-session = ["dep:tele-core"]
|
||||||
|
core-session-download = ["core-session", "tele-core/tdlib-download"]
|
||||||
|
core-session-local-tdlib = ["core-session", "tele-core/tdlib-local"]
|
||||||
standalone-fake = []
|
standalone-fake = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tele-core = { path = "../tele-core", features = ["test-support"], optional = true }
|
tele-core = { path = "../tele-core", default-features = false, features = ["test-support"], optional = true }
|
||||||
tokio = { version = "1", features = ["rt-multi-thread"] }
|
tokio = { version = "1", features = ["rt-multi-thread"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
uniffi = { version = "0.31.1", features = ["tokio"] }
|
uniffi = { version = "0.31.1", features = ["tokio"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tele-core = { path = "../tele-core", features = ["test-support"] }
|
tele-core = { path = "../tele-core", default-features = false, features = ["test-support", "tdlib-download"] }
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Current scope:
|
|||||||
|
|
||||||
- Exposes a fake-backed `SessionHandle` for Swift integration tests and app shell work.
|
- Exposes a fake-backed `SessionHandle` for Swift integration tests and app shell work.
|
||||||
- Mirrors the `tele-core::session` DTO/event model with UniFFI-compatible records and enums.
|
- Mirrors the `tele-core::session` DTO/event model with UniFFI-compatible records and enums.
|
||||||
- Keeps real TDLib session creation out of this crate until iOS simulator/device linking is validated.
|
- Supports a fake-only build for UI work and a real TDLib build path using local iOS TDLib artifacts.
|
||||||
|
|
||||||
Generate Swift bindings and headers:
|
Generate Swift bindings and headers:
|
||||||
|
|
||||||
@@ -40,5 +40,7 @@ Current linking status:
|
|||||||
|
|
||||||
- Xcode is installed at `/Applications/Xcode.app`, and `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -version` reports Xcode 26.5.
|
- Xcode is installed at `/Applications/Xcode.app`, and `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -version` reports Xcode 26.5.
|
||||||
- The iOS 26.5 simulator runtime is installed and `scripts/check-ios-prereqs.sh` passes with available iPhone/iPad simulators.
|
- The iOS 26.5 simulator runtime is installed and `scripts/check-ios-prereqs.sh` passes with available iPhone/iPad simulators.
|
||||||
- The current app shell uses the fake Swift bridge. Real TDLib iOS simulator/device linking is still pending until TDLib is built for `iphonesimulator` and `iphoneos` and wired into the UniFFI target.
|
- The current app shell uses the fake Swift bridge.
|
||||||
- Run `scripts/check-ios-tdlib-linking.sh` to reproduce the current TDLib iOS blocker documented in `docs/ios/tdlib-linking.md`.
|
- `tdlib-rs` does not publish iOS `download-tdlib` archives, so real iOS linking uses `tele-core/tdlib-local` and `LOCAL_TDLIB_PATH`.
|
||||||
|
- Local TDLib linking is validated for `aarch64-apple-ios-sim` via `scripts/check-ios-tdlib-linking.sh` and for `aarch64-apple-ios` via `IOS_RUST_TARGET=aarch64-apple-ios scripts/build-ios-ffi-with-local-tdlib.sh`.
|
||||||
|
- `scripts/build-ios-real-ffi-xcframework.sh` packages local simulator Rust slices plus local `libtdjson` into app-local XCFrameworks, generates Swift bindings, and enables Xcode builds with `TELE_IOS_USE_LOCAL_FFI=1`.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ images = ["dep:ratatui-image", "dep:image", "tele-core/images"]
|
|||||||
test-support = ["tele-core/test-support"]
|
test-support = ["tele-core/test-support"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tele-core = { path = "../tele-core" }
|
tele-core = { path = "../tele-core", default-features = false, features = ["tdlib-download"] }
|
||||||
ratatui = "0.29"
|
ratatui = "0.29"
|
||||||
crossterm = "0.28"
|
crossterm = "0.28"
|
||||||
tdlib-rs = { version = "1.2.0", features = ["download-tdlib"] }
|
tdlib-rs = { version = "1.2.0", features = ["download-tdlib"] }
|
||||||
|
|||||||
1
crates/vendor/tdlib-rs/.cargo-ok
vendored
Normal file
1
crates/vendor/tdlib-rs/.cargo-ok
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"v":1}
|
||||||
6
crates/vendor/tdlib-rs/.cargo_vcs_info.json
vendored
Normal file
6
crates/vendor/tdlib-rs/.cargo_vcs_info.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"git": {
|
||||||
|
"sha1": "b60e42456ddbcdcef994f9ffd07c92f1e94dc543"
|
||||||
|
},
|
||||||
|
"path_in_vcs": "tdlib-rs"
|
||||||
|
}
|
||||||
2407
crates/vendor/tdlib-rs/Cargo.lock
generated
vendored
Normal file
2407
crates/vendor/tdlib-rs/Cargo.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
133
crates/vendor/tdlib-rs/Cargo.toml
vendored
Normal file
133
crates/vendor/tdlib-rs/Cargo.toml
vendored
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g., crates.io) dependencies.
|
||||||
|
#
|
||||||
|
# If you are reading this file be aware that the original Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable).
|
||||||
|
# See Cargo.toml.orig for the original contents.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
name = "tdlib-rs"
|
||||||
|
version = "1.2.0"
|
||||||
|
authors = [
|
||||||
|
"Federico Bruzzone <federico.bruzzone.i@gmail.com>",
|
||||||
|
"Andrea Longoni",
|
||||||
|
]
|
||||||
|
build = "build.rs"
|
||||||
|
autolib = false
|
||||||
|
autobins = false
|
||||||
|
autoexamples = false
|
||||||
|
autotests = false
|
||||||
|
autobenches = false
|
||||||
|
description = "Rust wrapper around the Telegram Database Library."
|
||||||
|
homepage = "https://github.com/FedericoBruzzone/tdlib-rs"
|
||||||
|
documentation = "https://docs.rs/tdlib-rs"
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = [
|
||||||
|
"telegram",
|
||||||
|
"tdlib",
|
||||||
|
"tdjson",
|
||||||
|
"tdlib-rs",
|
||||||
|
"telegram-api",
|
||||||
|
]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/FedericoBruzzone/tdlib-rs"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = [
|
||||||
|
"docs",
|
||||||
|
"bots-only-api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata.system-deps]
|
||||||
|
tdjson = "1.8.29"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
bots-only-api = []
|
||||||
|
default = []
|
||||||
|
docs = []
|
||||||
|
download-tdlib = [
|
||||||
|
"dep:reqwest",
|
||||||
|
"dep:zip",
|
||||||
|
]
|
||||||
|
local-tdlib = []
|
||||||
|
pkg-config = ["dep:system-deps"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "tdlib_rs"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "get_me"
|
||||||
|
path = "examples/get_me.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "test_ci"
|
||||||
|
path = "examples/test_ci.rs"
|
||||||
|
|
||||||
|
[dependencies.dirs]
|
||||||
|
version = "6.0.0"
|
||||||
|
|
||||||
|
[dependencies.futures-channel]
|
||||||
|
version = "0.3"
|
||||||
|
|
||||||
|
[dependencies.log]
|
||||||
|
version = "0.4"
|
||||||
|
|
||||||
|
[dependencies.once_cell]
|
||||||
|
version = "1.18"
|
||||||
|
|
||||||
|
[dependencies.reqwest]
|
||||||
|
version = "0.12.4"
|
||||||
|
features = ["blocking"]
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["derive"]
|
||||||
|
|
||||||
|
[dependencies.serde_json]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.serde_with]
|
||||||
|
version = "3.2"
|
||||||
|
|
||||||
|
[dependencies.system-deps]
|
||||||
|
version = "7"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[dependencies.zip]
|
||||||
|
version = "2.0.0"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[dev-dependencies.tokio]
|
||||||
|
version = "1"
|
||||||
|
features = [
|
||||||
|
"macros",
|
||||||
|
"rt-multi-thread",
|
||||||
|
"sync",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-dependencies.reqwest]
|
||||||
|
version = "0.12.4"
|
||||||
|
features = ["blocking"]
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[build-dependencies.system-deps]
|
||||||
|
version = "7"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[build-dependencies.tdlib-rs-gen]
|
||||||
|
version = "1.2.0"
|
||||||
|
|
||||||
|
[build-dependencies.tdlib-rs-parser]
|
||||||
|
version = "1.2.0"
|
||||||
|
|
||||||
|
[build-dependencies.zip]
|
||||||
|
version = "2.0.0"
|
||||||
|
optional = true
|
||||||
57
crates/vendor/tdlib-rs/Cargo.toml.orig
generated
vendored
Normal file
57
crates/vendor/tdlib-rs/Cargo.toml.orig
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
[package]
|
||||||
|
name = "tdlib-rs"
|
||||||
|
version = "1.2.0"
|
||||||
|
authors = [
|
||||||
|
"Federico Bruzzone <federico.bruzzone.i@gmail.com>",
|
||||||
|
"Andrea Longoni",
|
||||||
|
]
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
homepage = "https://github.com/FedericoBruzzone/tdlib-rs"
|
||||||
|
repository = "https://github.com/FedericoBruzzone/tdlib-rs"
|
||||||
|
documentation = "https://docs.rs/tdlib-rs"
|
||||||
|
keywords = ["telegram", "tdlib", "tdjson", "tdlib-rs", "telegram-api"]
|
||||||
|
description = "Rust wrapper around the Telegram Database Library."
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["docs", "bots-only-api"]
|
||||||
|
|
||||||
|
[package.metadata.system-deps]
|
||||||
|
tdjson = "1.8.29"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# The default feature build the library using the local tdlib library
|
||||||
|
default = []
|
||||||
|
# This feature is used to enable the functions only available to the Telegram bots
|
||||||
|
bots-only-api = []
|
||||||
|
# This feature is used to build the documentation preventing linking to the tdjson library
|
||||||
|
docs = []
|
||||||
|
# This feature is used to build the library using the tdlib library installed in the system
|
||||||
|
local-tdlib = []
|
||||||
|
# This feature is used to build the library using pkg-config
|
||||||
|
pkg-config = ["dep:system-deps"]
|
||||||
|
# This feature is used to build the library using the tdlib library downloaded from github
|
||||||
|
download-tdlib = ["dep:reqwest", "dep:zip"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4"
|
||||||
|
futures-channel = "0.3"
|
||||||
|
once_cell = "1.18"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde_with = "3.2"
|
||||||
|
system-deps = { version = "7", optional = true }
|
||||||
|
reqwest = { version = "0.12.4", features = ["blocking"], optional = true }
|
||||||
|
zip = { version = "2.0.0", optional = true }
|
||||||
|
dirs = "6.0.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tdlib-rs-gen = { path = "../tdlib-rs-gen", version = "1.2.0" }
|
||||||
|
tdlib-rs-parser = { path = "../tdlib-rs-parser", version = "1.2.0" }
|
||||||
|
system-deps = { version = "7", optional = true }
|
||||||
|
reqwest = { version = "0.12.4", features = ["blocking"], optional = true }
|
||||||
|
zip = { version = "2.0.0", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time"] }
|
||||||
158
crates/vendor/tdlib-rs/README.md
vendored
Normal file
158
crates/vendor/tdlib-rs/README.md
vendored
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
[github-license-mit]: https://github.com/FedericoBruzzone/tdlib-rs/blob/main/LICENSE-MIT
|
||||||
|
[github-license-apache]: https://github.com/FedericoBruzzone/tdlib-rs/blob/main/LICENSE-APACHE
|
||||||
|
|
||||||
|
# tdlib-rs
|
||||||
|
|
||||||
|
[](https://crates.io/crates/tdlib_rs)
|
||||||
|
[](https://docs.rs/tdlib-rs/latest/tdlib_rs/)
|
||||||
|
[](https://github.com/FedericoBruzzone/tdlib-rs/actions/workflows/ci-linux.yml)
|
||||||
|
[](https://github.com/FedericoBruzzone/tdlib-rs/actions/workflows/ci-windows.yml)
|
||||||
|
[](https://github.com/FedericoBruzzone/tdlib-rs/actions/workflows/ci-macos.yml)
|
||||||
|
[](https://crates.io/crates/tdlib_rs)
|
||||||
|

|
||||||
|
|
||||||
|
A Rust wrapper around the Telegram Database library. It includes a generator to automatically generate the types and functions from the TDLib's [Type Language](https://core.telegram.org/mtproto/TL) file.
|
||||||
|
|
||||||
|
## Why this fork?
|
||||||
|
|
||||||
|
This is an improved version of the [tdlib-rs](https://github.com/paper-plane-developers/tdlib-rs) library, with the following additional features:
|
||||||
|
|
||||||
|
1. It is cross-platform, it works on Windows, Linux and MacOS.
|
||||||
|
2. Not required `tdlib` to be compiled and installed on the system.
|
||||||
|
3. Not required `pkg-config` to build the library and associated exported variables.
|
||||||
|
4. Three different ways to build the library:
|
||||||
|
- `download-tdlib`: download the precompiled library from the GitHub releases.
|
||||||
|
- `local-tdlib`: use the `tdlib` installed on the system.
|
||||||
|
- `pkg-config`: use the `pkg-config` to build the library.
|
||||||
|
5. It is possible to download the `tdlib` library from the GitHub releases.
|
||||||
|
|
||||||
|
## Information
|
||||||
|
|
||||||
|
We provide a precompiled version of the library for the supported platforms:
|
||||||
|
|
||||||
|
- Linux (x86_64)
|
||||||
|
- Linux (arm64)
|
||||||
|
- macOS Intel (x86_64)
|
||||||
|
- macOS Apple Silicon (arm64)
|
||||||
|
- Windows (x86_64)
|
||||||
|
- Windows (arm64)
|
||||||
|
|
||||||
|
We compile it in the CI and we upload the artifacts to the GitHub releases, so we can download it and use to build this library.
|
||||||
|
|
||||||
|
It's mainly created for using it in the [tgt](https://github.com/FedericoBruzzone/tgt) client, but it should work also for any other Rust project.
|
||||||
|
|
||||||
|
Current supported TDLib version: [1.8.29](https://github.com/tdlib/td/commit/af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6).
|
||||||
|
|
||||||
|
## Cargo features
|
||||||
|
|
||||||
|
Please see the documentation of the module `build` for more information about the features [here](https://docs.rs/tdlib-rs/latest/tdlib_rs/build/index.html).
|
||||||
|
It functions that you can use to build the library in different ways.
|
||||||
|
|
||||||
|
### download-tdlib
|
||||||
|
|
||||||
|
If you don't want to compile and intall the `tdlib` on your system manually, you should enable the `download-tdlib` feature in the `Cargo.toml` file:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
tdlib = { version = "...", features = [ "download-tdlib" ] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tdlib = { version = "...", features = [ "download-tdlib" ] }
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// build.rs
|
||||||
|
fn main() {
|
||||||
|
tdlib_rs::build::build(None);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### local-tdlib
|
||||||
|
|
||||||
|
`local-tdlib` require you to have the `tdlib` (version 1.8.29) compiled and installed on your system, and the following variables exported, for example in the `.bashrc` file:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# The path to the tdlib folder
|
||||||
|
export LOCAL_TDLIB_PATH=$HOME/lib/tdlib
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can enable the `local-tdlib` feature in the `Cargo.toml` file:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
tdlib = { version = "...", features = [ "local-tdlib" ] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tdlib = { version = "...", features = [ "local-tdlib" ] }
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// build.rs
|
||||||
|
fn main() {
|
||||||
|
tdlib_rs::build::build(None);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### pkg-config
|
||||||
|
|
||||||
|
If you want to use the `pkg-config` to build this library, you should enable the `pkg-config` feature in the `Cargo.toml` file:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
tdlib = { version = "...", features = [ "pkg-config" ] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tdlib = { version = "...", features = [ "pkg-config" ] }
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// build.rs
|
||||||
|
fn main() {
|
||||||
|
tdlib_rs::build::build(None);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
remember to have the `tdlib` (version 1.8.29) compiled on your system, and the following variables exported, for example in the `.bashrc` file:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# pkg-config configuration
|
||||||
|
export PKG_CONFIG_PATH=$HOME/lib/tdlib/lib/pkgconfig/:$PKG_CONFIG_PATH
|
||||||
|
|
||||||
|
# dynmic linker configuration
|
||||||
|
export LD_LIBRARY_PATH=$HOME/lib/tdlib/lib/:$LD_LIBRARY_PATH
|
||||||
|
```
|
||||||
|
|
||||||
|
### docs
|
||||||
|
|
||||||
|
This feature skip the linking of the library and only generate the code of `generated.rs`.
|
||||||
|
Is used only for testing.
|
||||||
|
|
||||||
|
### bots-only-api
|
||||||
|
|
||||||
|
This feature enable the generation of the functions only used by Telegram bots.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This repository are licensed under either of
|
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE][github-license-apache] or <http://www.apache.org/licenses/LICENSE-2.0>)
|
||||||
|
- MIT license ([LICENSE-MIT][github-license-mit] or <http://opensource.org/licenses/MIT>)
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
Please review the license file provided in the repository for more information regarding the terms and conditions of the license.
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
If you have any questions, suggestions, or feedback, do not hesitate to [contact me](https://federicobruzzone.github.io/).
|
||||||
|
|
||||||
|
Mantainers:
|
||||||
|
|
||||||
|
- [FedericoBruzzone](https://github.com/FedericoBruzzone)
|
||||||
|
- [Andreal2000](https://github.com/Andreal2000)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- [grammers](https://github.com/Lonami/grammers): the `tdlib-tl-gen` and `tdlib-tl-parser` projects are forks of the `grammers-tl-gen` and `grammers-tl-parser` projects.
|
||||||
|
- [rust-tdlib](https://github.com/aCLr/rust-tdlib): for inspiration about some client code.
|
||||||
|
- [tdlib-rs](https://github.com/paper-plane-developers/tdlib-rs): for inspiration about the generator code.
|
||||||
270
crates/vendor/tdlib-rs/build.rs
vendored
Normal file
270
crates/vendor/tdlib-rs/build.rs
vendored
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
// Copyright 2020 - developers of the `grammers` project.
|
||||||
|
// Copyright 2021 - developers of the `tdlib-rs` project.
|
||||||
|
// Copyright 2024 - developers of the `tgt` and `tdlib-rs` projects.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Read, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
use tdlib_rs_gen::generate_rust_code;
|
||||||
|
use tdlib_rs_parser::parse_tl_file;
|
||||||
|
use tdlib_rs_parser::tl::Definition;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[cfg(not(any(feature = "docs", feature = "pkg-config")))]
|
||||||
|
/// The version of the TDLib library.
|
||||||
|
const TDLIB_VERSION: &str = "1.8.29";
|
||||||
|
|
||||||
|
/// Load the type language definitions from a certain file.
|
||||||
|
/// Parse errors will be printed to `stderr`, and only the
|
||||||
|
/// valid results will be returned.
|
||||||
|
fn load_tl(file: &str) -> std::io::Result<Vec<Definition>> {
|
||||||
|
let mut file = File::open(file)?;
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)?;
|
||||||
|
Ok(parse_tl_file(contents)
|
||||||
|
.filter_map(|d| match d {
|
||||||
|
Ok(d) => Some(d),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("TL: parse error: {e:?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "local-tdlib")]
|
||||||
|
/// Copy all files from a directory to another.
|
||||||
|
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
|
||||||
|
std::fs::create_dir_all(&dst)?;
|
||||||
|
for entry in std::fs::read_dir(src)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let ty = entry.file_type()?;
|
||||||
|
if ty.is_dir() {
|
||||||
|
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||||
|
} else {
|
||||||
|
std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "local-tdlib")]
|
||||||
|
/// Copy all the tdlib folder find in the LOCAL_TDLIB_PATH environment variable to the OUT_DIR/tdlib folder
|
||||||
|
fn copy_local_tdlib() {
|
||||||
|
match env::var("LOCAL_TDLIB_PATH") {
|
||||||
|
Ok(tdlib_path) => {
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
let prefix = format!("{out_dir}/tdlib");
|
||||||
|
copy_dir_all(Path::new(&tdlib_path), Path::new(&prefix)).unwrap();
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
panic!("The LOCAL_TDLIB_PATH env variable must be set to the path of the tdlib folder");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "download-tdlib", feature = "local-tdlib"))]
|
||||||
|
/// Build the project using the generic build configuration.
|
||||||
|
/// The current supported platforms are:
|
||||||
|
/// - Linux x86_64
|
||||||
|
/// - Linux aarch64
|
||||||
|
/// - Windows x86_64
|
||||||
|
/// - Windows aarch64
|
||||||
|
/// - MacOS x86_64
|
||||||
|
/// - MacOS aarch64
|
||||||
|
fn generic_build() {
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
let prefix = format!("{out_dir}/tdlib");
|
||||||
|
let include_dir = format!("{prefix}/include");
|
||||||
|
let lib_dir = format!("{prefix}/lib");
|
||||||
|
let lib_path = {
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "linux", target_arch = "x86_64"),
|
||||||
|
all(target_os = "linux", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
format!("{lib_dir}/libtdjson.so.{TDLIB_VERSION}")
|
||||||
|
}
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "macos", target_arch = "x86_64"),
|
||||||
|
all(target_os = "macos", target_arch = "aarch64"),
|
||||||
|
all(target_os = "ios", target_arch = "x86_64"),
|
||||||
|
all(target_os = "ios", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
format!("{lib_dir}/libtdjson.{TDLIB_VERSION}.dylib")
|
||||||
|
}
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "windows", target_arch = "x86_64"),
|
||||||
|
all(target_os = "windows", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
format!(r"{lib_dir}\tdjson.lib")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !std::path::PathBuf::from(lib_path.clone()).exists() {
|
||||||
|
panic!("tdjson shared library not found at {lib_path}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "windows", target_arch = "x86_64"),
|
||||||
|
all(target_os = "windows", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
let bin_dir = format!(r"{prefix}\bin");
|
||||||
|
println!("cargo:rustc-link-search=native={bin_dir}");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-search=native={lib_dir}");
|
||||||
|
println!("cargo:include={include_dir}");
|
||||||
|
println!("cargo:rustc-link-lib=dylib=tdjson");
|
||||||
|
println!("cargo:rustc-link-arg=-Wl,-rpath,{lib_dir}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "download-tdlib")]
|
||||||
|
fn download_tdlib() {
|
||||||
|
let base_url = "https://github.com/FedericoBruzzone/tdlib-rs/releases/download";
|
||||||
|
let url = format!(
|
||||||
|
"{}/v{}/tdlib-{}-{}-{}.zip",
|
||||||
|
base_url,
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
TDLIB_VERSION,
|
||||||
|
std::env::var("CARGO_CFG_TARGET_OS").unwrap(),
|
||||||
|
std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
|
||||||
|
);
|
||||||
|
// let target_os = if cfg!(target_os = "windows") {
|
||||||
|
// "Windows"
|
||||||
|
// } else if cfg!(target_os = "linux") {
|
||||||
|
// "Linux"
|
||||||
|
// } else if cfg!(target_os = "macos") {
|
||||||
|
// "macOS"
|
||||||
|
// } else {
|
||||||
|
// ""
|
||||||
|
// };
|
||||||
|
// let target_arch = if cfg!(target_arch = "x86_64") {
|
||||||
|
// "X64"
|
||||||
|
// } else if cfg!(target_arch = "aarch64") {
|
||||||
|
// "ARM64"
|
||||||
|
// } else {
|
||||||
|
// ""
|
||||||
|
// };
|
||||||
|
// let url = format!(
|
||||||
|
// "{}/test/{}-{}-TDLib-{}.zip",
|
||||||
|
// base_url, target_os, target_arch, "2589c3fd46925f5d57e4ec79233cd1bd0f5d0c09"
|
||||||
|
// );
|
||||||
|
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
let tdlib_dir = format!("{}/tdlib", &out_dir);
|
||||||
|
let zip_path = format!("{}.zip", &tdlib_dir);
|
||||||
|
|
||||||
|
// Create the request
|
||||||
|
let response = reqwest::blocking::get(&url).unwrap();
|
||||||
|
|
||||||
|
// Check if the response status is successful
|
||||||
|
if response.status().is_success() {
|
||||||
|
// Create a file to write to
|
||||||
|
let mut dest = File::create(&zip_path).unwrap();
|
||||||
|
|
||||||
|
// Get the response bytes and write to the file
|
||||||
|
let content = response.bytes().unwrap();
|
||||||
|
std::io::copy(&mut content.as_ref(), &mut dest).unwrap();
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"[{}] Failed to download file: {}\n{}\n{}",
|
||||||
|
"Your OS or architecture may be unsupported.",
|
||||||
|
"Please try using the `pkg-config` or `local-tdlib` features.",
|
||||||
|
response.status(),
|
||||||
|
&url
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut archive = zip::ZipArchive::new(File::open(&zip_path).unwrap()).unwrap();
|
||||||
|
|
||||||
|
for i in 0..archive.len() {
|
||||||
|
let mut file = archive.by_index(i).unwrap();
|
||||||
|
let outpath = Path::new(&out_dir).join(file.name());
|
||||||
|
|
||||||
|
if (*file.name()).ends_with('/') {
|
||||||
|
std::fs::create_dir_all(&outpath).unwrap();
|
||||||
|
} else {
|
||||||
|
if let Some(p) = outpath.parent() {
|
||||||
|
if !p.exists() {
|
||||||
|
std::fs::create_dir_all(p).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut outfile = File::create(&outpath).unwrap();
|
||||||
|
std::io::copy(&mut file, &mut outfile).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and set permissions
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
if let Some(mode) = file.unix_mode() {
|
||||||
|
std::fs::set_permissions(&outpath, std::fs::Permissions::from_mode(mode)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = std::fs::remove_file(&zip_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
#[cfg(all(feature = "docs", feature = "pkg-config"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"docs\" and feature \"pkg-config\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
#[cfg(all(feature = "docs", feature = "download-tdlib"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"docs\" and feature \"download-tdlib\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
#[cfg(all(feature = "pkg-config", feature = "download-tdlib"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"pkg-config\" and feature \"download-tdlib\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
#[cfg(feature = "local-tdlib")]
|
||||||
|
println!("cargo:rerun-if-env-changed=LOCAL_TDLIB_PATH");
|
||||||
|
|
||||||
|
// Prevent linking libraries to avoid documentation failure
|
||||||
|
#[cfg(not(feature = "docs"))]
|
||||||
|
{
|
||||||
|
// It requires the following variables to be set:
|
||||||
|
// - export PKG_CONFIG_PATH=$HOME/lib/tdlib/lib/pkgconfig/:$PKG_CONFIG_PATH
|
||||||
|
// - export LD_LIBRARY_PATH=$HOME/lib/tdlib/lib/:$LD_LIBRARY_PATH
|
||||||
|
#[cfg(feature = "pkg-config")]
|
||||||
|
system_deps::Config::new().probe().unwrap();
|
||||||
|
|
||||||
|
#[cfg(feature = "download-tdlib")]
|
||||||
|
download_tdlib();
|
||||||
|
|
||||||
|
// It requires the following variable to be set:
|
||||||
|
// - export LOCAL_TDLIB_PATH=$HOME/lib/tdlib
|
||||||
|
#[cfg(feature = "local-tdlib")]
|
||||||
|
copy_local_tdlib();
|
||||||
|
|
||||||
|
#[cfg(any(feature = "download-tdlib", feature = "local-tdlib"))]
|
||||||
|
generic_build();
|
||||||
|
}
|
||||||
|
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
let definitions = load_tl("tl/api.tl")?;
|
||||||
|
|
||||||
|
let mut file = BufWriter::new(File::create(Path::new(&out_dir).join("generated.rs"))?);
|
||||||
|
|
||||||
|
generate_rust_code(&mut file, &definitions, cfg!(feature = "bots-only-api"))?;
|
||||||
|
|
||||||
|
file.flush()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
193
crates/vendor/tdlib-rs/examples/get_me.rs
vendored
Normal file
193
crates/vendor/tdlib-rs/examples/get_me.rs
vendored
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
// cargo run -p tdlib-rs --example get_me --features default
|
||||||
|
// cargo run -p tdlib-rs --example get_me --features download-tdlib
|
||||||
|
// cargo run -p tdlib-rs --example get_me --features pkg-config
|
||||||
|
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
use tdlib_rs::{
|
||||||
|
enums::{self, AuthorizationState, Update, User},
|
||||||
|
functions,
|
||||||
|
};
|
||||||
|
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||||
|
|
||||||
|
fn ask_user(string: &str) -> String {
|
||||||
|
println!("{string}");
|
||||||
|
let mut input = String::new();
|
||||||
|
std::io::stdin().read_line(&mut input).unwrap();
|
||||||
|
input.trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_update(update: Update, auth_tx: &Sender<AuthorizationState>) {
|
||||||
|
if let Update::AuthorizationState(update) = update {
|
||||||
|
auth_tx.send(update.authorization_state).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_authorization_state(
|
||||||
|
client_id: i32,
|
||||||
|
mut auth_rx: Receiver<AuthorizationState>,
|
||||||
|
run_flag: Arc<AtomicBool>,
|
||||||
|
) -> Receiver<AuthorizationState> {
|
||||||
|
while let Some(state) = auth_rx.recv().await {
|
||||||
|
match state {
|
||||||
|
AuthorizationState::WaitTdlibParameters => {
|
||||||
|
let response = functions::set_tdlib_parameters(
|
||||||
|
false,
|
||||||
|
"get_me_db".into(),
|
||||||
|
String::new(),
|
||||||
|
String::new(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
env!("API_ID").parse().unwrap(),
|
||||||
|
env!("API_HASH").into(),
|
||||||
|
"en".into(),
|
||||||
|
"Desktop".into(),
|
||||||
|
String::new(),
|
||||||
|
env!("CARGO_PKG_VERSION").into(),
|
||||||
|
client_id,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(error) = response {
|
||||||
|
println!("{}", error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthorizationState::WaitPhoneNumber => loop {
|
||||||
|
let input = ask_user("Enter your phone number (include the country calling code):");
|
||||||
|
let response =
|
||||||
|
functions::set_authentication_phone_number(input, None, client_id).await;
|
||||||
|
match response {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) => println!("{}", e.message),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AuthorizationState::WaitOtherDeviceConfirmation(x) => {
|
||||||
|
println!(
|
||||||
|
"Please confirm this login link on another device: {}",
|
||||||
|
x.link
|
||||||
|
);
|
||||||
|
}
|
||||||
|
AuthorizationState::WaitEmailAddress(_x) => {
|
||||||
|
let email_address = ask_user("Please enter email address: ");
|
||||||
|
let response =
|
||||||
|
functions::set_authentication_email_address(email_address, client_id).await;
|
||||||
|
match response {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) => println!("{}", e.message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthorizationState::WaitEmailCode(_x) => {
|
||||||
|
let code = ask_user("Please enter email authentication code: ");
|
||||||
|
let response = functions::check_authentication_email_code(
|
||||||
|
enums::EmailAddressAuthentication::Code(
|
||||||
|
tdlib_rs::types::EmailAddressAuthenticationCode { code },
|
||||||
|
),
|
||||||
|
client_id,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
match response {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) => println!("{}", e.message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthorizationState::WaitCode(_) => loop {
|
||||||
|
let input = ask_user("Enter the verification code:");
|
||||||
|
let response = functions::check_authentication_code(input, client_id).await;
|
||||||
|
match response {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) => println!("{}", e.message),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AuthorizationState::WaitRegistration(_x) => {
|
||||||
|
// x useless but contains the TOS if we want to show it
|
||||||
|
let first_name = ask_user("Please enter your first name: ");
|
||||||
|
let last_name = ask_user("Please enter your last name: ");
|
||||||
|
functions::register_user(first_name, last_name, false, client_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
AuthorizationState::WaitPassword(_x) => {
|
||||||
|
let password = ask_user("Please enter password: ");
|
||||||
|
functions::check_authentication_password(password, client_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
AuthorizationState::Ready => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
AuthorizationState::Closed => {
|
||||||
|
// Set the flag to false to stop receiving updates from the
|
||||||
|
// spawned task
|
||||||
|
run_flag.store(false, Ordering::Release);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auth_rx
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
// Create the client object
|
||||||
|
let client_id = tdlib_rs::create_client();
|
||||||
|
|
||||||
|
// Create a mpsc channel for handling AuthorizationState updates separately
|
||||||
|
// from the task
|
||||||
|
let (auth_tx, auth_rx) = mpsc::channel(5);
|
||||||
|
|
||||||
|
// Create a flag to make it possible to stop receiving updates
|
||||||
|
let run_flag = Arc::new(AtomicBool::new(true));
|
||||||
|
let run_flag_clone = run_flag.clone();
|
||||||
|
|
||||||
|
// Spawn a task to receive updates/responses
|
||||||
|
let handle = tokio::spawn(async move {
|
||||||
|
while run_flag_clone.load(Ordering::Acquire) {
|
||||||
|
let result = tokio::task::spawn_blocking(tdlib_rs::receive)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some((update, _client_id)) = result {
|
||||||
|
handle_update(update, &auth_tx).await;
|
||||||
|
} else {
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// tokio::spawn(async move {
|
||||||
|
// while run_flag_clone.load(Ordering::Acquire) {
|
||||||
|
// if let Some((update, _client_id)) = tdlib_rs::receive() {
|
||||||
|
// handle_update(update, &auth_tx).await;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Set a fairly low verbosity level. We mainly do this because tdlib
|
||||||
|
// requires to perform a random request with the client to start receiving
|
||||||
|
// updates for it.
|
||||||
|
functions::set_log_verbosity_level(2, client_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Handle the authorization state to authenticate the client
|
||||||
|
let auth_rx = handle_authorization_state(client_id, auth_rx, run_flag.clone()).await;
|
||||||
|
|
||||||
|
// Run the get_me() method to get user information
|
||||||
|
let User::User(me) = functions::get_me(client_id).await.unwrap();
|
||||||
|
println!("Hi, I'm {}", me.first_name);
|
||||||
|
|
||||||
|
// Tell the client to close
|
||||||
|
functions::close(client_id).await.unwrap();
|
||||||
|
|
||||||
|
// Handle the authorization state to wait for the "Closed" state
|
||||||
|
handle_authorization_state(client_id, auth_rx, run_flag.clone()).await;
|
||||||
|
|
||||||
|
// Wait for the previously spawned task to end the execution
|
||||||
|
handle.await.unwrap();
|
||||||
|
}
|
||||||
12
crates/vendor/tdlib-rs/examples/test_ci.rs
vendored
Normal file
12
crates/vendor/tdlib-rs/examples/test_ci.rs
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// cargo run -p tdlib-rs --example test_ci --features default
|
||||||
|
// cargo run -p tdlib-rs --example test_ci --features download-tdlib
|
||||||
|
// cargo run -p tdlib-rs --example test_ci --features pkg-config
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
// Create the client object for testing
|
||||||
|
let _client_id = tdlib_rs::create_client();
|
||||||
|
|
||||||
|
// Exit 0
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
493
crates/vendor/tdlib-rs/src/build.rs
vendored
Normal file
493
crates/vendor/tdlib-rs/src/build.rs
vendored
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
//! The build module is used to build the project using the enabled features.
|
||||||
|
//! The features are correctly set when exactly one of the following features is enabled:
|
||||||
|
//! - `local-tdlib`
|
||||||
|
//! - `pkg-config`
|
||||||
|
//! - `download-tdlib`
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[cfg(not(any(feature = "docs", feature = "pkg-config")))]
|
||||||
|
const TDLIB_VERSION: &str = "1.8.29";
|
||||||
|
#[cfg(feature = "download-tdlib")]
|
||||||
|
const TDLIB_CARGO_PKG_VERSION: &str = "1.2.0";
|
||||||
|
|
||||||
|
// WARNING: This function is not used in the current version of the library.
|
||||||
|
// #[cfg(not(any(feature = "docs", feature = "pkg-config", feature = "download-tdlib")))]
|
||||||
|
// fn copy_local_tdlib() {
|
||||||
|
// match std::env::var("LOCAL_TDLIB_PATH") {
|
||||||
|
// Ok(tdlib_path) => {
|
||||||
|
// let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
// let prefix = format!("{}/tdlib", out_dir);
|
||||||
|
// copy_dir_all(std::path::Path::new(&tdlib_path), std::path::Path::new(&prefix)).unwrap();
|
||||||
|
// }
|
||||||
|
// Err(_) => {
|
||||||
|
// panic!("The LOCAL_TDLIB_PATH env variable must be set to the path of the tdlib folder");
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[cfg(feature = "download-tdlib")]
|
||||||
|
/// Copy all files from a directory to another.
|
||||||
|
/// It assumes that the source directory exists.
|
||||||
|
/// If the destination directory does not exist, it will be created.
|
||||||
|
fn copy_dir_all(
|
||||||
|
src: impl AsRef<std::path::Path>,
|
||||||
|
dst: impl AsRef<std::path::Path>,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
std::fs::create_dir_all(&dst)?;
|
||||||
|
for entry in std::fs::read_dir(src)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let ty = entry.file_type()?;
|
||||||
|
if ty.is_dir() {
|
||||||
|
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||||
|
} else {
|
||||||
|
std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "download-tdlib")]
|
||||||
|
/// Download the tdlib library from the GitHub release page.
|
||||||
|
/// The function will download the tdlib library from the GitHub release page, and extract the
|
||||||
|
/// files in the OUT_DIR/tdlib folder.
|
||||||
|
/// The OUT_DIR environment variable is set by Cargo and points to the target directory.
|
||||||
|
/// The OS and architecture currently supported are:
|
||||||
|
/// - Linux x86_64
|
||||||
|
/// - Linux aarch64
|
||||||
|
/// - Windows x86_64
|
||||||
|
/// - Windows aarch64
|
||||||
|
/// - MacOS x86_64
|
||||||
|
/// - MacOS aarch64
|
||||||
|
///
|
||||||
|
/// If the OS or architecture is not supported, the function will panic.
|
||||||
|
fn download_tdlib() {
|
||||||
|
let base_url = "https://github.com/FedericoBruzzone/tdlib-rs/releases/download";
|
||||||
|
let url = format!(
|
||||||
|
"{}/v{}/tdlib-{}-{}-{}.zip",
|
||||||
|
base_url,
|
||||||
|
TDLIB_CARGO_PKG_VERSION,
|
||||||
|
TDLIB_VERSION,
|
||||||
|
std::env::var("CARGO_CFG_TARGET_OS").unwrap(),
|
||||||
|
std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
let tdlib_dir = format!("{}/tdlib", &out_dir);
|
||||||
|
let zip_path = format!("{}.zip", &tdlib_dir);
|
||||||
|
|
||||||
|
// Create the request
|
||||||
|
let response = reqwest::blocking::get(&url).unwrap();
|
||||||
|
|
||||||
|
// Check if the response status is successful
|
||||||
|
if response.status().is_success() {
|
||||||
|
// Create a file to write to
|
||||||
|
let mut dest = std::fs::File::create(&zip_path).unwrap();
|
||||||
|
|
||||||
|
// Get the response bytes and write to the file
|
||||||
|
let content = response.bytes().unwrap();
|
||||||
|
std::io::copy(&mut content.as_ref(), &mut dest).unwrap();
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"[{}] Failed to download file: {}\n{}\n{}",
|
||||||
|
"Your OS or architecture may be unsupported.",
|
||||||
|
"Please try using the `pkg-config` or `local-tdlib` features.",
|
||||||
|
response.status(),
|
||||||
|
&url
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut archive = zip::ZipArchive::new(std::fs::File::open(&zip_path).unwrap()).unwrap();
|
||||||
|
|
||||||
|
for i in 0..archive.len() {
|
||||||
|
let mut file = archive.by_index(i).unwrap();
|
||||||
|
let outpath = std::path::Path::new(&out_dir).join(file.name());
|
||||||
|
|
||||||
|
if (*file.name()).ends_with('/') {
|
||||||
|
std::fs::create_dir_all(&outpath).unwrap();
|
||||||
|
} else {
|
||||||
|
if let Some(p) = outpath.parent() {
|
||||||
|
if !p.exists() {
|
||||||
|
std::fs::create_dir_all(p).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut outfile = std::fs::File::create(&outpath).unwrap();
|
||||||
|
std::io::copy(&mut file, &mut outfile).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and set permissions
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
if let Some(mode) = file.unix_mode() {
|
||||||
|
std::fs::set_permissions(&outpath, std::fs::Permissions::from_mode(mode)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = std::fs::remove_file(&zip_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "download-tdlib", feature = "local-tdlib"))]
|
||||||
|
/// Build the project using the `download-tdlib` or `local-tdlib` feature.
|
||||||
|
/// # Arguments
|
||||||
|
/// - `lib_path`: The path where the tdlib library is located. If `None`, the path will be the `OUT_DIR` environment variable.
|
||||||
|
///
|
||||||
|
/// The function will pass to the `rustc` the following flags:
|
||||||
|
/// - `cargo:rustc-link-search=native=.../tdlib/lib`
|
||||||
|
/// - `cargo:include=.../tdlib/include`
|
||||||
|
/// - `cargo:rustc-link-lib=dylib=tdjson`
|
||||||
|
/// - `cargo:rustc-link-arg=-Wl,-rpath,.../tdlib/lib`
|
||||||
|
/// - `cargo:rustc-link-search=native=.../tdlib/bin` (only for Windows)
|
||||||
|
///
|
||||||
|
/// The `...` represents the `dest_path` or the `OUT_DIR` environment variable.
|
||||||
|
///
|
||||||
|
/// If the tdlib library is not found at the specified path, the function will panic.
|
||||||
|
///
|
||||||
|
/// The function will panic if the tdlib library is not found at the specified path.
|
||||||
|
fn generic_build(lib_path: Option<String>) {
|
||||||
|
let correct_lib_path: String;
|
||||||
|
match lib_path {
|
||||||
|
Some(lib_path) => {
|
||||||
|
if lib_path.ends_with('/') || lib_path.ends_with('\\') {
|
||||||
|
correct_lib_path = lib_path[..lib_path.len() - 1].to_string();
|
||||||
|
} else {
|
||||||
|
correct_lib_path = lib_path.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
correct_lib_path = format!("{}/tdlib", std::env::var("OUT_DIR").unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let prefix = correct_lib_path.to_string();
|
||||||
|
let include_dir = format!("{prefix}/include");
|
||||||
|
let lib_dir = format!("{prefix}/lib");
|
||||||
|
let mut_lib_path = {
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "linux", target_arch = "x86_64"),
|
||||||
|
all(target_os = "linux", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
format!("{lib_dir}/libtdjson.so.{TDLIB_VERSION}")
|
||||||
|
}
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "macos", target_arch = "x86_64"),
|
||||||
|
all(target_os = "macos", target_arch = "aarch64"),
|
||||||
|
all(target_os = "ios", target_arch = "x86_64"),
|
||||||
|
all(target_os = "ios", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
format!("{lib_dir}/libtdjson.{TDLIB_VERSION}.dylib")
|
||||||
|
}
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "windows", target_arch = "x86_64"),
|
||||||
|
all(target_os = "windows", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
format!(r"{lib_dir}\tdjson.lib")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !std::path::PathBuf::from(mut_lib_path.clone()).exists() {
|
||||||
|
panic!("tdjson shared library not found at {mut_lib_path}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should be not necessary, but it is a workaround because windows does not find the
|
||||||
|
// tdjson.dll using the commands below.
|
||||||
|
// TODO: investigate and if it is a bug in `cargo` or `rustc`, open an issue to `cargo` to fix
|
||||||
|
// this.
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "windows", target_arch = "x86_64"),
|
||||||
|
all(target_os = "windows", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
let bin_dir = format!(r"{prefix}\bin");
|
||||||
|
let cargo_bin = format!("{}/.cargo/bin", dirs::home_dir().unwrap().to_str().unwrap());
|
||||||
|
|
||||||
|
let libcrypto3x64 = format!(r"{bin_dir}\libcrypto-3-x64.dll");
|
||||||
|
let libssl3x64 = format!(r"{bin_dir}\libssl-3-x64.dll");
|
||||||
|
let tdjson = format!(r"{bin_dir}\tdjson.dll");
|
||||||
|
let zlib1 = format!(r"{bin_dir}\zlib1.dll");
|
||||||
|
|
||||||
|
let cargo_libcrypto3x64 = format!(r"{cargo_bin}\libcrypto-3-x64.dll");
|
||||||
|
let cargo_libssl3x64 = format!(r"{cargo_bin}\libssl-3-x64.dll");
|
||||||
|
let cargo_tdjson = format!(r"{cargo_bin}\tdjson.dll");
|
||||||
|
let cargo_zlib1 = format!(r"{cargo_bin}\zlib1.dll");
|
||||||
|
|
||||||
|
// Delete the files if they exist
|
||||||
|
let _ = std::fs::remove_file(&cargo_libcrypto3x64);
|
||||||
|
let _ = std::fs::remove_file(&cargo_libssl3x64);
|
||||||
|
let _ = std::fs::remove_file(&cargo_tdjson);
|
||||||
|
let _ = std::fs::remove_file(&cargo_zlib1);
|
||||||
|
|
||||||
|
// Move all files to cargo_bin
|
||||||
|
let _ = std::fs::copy(libcrypto3x64.clone(), cargo_libcrypto3x64.clone());
|
||||||
|
let _ = std::fs::copy(libssl3x64.clone(), cargo_libssl3x64.clone());
|
||||||
|
let _ = std::fs::copy(tdjson.clone(), cargo_tdjson.clone());
|
||||||
|
let _ = std::fs::copy(zlib1.clone(), cargo_zlib1.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
all(target_os = "windows", target_arch = "x86_64"),
|
||||||
|
all(target_os = "windows", target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
let bin_dir = format!(r"{prefix}\bin");
|
||||||
|
println!("cargo:rustc-link-search=native={bin_dir}");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-search=native={lib_dir}");
|
||||||
|
println!("cargo:include={include_dir}");
|
||||||
|
println!("cargo:rustc-link-lib=dylib=tdjson");
|
||||||
|
println!("cargo:rustc-link-arg=-Wl,-rpath,{lib_dir}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the features are correctly set.
|
||||||
|
/// The features are correctly set when exactly one of the following features is enabled:
|
||||||
|
/// - `local-tdlib`
|
||||||
|
/// - `pkg-config`
|
||||||
|
/// - `download-tdlib`
|
||||||
|
/// - `docs` (only for tdlib documentation)
|
||||||
|
///
|
||||||
|
/// The following features cannot be enabled at the same time:
|
||||||
|
/// - `docs` and `pkg-config`
|
||||||
|
/// - `docs` and `download-tdlib`
|
||||||
|
/// - `docs` and `local-tdlib`
|
||||||
|
/// - `pkg-config` and `local-tdlib`
|
||||||
|
/// - `pkg-config` and `download-tdlib`
|
||||||
|
/// - `local-tdlib` and `download-tdlib`
|
||||||
|
///
|
||||||
|
/// If the features are not correctly set, the function will generate a compile error
|
||||||
|
pub fn check_features() {
|
||||||
|
// #[cfg(not(any(feature = "docs", feature = "local-tdlib", feature = "pkg-config", feature = "download-tdlib")))]
|
||||||
|
// println!("cargo:warning=No features enabled, you must enable at least one of the following features: docs, local-tdlib, pkg-config, download-tdlib");
|
||||||
|
// compile_error!("You must enable at least one of the following features: docs, local-tdlib, pkg-config, download-tdlib");
|
||||||
|
|
||||||
|
#[cfg(all(feature = "docs", feature = "pkg-config"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"docs\" and feature \"pkg-config\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
#[cfg(all(feature = "docs", feature = "download-tdlib"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"docs\" and feature \"download-tdlib\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
#[cfg(all(feature = "docs", feature = "local-tdlib"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"docs\" and feature \"local-tdlib\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(all(feature = "pkg-config", feature = "local-tdlib"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"pkg-config\" and feature \"local-tdlib\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
#[cfg(all(feature = "pkg-config", feature = "download-tdlib"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"pkg-config\" and feature \"download-tdlib\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
#[cfg(all(feature = "local-tdlib", feature = "download-tdlib"))]
|
||||||
|
compile_error!(
|
||||||
|
"feature \"local-tdlib\" and feature \"download-tdlib\" cannot be enabled at the same time"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the `rerun-if-changed` and `rerun-if-env-changed` flags for the build script.
|
||||||
|
/// The `rerun-if-changed` flag is set for the `build.rs` file.
|
||||||
|
/// The `rerun-if-env-changed` flag is set for the `LOCAL_TDLIB_PATH` environment variable.
|
||||||
|
pub fn set_rerun_if() {
|
||||||
|
#[cfg(feature = "local-tdlib")]
|
||||||
|
println!("cargo:rerun-if-env-changed=LOCAL_TDLIB_PATH");
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "pkg-config", feature = "docs"))]
|
||||||
|
#[allow(clippy::needless_doctest_main)]
|
||||||
|
/// Build the project using the `pkg-config` feature.
|
||||||
|
/// Using the `pkg-config` feature, the function will probe the system dependencies.
|
||||||
|
/// It means that the function assumes that the tdlib library is compiled in the system.
|
||||||
|
/// It requires the following variables to be set:
|
||||||
|
/// - `PKG_CONFIG_PATH=$HOME/lib/tdlib/lib/pkgconfig/:$PKG_CONFIG_PATH`
|
||||||
|
/// - `LD_LIBRARY_PATH=$HOME/lib/tdlib/lib/:$LD_LIBRARY_PATH`
|
||||||
|
///
|
||||||
|
/// If the variables are not set, the function will panic.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Cargo.toml:
|
||||||
|
/// ```toml
|
||||||
|
/// [dependencies]
|
||||||
|
/// tdlib = { version = "...", features = ["pkg-config"] }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// build.rs:
|
||||||
|
/// ```rust
|
||||||
|
/// fn main() {
|
||||||
|
/// tdlib_rs::build::check_features();
|
||||||
|
/// tdlib_rs::build::set_rerun_if();
|
||||||
|
/// tdlib_rs::build::build_pkg_config();
|
||||||
|
/// // Other build configurations
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn build_pkg_config() {
|
||||||
|
#[cfg(not(feature = "docs"))]
|
||||||
|
{
|
||||||
|
system_deps::Config::new().probe().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "download-tdlib", feature = "docs"))]
|
||||||
|
#[allow(clippy::needless_doctest_main)]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
/// Build the project using the `download-tdlib` feature.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// - `dest_path`: The destination path where the tdlib library will be copied. If `None`, the path will be the `OUT_DIR` environment variable.
|
||||||
|
///
|
||||||
|
/// Note that this function will pass to the `rustc` the following flags:
|
||||||
|
/// - `cargo:rustc-link-search=native=.../tdlib/lib`
|
||||||
|
/// - `cargo:include=.../tdlib/include`
|
||||||
|
/// - `cargo:rustc-link-lib=dylib=tdjson`
|
||||||
|
/// - `cargo:rustc-link-arg=-Wl,-rpath,.../tdlib/lib`
|
||||||
|
/// - `cargo:rustc-link-search=native=.../tdlib/bin` (only for Windows)
|
||||||
|
///
|
||||||
|
/// The `...` represents the `dest_path` or the `OUT_DIR` environment variable.
|
||||||
|
///
|
||||||
|
/// The function will download the tdlib library from the GitHub release page.
|
||||||
|
/// Using the `download-tdlib` feature, no system dependencies are required.
|
||||||
|
/// The OS and architecture currently supported are:
|
||||||
|
/// - Linux x86_64
|
||||||
|
/// - Linux aarch64
|
||||||
|
/// - Windows x86_64
|
||||||
|
/// - Windows aarch64
|
||||||
|
/// - MacOS x86_64
|
||||||
|
/// - MacOS aarch64
|
||||||
|
///
|
||||||
|
/// If the OS or architecture is not supported, the function will panic.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Cargo.toml:
|
||||||
|
/// ```toml
|
||||||
|
/// [dependencies]
|
||||||
|
/// tdlib = { version = "...", features = ["download-tdlib"] }
|
||||||
|
///
|
||||||
|
/// [build-dependencies]
|
||||||
|
/// tdlib = { version = "...", features = [ "download-tdlib" ] }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// build.rs:
|
||||||
|
/// ```rust
|
||||||
|
/// fn main() {
|
||||||
|
/// tdlib_rs::build::check_features();
|
||||||
|
/// tdlib_rs::build::set_rerun_if();
|
||||||
|
/// tdlib_rs::build::build_download_tdlib(None);
|
||||||
|
/// // Other build configurations
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn build_download_tdlib(dest_path: Option<String>) {
|
||||||
|
#[cfg(not(feature = "docs"))]
|
||||||
|
{
|
||||||
|
download_tdlib();
|
||||||
|
if let Some(dest_path) = &dest_path {
|
||||||
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
let tdlib_dir = format!("{}/tdlib", &out_dir);
|
||||||
|
copy_dir_all(
|
||||||
|
std::path::Path::new(&tdlib_dir),
|
||||||
|
std::path::Path::new(&dest_path),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
generic_build(dest_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "local-tdlib", feature = "docs"))]
|
||||||
|
#[allow(clippy::needless_doctest_main)]
|
||||||
|
/// Build the project using the `local-tdlib` feature.
|
||||||
|
/// Using the `local-tdlib` feature, the function will copy the tdlib library from the
|
||||||
|
/// `LOCAL_TDLIB_PATH` environment variable.
|
||||||
|
/// The tdlib folder must contain the `lib` and `include` folders.
|
||||||
|
/// You can directly download the tdlib library from the [TDLib Release GitHub page](https://github.com/FedericoBruzzone/tdlib-rs/releases).
|
||||||
|
///
|
||||||
|
/// The `LOCAL_TDLIB_PATH` environment variable must be set to the path of the tdlib folder.
|
||||||
|
///
|
||||||
|
/// The function will pass to the `rustc` the following flags:
|
||||||
|
/// - `cargo:rustc-link-search=native=.../tdlib/lib`
|
||||||
|
/// - `cargo:include=.../tdlib/include`
|
||||||
|
/// - `cargo:rustc-link-lib=dylib=tdjson`
|
||||||
|
/// - `cargo:rustc-link-arg=-Wl,-rpath,.../tdlib/lib`
|
||||||
|
/// - `cargo:rustc-link-search=native=.../tdlib/bin` (only for Windows)
|
||||||
|
///
|
||||||
|
/// The `...` represents the `LOCAL_TDLIB_PATH` environment variable.
|
||||||
|
///
|
||||||
|
/// If the `LOCAL_TDLIB_PATH` environment variable is not set, the function will panic.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Cargo.toml:
|
||||||
|
/// ```toml
|
||||||
|
/// [dependencies]
|
||||||
|
/// tdlib = { version = "...", features = ["local-tdlib"] }
|
||||||
|
///
|
||||||
|
/// [build-dependencies]
|
||||||
|
/// tdlib = { version = "...", features = [ "download-tdlib" ] }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// build.rs:
|
||||||
|
/// ```rust
|
||||||
|
/// fn main() {
|
||||||
|
/// tdlib_rs::build::check_features();
|
||||||
|
/// tdlib_rs::build::set_rerun_if();
|
||||||
|
/// tdlib_rs::build::build_local_tdlib();
|
||||||
|
/// // Other build configurations
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn build_local_tdlib() {
|
||||||
|
#[cfg(not(feature = "docs"))]
|
||||||
|
{
|
||||||
|
// copy_local_tdlib();
|
||||||
|
let path = std::env::var("LOCAL_TDLIB_PATH").unwrap();
|
||||||
|
generic_build(Some(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_doctest_main)]
|
||||||
|
/// Build the project using the enabled features.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// - `dest_path`: The destination path where the tdlib library will be copied. If `None`, the path
|
||||||
|
/// will be the `OUT_DIR` environment variable. This argument is used only when the
|
||||||
|
/// `download-tdlib` feature is enabled.
|
||||||
|
///
|
||||||
|
/// The function will check if the features are correctly set.
|
||||||
|
/// The function will set the `rerun-if-changed` and `rerun-if-env-changed` flags for the build
|
||||||
|
/// script.
|
||||||
|
/// The function will build the project using the enabled feature.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Cargo.toml:
|
||||||
|
/// ```toml
|
||||||
|
/// [dependencies]
|
||||||
|
/// tdlib = { version = "...", features = ["download-tdlib"] }
|
||||||
|
///
|
||||||
|
/// [build-dependencies]
|
||||||
|
/// tdlib = { version = "...", features = [ "download-tdlib" ] }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// build.rs:
|
||||||
|
/// ```rust
|
||||||
|
/// fn main() {
|
||||||
|
/// tdlib_rs::build::build(None);
|
||||||
|
/// // Other build configurations
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn build(_dest_path: Option<String>) {
|
||||||
|
check_features();
|
||||||
|
set_rerun_if();
|
||||||
|
|
||||||
|
#[cfg(feature = "pkg-config")]
|
||||||
|
build_pkg_config();
|
||||||
|
#[cfg(feature = "download-tdlib")]
|
||||||
|
build_download_tdlib(_dest_path);
|
||||||
|
#[cfg(feature = "local-tdlib")]
|
||||||
|
build_local_tdlib();
|
||||||
|
}
|
||||||
10
crates/vendor/tdlib-rs/src/generated.rs
vendored
Normal file
10
crates/vendor/tdlib-rs/src/generated.rs
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2020 - developers of the `grammers` project.
|
||||||
|
// Copyright 2021 - developers of the `tdlib-rs` project.
|
||||||
|
// Copyright 2024 - developers of the `tgt` and `tdlib-rs` projects.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
||||||
69
crates/vendor/tdlib-rs/src/lib.rs
vendored
Normal file
69
crates/vendor/tdlib-rs/src/lib.rs
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2020 - developers of the `grammers` project.
|
||||||
|
// Copyright 2021 - developers of the `tdlib-rs` project.
|
||||||
|
// Copyright 2024 - developers of the `tgt` and `tdlib-rs` projects.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
pub mod build;
|
||||||
|
mod generated;
|
||||||
|
mod observer;
|
||||||
|
mod tdjson;
|
||||||
|
|
||||||
|
pub use generated::{enums, functions, types};
|
||||||
|
|
||||||
|
use enums::Update;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
|
static EXTRA_COUNTER: AtomicU32 = AtomicU32::new(0);
|
||||||
|
static OBSERVER: Lazy<observer::Observer> = Lazy::new(observer::Observer::new);
|
||||||
|
|
||||||
|
/// Create a TdLib client returning its id. Note that to start receiving
|
||||||
|
/// updates for a client you need to send at least a request with it first.
|
||||||
|
pub fn create_client() -> i32 {
|
||||||
|
tdjson::create_client()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Receive a single update or response from TdLib. If it's an update, it
|
||||||
|
/// returns a tuple with the `Update` and the associated `client_id`.
|
||||||
|
/// Note that to start receiving updates for a client you need to send
|
||||||
|
/// at least a request with it first.
|
||||||
|
pub fn receive() -> Option<(Update, i32)> {
|
||||||
|
let response = tdjson::receive(2.0);
|
||||||
|
if let Some(response_str) = response {
|
||||||
|
let response: Value = serde_json::from_str(&response_str).unwrap();
|
||||||
|
|
||||||
|
match response.get("@extra") {
|
||||||
|
Some(_) => {
|
||||||
|
OBSERVER.notify(response);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let client_id = response["@client_id"].as_i64().unwrap() as i32;
|
||||||
|
match serde_json::from_value(response) {
|
||||||
|
Ok(update) => {
|
||||||
|
return Some((update, client_id));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Received an unknown response: {response_str}\nReason: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn send_request(client_id: i32, mut request: Value) -> Value {
|
||||||
|
let extra = EXTRA_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
|
request["@extra"] = serde_json::to_value(extra).unwrap();
|
||||||
|
|
||||||
|
let receiver = OBSERVER.subscribe(extra);
|
||||||
|
tdjson::send(client_id, request.to_string());
|
||||||
|
|
||||||
|
receiver.await.unwrap()
|
||||||
|
}
|
||||||
45
crates/vendor/tdlib-rs/src/observer.rs
vendored
Normal file
45
crates/vendor/tdlib-rs/src/observer.rs
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2020 - developers of the `grammers` project.
|
||||||
|
// Copyright 2021 - developers of the `tdlib-rs` project.
|
||||||
|
// Copyright 2024 - developers of the `tgt` project.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
use futures_channel::oneshot;
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
pub(super) struct Observer {
|
||||||
|
requests: RwLock<HashMap<u32, oneshot::Sender<Value>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Observer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Observer {
|
||||||
|
requests: RwLock::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscribe(&self, extra: u32) -> oneshot::Receiver<Value> {
|
||||||
|
let (sender, receiver) = oneshot::channel();
|
||||||
|
self.requests.write().unwrap().insert(extra, sender);
|
||||||
|
receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notify(&self, response: Value) {
|
||||||
|
let extra = response["@extra"].as_u64().unwrap() as u32;
|
||||||
|
match self.requests.write().unwrap().remove(&extra) {
|
||||||
|
Some(sender) => {
|
||||||
|
if sender.send(response).is_err() {
|
||||||
|
log::warn!("Got a response of an unaccessible request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
log::warn!("Got a response of an unknown request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
crates/vendor/tdlib-rs/src/tdjson.rs
vendored
Normal file
35
crates/vendor/tdlib-rs/src/tdjson.rs
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2020 - developers of the `grammers` project.
|
||||||
|
// Copyright 2021 - developers of the `tdlib-rs` project.
|
||||||
|
// Copyright 2024 - developers of the `tgt` project.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::os::raw::{c_char, c_double, c_int};
|
||||||
|
|
||||||
|
#[link(name = "tdjson")]
|
||||||
|
extern "C" {
|
||||||
|
fn td_create_client_id() -> c_int;
|
||||||
|
fn td_send(client_id: c_int, request: *const c_char);
|
||||||
|
fn td_receive(timeout: c_double) -> *const c_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn create_client() -> i32 {
|
||||||
|
unsafe { td_create_client_id() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn send(client_id: i32, request: String) {
|
||||||
|
let cstring = CString::new(request).unwrap();
|
||||||
|
unsafe { td_send(client_id, cstring.as_ptr()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn receive(timeout: f64) -> Option<String> {
|
||||||
|
unsafe {
|
||||||
|
td_receive(timeout)
|
||||||
|
.as_ref()
|
||||||
|
.map(|response| CStr::from_ptr(response).to_string_lossy().into_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
10841
crates/vendor/tdlib-rs/tl/api.tl
vendored
Normal file
10841
crates/vendor/tdlib-rs/tl/api.tl
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9177
crates/vendor/tdlib-rs/tl/api_1.8.19.tl
vendored
Normal file
9177
crates/vendor/tdlib-rs/tl/api_1.8.19.tl
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ Local toolchain status:
|
|||||||
- `scripts/check-ios-prereqs.sh` passes.
|
- `scripts/check-ios-prereqs.sh` passes.
|
||||||
- `scripts/run-ios-simulator-app.sh` launches the fake-backed SwiftUI shell in iOS Simulator.
|
- `scripts/run-ios-simulator-app.sh` launches the fake-backed SwiftUI shell in iOS Simulator.
|
||||||
|
|
||||||
Current real TDLib blocker:
|
Previous real TDLib blocker:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer cargo build -p tele-ios-ffi --target aarch64-apple-ios-sim --release
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer cargo build -p tele-ios-ffi --target aarch64-apple-ios-sim --release
|
||||||
@@ -25,10 +25,83 @@ Interpretation:
|
|||||||
|
|
||||||
- Rust, Swift, Xcode, and the iOS simulator runtime are working.
|
- Rust, Swift, Xcode, and the iOS simulator runtime are working.
|
||||||
- The fake-backed iOS app shell can be built, installed, launched, and rendered.
|
- The fake-backed iOS app shell can be built, installed, launched, and rendered.
|
||||||
- Real TDLib iOS linking is blocked because `tdlib-rs` 1.2.0 does not publish the iOS static library artifact requested by its `download-tdlib` build script.
|
- `download-tdlib` cannot be used for iOS because `tdlib-rs` 1.2.0 does not publish the iOS artifact requested by its build script.
|
||||||
|
|
||||||
Next viable paths:
|
Current real TDLib status:
|
||||||
|
|
||||||
1. Build TDLib for `iphoneos` and `iphonesimulator` locally and switch the Rust dependency path to `local-tdlib` or `pkg-config`.
|
- `scripts/build-tdlib-ios.sh` builds TDLib `1.8.29` locally for iOS device and simulator.
|
||||||
2. Add a fake-only `tele-ios-ffi` build feature that avoids linking TDLib for simulator UI work, while keeping real TDLib behind a separate feature.
|
- `.build/tdlib-ios/iphoneos/lib/libtdjson.1.8.29.dylib` is `arm64`.
|
||||||
3. Replace the `tdlib-rs` packaging path for iOS with a lower-level C ABI/XCFramework if UniFFI plus `tdlib-rs` cannot link cleanly on device.
|
- `.build/tdlib-ios/iphonesimulator/lib/libtdjson.1.8.29.dylib` is a universal `x86_64` + `arm64` simulator dylib.
|
||||||
|
- `scripts/check-ios-tdlib-linking.sh` builds `tele-ios-ffi` for `aarch64-apple-ios-sim` with local TDLib.
|
||||||
|
- `IOS_RUST_TARGET=aarch64-apple-ios scripts/build-ios-ffi-with-local-tdlib.sh` builds `tele-ios-ffi` for device with local TDLib.
|
||||||
|
- `scripts/build-ios-real-ffi-xcframework.sh` packages simulator Rust slices into `tele_ios_ffi.xcframework`, packages local `libtdjson` into `tdjson.xcframework`, and writes generated Swift bindings into the Swift package's local `Generated` path.
|
||||||
|
- `TELE_IOS_USE_LOCAL_FFI=1 scripts/build-ios-simulator-app.sh` builds and packages the SwiftUI simulator app against the real Rust/TDLib FFI path, including `Frameworks/libtdjson.dylib` in the `.app` bundle.
|
||||||
|
- The repo patches `tdlib-rs` through `crates/vendor/tdlib-rs` because upstream `src/build.rs` does not handle `target_os = "ios"` for `local-tdlib`.
|
||||||
|
|
||||||
|
Selected path:
|
||||||
|
|
||||||
|
1. Keep `download-tdlib` for the terminal/macOS build path.
|
||||||
|
2. Build TDLib locally for iOS and iOS Simulator from the TDLib source commit matching TDLib `1.8.29`.
|
||||||
|
3. Build `tele-ios-ffi` with `tele-core/tdlib-local` and `LOCAL_TDLIB_PATH`.
|
||||||
|
4. Package the resulting Rust FFI library and TDLib dylib into the iOS app/XCFramework path.
|
||||||
|
|
||||||
|
The TDLib source commit used for `1.8.29` is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6
|
||||||
|
```
|
||||||
|
|
||||||
|
This can be checked with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm info prebuilt-tdlib@td-1.8.29 tdlib --json
|
||||||
|
```
|
||||||
|
|
||||||
|
Build local TDLib artifacts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/build-tdlib-ios.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This writes local, untracked outputs to:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.build/tdlib-ios/iphoneos/
|
||||||
|
.build/tdlib-ios/iphonesimulator/
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the real iOS FFI path against local TDLib:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/build-ios-ffi-with-local-tdlib.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
or for a device target:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer IOS_RUST_TARGET=aarch64-apple-ios scripts/build-ios-ffi-with-local-tdlib.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Package the real FFI path for the Swift app and build the simulator `.app`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/build-ios-real-ffi-xcframework.sh
|
||||||
|
TELE_IOS_USE_LOCAL_FFI=1 DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer scripts/build-ios-simulator-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Known local prerequisites:
|
||||||
|
|
||||||
|
- Xcode with the iOS SDK installed.
|
||||||
|
- Homebrew build tools: `brew install cmake gperf coreutils`.
|
||||||
|
- Rust iOS targets: `rustup target add aarch64-apple-ios-sim aarch64-apple-ios`.
|
||||||
|
- `scripts/build-tdlib-ios.sh` builds only the required OpenSSL platforms through TDLib's vendored `Python-Apple-support` flow, with a local patch for the simulator target triple under Xcode 26.
|
||||||
|
- TDLib CMake uses `TDLIB_IOS_DEPLOYMENT_TARGET=17.0` by default to match the Swift package minimum iOS version.
|
||||||
|
- TDLib's `prepare_cross_compiling` target is run as a host-side generation step before cross-compiling, so generated TL/MIME sources exist for the iOS build.
|
||||||
|
|
||||||
|
Example local blocker if these tools are missing:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Required tool not found: cmake
|
||||||
|
```
|
||||||
|
|
||||||
|
CMake 4.x compatibility is handled by passing `-DCMAKE_POLICY_VERSION_MINIMUM=3.5` to TDLib's configure step.
|
||||||
|
|||||||
@@ -45,6 +45,33 @@ Architecture default: Rust `tele-core` remains the source of Telegram state and
|
|||||||
- Swift sample test can create a fake session, receive events, load chats, open a chat, send a message, react, and search.
|
- Swift sample test can create a fake session, receive events, load chats, open a chat, send a message, react, and search.
|
||||||
- Real TDLib linking is validated for iOS simulator and device or documented as blocked with exact linker error.
|
- Real TDLib linking is validated for iOS simulator and device or documented as blocked with exact linker error.
|
||||||
|
|
||||||
|
#### Phase 2A: Local TDLib for iOS
|
||||||
|
|
||||||
|
`tdlib-rs` 1.2.0 with `download-tdlib` downloads prebuilt TDLib archives from `FedericoBruzzone/tdlib-rs` releases using the pattern `tdlib-{tdlib_version}-{target_os}-{target_arch}.zip`. The terminal/macOS build works because the macOS archive exists. The iOS archives, for example `tdlib-1.8.29-ios-aarch64.zip`, are not published, so iOS real linking must not depend on `download-tdlib`.
|
||||||
|
|
||||||
|
- Keep `download-tdlib` for the terminal/macOS build path while it remains useful there.
|
||||||
|
- Switch the iOS FFI build path to `tdlib-rs` `local-tdlib` support.
|
||||||
|
- Pin the local TDLib build to the TDLib version expected by `tdlib-rs` 1.2.0: `1.8.29`.
|
||||||
|
- Add `scripts/build-tdlib-ios.sh` to build TDLib locally for:
|
||||||
|
- `arm64-apple-ios`
|
||||||
|
- `arm64-apple-ios-sim`
|
||||||
|
- optionally `x86_64-apple-ios-sim` if Intel Mac simulator support is needed.
|
||||||
|
- Store generated TDLib artifacts outside git, for example:
|
||||||
|
- `.build/tdlib-ios/iphoneos/include`
|
||||||
|
- `.build/tdlib-ios/iphoneos/lib`
|
||||||
|
- `.build/tdlib-ios/iphonesimulator/include`
|
||||||
|
- `.build/tdlib-ios/iphonesimulator/lib`
|
||||||
|
- Add `scripts/build-ios-ffi-with-local-tdlib.sh` to set `LOCAL_TDLIB_PATH` and build `tele-ios-ffi` for simulator/device targets.
|
||||||
|
- Patch `tdlib-rs` through `crates/vendor/tdlib-rs` until upstream handles `target_os = "ios"` in its `local-tdlib` build helper.
|
||||||
|
- Run TDLib's host-side `prepare_cross_compiling` target before the iOS cross-build, because TDLib 1.8.29 expects generated TL/MIME sources to exist during cross-compilation.
|
||||||
|
- After simulator and device Rust builds link, package the Rust FFI output and TDLib dependency into an iOS-consumable XCFramework or documented adjacent native dependency.
|
||||||
|
- Acceptance:
|
||||||
|
- `scripts/check-ios-tdlib-linking.sh` no longer fails because of a missing GitHub release archive. Completed on 2026-05-21.
|
||||||
|
- `cargo build -p tele-ios-ffi --target aarch64-apple-ios-sim --release` links with local TDLib. Completed on 2026-05-21 through `scripts/check-ios-tdlib-linking.sh`.
|
||||||
|
- `cargo build -p tele-ios-ffi --target aarch64-apple-ios --release` links with local TDLib. Completed on 2026-05-21 through `IOS_RUST_TARGET=aarch64-apple-ios scripts/build-ios-ffi-with-local-tdlib.sh`.
|
||||||
|
- The Xcode app can be built against the real FFI path, not only the fake bridge. Completed on 2026-05-21 through `scripts/build-ios-real-ffi-xcframework.sh` and `TELE_IOS_USE_LOCAL_FFI=1 scripts/build-ios-simulator-app.sh`.
|
||||||
|
- Any remaining CMake/OpenSSL/zlib/linker blockers are documented with the exact command and error text.
|
||||||
|
|
||||||
### Phase 3: iOS App Shell
|
### Phase 3: iOS App Shell
|
||||||
|
|
||||||
- Add native app under `apps/ios/TeleTuiIOS`.
|
- Add native app under `apps/ios/TeleTuiIOS`.
|
||||||
|
|||||||
55
scripts/build-ios-ffi-with-local-tdlib.sh
Executable file
55
scripts/build-ios-ffi-with-local-tdlib.sh
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
target="${IOS_RUST_TARGET:-aarch64-apple-ios-sim}"
|
||||||
|
|
||||||
|
case "${target}" in
|
||||||
|
aarch64-apple-ios)
|
||||||
|
tdlib_platform_dir="${TDLIB_IOS_PLATFORM_DIR:-iphoneos}"
|
||||||
|
;;
|
||||||
|
aarch64-apple-ios-sim | x86_64-apple-ios)
|
||||||
|
tdlib_platform_dir="${TDLIB_IOS_PLATFORM_DIR:-iphonesimulator}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Unsupported iOS Rust target: %s\n' "${target}" >&2
|
||||||
|
printf 'Supported targets: aarch64-apple-ios, aarch64-apple-ios-sim, x86_64-apple-ios\n' >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
tdlib_root="${LOCAL_TDLIB_PATH:-${repo_root}/.build/tdlib-ios/${tdlib_platform_dir}}"
|
||||||
|
tdlib_version="${TDLIB_VERSION:-1.8.29}"
|
||||||
|
|
||||||
|
if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]]; then
|
||||||
|
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "${tdlib_root}/include" ]]; then
|
||||||
|
printf 'TDLib include directory not found: %s\n' "${tdlib_root}/include" >&2
|
||||||
|
printf 'Run scripts/build-tdlib-ios.sh first or set LOCAL_TDLIB_PATH to a TDLib install root.\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "${tdlib_root}/lib/libtdjson.${tdlib_version}.dylib" ]]; then
|
||||||
|
printf 'TDLib dylib not found: %s\n' "${tdlib_root}/lib/libtdjson.${tdlib_version}.dylib" >&2
|
||||||
|
printf 'tdlib-rs local-tdlib expects the versioned dylib name on macOS-hosted builds.\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "${repo_root}"
|
||||||
|
|
||||||
|
if ! rustup target list --installed | grep -qx "${target}"; then
|
||||||
|
rustup target add "${target}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export LOCAL_TDLIB_PATH="${tdlib_root}"
|
||||||
|
|
||||||
|
cargo build \
|
||||||
|
-p tele-ios-ffi \
|
||||||
|
--no-default-features \
|
||||||
|
--features core-session-local-tdlib \
|
||||||
|
--target "${target}" \
|
||||||
|
--release
|
||||||
|
|
||||||
|
printf 'Built tele-ios-ffi for %s with LOCAL_TDLIB_PATH=%s\n' "${target}" "${LOCAL_TDLIB_PATH}"
|
||||||
131
scripts/build-ios-real-ffi-xcframework.sh
Executable file
131
scripts/build-ios-real-ffi-xcframework.sh
Executable file
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
package_dir="${repo_root}/apps/ios/TeleTuiIOS"
|
||||||
|
out_dir="${1:-${repo_root}/build/ios-real-ffi-xcframework}"
|
||||||
|
artifacts_dir="${package_dir}/BinaryArtifacts"
|
||||||
|
swift_sources_dir="${package_dir}/Generated/tele_ios_ffi/Sources/tele_ios_ffi"
|
||||||
|
framework_name="${IOS_FFI_FRAMEWORK_NAME:-tele_ios_ffi}"
|
||||||
|
tdjson_framework_name="${IOS_TDJSON_FRAMEWORK_NAME:-tdjson}"
|
||||||
|
targets="${IOS_RUST_TARGETS:-}"
|
||||||
|
|
||||||
|
if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]]; then
|
||||||
|
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${targets}" ]]; then
|
||||||
|
targets="x86_64-apple-ios aarch64-apple-ios-sim"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "${repo_root}"
|
||||||
|
|
||||||
|
case "${out_dir}" in
|
||||||
|
"" | "/" | "/tmp" | "/private" | "/private/tmp")
|
||||||
|
printf 'Refusing unsafe output directory: %s\n' "${out_dir}" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
rm -rf "${out_dir}"
|
||||||
|
mkdir -p "${out_dir}/Swift" "${out_dir}/Headers" "${out_dir}/TdjsonHeaders"
|
||||||
|
|
||||||
|
tdjson_args=()
|
||||||
|
first_lib_path=""
|
||||||
|
simulator_libs=()
|
||||||
|
device_lib=""
|
||||||
|
seen_simulator=0
|
||||||
|
seen_device=0
|
||||||
|
|
||||||
|
for target in ${targets}; do
|
||||||
|
IOS_RUST_TARGET="${target}" "${repo_root}/scripts/build-ios-ffi-with-local-tdlib.sh"
|
||||||
|
lib_path="${repo_root}/target/${target}/release/libtele_ios_ffi.a"
|
||||||
|
if [[ -z "${first_lib_path}" ]]; then
|
||||||
|
first_lib_path="${lib_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${target}" in
|
||||||
|
aarch64-apple-ios)
|
||||||
|
seen_device=1
|
||||||
|
device_lib="${lib_path}"
|
||||||
|
;;
|
||||||
|
aarch64-apple-ios-sim | x86_64-apple-ios)
|
||||||
|
seen_simulator=1
|
||||||
|
simulator_libs+=("${lib_path}")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Unsupported iOS Rust target for XCFramework packaging: %s\n' "${target}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "${first_lib_path}" ]]; then
|
||||||
|
printf 'No Rust targets selected for iOS FFI packaging\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Swift" --swift-sources
|
||||||
|
cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Headers" --headers
|
||||||
|
cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Headers" \
|
||||||
|
--modulemap \
|
||||||
|
--module-name tele_ios_ffiFFI \
|
||||||
|
--modulemap-filename module.modulemap
|
||||||
|
|
||||||
|
cat > "${out_dir}/TdjsonHeaders/tdjson.h" <<'HEADER'
|
||||||
|
void td_json_client_send(void *client, const char *request);
|
||||||
|
const char *td_json_client_receive(void *client, double timeout);
|
||||||
|
const char *td_json_client_execute(void *client, const char *request);
|
||||||
|
void *td_json_client_create(void);
|
||||||
|
void td_json_client_destroy(void *client);
|
||||||
|
HEADER
|
||||||
|
|
||||||
|
if [[ "${seen_simulator}" == "1" ]]; then
|
||||||
|
tdjson_args+=(
|
||||||
|
"-library" "${repo_root}/.build/tdlib-ios/iphonesimulator/lib/libtdjson.1.8.29.dylib"
|
||||||
|
"-headers" "${out_dir}/TdjsonHeaders"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${seen_device}" == "1" ]]; then
|
||||||
|
tdjson_args+=(
|
||||||
|
"-library" "${repo_root}/.build/tdlib-ios/iphoneos/lib/libtdjson.1.8.29.dylib"
|
||||||
|
"-headers" "${out_dir}/TdjsonHeaders"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "${artifacts_dir}/${framework_name}.xcframework" \
|
||||||
|
"${artifacts_dir}/${tdjson_framework_name}.xcframework" \
|
||||||
|
"${swift_sources_dir}"
|
||||||
|
mkdir -p "${artifacts_dir}" "${swift_sources_dir}"
|
||||||
|
|
||||||
|
ffi_args=()
|
||||||
|
if [[ "${#simulator_libs[@]}" -gt 0 ]]; then
|
||||||
|
simulator_lib="${out_dir}/libtele_ios_ffi-iphonesimulator.a"
|
||||||
|
if [[ "${#simulator_libs[@]}" -eq 1 ]]; then
|
||||||
|
cp "${simulator_libs[0]}" "${simulator_lib}"
|
||||||
|
else
|
||||||
|
xcrun lipo -create "${simulator_libs[@]}" -output "${simulator_lib}"
|
||||||
|
fi
|
||||||
|
ffi_args+=("-library" "${simulator_lib}" "-headers" "${out_dir}/Headers")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${device_lib}" ]]; then
|
||||||
|
ffi_args+=("-library" "${device_lib}" "-headers" "${out_dir}/Headers")
|
||||||
|
fi
|
||||||
|
|
||||||
|
xcodebuild -create-xcframework \
|
||||||
|
"${ffi_args[@]}" \
|
||||||
|
-output "${artifacts_dir}/${framework_name}.xcframework"
|
||||||
|
|
||||||
|
xcodebuild -create-xcframework \
|
||||||
|
"${tdjson_args[@]}" \
|
||||||
|
-output "${artifacts_dir}/${tdjson_framework_name}.xcframework"
|
||||||
|
|
||||||
|
cp "${out_dir}/Swift/tele_ios_ffi.swift" "${swift_sources_dir}/tele_ios_ffi.swift"
|
||||||
|
|
||||||
|
printf 'Generated real iOS FFI artifacts:\n'
|
||||||
|
printf ' %s\n' "${artifacts_dir}/${framework_name}.xcframework"
|
||||||
|
printf ' %s\n' "${artifacts_dir}/${tdjson_framework_name}.xcframework"
|
||||||
|
printf ' %s\n' "${swift_sources_dir}/tele_ios_ffi.swift"
|
||||||
|
printf 'Build Swift package with: TELE_IOS_USE_LOCAL_FFI=1 DEVELOPER_DIR=%s xcodebuild ...\n' "${DEVELOPER_DIR:-}"
|
||||||
@@ -81,6 +81,17 @@ cat > "${app_path}/Info.plist" <<PLIST
|
|||||||
</plist>
|
</plist>
|
||||||
PLIST
|
PLIST
|
||||||
|
|
||||||
|
tdjson_path="${product_dir}/libtdjson.1.8.29.dylib"
|
||||||
|
if [[ -f "${tdjson_path}" ]]; then
|
||||||
|
mkdir -p "${app_path}/Frameworks"
|
||||||
|
cp "${tdjson_path}" "${app_path}/Frameworks/libtdjson.dylib"
|
||||||
|
codesign --remove-signature "${app_path}/TeleTuiIOSApp" >/dev/null 2>&1 || true
|
||||||
|
if ! otool -l "${app_path}/TeleTuiIOSApp" | grep -q '@executable_path/Frameworks'; then
|
||||||
|
install_name_tool -add_rpath '@executable_path/Frameworks' "${app_path}/TeleTuiIOSApp"
|
||||||
|
fi
|
||||||
|
codesign --force --sign - --timestamp=none "${app_path}/Frameworks/libtdjson.dylib" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
codesign --force --sign - --timestamp=none "${app_path}/TeleTuiIOSApp" >/dev/null
|
codesign --force --sign - --timestamp=none "${app_path}/TeleTuiIOSApp" >/dev/null
|
||||||
codesign --force --sign - --timestamp=none "${app_path}" >/dev/null
|
codesign --force --sign - --timestamp=none "${app_path}" >/dev/null
|
||||||
|
|
||||||
|
|||||||
187
scripts/build-tdlib-ios.sh
Executable file
187
scripts/build-tdlib-ios.sh
Executable file
@@ -0,0 +1,187 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
tdlib_version="${TDLIB_VERSION:-1.8.29}"
|
||||||
|
tdlib_commit="${TDLIB_COMMIT:-af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6}"
|
||||||
|
tdlib_repo="${TDLIB_REPO:-https://github.com/tdlib/td.git}"
|
||||||
|
source_dir="${TDLIB_SOURCE_DIR:-${repo_root}/.build/tdlib-src}"
|
||||||
|
build_root="${TDLIB_BUILD_ROOT:-${repo_root}/.build/tdlib-ios-build}"
|
||||||
|
output_root="${TDLIB_OUTPUT_ROOT:-${repo_root}/.build/tdlib-ios}"
|
||||||
|
platforms="${TDLIB_IOS_PLATFORMS:-iOS iOS-simulator}"
|
||||||
|
openssl_platforms="${TDLIB_OPENSSL_PLATFORMS:-iOS iOS-simulator}"
|
||||||
|
ios_deployment_target="${TDLIB_IOS_DEPLOYMENT_TARGET:-17.0}"
|
||||||
|
jobs="${TDLIB_BUILD_JOBS:-3}"
|
||||||
|
|
||||||
|
if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]]; then
|
||||||
|
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_tool() {
|
||||||
|
if ! command -v "$1" >/dev/null 2>&1; then
|
||||||
|
printf 'Required tool not found: %s\n' "$1" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
missing=0
|
||||||
|
for tool in git cmake c++ gperf make perl rsync xcodebuild xcrun install_name_tool; do
|
||||||
|
require_tool "${tool}" || missing=1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "${missing}" -ne 0 ]]; then
|
||||||
|
printf '\nInstall missing TDLib build dependencies on macOS with:\n' >&2
|
||||||
|
printf ' brew install cmake gperf coreutils\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! xcrun --sdk iphoneos --show-sdk-path >/dev/null; then
|
||||||
|
printf 'The iphoneos SDK is unavailable through xcrun.\n' >&2
|
||||||
|
printf 'Set DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer and install the iOS platform in Xcode.\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "${source_dir}")" "${build_root}" "${output_root}"
|
||||||
|
|
||||||
|
if [[ ! -d "${source_dir}/.git" ]]; then
|
||||||
|
git clone "${tdlib_repo}" "${source_dir}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "${source_dir}" fetch --depth 1 origin "${tdlib_commit}"
|
||||||
|
git -C "${source_dir}" checkout --detach "${tdlib_commit}"
|
||||||
|
|
||||||
|
openssl_root="${source_dir}/example/ios/third_party/openssl"
|
||||||
|
python_apple_support_dir="${source_dir}/example/ios/Python-Apple-support"
|
||||||
|
|
||||||
|
prepare_python_apple_support() {
|
||||||
|
if [[ ! -d "${python_apple_support_dir}/.git" ]]; then
|
||||||
|
git clone https://github.com/beeware/Python-Apple-support "${python_apple_support_dir}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "${python_apple_support_dir}" checkout 6f43aba0ddd5a9f52f39775d0141bd4363614020
|
||||||
|
git -C "${python_apple_support_dir}" reset --hard
|
||||||
|
(
|
||||||
|
cd "${python_apple_support_dir}"
|
||||||
|
git apply ../Python-Apple-support.patch
|
||||||
|
# Python-Apple-support at this revision emits apple-ios-simulator-simulator
|
||||||
|
# under newer Xcode SDK naming. Use the base OS name before appending
|
||||||
|
# "-simulator" to the target triple.
|
||||||
|
perl -pi -e 's/apple-\$\$\(OS_LOWER-\$\(target\)\)-simulator/apple-\$\$\(patsubst %-simulator,%,\$\$\(OS_LOWER-\$\(target\)\)\)-simulator/' Makefile
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_td_auto_sources() {
|
||||||
|
local host_build_dir="${build_root}/build-host-generate"
|
||||||
|
local td_auto_dir="${source_dir}/td/generate/auto/td/telegram"
|
||||||
|
local mime_auto_dir="${source_dir}/tdutils/generate/auto"
|
||||||
|
|
||||||
|
if [[ -f "${td_auto_dir}/td_api.cpp" \
|
||||||
|
&& -f "${td_auto_dir}/td_api_json.cpp" \
|
||||||
|
&& -f "${mime_auto_dir}/mime_type_to_extension.cpp" \
|
||||||
|
&& -f "${mime_auto_dir}/extension_to_mime_type.cpp" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ZERO_AR_DATE=1 cmake -S "${source_dir}" -B "${host_build_dir}" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||||
|
-DCMAKE_MAKE_PROGRAM=make
|
||||||
|
|
||||||
|
cmake --build "${host_build_dir}" --target prepare_cross_compiling -- -j"${jobs}"
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_openssl_platform() {
|
||||||
|
local platform="$1"
|
||||||
|
local output_dir="${openssl_root}/${platform}"
|
||||||
|
|
||||||
|
if [[ -f "${output_dir}/lib/libcrypto.a" && -f "${output_dir}/lib/libssl.a" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
prepare_python_apple_support
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "${python_apple_support_dir}"
|
||||||
|
rm -rf "build/${platform}" "install/${platform}" "merge/${platform}"
|
||||||
|
make "OpenSSL-${platform}"
|
||||||
|
)
|
||||||
|
|
||||||
|
rm -rf "${output_dir}"
|
||||||
|
mkdir -p "${output_dir}/lib"
|
||||||
|
cp "${python_apple_support_dir}/merge/${platform}/openssl/lib/libcrypto.a" "${output_dir}/lib/"
|
||||||
|
cp "${python_apple_support_dir}/merge/${platform}/openssl/lib/libssl.a" "${output_dir}/lib/"
|
||||||
|
cp -R "${python_apple_support_dir}/merge/${platform}/openssl/include" "${output_dir}/include"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ ! -f "${openssl_root}/iOS/lib/libcrypto.a" || ! -f "${openssl_root}/iOS-simulator/lib/libcrypto.a" ]]; then
|
||||||
|
printf 'OpenSSL for iOS was not found under %s.\n' "${openssl_root}" >&2
|
||||||
|
printf 'Building only required OpenSSL platforms: %s\n' "${openssl_platforms}"
|
||||||
|
for platform in ${openssl_platforms}; do
|
||||||
|
prepare_openssl_platform "${platform}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
prepare_td_auto_sources
|
||||||
|
|
||||||
|
build_platform() {
|
||||||
|
local td_platform="$1"
|
||||||
|
local ios_platform
|
||||||
|
local out_platform
|
||||||
|
|
||||||
|
case "${td_platform}" in
|
||||||
|
iOS)
|
||||||
|
ios_platform="OS"
|
||||||
|
out_platform="iphoneos"
|
||||||
|
;;
|
||||||
|
iOS-simulator)
|
||||||
|
ios_platform="SIMULATOR"
|
||||||
|
out_platform="iphonesimulator"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'Unsupported TDLib iOS platform: %s\n' "${td_platform}" >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
local openssl_path="${openssl_root}/${td_platform}"
|
||||||
|
local openssl_crypto_library="${openssl_path}/lib/libcrypto.a"
|
||||||
|
local openssl_ssl_library="${openssl_path}/lib/libssl.a"
|
||||||
|
local build_dir="${build_root}/build-${td_platform}"
|
||||||
|
local install_dir="${build_root}/install-${td_platform}"
|
||||||
|
local output_dir="${output_root}/${out_platform}"
|
||||||
|
|
||||||
|
if [[ ! -f "${openssl_crypto_library}" || ! -f "${openssl_ssl_library}" ]]; then
|
||||||
|
printf 'OpenSSL libraries are missing for %s under %s\n' "${td_platform}" "${openssl_path}" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf "${build_dir}" "${install_dir}" "${output_dir}"
|
||||||
|
mkdir -p "${build_dir}" "${install_dir}" "${output_dir}/include" "${output_dir}/lib"
|
||||||
|
|
||||||
|
ZERO_AR_DATE=1 cmake -S "${source_dir}" -B "${build_dir}" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||||
|
-DCMAKE_INSTALL_PREFIX="${install_dir}" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="${source_dir}/CMake/iOS.cmake" \
|
||||||
|
-DIOS_PLATFORM="${ios_platform}" \
|
||||||
|
-DIOS_DEPLOYMENT_TARGET="${ios_deployment_target}" \
|
||||||
|
-DCMAKE_MAKE_PROGRAM=make \
|
||||||
|
-DOPENSSL_FOUND=1 \
|
||||||
|
-DOPENSSL_CRYPTO_LIBRARY="${openssl_crypto_library}" \
|
||||||
|
-DOPENSSL_SSL_LIBRARY="${openssl_ssl_library}" \
|
||||||
|
-DOPENSSL_INCLUDE_DIR="${openssl_path}/include" \
|
||||||
|
-DOPENSSL_LIBRARIES="${openssl_crypto_library};${openssl_ssl_library}"
|
||||||
|
|
||||||
|
cmake --build "${build_dir}" --target install -- -j"${jobs}"
|
||||||
|
|
||||||
|
install_name_tool -id @rpath/libtdjson.dylib "${install_dir}/lib/libtdjson.dylib"
|
||||||
|
rsync -a "${install_dir}/include/" "${output_dir}/include/"
|
||||||
|
cp "${install_dir}/lib/libtdjson.dylib" "${output_dir}/lib/libtdjson.dylib"
|
||||||
|
cp "${install_dir}/lib/libtdjson.dylib" "${output_dir}/lib/libtdjson.${tdlib_version}.dylib"
|
||||||
|
|
||||||
|
printf 'Installed TDLib %s for %s at %s\n' "${tdlib_version}" "${td_platform}" "${output_dir}"
|
||||||
|
}
|
||||||
|
|
||||||
|
for platform in ${platforms}; do
|
||||||
|
build_platform "${platform}"
|
||||||
|
done
|
||||||
@@ -5,10 +5,4 @@ if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]
|
|||||||
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||||
fi
|
fi
|
||||||
|
|
||||||
target="${IOS_RUST_TARGET:-aarch64-apple-ios-sim}"
|
exec "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/build-ios-ffi-with-local-tdlib.sh"
|
||||||
|
|
||||||
if ! rustup target list --installed | grep -qx "${target}"; then
|
|
||||||
rustup target add "${target}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cargo build -p tele-ios-ffi --target "${target}" --release
|
|
||||||
|
|||||||
Reference in New Issue
Block a user