Merge branch 'master' into postgres_storage

This commit is contained in:
Tima Kinsart 2024-04-08 16:32:34 +05:00 committed by GitHub
commit 53c4109808
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 2877 additions and 119 deletions

44
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,44 @@
version: 2
updates:
# This updates the `Cargo.lock` file.
#
# -----------------------------------------------------------------------------------------------
#
# Generally Rust libraries do not have lock files. This grows from the idea that you always want
# to run CI with the most recent (semver compatible) dependency versions, since those are the
# versions new users will get.
#
# However this approach worsens the contribution experience, since PR's CI can fail because of
# a minor dependency update (e.g. because of an MSRV change or an accidental breaking change).
#
# To prevent this and make contribution experience a little bit better we include the lock file
# in the repository. To combat the problem of running CI against old versions, we have this
# dependabot job, which updates the `Cargo.lock` (and `Cargo.lock` only), every once in a while.
- package-ecosystem: "cargo"
# Directory where to search for build system configuration
directory: "/"
# Only change `Cargo.lock`, never change `Cargo.toml`
versioning-strategy: "lockfile-only"
# Check for updates weekly.
# This makes sure dependabot doesn't open PRs too often.
schedule:
interval: "weekly"
# Group dependencies, so dependabot does not open a million pull requests and instead just
# makes "bump everything" every once in a while
groups:
lock:
patterns: ["*"]
# Allow both direct and indirect updates for all packages
allow:
- dependency-type: "all"
# Which labels to apply
labels: ["A-dependencies"]
# Stop dependabot from updating dependencies when the previous dependabot PR hasn't been
# merged/closed yet
open-pull-requests-limit: 1

View file

@ -19,7 +19,8 @@ env:
# When updating this, also update:
# - crates/teloxide-core/src/codegen.rs
# - rust-toolchain.toml
rust_nightly: nightly-2023-09-27
# - below in the test matrix
rust_nightly: nightly-2024-03-20
# When updating this, also update:
# - **/README.md
# - **/src/lib.rs
@ -104,7 +105,7 @@ jobs:
toolchain: beta
features: "--features full"
- rust: nightly
toolchain: nightly-2023-09-27
toolchain: nightly-2024-03-20
features: "--features full nightly"
- rust: msrv
toolchain: 1.70.0
@ -122,6 +123,26 @@ jobs:
- name: Cache Dependencies
uses: Swatinem/rust-cache@v2
# Generally MSRV dump is not considered a breaking change in by the Rust community.
# Thus a minor or a patch version dump of a dependency of ours, can bump MSRV.
# (remember that `cargo` uses newest semver compatible versions by default)
#
# It's silly to bump MSRV every time minor dependency update does (note that this update can
# happen even after our crate is published; so users may need to downgrade crates in
# `Cargo.lock` independently of how we test our crates), so we downgrade their versions in
# MSRV CI specifically instead. This allows as to
# 1. Not update MSRV unless we really need to
# 2. Test newest (or at least newer) versions of crates in CI
#
# Example command: `cargo update -p atomic-write-file@0.1.3 --precise 0.1.2`
- name: Downgrade deps for MSRV
if: ${{ matrix.rust == 'msrv' }}
run: |
cargo update -p sqlx --precise 0.7.3
cargo update -p atomic-write-file --precise 0.1.2
exit 0
# NB. Don't test (build) examples so we can use non-msrv features in them (--tests/--doc)
- name: Compile
run: |

1
.gitignore vendored
View file

@ -1,5 +1,4 @@
/target
Cargo.lock
.idea/
.vscode/
*.sqlite

View file

@ -44,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `filter_video_chat_ended`
- `filter_video_chat_participants_invited`
- `filter_web_app_data`
- `PostgresStorage` a persistent dialogue storage based on [PostgreSQL](https://www.postgresql.org/)([PR 996](https://github.com/teloxide/teloxide/pull/996))
- Implement `PostgresStorage`, a persistent dialogue storage based on [PostgreSQL](https://www.postgresql.org/)([PR 996](https://github.com/teloxide/teloxide/pull/996)).
- Implement `GetChatId` for `teloxide_core::types::{Chat, ChatJoinRequest, ChatMemberUpdated}`.
### Fixed
@ -53,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix typos in documentation ([PR 953](https://github.com/teloxide/teloxide/pull/953))
- Use `Seconds` instead of `String` in `InlineQueryResultAudio` for `audio_duration` ([PR 994](https://github.com/teloxide/teloxide/pull/994))
- High CPU usage on network errors ([PR 1002](https://github.com/teloxide/teloxide/pull/1002), [Issue 780](https://github.com/teloxide/teloxide/issues/780))
- Fix app build errors when using items gated behind sqlite-storage with the feature sqlite-storage-rustls ([PR 1018](https://github.com/teloxide/teloxide/pull/1018))
### Changed

2716
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -335,6 +335,7 @@ Feel free to propose your own bot to our collection!
- [`zamazan4ik/npaperbot-telegram`](https://github.com/zamazan4ik/npaperbot-telegram) — Telegram bot for searching via C++ proposals.
- [`studentenherz/dlebot`](https://github.com/studentenherz/dlebot) — A bot to query definitions of words from the Spanish Language Dictionary.
- [`fr0staman/fr0staman_bot`](https://github.com/fr0staman/fr0staman_bot) — Feature rich Telegram game-like bot with pigs 🐽.
- [`franciscofigueira/transferBot`](https://github.com/franciscofigueira/transferBot) — Telegram bot that notifies of crypto token transfers.
<details>
<summary>Show bots using `teloxide` older than v0.6.0</summary>

View file

@ -12,7 +12,7 @@ use url::Url;
use crate::{
payloads::GetMe,
requests::{HasPayload, Request, Requester},
types::{Me, Recipient, *},
types::*,
};
/// `get_me` cache.

View file

@ -11,7 +11,7 @@ use crate::{
},
prelude::Requester,
requests::{HasPayload, Output, Request},
types::{InputFile, ParseMode, Recipient, *},
types::*,
};
/// Default parse mode adaptor, see

View file

@ -23,7 +23,7 @@ use xshell::{cmd, Shell};
fn ensure_rustfmt(sh: &Shell) {
// FIXME(waffle): find a better way to set toolchain
let toolchain = "nightly-2023-09-27";
let toolchain = "nightly-2024-03-20";
let version = cmd!(sh, "rustup run {toolchain} rustfmt --version").read().unwrap_or_default();
@ -36,7 +36,7 @@ fn ensure_rustfmt(sh: &Shell) {
}
pub fn reformat(text: String) -> String {
let toolchain = "nightly-2023-09-27";
let toolchain = "nightly-2024-03-20";
let sh = Shell::new().unwrap();
ensure_rustfmt(&sh);

View file

@ -677,8 +677,12 @@ impl_api_error! {
/// [`SendMessage`]: crate::payloads::SendMessage
WrongHttpUrl = "Bad Request: wrong HTTP URL",
/// Occurs when bot tries GetUpdate before the timeout. Make sure that only
/// one Updater is running.
/// Occurs when multiple [`GetUpdates`] calls happen at the same time.
///
/// This can happen if
/// 1. You are running multiple bot instances
/// 2. You are running multiple update consumers (like `Dispatcher` or `repl`)
/// 3. You are calling [`GetUpdates`] yourself and the second call is done before the first one finishes
///
/// May happen in methods:
/// 1. [`GetUpdates`]

View file

@ -61,7 +61,7 @@
html_logo_url = "https://cdn.discordapp.com/attachments/224881373326999553/798598120760934410/logo.png",
html_favicon_url = "https://cdn.discordapp.com/attachments/224881373326999553/798598120760934410/logo.png"
)]
#![forbid(unsafe_code)]
//
// we pass "--cfg docsrs" when building docs to add `This is supported on feature="..." only.`
//
// To properly build docs of this crate run
@ -78,16 +78,29 @@
)]
#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
#![cfg_attr(all(feature = "full", docsrs), deny(rustdoc::broken_intra_doc_links))]
//
// Lint levels
#![forbid(unsafe_code)]
//#![deny(missing_docs)]
#![warn(clippy::print_stdout, clippy::dbg_macro)]
#![allow(clippy::let_and_return)]
#![allow(clippy::bool_assert_comparison)]
// Unless this becomes machine applicable, I'm not adding 334 #[must_use]s (waffle)
#![allow(clippy::return_self_not_must_use)]
// Workaround for CI
#![allow(rustdoc::bare_urls)]
// FIXME: deal with these lints
#![allow(
// Sometimes it's more readable to assign to a variable and return it immediately
clippy::let_and_return,
// When you are testing ->bool functions, it makes sense to `assert_eq!(f(..), false)`
clippy::bool_assert_comparison,
// Unless this becomes machine applicable, I'm not adding 334 #[must_use]s (waffle)
clippy::return_self_not_must_use,
// This is dumb. `T: ?Sized where T: Trait` IMO makes perfect sense
clippy::multiple_bound_locations,
// Workaround for CI
// FIXME: do we still need this?
rustdoc::bare_urls,
// FIXME: deal with these lints
clippy::collapsible_str_replace,
clippy::borrow_deref_ref,
clippy::unnecessary_lazy_evaluations,

View file

@ -49,7 +49,7 @@ impl<R> From<TelegramResponse<R>> for ResponseResult<R> {
#[cfg(test)]
mod tests {
use super::*;
use crate::{errors::ApiError, types::Update};
use crate::types::Update;
#[test]
fn parse_terminated_by_other_get_updates() {

View file

@ -20,4 +20,3 @@ mod payload;
mod request;
mod requester;
mod requester_ext;
mod utils;

View file

@ -3,11 +3,7 @@
use url::Url;
use crate::{
payloads::{GetMe, SendMessage, *},
requests::Request,
types::*,
};
use crate::{payloads::*, requests::Request, types::*};
/// Telegram Bot API client.
///

View file

@ -1,16 +0,0 @@
use bytes::{Bytes, BytesMut};
use tokio_util::codec::Decoder;
struct FileDecoder;
impl Decoder for FileDecoder {
type Item = Bytes;
type Error = std::io::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
if src.is_empty() {
return Ok(None);
}
Ok(Some(src.split().freeze()))
}
}

View file

@ -268,16 +268,12 @@ pub use user_id::*;
use serde::Serialize;
/// Converts an `i64` timestump to a `choro::DateTime`, producing serde error
/// for invalid timestumps
/// Converts an `i64` timestamp to a `choro::DateTime`, producing serde error
/// for invalid timestamps
pub(crate) fn serde_timestamp<E: serde::de::Error>(
timestamp: i64,
) -> Result<chrono::DateTime<chrono::Utc>, E> {
use chrono::{DateTime, NaiveDateTime, Utc};
NaiveDateTime::from_timestamp_opt(timestamp, 0)
.ok_or_else(|| E::custom("invalid timestump"))
.map(|naive| DateTime::from_naive_utc_and_offset(naive, Utc))
chrono::DateTime::from_timestamp(timestamp, 0).ok_or_else(|| E::custom("invalid timestump"))
}
pub(crate) mod serde_opt_date_from_unix_timestamp {
@ -313,10 +309,7 @@ pub(crate) mod serde_opt_date_from_unix_timestamp {
{
let json = r#"{"date":1}"#;
let expected = DateTime::from_naive_utc_and_offset(
chrono::NaiveDateTime::from_timestamp_opt(1, 0).unwrap(),
Utc,
);
let expected = DateTime::from_timestamp(1, 0).unwrap();
let Struct { date } = serde_json::from_str(json).unwrap();
assert_eq!(date, Some(expected));

View file

@ -36,8 +36,6 @@ pub struct Animation {
#[cfg(test)]
mod tests {
use crate::types::FileMeta;
use super::*;
#[test]

View file

@ -36,8 +36,6 @@ pub struct Audio {
#[cfg(test)]
mod tests {
use crate::types::{FileMeta, Seconds};
use super::*;
#[test]

View file

@ -702,7 +702,7 @@ mod tests {
can_invite_users: true,
can_pin_messages: true,
until_date: UntilDate::Date(
chrono::NaiveDateTime::from_timestamp_opt(1620000000, 0).unwrap().and_utc(),
chrono::DateTime::from_timestamp(1620000000, 0).unwrap(),
),
}),
};

View file

@ -15,15 +15,8 @@ use tokio::{
use tokio_util::codec::{Decoder, FramedRead};
use std::{
borrow::Cow,
convert::{Infallible, TryFrom},
fmt,
future::Future,
io, iter, mem,
path::PathBuf,
pin::Pin,
sync::Arc,
task,
borrow::Cow, convert::Infallible, fmt, future::Future, io, iter, mem, path::PathBuf, pin::Pin,
sync::Arc, task,
};
use crate::types::InputSticker;

View file

@ -1748,7 +1748,7 @@ mod tests {
Message {
id: MessageId(198283),
thread_id: None,
date: chrono::NaiveDateTime::from_timestamp_opt(1567927221, 0).unwrap().and_utc(),
date: chrono::DateTime::from_timestamp(1567927221, 0).unwrap(),
chat: Chat {
id: ChatId(250918540),
kind: ChatKind::Private(ChatPrivate {

View file

@ -264,7 +264,6 @@ pub enum MessageEntityKind {
mod tests {
use super::*;
use cool_asserts::assert_matches;
use MessageEntity;
use MessageEntityKind::*;
#[test]

View file

@ -2,10 +2,7 @@
// (for built ins there no warnings, but for (De)Serialize, there are)
#![allow(deprecated)]
use std::{
convert::{TryFrom, TryInto},
str::FromStr,
};
use std::str::FromStr;
use serde::{Deserialize, Serialize};
@ -184,8 +181,8 @@ impl FromStr for ParseMode {
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
#![allow(deprecated)]
use super::*;

View file

@ -20,7 +20,6 @@ pub enum ResponseParameters {
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{ChatId, Seconds};
#[test]
fn migrate_to_chat_id_deserialization() {

View file

@ -26,8 +26,11 @@ impl Seconds {
}
/// Returns [`chrono::Duration`] equivalent of this duration.
// FIXME: rename to `time_delta` (the new name of `chrono::Duration`)?
pub fn chrono_duration(self) -> chrono::Duration {
chrono::Duration::seconds(self.seconds() as i64)
// Unwrap: `self.seconds()` is a `u32`, which is always between `-i64::MAX/1000`
// and `i64::MAX/1000`
chrono::Duration::try_seconds(self.seconds() as i64).unwrap()
}
}

View file

@ -1,4 +1,4 @@
use std::{convert::TryFrom, ops::Deref};
use std::ops::Deref;
use serde::{Deserialize, Serialize};

View file

@ -384,16 +384,13 @@ mod test {
MessageId, MessageKind, Update, UpdateId, UpdateKind, User, UserId,
};
use chrono::{DateTime, NaiveDateTime, Utc};
use chrono::DateTime;
// TODO: more tests for deserialization
#[test]
fn message() {
let timestamp = 1_569_518_342;
let date = DateTime::from_naive_utc_and_offset(
NaiveDateTime::from_timestamp_opt(timestamp, 0).unwrap(),
Utc,
);
let date = DateTime::from_timestamp(timestamp, 0).unwrap();
let json = r#"{
"update_id":892252934,

View file

@ -1,5 +1,3 @@
use std::iter::FromIterator;
pub(crate) struct Unzip<A, B>(pub A, pub B);
impl<A, B, T, U> FromIterator<(T, U)> for Unzip<A, B>

View file

@ -129,9 +129,11 @@ async fn mute_user(bot: Bot, msg: Message, time: Duration) -> ResponseResult<()>
// Calculates time of user restriction.
fn calc_restrict_time(time: u64, unit: UnitOfTime) -> Duration {
// FIXME: actually handle the case of too big integers correctly, instead of
// unwrapping
match unit {
UnitOfTime::Hours => Duration::hours(time as i64),
UnitOfTime::Minutes => Duration::minutes(time as i64),
UnitOfTime::Seconds => Duration::seconds(time as i64),
UnitOfTime::Hours => Duration::try_hours(time as i64).unwrap(),
UnitOfTime::Minutes => Duration::try_minutes(time as i64).unwrap(),
UnitOfTime::Seconds => Duration::try_seconds(time as i64).unwrap(),
}
}

View file

@ -1,9 +1,4 @@
use teloxide::{
dispatching::Dispatcher,
prelude::*,
types::{ChatMemberUpdated, ParseMode, Update},
utils::html,
};
use teloxide::{prelude::*, types::ParseMode, utils::html};
use teloxide_core::adaptors::DefaultParseMode;
/// We use a type alias to be able to write just `bot: Bot` in handlers, instead

View file

@ -3,11 +3,7 @@
use rand::Rng;
use teloxide::{
prelude::*,
types::{Dice, Update, UserId},
utils::command::BotCommands,
};
use teloxide::{prelude::*, types::Dice, utils::command::BotCommands};
#[tokio::main]
async fn main() {

View file

@ -3,7 +3,6 @@ use teloxide::{
types::{
InlineQueryResult, InlineQueryResultArticle, InputMessageContent, InputMessageContentText,
},
Bot,
};
#[tokio::main]

View file

@ -96,7 +96,7 @@
#[cfg(feature = "redis-storage")]
pub use self::{RedisStorage, RedisStorageError};
#[cfg(feature = "sqlite-storage-nativetls")]
#[cfg(any(feature = "sqlite-storage-nativetls", feature = "sqlite-storage-rustls"))]
pub use self::{SqliteStorage, SqliteStorageError};
#[cfg(feature = "postgres-storage-nativetls")]

View file

@ -1,6 +1,8 @@
use crate::types::{CallbackQuery, ChatId, Message, Update};
use crate::types::{
CallbackQuery, Chat, ChatId, ChatJoinRequest, ChatMemberUpdated, Message, Update,
};
/// Something that may has a chat ID.
/// Something that may have a chat ID.
pub trait GetChatId {
#[must_use]
fn chat_id(&self) -> Option<ChatId>;
@ -23,3 +25,21 @@ impl GetChatId for Update {
self.chat().map(|chat| chat.id)
}
}
impl GetChatId for Chat {
fn chat_id(&self) -> Option<ChatId> {
Some(self.id)
}
}
impl GetChatId for ChatMemberUpdated {
fn chat_id(&self) -> Option<ChatId> {
Some(self.chat.id)
}
}
impl GetChatId for ChatJoinRequest {
fn chat_id(&self) -> Option<ChatId> {
Some(self.chat.id)
}
}

View file

@ -6,7 +6,7 @@ mod trace_storage;
#[cfg(feature = "redis-storage")]
mod redis_storage;
#[cfg(feature = "sqlite-storage-nativetls")]
#[cfg(any(feature = "sqlite-storage-nativetls", feature = "sqlite-storage-rustls"))]
mod sqlite_storage;
#[cfg(feature = "postgres-storage-nativetls")]
@ -25,7 +25,7 @@ pub use redis_storage::{RedisStorage, RedisStorageError};
pub use serializer::Serializer;
use std::sync::Arc;
#[cfg(feature = "sqlite-storage-nativetls")]
#[cfg(any(feature = "sqlite-storage-nativetls", feature = "sqlite-storage-rustls"))]
pub use sqlite_storage::{SqliteStorage, SqliteStorageError};
#[cfg(feature = "postgres-storage-nativetls")]

View file

@ -1,8 +1,4 @@
use std::{
fmt::Debug,
marker::{Send, Sync},
sync::Arc,
};
use std::{fmt::Debug, sync::Arc};
use futures::future::BoxFuture;
use teloxide_core::types::ChatId;

View file

@ -63,7 +63,7 @@ pub trait UpdateListener:
type Err;
/// Returns a token which stops this listener.
///
///
/// The [`stop`] function of the token is not guaranteed to have an
/// immediate effect. That is, some listeners can return updates even
/// after [`stop`] is called (e.g.: because of buffering).

View file

@ -1,5 +1,4 @@
use std::{
convert::TryInto,
future::Future,
mem,
pin::Pin,
@ -196,20 +195,20 @@ where
/// telegram.
///
/// ```mermaid
/// sequenceDiagram
/// sequenceDiagram
/// participant C as Consumer
/// participant P as Polling
/// participant T as Telegram
///
/// link C: Dispatcher @ ../struct.Dispatcher.html
/// link C: repl @ ../../fn.repl.html
///
///
/// C->>P: next
///
/// P->>+T: Updates? (offset = 0)
/// Note right of T: timeout
/// T->>-P: None
///
///
/// P->>+T: Updates? (offset = 0)
/// Note right of T: <= timeout
/// T->>-P: updates with ids [3, 4]
@ -218,10 +217,10 @@ where
///
/// C->>P: next
/// P->>C: update(4)
///
///
/// C->>P: next
///
/// P->>+T: Updates? (offset = 5)
/// P->>+T: Updates? (offset = 5)
/// Note right of T: <= timeout
/// T->>-P: updates with ids [5]
///

View file

@ -115,8 +115,6 @@ pub fn user_mention_or_link(user: &User) -> String {
#[cfg(test)]
mod tests {
use teloxide_core::types::UserId;
use super::*;
#[test]

View file

@ -157,7 +157,6 @@ pub fn user_mention_or_link(user: &User) -> String {
#[cfg(test)]
mod tests {
use super::*;
use teloxide_core::types::{User, UserId};
#[test]
fn test_bold() {

View file

@ -1,4 +1,4 @@
[toolchain]
channel = "nightly-2023-09-27"
channel = "nightly-2024-03-20"
components = ["rustfmt", "clippy"]
profile = "minimal"