opentele2-grammers
The bridge between opentele2 and grammers 0.11: grammers sessions and connection params from tdata accounts and API profiles, and back. The core never depends on grammers; this crate is the optional bridge.
[dependencies]
opentele2-core = "2.0.0"
opentele2-grammers = "2.0.0"
# opentele2-grammers = { version = "2.0.0", features = ["client"] }Features
| Feature | Default | Effect |
|---|---|---|
client | no | The client flows over grammers-client 0.11 in the client module: QR login with DC migration and 2FA, the self user id, session admin, the seven consistency checks and tdata from a client session. Off by default so the default crate has no client. |
Sessions and params
pub fn session_data(account: &Account) -> SessionData;
pub fn account_from_session(data: &SessionData, index: i32) -> Result<Account>;
pub fn connection_params(profile: &ApiProfile) -> ConnectionParams;| Function | Description |
|---|---|
session_data(account) | A grammers SessionData for a tdata account, ready for MemorySession::from or SessionData::import_to: the main DC as home DC, the DCs with an IPv4 and an IPv6 endpoint (the stored config’s when there is one, else every production DC), the account’s key on the main DC only, the self user in peer_infos and an empty updates state. It cannot fail. |
account_ | The inverse: the home DC key and the self user of a SessionData as the account at index. Error::AuthKeyNotFound without a home DC key, Error::BadConfigData without exactly one self user id. |
connection_ | A grammers ConnectionParams with the profile’s device model, system version, app version and language codes. Pass the profile’s api_id to grammers separately and its api_hash at sign-in. |
use grammers_session::storages::MemorySession;
use opentele2_core::api::{self, Client, Versions};
use opentele2_core::tdata::TData;
fn main() -> opentele2_core::Result<()> {
let tdata = TData::load("tdata", b"", None)?;
let account = tdata.main_account().expect("folder has an account");
let _session = MemorySession::from(opentele2_grammers::session_data(account));
let desktop = api::profile(Client::Desktop, &Versions::offline());
let _params = opentele2_grammers::connection_params(&desktop);
Ok(())
}grammers 0.11 builds initConnection itself and always sends an empty lang_pack and no
params, so a session driven by grammers with the desktop profile is not byte-identical on the
wire to Telegram Desktop: the device, system, app and language fields match, those two do not.
grammers’ SessionData and its DcOption print the raw auth key with Debug; do not log them.
client (feature client)
Every flow runs over an Invoker, which grammers_client::Client implements, so it can also run
over a fake that returns canned TL objects. Flows that read or change session state also take the
grammers Session the client’s SenderPool was built with.
pub trait Invoker: Sync {
fn invoke<R>(&self, request: &R)
-> impl Future<Output = Result<R::Return, InvocationError>> + Send
where
R: RemoteCall + Sync;
}
pub async fn is_authorized<I: Invoker>(invoker: &I) -> Result<bool, ClientError>;
pub async fn qr_login<A, N, S>(authorized: &A, new: &N, new_session: &S, api_id: i32,
api_hash: &str, password: Option<&str>) -> Result<i64, ClientError>;
pub async fn post_login_requests<I, D, F>(invoker: &I, lang_pack: &str, delay: D) -> usize;
pub async fn get_me_id<I: Invoker>(invoker: &I) -> Result<i64, ClientError>;
pub async fn sessions<I: Invoker>(invoker: &I) -> Result<Vec<tl::types::Authorization>, ClientError>;
pub async fn current_session<I: Invoker>(invoker: &I) -> Result<Option<tl::types::Authorization>, ClientError>;
pub async fn terminate_session<I: Invoker>(invoker: &I, hash: i64) -> Result<(), ClientError>;
pub async fn terminate_all_sessions<I: Invoker>(invoker: &I) -> Result<usize, ClientError>;
pub fn session_row(authorization: &tl::types::Authorization) -> SessionRow;
pub async fn sessions_table<I: Invoker>(invoker: &I) -> Result<String, ClientError>;
pub async fn is_official_app<I: Invoker>(invoker: &I) -> Result<bool, ClientError>;
pub async fn run_consistency_checks<I: Invoker>(invoker: &I,
expectations: &ConsistencyExpectations) -> ConsistencyReport;
pub async fn account_from_client<I, S>(invoker: &I, session: &S, index: i32) -> Result<Account, ClientError>;
pub async fn tdata_from_client<I, S>(invoker: &I, session: &S, passcode: &[u8],
rng: &mut (dyn FnMut(&mut [u8]) + Send)) -> Result<TData, ClientError>;| Function | Description |
|---|---|
qr_login(...) | Logs new in through authorized by QR login, following auth., with the 2FA password; resolves to the new user id. |
post_ | Sends the requests an official client sends after login; delay(min_ms, max_ms) is the caller’s timer. Returns how many failed. |
get_me_id, is_authorized | The self user id, and whether the session is authorised. |
sessions, current_session, terminate_session, terminate_all_sessions | Session admin over account. and account.. |
session_row, sessions_table, is_official_app | The session table row and table, and whether the current session is official. |
run_ | The seven checks of Check::ALL, returning the core ConsistencyReport; its warning is left to the caller. |
account_ | The client’s current session as a tdata account. |
tdata_ | A new folder with that account; save it with TData::save_random. |
ClientError names why a flow failed: NoPasswordProvided, PasswordIncorrect,
AuthTokenAlreadyAccepted, AuthTokenExpired, AuthTokenInvalid, QrLoginTimeout,
FreshResetAuthorisationForbidden, HashInvalid, UnsupportedPasswordAlgorithm, Srp,
SignUpRequired, UserIdUnresolved, Invocation (grammers’ InvocationError) and Core (the
core Error).
Limits
- QR login waits for no
updateLoginToken: grammers 0.11 delivers updates only throughSenderPool::updates, which the caller owns, soqr_loginexports the token again as soon asauth.acceptLoginTokenreturns. - The crate has no warning channel: the per-attempt QR warnings are not emitted, and the existing-session warnings and the consistency warning are left to the caller.
- Connecting the new client and handling an existing session are left to the caller, who builds the new client’s session. No flow here logs out.
- The
lang_packcheck asks about the profile’s lang pack, while grammers 0.11 sends an empty one.