Wire local TDLib into iOS FFI build
This commit is contained in:
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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user