Browse Source

[Build] Attempt to migrate to teloxide 0.7

Slava Barinov 3 years ago
parent
commit
a82630dbc0
4 changed files with 361 additions and 231 deletions
  1. 126 51
      Cargo.lock
  2. 3 2
      Cargo.toml
  3. 3 2
      src/categories.rs
  4. 229 176
      src/telegram.rs

+ 126 - 51
Cargo.lock

@@ -26,6 +26,25 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "anyhow"
+version = "1.0.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
+
+[[package]]
+name = "aquamarine"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96e14cb2a51c8b45d26a4219981985c7350fc05eacb7b5b2939bceb2ffefdf3e"
+dependencies = [
+ "itertools",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "async-trait"
 version = "0.1.52"
@@ -50,9 +69,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "base64"
@@ -193,9 +212,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
 
 [[package]]
 name = "core-foundation"
-version = "0.9.2"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -324,6 +343,15 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "dptree"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16b8b3726948013829e2d4889a52f2fd84337121a8bffd96af1f7e04aade82af"
+dependencies = [
+ "futures",
+]
+
 [[package]]
 name = "either"
 version = "1.6.1"
@@ -358,6 +386,16 @@ dependencies = [
  "termcolor",
 ]
 
+[[package]]
+name = "erasable"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f11890ce181d47a64e5d1eb4b6caba0e7bae911a356723740d058a5d0340b7d"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
 [[package]]
 name = "errno"
 version = "0.2.8"
@@ -454,9 +492,9 @@ dependencies = [
 
 [[package]]
 name = "futures"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
+checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -469,9 +507,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
+checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -479,15 +517,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
+checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
+checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -496,15 +534,15 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
+checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
+checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -513,21 +551,21 @@ dependencies = [
 
 [[package]]
 name = "futures-sink"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
+checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
 
 [[package]]
 name = "futures-task"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
+checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
 
 [[package]]
 name = "futures-util"
-version = "0.3.19"
+version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
+checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -625,9 +663,9 @@ dependencies = [
 
 [[package]]
 name = "httparse"
-version = "1.5.1"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
+checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
 
 [[package]]
 name = "httpdate"
@@ -646,9 +684,9 @@ dependencies = [
 
 [[package]]
 name = "hyper"
-version = "0.14.16"
+version = "0.14.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
+checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -659,7 +697,7 @@ dependencies = [
  "http-body",
  "httparse",
  "httpdate",
- "itoa 0.4.8",
+ "itoa 1.0.1",
  "pin-project-lite",
  "socket2",
  "tokio",
@@ -732,6 +770,15 @@ version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
 
+[[package]]
+name = "itertools"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
 version = "0.4.8"
@@ -761,9 +808,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.116"
+version = "0.2.118"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74"
+checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94"
 
 [[package]]
 name = "linked-hash-map"
@@ -917,9 +964,9 @@ dependencies = [
 
 [[package]]
 name = "ntapi"
-version = "0.3.6"
+version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
 dependencies = [
  "winapi",
 ]
@@ -1151,10 +1198,20 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "rc-box"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "411ce666af35dbb23bad34b28f1c349e247c29b6b93573cc9374589dbcf5b884"
+dependencies = [
+ "erasable",
+]
+
 [[package]]
 name = "receqif"
 version = "0.1.0"
 dependencies = [
+ "anyhow",
  "cc",
  "chrono",
  "const_format",
@@ -1356,9 +1413,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "security-framework"
-version = "2.5.0"
+version = "2.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d09d3c15d814eda1d6a836f2f2b56a6abc1446c8a34351cb3180d3db92ffe4ce"
+checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
 dependencies = [
  "bitflags",
  "core-foundation",
@@ -1369,9 +1426,9 @@ dependencies = [
 
 [[package]]
 name = "security-framework-sys"
-version = "2.5.0"
+version = "2.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e90dd10c41c6bfc633da6e0c659bd25d31e0791e5974ac42970267d59eba87f7"
+checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -1379,9 +1436,9 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
+checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7"
 
 [[package]]
 name = "serde"
@@ -1415,9 +1472,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.78"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085"
+checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
 dependencies = [
  "itoa 1.0.1",
  "ryu",
@@ -1553,16 +1610,30 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "take_mut"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
+
+[[package]]
+name = "takecell"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e"
+
 [[package]]
 name = "teloxide"
-version = "0.5.3"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9964854e5ec3a5a44a9f50ebb7641327f1084ab4fc37a6c4a23cc011a388dc2e"
+checksum = "c8e0169f0a02dc7dc3a2a17f2b83d0f616bd366124a723c14e044524b635d711"
 dependencies = [
+ "aquamarine",
  "async-trait",
  "bincode",
  "bytes",
  "derive_more",
+ "dptree",
  "flurry",
  "futures",
  "log",
@@ -1581,10 +1652,11 @@ dependencies = [
 
 [[package]]
 name = "teloxide-core"
-version = "0.3.4"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "114c9057a3a2f74d937ece64029b362f583a69fb4b7405722c6dc03cd5bb4658"
+checksum = "9d067597ddd4bee33b348a6de609beb653d0b226eb721ff08f57e1c65d04ec9d"
 dependencies = [
+ "bitflags",
  "bytes",
  "chrono",
  "derive_more",
@@ -1595,10 +1667,13 @@ dependencies = [
  "never",
  "once_cell",
  "pin-project",
+ "rc-box",
  "reqwest",
  "serde",
  "serde_json",
  "serde_with_macros",
+ "take_mut",
+ "takecell",
  "thiserror",
  "tokio",
  "tokio-util",
@@ -1608,9 +1683,9 @@ dependencies = [
 
 [[package]]
 name = "teloxide-macros"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fb7e97b8bef2231aea6643558147c7f9c112675c4ca49f24d8fac2edff1216d"
+checksum = "fdecc526f8c0ee61d546426fa61a32bc650c4c5c17ba6d97333153ebd562cf3f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1766,9 +1841,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
 
 [[package]]
 name = "tracing"
-version = "0.1.29"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
+checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9"
 dependencies = [
  "cfg-if 1.0.0",
  "pin-project-lite",
@@ -1777,9 +1852,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.21"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
+checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23"
 dependencies = [
  "lazy_static",
 ]
@@ -1816,9 +1891,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.8.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
 
 [[package]]
 name = "unicode-width"

+ 3 - 2
Cargo.toml

@@ -17,7 +17,8 @@ radix_trie = { version = "0.2", features = ["serde"] }
 libc = { version = "0.2" }
 const_format = "0.2"
 futures = { version = "0.3.0", optional = true }
-teloxide = { version = "0.5.3", features = ["auto-send", "macros", "bincode-serializer"], optional = true }
+teloxide = { version = "0.7.0", features = ["auto-send", "macros", "bincode-serializer"], optional = true }
+anyhow = { version = "1.0.52", optional = true }
 log = { version = "0.4.8", optional = true }
 pretty_env_logger = { version = "0.4.0", optional = true }
 tokio = { version =  "1.3", features = ["rt-multi-thread", "macros"], optional = true }
@@ -34,4 +35,4 @@ pkg-config = { version = "0.3", optional = true }
 [features]
 default = [ "telegram" ]
 tv = [ "cc", "pkg-config" ]
-telegram = [ "teloxide", "log", "pretty_env_logger", "tokio", "tokio-stream", "derive_more", "thiserror", "futures" ]
+telegram = [ "teloxide", "log", "pretty_env_logger", "tokio", "tokio-stream", "derive_more", "thiserror", "futures", "anyhow" ]

+ 3 - 2
src/categories.rs

@@ -1,5 +1,5 @@
 #[cfg(feature = "telegram")]
-use crate::telegram::{bot_is_running, input_category_from_tg};
+use crate::telegram::bot_is_running;
 use crate::ui::input_category;
 use libc::isatty;
 use radix_trie::Trie;
@@ -80,6 +80,7 @@ pub fn get_top_category<'a>(item: &str, storage: &'a CatStats) -> Option<&'a str
 }
 
 /// Request category from user via telegram interface
+/*
 #[cfg(feature = "telegram")]
 pub fn get_category_from_tg(
     item: &str,
@@ -98,7 +99,7 @@ pub fn get_category_from_tg(
         String::new()
     }
 }
-
+*/
 /// Choose proper category or ask user
 pub fn get_category(item: &str, storage: &mut CatStats, accounts: &[String]) -> String {
     let istty = unsafe { isatty(libc::STDOUT_FILENO as i32) } != 0;

+ 229 - 176
src/telegram.rs

@@ -1,4 +1,4 @@
-use crate::categories::{get_category_from_tg, CatStats};
+use crate::categories::CatStats;
 use crate::convert::{convert, non_cat_items};
 use crate::tgusermanager::{user_manager, TgManagerCommand};
 use crate::user::User;
@@ -14,11 +14,14 @@ use std::sync::{
 };
 use teloxide::types::*;
 use teloxide::{
-    dispatching::dialogue::{InMemStorage, Storage},
-    DownloadError, RequestError,
+    dispatching2::dialogue::{InMemStorage, Storage},
+    macros::DialogueState,
+    net::Download,
+    prelude2::*,
+    types::File as TgFile,
+    utils::command::BotCommand,
+    Bot, DownloadError, RequestError,
 };
-use teloxide::{net::Download, types::File as TgFile, Bot};
-use teloxide::{prelude::*, utils::command::BotCommand};
 use thiserror::Error;
 use tokio::fs::File;
 use tokio::io::AsyncWriteExt;
@@ -78,16 +81,22 @@ enum Command {
 static IS_RUNNING: AtomicBool = AtomicBool::new(false);
 
 #[cfg(feature = "telegram")]
-async fn download_file(downloader: &Bot, file_id: &str) -> Result<String, FileReceiveError> {
+async fn download_file(
+    downloader: &AutoSend<Bot>,
+    file_id: &str,
+) -> Result<String, FileReceiveError> {
     let TgFile {
         file_id, file_path, ..
     } = downloader.get_file(file_id).send().await?;
+    log::info!("Attempt to download file");
     let filepath = format!("/tmp/{}", file_id);
+    log::info!("Path: {}", filepath);
     let mut file = File::create(&filepath).await?;
     downloader.download_file(&file_path, &mut file).await?;
     Ok(filepath)
 }
 
+/*
 #[cfg(feature = "telegram")]
 async fn convert_file(
     jsonfile: &str,
@@ -118,12 +127,12 @@ async fn convert_file(
     file.write(t.to_string().as_bytes()).await?;
     Ok(filepath)
 }
-
+*/
 #[cfg(feature = "telegram")]
 pub fn bot_is_running() -> bool {
     IS_RUNNING.load(Ordering::SeqCst)
 }
-
+/*
 #[cfg(feature = "telegram")]
 pub async fn input_category_from_tg(
     item: &str,
@@ -149,126 +158,120 @@ pub async fn input_category_from_tg(
         .unwrap();
     String::new()
 }
-
-#[derive(Transition, From, Clone)]
-pub enum Dialogue {
-    Idle(IdleState),
-    NewJson(NewJsonState),
-    CategorySelect(CategorySelectState),
-    SubCategorySelect(SubCategorySelectState),
-    ItemReady(ItemReadyState),
-    Ready(QIFReadyState),
+*/
+#[derive(DialogueState, Clone)]
+#[handler_out(anyhow::Result<()>)]
+pub enum State {
+    #[handler(handle_idle)]
+    Idle,
+
+    #[handler(handle_json)]
+    NewJson { filename: String },
+
+    #[handler(handle_category)]
+    CategorySelect { filename: String, item: String },
+
+    #[handler(handle_subcategory)]
+    SubCategorySelect {
+        filename: String,
+        item: String,
+        category: String,
+    },
+
+    #[handler(handle_item_ready)]
+    ItemReady {
+        filename: String,
+        item: String,
+        fullcat: String,
+    },
+
+    #[handler(handle_qif_ready)]
+    Ready,
 }
 
-impl Default for Dialogue {
+impl Default for State {
     fn default() -> Self {
-        Self::Idle(IdleState)
+        Self::Idle
     }
 }
 
-#[derive(Clone)]
-pub struct IdleState;
-
-#[derive(Clone)]
-pub struct NewJsonState {
-    pub filename: String,
-}
-
-#[derive(Clone)]
-pub struct CategorySelectState {
-    pub filename: String,
-    pub item: String,
-}
-
-#[derive(Clone)]
-pub struct SubCategorySelectState {
-    pub filename: String,
-    pub item: String,
-    pub category: String,
-}
-
-#[derive(Clone)]
-pub struct ItemReadyState {
-    pub filename: String,
-    pub item: String,
-    pub fullcat: String,
+type QIFDialogue = Dialogue<State, InMemStorage<State>>;
+
+async fn handle_idle(
+    bot: AutoSend<Bot>,
+    msg: Message,
+    dialogue: QIFDialogue,
+) -> anyhow::Result<()> {
+    bot.send_message(msg.chat.id, "Upload your file").await?;
+    dialogue
+        .update(State::NewJson {
+            filename: "test".to_string(),
+        })
+        .await?;
+    Ok(())
 }
 
-#[derive(Clone)]
-pub struct QIFReadyState;
-
-#[teloxide(subtransition)]
-async fn new_json(
-    state: NewJsonState,
-    cx: TransitionIn<AutoSend<Bot>>,
-    item: String,
-) -> TransitionOut<Dialogue> {
-    log::info!("File {}", &state.filename);
+async fn handle_json(
+    bot: AutoSend<Bot>,
+    msg: Message,
+    dialogue: QIFDialogue,
+    (filename,): (String,), // Available from `State::Idle`.
+) -> anyhow::Result<()> {
+    log::info!("File {}", &filename);
     let mut is_file = false;
     let mut file_id: String = "".to_string();
     {
-        let update = &cx.update;
-        if let MessageKind::Common(msg) = &update.kind {
+        if let MessageKind::Common(msg) = &msg.kind {
+            log::info!("It's message");
             if let MediaKind::Document(doc) = &msg.media_kind {
                 is_file = true;
-                file_id = String::from_str(&state.filename).unwrap_or("".to_string());
+                file_id = String::from_str(&doc.document.file_id).unwrap_or("".to_string());
+                log::info!("It's file with id {:}", file_id);
             }
         }
     }
+
     if is_file {
         log::info!("File {} received", file_id);
-        cx.answer(format!("New file received!!!111 {}", file_id))
+        bot.send_message(msg.chat.id, format!("New file received!!!111 {}", file_id))
             .await?;
     } else {
-        cx.answer(format!("Unsupported media provided")).await?;
+        bot.send_message(msg.chat.id, format!("Unsupported media provided"))
+            .await?;
     }
 
-    if let Ok(newfile) = download_file(cx.requester.inner(), &file_id).await {
-        cx.answer(format!("File received: {:} ", newfile)).await?;
-        if let Some(tguser) = cx.update.from() {
-            let user = User::new(tguser.id, &None);
-            cx.answer(format!("Active user: {:} ", tguser.id)).await?;
-            let filepath = format!("{}.qif", &newfile);
-            log::info!("Received file {}", &filepath);
-            let mut i = non_cat_items(&newfile, &user);
-            if let Some(item) = i.pop() {
-                log::info!("No category for {}", &item);
-                cx.answer(format!("Select category for {}", item)).await?;
-                next(CategorySelectState {
-                    filename: state.filename,
-                    item,
+    if let Ok(newfile) = download_file(&bot, &file_id).await {
+        bot.send_message(msg.chat.id, format!("File received: {:} ", newfile))
+            .await?;
+        let user = User::new(msg.chat.id, &None);
+        bot.send_message(msg.chat.id, format!("Active user: {:} ", msg.chat.id))
+            .await?;
+        let filepath = format!("{}.qif", &newfile);
+        log::info!("Received file {}", &filepath);
+        let mut i = non_cat_items(&newfile, &user);
+        if let Some(item) = i.pop() {
+            log::info!("No category for {}", &item);
+            bot.send_message(msg.chat.id, format!("Select category for {}", item))
+                .await?;
+            dialogue
+                .update(State::CategorySelect {
+                    filename: filename,
+                    item: item,
                 })
-            } else {
-                log::info!("Empty state");
-                next(state)
-            }
-
-        /*            if let Ok(result) = convert_file(&newfile, &mut user, &cx).await {
-                        cx.answer(format!("File converted into: {:} ", result))
-                            .await?;
-                        next(CategorySelectState { item: file_id })
-
-                    } else {
-                        next(state)
-                    }
-        */
+                .await?;
         } else {
             log::info!("Empty state 2");
-            next(state)
         }
-    } else {
-        log::info!("Newfile {} fail", item);
-        cx.answer("Waiting for a JSON receipt in new_json").await?;
-        next(state)
     }
+    Ok(())
 }
 
-#[teloxide(subtransition)]
-async fn category_select(
-    state: CategorySelectState,
-    cx: TransitionIn<AutoSend<Bot>>,
-    ans: String,
-) -> TransitionOut<Dialogue> {
+async fn handle_category(
+    bot: AutoSend<Bot>,
+    msg: Message,
+    dialogue: QIFDialogue,
+    (filename, item): (String, String), // Available from `State::Idle`.
+) -> anyhow::Result<()> {
     let accounts = [
         "Expenses:Alco".to_string(),
         "Expenses:Groceries".to_string(),
@@ -285,67 +288,78 @@ async fn category_select(
             }),
     );
 
-    cx.answer(format!("Input category for {}", state.item))
+    bot.send_message(msg.chat.id, format!("Input subcategory for {}", item))
         .reply_markup(ReplyMarkup::InlineKeyboard(keyboard))
         .await?;
 
-    next(SubCategorySelectState {
-        filename: state.filename,
-        item: state.item,
-        category: ans,
-    })
+    match msg.text() {
+        Some(cat) => {
+            dialogue
+                .update(State::SubCategorySelect {
+                    filename: filename,
+                    item: item,
+                    category: cat.to_string(),
+                })
+                .await?;
+        }
+        None => {
+            bot.send_message(msg.chat.id, "Send me a category.").await?;
+        }
+    }
+    Ok(())
 }
 
-#[teloxide(subtransition)]
-async fn subcategory_select(
-    state: SubCategorySelectState,
-    cx: TransitionIn<AutoSend<Bot>>,
-    subcategory: String,
-) -> TransitionOut<Dialogue> {
-    cx.answer(format!("Select subcategory for {}", state.item))
-        .await?;
-    next(ItemReadyState {
-        filename: state.filename,
-        item: state.item,
-        fullcat: format!("{}:{}", state.category, subcategory),
-    })
+async fn handle_subcategory(
+    bot: AutoSend<Bot>,
+    msg: Message,
+    dialogue: QIFDialogue,
+    (filename, item, category): (String, String, String), // Available from `State::Idle`.
+) -> anyhow::Result<()> {
+    match msg.text() {
+        Some(subcategory) => {
+            bot.send_message(msg.chat.id, "Item ready").await?;
+            dialogue
+                .update(State::ItemReady {
+                    filename: filename,
+                    item: item,
+                    fullcat: format!("{}:{}", category, subcategory),
+                })
+                .await?;
+        }
+        None => {
+            bot.send_message(msg.chat.id, "Send me a subcategory.")
+                .await?;
+        }
+    }
+    Ok(())
 }
 
-#[teloxide(subtransition)]
-async fn item_ready(
-    state: ItemReadyState,
-    cx: TransitionIn<AutoSend<Bot>>,
-    item: String,
-) -> TransitionOut<Dialogue> {
-    cx.answer(format!(
-        "Item {} is ready for caterogy {}",
-        state.item, state.fullcat
-    ))
+async fn handle_item_ready(
+    bot: AutoSend<Bot>,
+    msg: Message,
+    dialogue: QIFDialogue,
+    (filename, item, fullcat): (String, String, String), // Available from `State::Idle`.
+) -> anyhow::Result<()> {
+    bot.send_message(
+        msg.chat.id,
+        format!("Item {} is ready for caterogy {}", item, fullcat),
+    )
     .await?;
-    next(QIFReadyState)
-}
-
-#[teloxide(subtransition)]
-async fn qif_ready(
-    state: QIFReadyState,
-    cx: TransitionIn<AutoSend<Bot>>,
-    item: String,
-) -> TransitionOut<Dialogue> {
-    cx.answer(format!("QIF is ready for {}", item)).await?;
-    next(IdleState)
+    dialogue.update(State::Ready).await?;
+    Ok(())
 }
 
-#[teloxide(subtransition)]
-async fn idling(
-    state: IdleState,
-    cx: TransitionIn<AutoSend<Bot>>,
-    item: String,
-) -> TransitionOut<Dialogue> {
-    cx.answer(format!("Waiting for json or command")).await?;
-    next(state)
+async fn handle_qif_ready(
+    bot: AutoSend<Bot>,
+    msg: Message,
+    dialogue: QIFDialogue,
+) -> anyhow::Result<()> {
+    bot.send_message(msg.chat.id, "QIF is ready.").await?;
+    dialogue.update(State::Idle).await?;
+    Ok(())
 }
-
-type StorageError = <InMemStorage<Dialogue> as Storage<Dialogue>>::Error;
+/*
+type StorageError = <InMemStorage<QIFDialogue> as Storage<QIFDialogue>>::Error;
 
 #[derive(Debug, Error)]
 enum Error {
@@ -463,6 +477,8 @@ where
             Some(Message { id, chat, .. }) => {
                 //                bot.edit_message_text(chat.id, id, text).await?;
                 bot.send_message(chat.id, text).await?;
+                let d = stor.get_dialogue(chat.id);
+                d.next(d);
             }
             None => {
                 if let Some(id) = query.inline_message_id {
@@ -475,6 +491,27 @@ where
         log::info!("You chose: {}", version);
     }
 
+    Ok(())
+}*/
+
+async fn callback_handler(q: CallbackQuery, bot: AutoSend<Bot>) -> anyhow::Result<()> {
+    if let Some(version) = q.data {
+        let text = format!("You chose: {}", version);
+
+        match q.message {
+            Some(Message { id, chat, .. }) => {
+                bot.edit_message_text(chat.id, id, text).await?;
+            }
+            None => {
+                if let Some(id) = q.inline_message_id {
+                    bot.edit_message_text_inline(id, text).await?;
+                }
+            }
+        }
+
+        log::info!("You chose: {}", version);
+    }
+
     Ok(())
 }
 
@@ -487,37 +524,53 @@ async fn run() {
 
     let manager = tokio::spawn(async move { user_manager(&mut rx).await });
 
-    let storage = InMemStorage::new();
+    //    let storage = InMemStorage::new();
 
     let bot = Bot::from_env().auto_send();
-    // TODO: Add Dispatcher to process UpdateKinds
-    Dispatcher::new(bot)
-        .messages_handler(DialogueDispatcher::with_storage(
-            move |DialogueWithCx { cx, dialogue }: In| {
-                let _tx = tx.clone();
-                async move {
-                    let dialogue = dialogue.expect("std::convert::Infallible");
-                    handle_message(cx, dialogue, _tx)
-                        .await
-                        .expect("Something wrong with the bot!")
-                }
-            },
-            storage.clone(),
-        ))
-        .callback_queries_handler({
-            move |rx: DispatcherHandlerRx<AutoSend<Bot>, CallbackQuery>| {
-                UnboundedReceiverStream::new(rx).for_each_concurrent(None, {
-                    move |cx| {
-                        let storage = storage.clone();
-                        async move {
-                            callback_handler(cx, storage).await.log_on_error().await;
-                        }
-                    }
-                })
-            }
-        })
+    let handler = dptree::entry()
+        .branch(
+            Update::filter_message()
+                .enter_dialogue::<Message, InMemStorage<State>, State>()
+                .dispatch_by::<State>(),
+        )
+        .branch(Update::filter_callback_query().endpoint(callback_handler));
+
+    Dispatcher::builder(bot, handler)
+        .dependencies(dptree::deps![InMemStorage::<State>::new()])
+        .build()
+        .setup_ctrlc_handler()
         .dispatch()
         .await;
+    /*
+        // TODO: Add Dispatcher to process UpdateKinds
+        Dispatcher::new(bot)
+            .messages_handler(DialogueDispatcher::with_storage(
+                move |DialogueWithCx { cx, dialogue }: In| {
+                    let _tx = tx.clone();
+                    async move {
+                        let dialogue = dialogue.expect("std::convert::Infallible");
+                        handle_message(cx, dialogue, _tx)
+                            .await
+                            .expect("Something wrong with the bot!")
+                    }
+                },
+                storage.clone(),
+            ))
+            .callback_queries_handler({
+                move |rx: DispatcherHandlerRx<AutoSend<Bot>, CallbackQuery>| {
+                    UnboundedReceiverStream::new(rx).for_each_concurrent(None, {
+                        move |cx| {
+                            let storage = storage.clone();
+                            async move {
+                                callback_handler(cx, storage).await.log_on_error().await;
+                            }
+                        }
+                    })
+                }
+            })
+            .dispatch()
+            .await;
+    */
     drop(manager);
     IS_RUNNING.store(false, Ordering::SeqCst);
 }