Hex Artifact Content
Logged in as anonymous

Artifact d44f60dcb6162e3e20ca4d5051453861195cde7d7e3ffae2410c0649ce41d3c2:


0000: 75 73 65 20 63 72 61 74 65 3a 3a 63 6f 6d 6d 61  use crate::comma
0010: 6e 64 3b 0a 0a 75 73 65 20 73 74 64 3a 3a 7b 0a  nd;..use std::{.
0020: 09 62 6f 72 72 6f 77 3a 3a 43 6f 77 2c 0a 09 63  .borrow::Cow,..c
0030: 6f 6c 6c 65 63 74 69 6f 6e 73 3a 3a 7b 0a 09 09  ollections::{...
0040: 42 54 72 65 65 4d 61 70 2c 0a 09 09 48 61 73 68  BTreeMap,...Hash
0050: 53 65 74 2c 0a 09 7d 2c 0a 09 6e 75 6d 3a 3a 54  Set,..},..num::T
0060: 72 79 46 72 6f 6d 49 6e 74 45 72 72 6f 72 2c 0a  ryFromIntError,.
0070: 09 73 79 6e 63 3a 3a 7b 0a 09 09 41 72 63 2c 0a  .sync::{...Arc,.
0080: 09 09 4d 75 74 65 78 0a 09 7d 2c 0a 7d 3b 0a 0a  ..Mutex..},.};..
0090: 75 73 65 20 61 6e 79 68 6f 77 3a 3a 7b 0a 09 61  use anyhow::{..a
00a0: 6e 79 68 6f 77 2c 0a 09 62 61 69 6c 2c 0a 09 52  nyhow,..bail,..R
00b0: 65 73 75 6c 74 2c 0a 7d 3b 0a 75 73 65 20 61 73  esult,.};.use as
00c0: 79 6e 63 5f 73 74 64 3a 3a 74 61 73 6b 3b 0a 75  ync_std::task;.u
00d0: 73 65 20 63 68 72 6f 6e 6f 3a 3a 44 61 74 65 54  se chrono::DateT
00e0: 69 6d 65 3b 0a 75 73 65 20 66 72 61 6e 6b 65 6e  ime;.use franken
00f0: 73 74 65 69 6e 3a 3a 7b 0a 09 63 6c 69 65 6e 74  stein::{..client
0100: 5f 72 65 71 77 65 73 74 3a 3a 42 6f 74 2c 0a 09  _reqwest::Bot,..
0110: 6d 65 74 68 6f 64 73 3a 3a 7b 0a 09 09 47 65 74  methods::{...Get
0120: 55 70 64 61 74 65 73 50 61 72 61 6d 73 2c 0a 09  UpdatesParams,..
0130: 09 53 65 6e 64 4d 65 73 73 61 67 65 50 61 72 61  .SendMessagePara
0140: 6d 73 0a 09 7d 2c 0a 09 74 79 70 65 73 3a 3a 7b  ms..},..types::{
0150: 0a 09 09 41 6c 6c 6f 77 65 64 55 70 64 61 74 65  ...AllowedUpdate
0160: 2c 0a 09 09 4d 65 73 73 61 67 65 45 6e 74 69 74  ,...MessageEntit
0170: 79 54 79 70 65 2c 0a 09 09 55 73 65 72 2c 0a 09  yType,...User,..
0180: 7d 2c 0a 09 75 70 64 61 74 65 73 3a 3a 55 70 64  },..updates::Upd
0190: 61 74 65 43 6f 6e 74 65 6e 74 2c 0a 09 41 73 79  ateContent,..Asy
01a0: 6e 63 54 65 6c 65 67 72 61 6d 41 70 69 2c 0a 09  ncTelegramApi,..
01b0: 50 61 72 73 65 4d 6f 64 65 2c 0a 7d 3b 0a 75 73  ParseMode,.};.us
01c0: 65 20 73 71 6c 78 3a 3a 70 6f 73 74 67 72 65 73  e sqlx::postgres
01d0: 3a 3a 50 67 50 6f 6f 6c 4f 70 74 69 6f 6e 73 3b  ::PgPoolOptions;
01e0: 0a 75 73 65 20 74 68 69 73 65 72 72 6f 72 3a 3a  .use thiserror::
01f0: 45 72 72 6f 72 3b 0a 0a 23 5b 64 65 72 69 76 65  Error;..#[derive
0200: 28 45 72 72 6f 72 2c 20 44 65 62 75 67 29 5d 0a  (Error, Debug)].
0210: 70 75 62 20 65 6e 75 6d 20 52 73 73 45 72 72 6f  pub enum RssErro
0220: 72 20 7b 0a 09 2f 2f 20 23 5b 65 72 72 6f 72 28  r {..// #[error(
0230: 74 72 61 6e 73 70 61 72 65 6e 74 29 5d 0a 09 2f  transparent)]../
0240: 2f 20 54 67 28 23 5b 66 72 6f 6d 5d 20 54 67 45  / Tg(#[from] TgE
0250: 72 72 6f 72 29 2c 0a 09 23 5b 65 72 72 6f 72 28  rror),..#[error(
0260: 74 72 61 6e 73 70 61 72 65 6e 74 29 5d 0a 09 49  transparent)]..I
0270: 6e 74 28 23 5b 66 72 6f 6d 5d 20 54 72 79 46 72  nt(#[from] TryFr
0280: 6f 6d 49 6e 74 45 72 72 6f 72 29 2c 0a 7d 0a 0a  omIntError),.}..
0290: 23 5b 64 65 72 69 76 65 28 43 6c 6f 6e 65 29 5d  #[derive(Clone)]
02a0: 0a 70 75 62 20 73 74 72 75 63 74 20 43 6f 72 65  .pub struct Core
02b0: 20 7b 0a 09 6f 77 6e 65 72 5f 63 68 61 74 3a 20   {..owner_chat: 
02c0: 69 36 34 2c 0a 09 70 75 62 20 74 67 3a 20 42 6f  i64,..pub tg: Bo
02d0: 74 2c 0a 09 70 75 62 20 6d 65 3a 20 55 73 65 72  t,..pub me: User
02e0: 2c 0a 09 70 6f 6f 6c 3a 20 73 71 6c 78 3a 3a 50  ,..pool: sqlx::P
02f0: 6f 6f 6c 3c 73 71 6c 78 3a 3a 50 6f 73 74 67 72  ool<sqlx::Postgr
0300: 65 73 3e 2c 0a 09 73 6f 75 72 63 65 73 3a 20 41  es>,..sources: A
0310: 72 63 3c 4d 75 74 65 78 3c 48 61 73 68 53 65 74  rc<Mutex<HashSet
0320: 3c 41 72 63 3c 69 33 32 3e 3e 3e 3e 2c 0a 09 68  <Arc<i32>>>>,..h
0330: 74 74 70 5f 63 6c 69 65 6e 74 3a 20 72 65 71 77  ttp_client: reqw
0340: 65 73 74 3a 3a 43 6c 69 65 6e 74 2c 0a 7d 0a 0a  est::Client,.}..
0350: 69 6d 70 6c 20 43 6f 72 65 20 7b 0a 09 70 75 62  impl Core {..pub
0360: 20 61 73 79 6e 63 20 66 6e 20 6e 65 77 28 73 65   async fn new(se
0370: 74 74 69 6e 67 73 3a 20 63 6f 6e 66 69 67 3a 3a  ttings: config::
0380: 43 6f 6e 66 69 67 29 20 2d 3e 20 52 65 73 75 6c  Config) -> Resul
0390: 74 3c 41 72 63 3c 43 6f 72 65 3e 3e 20 7b 0a 09  t<Arc<Core>> {..
03a0: 09 6c 65 74 20 6f 77 6e 65 72 5f 63 68 61 74 20  .let owner_chat 
03b0: 3d 20 73 65 74 74 69 6e 67 73 2e 67 65 74 5f 69  = settings.get_i
03c0: 6e 74 28 22 6f 77 6e 65 72 22 29 3f 3b 0a 09 09  nt("owner")?;...
03d0: 6c 65 74 20 61 70 69 5f 6b 65 79 20 3d 20 73 65  let api_key = se
03e0: 74 74 69 6e 67 73 2e 67 65 74 5f 73 74 72 69 6e  ttings.get_strin
03f0: 67 28 22 61 70 69 5f 6b 65 79 22 29 3f 3b 0a 09  g("api_key")?;..
0400: 09 6c 65 74 20 74 67 20 3d 20 42 6f 74 3a 3a 6e  .let tg = Bot::n
0410: 65 77 28 26 61 70 69 5f 6b 65 79 29 3b 0a 0a 09  ew(&api_key);...
0420: 09 6c 65 74 20 6d 75 74 20 63 6c 69 65 6e 74 20  .let mut client 
0430: 3d 20 72 65 71 77 65 73 74 3a 3a 43 6c 69 65 6e  = reqwest::Clien
0440: 74 3a 3a 62 75 69 6c 64 65 72 28 29 3b 0a 09 09  t::builder();...
0450: 69 66 20 6c 65 74 20 4f 6b 28 70 72 6f 78 79 29  if let Ok(proxy)
0460: 20 3d 20 73 65 74 74 69 6e 67 73 2e 67 65 74 5f   = settings.get_
0470: 73 74 72 69 6e 67 28 22 70 72 6f 78 79 22 29 20  string("proxy") 
0480: 7b 0a 09 09 09 6c 65 74 20 70 72 6f 78 79 20 3d  {....let proxy =
0490: 20 72 65 71 77 65 73 74 3a 3a 50 72 6f 78 79 3a   reqwest::Proxy:
04a0: 3a 61 6c 6c 28 70 72 6f 78 79 29 3f 3b 0a 09 09  :all(proxy)?;...
04b0: 09 63 6c 69 65 6e 74 20 3d 20 63 6c 69 65 6e 74  .client = client
04c0: 2e 70 72 6f 78 79 28 70 72 6f 78 79 29 3b 0a 09  .proxy(proxy);..
04d0: 09 7d 0a 09 09 6c 65 74 20 68 74 74 70 5f 63 6c  .}...let http_cl
04e0: 69 65 6e 74 20 3d 20 63 6c 69 65 6e 74 2e 62 75  ient = client.bu
04f0: 69 6c 64 28 29 3f 3b 0a 09 09 6c 65 74 20 6d 65  ild()?;...let me
0500: 20 3d 20 74 67 2e 67 65 74 5f 6d 65 28 29 2e 61   = tg.get_me().a
0510: 77 61 69 74 3f 3b 0a 09 09 6c 65 74 20 6d 65 20  wait?;...let me 
0520: 3d 20 6d 65 2e 72 65 73 75 6c 74 3b 0a 09 09 6c  = me.result;...l
0530: 65 74 20 63 6f 72 65 20 3d 20 41 72 63 3a 3a 6e  et core = Arc::n
0540: 65 77 28 43 6f 72 65 20 7b 0a 09 09 09 74 67 2c  ew(Core {....tg,
0550: 0a 09 09 09 6d 65 2c 0a 09 09 09 6f 77 6e 65 72  ....me,....owner
0560: 5f 63 68 61 74 2c 0a 09 09 09 70 6f 6f 6c 3a 20  _chat,....pool: 
0570: 50 67 50 6f 6f 6c 4f 70 74 69 6f 6e 73 3a 3a 6e  PgPoolOptions::n
0580: 65 77 28 29 0a 09 09 09 09 2e 6d 61 78 5f 63 6f  ew()......max_co
0590: 6e 6e 65 63 74 69 6f 6e 73 28 35 29 0a 09 09 09  nnections(5)....
05a0: 09 2e 61 63 71 75 69 72 65 5f 74 69 6d 65 6f 75  ..acquire_timeou
05b0: 74 28 73 74 64 3a 3a 74 69 6d 65 3a 3a 44 75 72  t(std::time::Dur
05c0: 61 74 69 6f 6e 3a 3a 6e 65 77 28 33 30 30 2c 20  ation::new(300, 
05d0: 30 29 29 0a 09 09 09 09 2e 69 64 6c 65 5f 74 69  0))......idle_ti
05e0: 6d 65 6f 75 74 28 73 74 64 3a 3a 74 69 6d 65 3a  meout(std::time:
05f0: 3a 44 75 72 61 74 69 6f 6e 3a 3a 6e 65 77 28 36  :Duration::new(6
0600: 30 2c 20 30 29 29 0a 09 09 09 09 2e 63 6f 6e 6e  0, 0))......conn
0610: 65 63 74 5f 6c 61 7a 79 28 26 73 65 74 74 69 6e  ect_lazy(&settin
0620: 67 73 2e 67 65 74 5f 73 74 72 69 6e 67 28 22 70  gs.get_string("p
0630: 67 22 29 3f 29 3f 2c 0a 09 09 09 73 6f 75 72 63  g")?)?,....sourc
0640: 65 73 3a 20 41 72 63 3a 3a 6e 65 77 28 4d 75 74  es: Arc::new(Mut
0650: 65 78 3a 3a 6e 65 77 28 48 61 73 68 53 65 74 3a  ex::new(HashSet:
0660: 3a 6e 65 77 28 29 29 29 2c 0a 09 09 09 68 74 74  :new())),....htt
0670: 70 5f 63 6c 69 65 6e 74 2c 0a 09 09 7d 29 3b 0a  p_client,...});.
0680: 09 09 6c 65 74 20 63 6c 6f 6e 65 20 3d 20 63 6f  ..let clone = co
0690: 72 65 2e 63 6c 6f 6e 65 28 29 3b 0a 09 09 74 61  re.clone();...ta
06a0: 73 6b 3a 3a 73 70 61 77 6e 28 61 73 79 6e 63 20  sk::spawn(async 
06b0: 6d 6f 76 65 20 7b 0a 09 09 09 6c 6f 6f 70 20 7b  move {....loop {
06c0: 0a 09 09 09 09 6c 65 74 20 64 65 6c 61 79 20 3d  .....let delay =
06d0: 20 6d 61 74 63 68 20 26 63 6c 6f 6e 65 2e 61 75   match &clone.au
06e0: 74 6f 66 65 74 63 68 28 29 2e 61 77 61 69 74 20  tofetch().await 
06f0: 7b 0a 09 09 09 09 09 45 72 72 28 65 72 72 29 20  {......Err(err) 
0700: 3d 3e 20 7b 0a 09 09 09 09 09 09 69 66 20 6c 65  => {.......if le
0710: 74 20 45 72 72 28 65 72 72 29 20 3d 20 63 6c 6f  t Err(err) = clo
0720: 6e 65 2e 73 65 6e 64 28 66 6f 72 6d 61 74 21 28  ne.send(format!(
0730: 22 f0 9f 9b 91 20 7b 65 72 72 3a 3f 7d 22 29 2c  "šŸ›‘ {err:?}"),
0740: 20 4e 6f 6e 65 2c 20 4e 6f 6e 65 29 2e 61 77 61   None, None).awa
0750: 69 74 20 7b 0a 09 09 09 09 09 09 09 65 70 72 69  it {........epri
0760: 6e 74 6c 6e 21 28 22 41 75 74 6f 66 65 74 63 68  ntln!("Autofetch
0770: 20 65 72 72 6f 72 3a 20 7b 65 72 72 3a 3f 7d 22   error: {err:?}"
0780: 29 3b 0a 09 09 09 09 09 09 7d 3b 0a 09 09 09 09  );.......};.....
0790: 09 09 73 74 64 3a 3a 74 69 6d 65 3a 3a 44 75 72  ..std::time::Dur
07a0: 61 74 69 6f 6e 3a 3a 66 72 6f 6d 5f 73 65 63 73  ation::from_secs
07b0: 28 36 30 29 0a 09 09 09 09 09 7d 2c 0a 09 09 09  (60)......},....
07c0: 09 09 4f 6b 28 74 69 6d 65 29 20 3d 3e 20 2a 74  ..Ok(time) => *t
07d0: 69 6d 65 2c 0a 09 09 09 09 7d 3b 0a 09 09 09 09  ime,.....};.....
07e0: 74 61 73 6b 3a 3a 73 6c 65 65 70 28 64 65 6c 61  task::sleep(dela
07f0: 79 29 2e 61 77 61 69 74 3b 0a 09 09 09 7d 0a 09  y).await;....}..
0800: 09 7d 29 3b 0a 09 09 4f 6b 28 63 6f 72 65 29 0a  .});...Ok(core).
0810: 09 7d 0a 0a 09 70 75 62 20 61 73 79 6e 63 20 66  .}...pub async f
0820: 6e 20 73 74 72 65 61 6d 28 26 73 65 6c 66 29 20  n stream(&self) 
0830: 2d 3e 20 52 65 73 75 6c 74 3c 28 29 3e 20 7b 0a  -> Result<()> {.
0840: 09 09 6c 65 74 20 6d 75 74 20 6f 66 66 73 65 74  ..let mut offset
0850: 3a 20 69 36 34 20 3d 20 30 3b 0a 09 09 6c 65 74  : i64 = 0;...let
0860: 20 6d 75 74 20 70 61 72 61 6d 73 20 3d 20 47 65   mut params = Ge
0870: 74 55 70 64 61 74 65 73 50 61 72 61 6d 73 20 7b  tUpdatesParams {
0880: 0a 09 09 09 6f 66 66 73 65 74 3a 20 4e 6f 6e 65  ....offset: None
0890: 2c 0a 09 09 09 6c 69 6d 69 74 3a 20 53 6f 6d 65  ,....limit: Some
08a0: 28 31 30 30 29 2c 0a 09 09 09 74 69 6d 65 6f 75  (100),....timeou
08b0: 74 3a 20 53 6f 6d 65 28 33 30 30 29 2c 0a 09 09  t: Some(300),...
08c0: 09 61 6c 6c 6f 77 65 64 5f 75 70 64 61 74 65 73  .allowed_updates
08d0: 3a 20 53 6f 6d 65 28 76 65 63 21 5b 41 6c 6c 6f  : Some(vec![Allo
08e0: 77 65 64 55 70 64 61 74 65 3a 3a 4d 65 73 73 61  wedUpdate::Messa
08f0: 67 65 5d 29 2c 0a 09 09 7d 3b 0a 09 09 6c 6f 6f  ge]),...};...loo
0900: 70 20 7b 0a 09 09 09 6c 65 74 20 75 70 64 61 74  p {....let updat
0910: 65 73 20 3d 20 73 65 6c 66 2e 74 67 2e 67 65 74  es = self.tg.get
0920: 5f 75 70 64 61 74 65 73 28 26 70 61 72 61 6d 73  _updates(&params
0930: 29 2e 61 77 61 69 74 3f 2e 72 65 73 75 6c 74 3b  ).await?.result;
0940: 0a 09 09 09 69 66 20 75 70 64 61 74 65 73 2e 69  ....if updates.i
0950: 73 5f 65 6d 70 74 79 28 29 20 7b 0a 09 09 09 09  s_empty() {.....
0960: 6f 66 66 73 65 74 20 3d 20 30 3b 0a 09 09 09 09  offset = 0;.....
0970: 70 61 72 61 6d 73 2e 6f 66 66 73 65 74 20 3d 20  params.offset = 
0980: 4e 6f 6e 65 3b 0a 09 09 09 09 63 6f 6e 74 69 6e  None;.....contin
0990: 75 65 3b 0a 09 09 09 7d 0a 09 09 09 66 6f 72 20  ue;....}....for 
09a0: 75 70 64 61 74 65 20 69 6e 20 75 70 64 61 74 65  update in update
09b0: 73 20 7b 0a 09 09 09 09 69 66 20 69 36 34 3a 3a  s {.....if i64::
09c0: 66 72 6f 6d 28 75 70 64 61 74 65 2e 75 70 64 61  from(update.upda
09d0: 74 65 5f 69 64 29 20 3e 3d 20 6f 66 66 73 65 74  te_id) >= offset
09e0: 20 7b 0a 09 09 09 09 09 6f 66 66 73 65 74 20 3d   {......offset =
09f0: 20 69 36 34 3a 3a 66 72 6f 6d 28 75 70 64 61 74   i64::from(updat
0a00: 65 2e 75 70 64 61 74 65 5f 69 64 29 20 2b 20 31  e.update_id) + 1
0a10: 3b 0a 09 09 09 09 09 70 61 72 61 6d 73 2e 6f 66  ;......params.of
0a20: 66 73 65 74 20 3d 20 53 6f 6d 65 28 6f 66 66 73  fset = Some(offs
0a30: 65 74 29 3b 0a 09 09 09 09 7d 0a 09 09 09 09 69  et);.....}.....i
0a40: 66 20 6c 65 74 20 55 70 64 61 74 65 43 6f 6e 74  f let UpdateCont
0a50: 65 6e 74 3a 3a 4d 65 73 73 61 67 65 28 6d 73 67  ent::Message(msg
0a60: 29 20 3d 20 75 70 64 61 74 65 2e 63 6f 6e 74 65  ) = update.conte
0a70: 6e 74 20 7b 0a 09 09 09 09 09 69 66 20 6c 65 74  nt {......if let
0a80: 20 53 6f 6d 65 28 74 65 78 74 29 20 3d 20 6d 73   Some(text) = ms
0a90: 67 2e 74 65 78 74 20 7b 0a 09 09 09 09 09 09 69  g.text {.......i
0aa0: 66 20 6c 65 74 20 53 6f 6d 65 28 65 6e 74 69 74  f let Some(entit
0ab0: 69 65 73 29 20 3d 20 6d 73 67 2e 65 6e 74 69 74  ies) = msg.entit
0ac0: 69 65 73 20 7b 0a 09 09 09 09 09 09 09 6c 65 74  ies {........let
0ad0: 20 63 68 61 72 73 3a 20 56 65 63 3c 75 31 36 3e   chars: Vec<u16>
0ae0: 20 3d 20 74 65 78 74 2e 65 6e 63 6f 64 65 5f 75   = text.encode_u
0af0: 74 66 31 36 28 29 2e 63 6f 6c 6c 65 63 74 28 29  tf16().collect()
0b00: 3b 0a 09 09 09 09 09 09 09 66 6f 72 20 65 6e 74  ;........for ent
0b10: 69 74 79 20 69 6e 20 65 6e 74 69 74 69 65 73 20  ity in entities 
0b20: 7b 0a 09 09 09 09 09 09 09 09 69 66 20 65 6e 74  {.........if ent
0b30: 69 74 79 2e 74 79 70 65 5f 66 69 65 6c 64 20 3d  ity.type_field =
0b40: 3d 20 4d 65 73 73 61 67 65 45 6e 74 69 74 79 54  = MessageEntityT
0b50: 79 70 65 3a 3a 42 6f 74 43 6f 6d 6d 61 6e 64 20  ype::BotCommand 
0b60: 26 26 20 65 6e 74 69 74 79 2e 6f 66 66 73 65 74  && entity.offset
0b70: 20 21 3d 20 30 20 7b 0a 09 09 09 09 09 09 09 09   != 0 {.........
0b80: 09 62 61 69 6c 21 28 22 63 6f 6d 6d 61 6e 64 73  .bail!("commands
0b90: 20 73 68 6f 75 6c 64 20 62 65 20 61 74 20 6d 65   should be at me
0ba0: 73 73 61 67 65 20 73 74 61 72 74 22 29 3b 0a 09  ssage start");..
0bb0: 09 09 09 09 09 09 09 7d 3b 0a 09 09 09 09 09 09  .......};.......
0bc0: 09 09 6c 65 74 20 63 6d 64 20 3d 20 53 74 72 69  ..let cmd = Stri
0bd0: 6e 67 3a 3a 66 72 6f 6d 5f 75 74 66 31 36 5f 6c  ng::from_utf16_l
0be0: 6f 73 73 79 28 26 63 68 61 72 73 5b 65 6e 74 69  ossy(&chars[enti
0bf0: 74 79 2e 6f 66 66 73 65 74 20 61 73 20 75 73 69  ty.offset as usi
0c00: 7a 65 2e 2e 65 6e 74 69 74 79 2e 6c 65 6e 67 74  ze..entity.lengt
0c10: 68 20 61 73 20 75 73 69 7a 65 5d 29 3b 0a 09 09  h as usize]);...
0c20: 09 09 09 09 09 09 6c 65 74 20 77 6f 72 64 73 3a  ......let words:
0c30: 20 56 65 63 3c 26 73 74 72 3e 20 3d 20 74 65 78   Vec<&str> = tex
0c40: 74 2e 73 70 6c 69 74 5f 77 68 69 74 65 73 70 61  t.split_whitespa
0c50: 63 65 28 29 2e 63 6f 6c 6c 65 63 74 28 29 3b 0a  ce().collect();.
0c60: 09 09 09 09 09 09 09 09 6d 61 74 63 68 20 63 6d  ........match cm
0c70: 64 2e 61 73 5f 72 65 66 28 29 20 7b 0a 09 09 09  d.as_ref() {....
0c80: 09 09 09 09 09 09 22 2f 63 68 65 63 6b 22 20 7c  ......"/check" |
0c90: 20 22 2f 63 6c 65 61 6e 22 20 7c 20 22 2f 65 6e   "/clean" | "/en
0ca0: 61 62 6c 65 22 20 7c 20 22 2f 64 65 6c 65 74 65  able" | "/delete
0cb0: 22 20 7c 20 22 2f 64 69 73 61 62 6c 65 22 20 3d  " | "/disable" =
0cc0: 3e 20 7b 20 63 6f 6d 6d 61 6e 64 3a 3a 63 6f 6d  > { command::com
0cd0: 6d 61 6e 64 28 73 65 6c 66 2c 20 6d 73 67 2e 63  mand(self, msg.c
0ce0: 68 61 74 2e 69 64 2c 20 77 6f 72 64 73 29 2e 61  hat.id, words).a
0cf0: 77 61 69 74 3f 20 7d 2c 0a 09 09 09 09 09 09 09  wait? },........
0d00: 09 09 22 2f 73 74 61 72 74 22 20 3d 3e 20 7b 20  .."/start" => { 
0d10: 63 6f 6d 6d 61 6e 64 3a 3a 73 74 61 72 74 28 73  command::start(s
0d20: 65 6c 66 2c 20 6d 73 67 2e 63 68 61 74 2e 69 64  elf, msg.chat.id
0d30: 29 2e 61 77 61 69 74 3f 3b 20 7d 2c 0a 09 09 09  ).await?; },....
0d40: 09 09 09 09 09 09 22 2f 6c 69 73 74 22 20 3d 3e  ......"/list" =>
0d50: 20 7b 20 63 6f 6d 6d 61 6e 64 3a 3a 6c 69 73 74   { command::list
0d60: 28 73 65 6c 66 2c 20 6d 73 67 2e 63 68 61 74 2e  (self, msg.chat.
0d70: 69 64 29 2e 61 77 61 69 74 3f 3b 20 7d 2c 0a 09  id).await?; },..
0d80: 09 09 09 09 09 09 09 09 22 2f 61 64 64 22 20 7c  ........"/add" |
0d90: 20 22 2f 75 70 64 61 74 65 22 20 3d 3e 20 7b 20   "/update" => { 
0da0: 63 6f 6d 6d 61 6e 64 3a 3a 75 70 64 61 74 65 28  command::update(
0db0: 73 65 6c 66 2c 20 6d 73 67 2e 63 68 61 74 2e 69  self, msg.chat.i
0dc0: 64 2c 20 77 6f 72 64 73 29 2e 61 77 61 69 74 3f  d, words).await?
0dd0: 3b 20 7d 2c 0a 09 09 09 09 09 09 09 09 09 61 6e  ; },..........an
0de0: 79 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09 09  y => {..........
0df0: 09 73 65 6c 66 2e 73 65 6e 64 28 66 6f 72 6d 61  .self.send(forma
0e00: 74 21 28 22 5c 5c 23 65 72 72 6f 72 5c 6e 60 60  t!("\\#error\n``
0e10: 60 5c 6e 55 6e 6b 6e 6f 77 6e 20 63 6f 6d 6d 61  `\nUnknown comma
0e20: 6e 64 3a 20 7b 61 6e 79 7d 5c 6e 60 60 60 22 29  nd: {any}\n```")
0e30: 2c 0a 09 09 09 09 09 09 09 09 09 09 09 53 6f 6d  ,............Som
0e40: 65 28 6d 73 67 2e 63 68 61 74 2e 69 64 29 2c 0a  e(msg.chat.id),.
0e50: 09 09 09 09 09 09 09 09 09 09 09 53 6f 6d 65 28  ...........Some(
0e60: 50 61 72 73 65 4d 6f 64 65 3a 3a 4d 61 72 6b 64  ParseMode::Markd
0e70: 6f 77 6e 56 32 29 0a 09 09 09 09 09 09 09 09 09  ownV2)..........
0e80: 09 29 2e 61 77 61 69 74 3f 3b 0a 09 09 09 09 09  .).await?;......
0e90: 09 09 09 09 7d 2c 0a 09 09 09 09 09 09 09 09 7d  ....},.........}
0ea0: 3b 0a 09 09 09 09 09 09 09 7d 3b 0a 09 09 09 09  ;........};.....
0eb0: 09 09 7d 3b 0a 09 09 09 09 09 7d 3b 0a 09 09 09  ..};......};....
0ec0: 09 7d 3b 0a 09 09 09 7d 0a 09 09 7d 0a 09 7d 0a  .};....}...}..}.
0ed0: 0a 09 70 75 62 20 61 73 79 6e 63 20 66 6e 20 73  ..pub async fn s
0ee0: 65 6e 64 20 3c 53 3e 28 26 73 65 6c 66 2c 20 6d  end <S>(&self, m
0ef0: 73 67 3a 20 53 2c 20 74 61 72 67 65 74 3a 20 4f  sg: S, target: O
0f00: 70 74 69 6f 6e 3c 69 36 34 3e 2c 20 6d 6f 64 65  ption<i64>, mode
0f10: 3a 20 4f 70 74 69 6f 6e 3c 50 61 72 73 65 4d 6f  : Option<ParseMo
0f20: 64 65 3e 29 20 2d 3e 20 52 65 73 75 6c 74 3c 28  de>) -> Result<(
0f30: 29 3e 0a 09 77 68 65 72 65 20 53 3a 20 49 6e 74  )>..where S: Int
0f40: 6f 3c 53 74 72 69 6e 67 3e 20 7b 0a 09 09 6c 65  o<String> {...le
0f50: 74 20 6d 73 67 20 3d 20 6d 73 67 2e 69 6e 74 6f  t msg = msg.into
0f60: 28 29 3b 0a 0a 09 09 6c 65 74 20 6d 6f 64 65 20  ();....let mode 
0f70: 3d 20 6d 6f 64 65 2e 75 6e 77 72 61 70 5f 6f 72  = mode.unwrap_or
0f80: 28 50 61 72 73 65 4d 6f 64 65 3a 3a 48 74 6d 6c  (ParseMode::Html
0f90: 29 3b 0a 09 09 6c 65 74 20 74 61 72 67 65 74 20  );...let target 
0fa0: 3d 20 74 61 72 67 65 74 2e 75 6e 77 72 61 70 5f  = target.unwrap_
0fb0: 6f 72 28 73 65 6c 66 2e 6f 77 6e 65 72 5f 63 68  or(self.owner_ch
0fc0: 61 74 29 3b 0a 09 09 6c 65 74 20 73 65 6e 64 20  at);...let send 
0fd0: 3d 20 53 65 6e 64 4d 65 73 73 61 67 65 50 61 72  = SendMessagePar
0fe0: 61 6d 73 3a 3a 62 75 69 6c 64 65 72 28 29 0a 09  ams::builder()..
0ff0: 09 09 2e 63 68 61 74 5f 69 64 28 74 61 72 67 65  ...chat_id(targe
1000: 74 29 0a 09 09 09 2e 74 65 78 74 28 6d 73 67 29  t).....text(msg)
1010: 0a 09 09 09 2e 70 61 72 73 65 5f 6d 6f 64 65 28  .....parse_mode(
1020: 6d 6f 64 65 29 0a 09 09 09 2e 62 75 69 6c 64 28  mode).....build(
1030: 29 3b 0a 09 09 73 65 6c 66 2e 74 67 2e 73 65 6e  );...self.tg.sen
1040: 64 5f 6d 65 73 73 61 67 65 28 26 73 65 6e 64 29  d_message(&send)
1050: 2e 61 77 61 69 74 3f 3b 0a 09 09 4f 6b 28 28 29  .await?;...Ok(()
1060: 29 0a 09 7d 0a 0a 09 70 75 62 20 61 73 79 6e 63  )..}...pub async
1070: 20 66 6e 20 63 68 65 63 6b 20 28 26 73 65 6c 66   fn check (&self
1080: 2c 20 69 64 3a 20 26 69 33 32 2c 20 6f 77 6e 65  , id: &i32, owne
1090: 72 3a 20 69 36 34 2c 20 72 65 61 6c 3a 20 62 6f  r: i64, real: bo
10a0: 6f 6c 29 20 2d 3e 20 52 65 73 75 6c 74 3c 43 6f  ol) -> Result<Co
10b0: 77 3c 27 5f 2c 20 73 74 72 3e 3e 20 7b 0a 09 09  w<'_, str>> {...
10c0: 6c 65 74 20 6d 75 74 20 70 6f 73 74 65 64 3a 20  let mut posted: 
10d0: 69 33 32 20 3d 20 30 3b 0a 09 09 6c 65 74 20 6d  i32 = 0;...let m
10e0: 75 74 20 63 6f 6e 6e 20 3d 20 73 65 6c 66 2e 70  ut conn = self.p
10f0: 6f 6f 6c 2e 61 63 71 75 69 72 65 28 29 2e 61 77  ool.acquire().aw
1100: 61 69 74 3f 3b 0a 0a 09 09 6c 65 74 20 69 64 20  ait?;....let id 
1110: 3d 20 7b 0a 09 09 09 6c 65 74 20 6d 75 74 20 73  = {....let mut s
1120: 65 74 20 3d 20 73 65 6c 66 2e 73 6f 75 72 63 65  et = self.source
1130: 73 2e 6c 6f 63 6b 28 29 2e 75 6e 77 72 61 70 28  s.lock().unwrap(
1140: 29 3b 0a 09 09 09 6d 61 74 63 68 20 73 65 74 2e  );....match set.
1150: 67 65 74 28 69 64 29 20 7b 0a 09 09 09 09 53 6f  get(id) {.....So
1160: 6d 65 28 69 64 29 20 3d 3e 20 69 64 2e 63 6c 6f  me(id) => id.clo
1170: 6e 65 28 29 2c 0a 09 09 09 09 4e 6f 6e 65 20 3d  ne(),.....None =
1180: 3e 20 7b 0a 09 09 09 09 09 6c 65 74 20 69 64 20  > {......let id 
1190: 3d 20 41 72 63 3a 3a 6e 65 77 28 2a 69 64 29 3b  = Arc::new(*id);
11a0: 0a 09 09 09 09 09 73 65 74 2e 69 6e 73 65 72 74  ......set.insert
11b0: 28 69 64 2e 63 6c 6f 6e 65 28 29 29 3b 0a 09 09  (id.clone());...
11c0: 09 09 09 69 64 2e 63 6c 6f 6e 65 28 29 0a 09 09  ...id.clone()...
11d0: 09 09 7d 2c 0a 09 09 09 7d 0a 09 09 7d 3b 0a 09  ..},....}...};..
11e0: 09 6c 65 74 20 63 6f 75 6e 74 20 3d 20 41 72 63  .let count = Arc
11f0: 3a 3a 73 74 72 6f 6e 67 5f 63 6f 75 6e 74 28 26  ::strong_count(&
1200: 69 64 29 3b 0a 09 09 69 66 20 63 6f 75 6e 74 20  id);...if count 
1210: 3d 3d 20 32 20 7b 0a 09 09 09 6c 65 74 20 73 6f  == 2 {....let so
1220: 75 72 63 65 20 3d 20 73 71 6c 78 3a 3a 71 75 65  urce = sqlx::que
1230: 72 79 21 28 22 73 65 6c 65 63 74 20 73 6f 75 72  ry!("select sour
1240: 63 65 5f 69 64 2c 20 63 68 61 6e 6e 65 6c 5f 69  ce_id, channel_i
1250: 64 2c 20 75 72 6c 2c 20 69 76 5f 68 61 73 68 2c  d, url, iv_hash,
1260: 20 6f 77 6e 65 72 2c 20 75 72 6c 5f 72 65 20 66   owner, url_re f
1270: 72 6f 6d 20 72 73 73 74 67 5f 73 6f 75 72 63 65  rom rsstg_source
1280: 20 77 68 65 72 65 20 73 6f 75 72 63 65 5f 69 64   where source_id
1290: 20 3d 20 24 31 20 61 6e 64 20 6f 77 6e 65 72 20   = $1 and owner 
12a0: 3d 20 24 32 22 2c 0a 09 09 09 09 2a 69 64 2c 20  = $2",.....*id, 
12b0: 6f 77 6e 65 72 29 2e 66 65 74 63 68 5f 6f 6e 65  owner).fetch_one
12c0: 28 26 6d 75 74 20 2a 63 6f 6e 6e 29 2e 61 77 61  (&mut *conn).awa
12d0: 69 74 3f 3b 0a 09 09 09 6c 65 74 20 64 65 73 74  it?;....let dest
12e0: 69 6e 61 74 69 6f 6e 20 3d 20 6d 61 74 63 68 20  ination = match 
12f0: 72 65 61 6c 20 7b 0a 09 09 09 09 74 72 75 65 20  real {.....true 
1300: 3d 3e 20 73 6f 75 72 63 65 2e 63 68 61 6e 6e 65  => source.channe
1310: 6c 5f 69 64 2c 0a 09 09 09 09 66 61 6c 73 65 20  l_id,.....false 
1320: 3d 3e 20 73 6f 75 72 63 65 2e 6f 77 6e 65 72 2c  => source.owner,
1330: 0a 09 09 09 7d 3b 0a 09 09 09 6c 65 74 20 6d 75  ....};....let mu
1340: 74 20 74 68 69 73 5f 66 65 74 63 68 3a 20 4f 70  t this_fetch: Op
1350: 74 69 6f 6e 3c 44 61 74 65 54 69 6d 65 3c 63 68  tion<DateTime<ch
1360: 72 6f 6e 6f 3a 3a 46 69 78 65 64 4f 66 66 73 65  rono::FixedOffse
1370: 74 3e 3e 20 3d 20 4e 6f 6e 65 3b 0a 09 09 09 6c  t>> = None;....l
1380: 65 74 20 6d 75 74 20 70 6f 73 74 73 3a 20 42 54  et mut posts: BT
1390: 72 65 65 4d 61 70 3c 44 61 74 65 54 69 6d 65 3c  reeMap<DateTime<
13a0: 63 68 72 6f 6e 6f 3a 3a 46 69 78 65 64 4f 66 66  chrono::FixedOff
13b0: 73 65 74 3e 2c 20 53 74 72 69 6e 67 3e 20 3d 20  set>, String> = 
13c0: 42 54 72 65 65 4d 61 70 3a 3a 6e 65 77 28 29 3b  BTreeMap::new();
13d0: 0a 0a 09 09 09 6c 65 74 20 72 65 73 70 6f 6e 73  .....let respons
13e0: 65 20 3d 20 73 65 6c 66 2e 68 74 74 70 5f 63 6c  e = self.http_cl
13f0: 69 65 6e 74 2e 67 65 74 28 26 73 6f 75 72 63 65  ient.get(&source
1400: 2e 75 72 6c 29 2e 73 65 6e 64 28 29 2e 61 77 61  .url).send().awa
1410: 69 74 3f 3b 0a 09 09 09 6c 65 74 20 73 74 61 74  it?;....let stat
1420: 75 73 20 3d 20 72 65 73 70 6f 6e 73 65 2e 73 74  us = response.st
1430: 61 74 75 73 28 29 3b 0a 09 09 09 6c 65 74 20 63  atus();....let c
1440: 6f 6e 74 65 6e 74 20 3d 20 72 65 73 70 6f 6e 73  ontent = respons
1450: 65 2e 62 79 74 65 73 28 29 2e 61 77 61 69 74 3f  e.bytes().await?
1460: 3b 0a 09 09 09 6d 61 74 63 68 20 72 73 73 3a 3a  ;....match rss::
1470: 43 68 61 6e 6e 65 6c 3a 3a 72 65 61 64 5f 66 72  Channel::read_fr
1480: 6f 6d 28 26 63 6f 6e 74 65 6e 74 5b 2e 2e 5d 29  om(&content[..])
1490: 20 7b 0a 09 09 09 09 4f 6b 28 66 65 65 64 29 20   {.....Ok(feed) 
14a0: 3d 3e 20 7b 0a 09 09 09 09 09 66 6f 72 20 69 74  => {......for it
14b0: 65 6d 20 69 6e 20 66 65 65 64 2e 69 74 65 6d 73  em in feed.items
14c0: 28 29 20 7b 0a 09 09 09 09 09 09 69 66 20 6c 65  () {.......if le
14d0: 74 20 53 6f 6d 65 28 6c 69 6e 6b 29 20 3d 20 69  t Some(link) = i
14e0: 74 65 6d 2e 6c 69 6e 6b 28 29 20 7b 0a 09 09 09  tem.link() {....
14f0: 09 09 09 09 6c 65 74 20 64 61 74 65 20 3d 20 6d  ....let date = m
1500: 61 74 63 68 20 69 74 65 6d 2e 70 75 62 5f 64 61  atch item.pub_da
1510: 74 65 28 29 20 7b 0a 09 09 09 09 09 09 09 09 53  te() {.........S
1520: 6f 6d 65 28 66 65 65 64 5f 64 61 74 65 29 20 3d  ome(feed_date) =
1530: 3e 20 44 61 74 65 54 69 6d 65 3a 3a 70 61 72 73  > DateTime::pars
1540: 65 5f 66 72 6f 6d 5f 72 66 63 32 38 32 32 28 66  e_from_rfc2822(f
1550: 65 65 64 5f 64 61 74 65 29 2c 0a 09 09 09 09 09  eed_date),......
1560: 09 09 09 4e 6f 6e 65 20 3d 3e 20 44 61 74 65 54  ...None => DateT
1570: 69 6d 65 3a 3a 70 61 72 73 65 5f 66 72 6f 6d 5f  ime::parse_from_
1580: 72 66 63 33 33 33 39 28 26 69 74 65 6d 2e 64 75  rfc3339(&item.du
1590: 62 6c 69 6e 5f 63 6f 72 65 5f 65 78 74 28 29 2e  blin_core_ext().
15a0: 75 6e 77 72 61 70 28 29 2e 64 61 74 65 73 28 29  unwrap().dates()
15b0: 5b 30 5d 29 2c 0a 09 09 09 09 09 09 09 7d 3f 3b  [0]),........}?;
15c0: 0a 09 09 09 09 09 09 09 6c 65 74 20 75 72 6c 20  ........let url 
15d0: 3d 20 6c 69 6e 6b 3b 0a 09 09 09 09 09 09 09 70  = link;........p
15e0: 6f 73 74 73 2e 69 6e 73 65 72 74 28 64 61 74 65  osts.insert(date
15f0: 2c 20 75 72 6c 2e 74 6f 5f 73 74 72 69 6e 67 28  , url.to_string(
1600: 29 29 3b 0a 09 09 09 09 09 09 7d 0a 09 09 09 09  ));.......}.....
1610: 09 7d 3b 0a 09 09 09 09 7d 2c 0a 09 09 09 09 45  .};.....},.....E
1620: 72 72 28 65 72 72 29 20 3d 3e 20 6d 61 74 63 68  rr(err) => match
1630: 20 65 72 72 20 7b 0a 09 09 09 09 09 72 73 73 3a   err {......rss:
1640: 3a 45 72 72 6f 72 3a 3a 49 6e 76 61 6c 69 64 53  :Error::InvalidS
1650: 74 61 72 74 54 61 67 20 3d 3e 20 7b 0a 09 09 09  tartTag => {....
1660: 09 09 09 6d 61 74 63 68 20 61 74 6f 6d 5f 73 79  ...match atom_sy
1670: 6e 64 69 63 61 74 69 6f 6e 3a 3a 46 65 65 64 3a  ndication::Feed:
1680: 3a 72 65 61 64 5f 66 72 6f 6d 28 26 63 6f 6e 74  :read_from(&cont
1690: 65 6e 74 5b 2e 2e 5d 29 20 7b 0a 09 09 09 09 09  ent[..]) {......
16a0: 09 09 4f 6b 28 66 65 65 64 29 20 3d 3e 20 7b 0a  ..Ok(feed) => {.
16b0: 09 09 09 09 09 09 09 09 66 6f 72 20 69 74 65 6d  ........for item
16c0: 20 69 6e 20 66 65 65 64 2e 65 6e 74 72 69 65 73   in feed.entries
16d0: 28 29 20 7b 0a 09 09 09 09 09 09 09 09 09 6c 65  () {..........le
16e0: 74 20 64 61 74 65 20 3d 20 69 74 65 6d 2e 70 75  t date = item.pu
16f0: 62 6c 69 73 68 65 64 28 29 2e 75 6e 77 72 61 70  blished().unwrap
1700: 28 29 3b 0a 09 09 09 09 09 09 09 09 09 6c 65 74  ();..........let
1710: 20 75 72 6c 20 3d 20 69 74 65 6d 2e 6c 69 6e 6b   url = item.link
1720: 73 28 29 5b 30 5d 2e 68 72 65 66 28 29 3b 0a 09  s()[0].href();..
1730: 09 09 09 09 09 09 09 09 70 6f 73 74 73 2e 69 6e  ........posts.in
1740: 73 65 72 74 28 2a 64 61 74 65 2c 20 75 72 6c 2e  sert(*date, url.
1750: 74 6f 5f 73 74 72 69 6e 67 28 29 29 3b 0a 09 09  to_string());...
1760: 09 09 09 09 09 09 7d 3b 0a 09 09 09 09 09 09 09  ......};........
1770: 7d 2c 0a 09 09 09 09 09 09 09 45 72 72 28 65 72  },........Err(er
1780: 72 29 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09  r) => {.........
1790: 62 61 69 6c 21 28 22 55 6e 73 75 70 70 6f 72 74  bail!("Unsupport
17a0: 65 64 20 6f 72 20 6d 61 6e 67 6c 65 64 20 63 6f  ed or mangled co
17b0: 6e 74 65 6e 74 3a 5c 6e 7b 3a 3f 7d 5c 6e 7b 65  ntent:\n{:?}\n{e
17c0: 72 72 3a 23 3f 7d 5c 6e 7b 73 74 61 74 75 73 3a  rr:#?}\n{status:
17d0: 23 3f 7d 5c 6e 22 2c 20 26 73 6f 75 72 63 65 2e  #?}\n", &source.
17e0: 75 72 6c 29 0a 09 09 09 09 09 09 09 7d 2c 0a 09  url)........},..
17f0: 09 09 09 09 09 7d 0a 09 09 09 09 09 7d 2c 0a 09  .....}......},..
1800: 09 09 09 09 72 73 73 3a 3a 45 72 72 6f 72 3a 3a  ....rss::Error::
1810: 45 6f 66 20 3d 3e 20 28 29 2c 0a 09 09 09 09 09  Eof => (),......
1820: 5f 20 3d 3e 20 62 61 69 6c 21 28 22 55 6e 73 75  _ => bail!("Unsu
1830: 70 70 6f 72 74 65 64 20 6f 72 20 6d 61 6e 67 6c  pported or mangl
1840: 65 64 20 63 6f 6e 74 65 6e 74 3a 5c 6e 7b 3a 3f  ed content:\n{:?
1850: 7d 5c 6e 7b 65 72 72 3a 23 3f 7d 5c 6e 7b 73 74  }\n{err:#?}\n{st
1860: 61 74 75 73 3a 23 3f 7d 5c 6e 22 2c 20 26 73 6f  atus:#?}\n", &so
1870: 75 72 63 65 2e 75 72 6c 29 0a 09 09 09 09 7d 0a  urce.url).....}.
1880: 09 09 09 7d 3b 0a 09 09 09 66 6f 72 20 28 64 61  ...};....for (da
1890: 74 65 2c 20 75 72 6c 29 20 69 6e 20 70 6f 73 74  te, url) in post
18a0: 73 2e 69 74 65 72 28 29 20 7b 0a 09 09 09 09 6c  s.iter() {.....l
18b0: 65 74 20 70 6f 73 74 5f 75 72 6c 3a 20 43 6f 77  et post_url: Cow
18c0: 3c 73 74 72 3e 20 3d 20 6d 61 74 63 68 20 73 6f  <str> = match so
18d0: 75 72 63 65 2e 75 72 6c 5f 72 65 20 7b 0a 09 09  urce.url_re {...
18e0: 09 09 09 53 6f 6d 65 28 72 65 66 20 78 29 20 3d  ...Some(ref x) =
18f0: 3e 20 73 65 64 72 65 67 65 78 3a 3a 52 65 70 6c  > sedregex::Repl
1900: 61 63 65 43 6f 6d 6d 61 6e 64 3a 3a 6e 65 77 28  aceCommand::new(
1910: 78 29 3f 2e 65 78 65 63 75 74 65 28 75 72 6c 29  x)?.execute(url)
1920: 2c 0a 09 09 09 09 09 4e 6f 6e 65 20 3d 3e 20 75  ,......None => u
1930: 72 6c 2e 69 6e 74 6f 28 29 2c 0a 09 09 09 09 7d  rl.into(),.....}
1940: 3b 0a 09 09 09 09 69 66 20 6c 65 74 20 53 6f 6d  ;.....if let Som
1950: 65 28 65 78 69 73 74 73 29 20 3d 20 73 71 6c 78  e(exists) = sqlx
1960: 3a 3a 71 75 65 72 79 21 28 22 73 65 6c 65 63 74  ::query!("select
1970: 20 65 78 69 73 74 73 28 73 65 6c 65 63 74 20 74   exists(select t
1980: 72 75 65 20 66 72 6f 6d 20 72 73 73 74 67 5f 70  rue from rsstg_p
1990: 6f 73 74 20 77 68 65 72 65 20 75 72 6c 20 3d 20  ost where url = 
19a0: 24 31 20 61 6e 64 20 73 6f 75 72 63 65 5f 69 64  $1 and source_id
19b0: 20 3d 20 24 32 29 20 61 73 20 65 78 69 73 74 73   = $2) as exists
19c0: 3b 22 2c 0a 09 09 09 09 09 26 70 6f 73 74 5f 75  ;",......&post_u
19d0: 72 6c 2c 20 2a 69 64 29 2e 66 65 74 63 68 5f 6f  rl, *id).fetch_o
19e0: 6e 65 28 26 6d 75 74 20 2a 63 6f 6e 6e 29 2e 61  ne(&mut *conn).a
19f0: 77 61 69 74 3f 2e 65 78 69 73 74 73 20 7b 0a 09  wait?.exists {..
1a00: 09 09 09 09 69 66 20 21 20 65 78 69 73 74 73 20  ....if ! exists 
1a10: 7b 0a 09 09 09 09 09 09 69 66 20 74 68 69 73 5f  {.......if this_
1a20: 66 65 74 63 68 2e 69 73 5f 6e 6f 6e 65 28 29 20  fetch.is_none() 
1a30: 7c 7c 20 2a 64 61 74 65 20 3e 20 74 68 69 73 5f  || *date > this_
1a40: 66 65 74 63 68 2e 75 6e 77 72 61 70 28 29 20 7b  fetch.unwrap() {
1a50: 0a 09 09 09 09 09 09 09 74 68 69 73 5f 66 65 74  ........this_fet
1a60: 63 68 20 3d 20 53 6f 6d 65 28 2a 64 61 74 65 29  ch = Some(*date)
1a70: 3b 0a 09 09 09 09 09 09 7d 3b 0a 09 09 09 09 09  ;.......};......
1a80: 09 73 65 6c 66 2e 73 65 6e 64 28 20 6d 61 74 63  .self.send( matc
1a90: 68 20 26 73 6f 75 72 63 65 2e 69 76 5f 68 61 73  h &source.iv_has
1aa0: 68 20 7b 0a 09 09 09 09 09 09 09 53 6f 6d 65 28  h {........Some(
1ab0: 68 61 73 68 29 20 3d 3e 20 66 6f 72 6d 61 74 21  hash) => format!
1ac0: 28 22 3c 61 20 68 72 65 66 3d 5c 22 68 74 74 70  ("<a href=\"http
1ad0: 73 3a 2f 2f 74 2e 6d 65 2f 69 76 3f 75 72 6c 3d  s://t.me/iv?url=
1ae0: 7b 70 6f 73 74 5f 75 72 6c 7d 26 72 68 61 73 68  {post_url}&rhash
1af0: 3d 7b 68 61 73 68 7d 5c 22 3e 20 3c 2f 61 3e 7b  ={hash}\"> </a>{
1b00: 70 6f 73 74 5f 75 72 6c 7d 22 29 2c 0a 09 09 09  post_url}"),....
1b10: 09 09 09 09 4e 6f 6e 65 20 3d 3e 20 66 6f 72 6d  ....None => form
1b20: 61 74 21 28 22 7b 70 6f 73 74 5f 75 72 6c 7d 22  at!("{post_url}"
1b30: 29 2c 0a 09 09 09 09 09 09 7d 2c 20 53 6f 6d 65  ),.......}, Some
1b40: 28 64 65 73 74 69 6e 61 74 69 6f 6e 29 2c 20 53  (destination), S
1b50: 6f 6d 65 28 50 61 72 73 65 4d 6f 64 65 3a 3a 48  ome(ParseMode::H
1b60: 74 6d 6c 29 29 2e 61 77 61 69 74 3f 3b 0a 09 09  tml)).await?;...
1b70: 09 09 09 09 73 71 6c 78 3a 3a 71 75 65 72 79 21  ....sqlx::query!
1b80: 28 22 69 6e 73 65 72 74 20 69 6e 74 6f 20 72 73  ("insert into rs
1b90: 73 74 67 5f 70 6f 73 74 20 28 73 6f 75 72 63 65  stg_post (source
1ba0: 5f 69 64 2c 20 70 6f 73 74 65 64 2c 20 75 72 6c  _id, posted, url
1bb0: 29 20 76 61 6c 75 65 73 20 28 24 31 2c 20 24 32  ) values ($1, $2
1bc0: 2c 20 24 33 29 3b 22 2c 0a 09 09 09 09 09 09 09  , $3);",........
1bd0: 2a 69 64 2c 20 64 61 74 65 2c 20 26 70 6f 73 74  *id, date, &post
1be0: 5f 75 72 6c 29 2e 65 78 65 63 75 74 65 28 26 6d  _url).execute(&m
1bf0: 75 74 20 2a 63 6f 6e 6e 29 2e 61 77 61 69 74 3f  ut *conn).await?
1c00: 3b 0a 09 09 09 09 09 7d 3b 0a 09 09 09 09 7d 3b  ;......};.....};
1c10: 0a 09 09 09 09 70 6f 73 74 65 64 20 2b 3d 20 31  .....posted += 1
1c20: 3b 0a 09 09 09 7d 3b 0a 09 09 09 70 6f 73 74 73  ;....};....posts
1c30: 2e 63 6c 65 61 72 28 29 3b 0a 09 09 7d 3b 0a 09  .clear();...};..
1c40: 09 73 71 6c 78 3a 3a 71 75 65 72 79 21 28 22 75  .sqlx::query!("u
1c50: 70 64 61 74 65 20 72 73 73 74 67 5f 73 6f 75 72  pdate rsstg_sour
1c60: 63 65 20 73 65 74 20 6c 61 73 74 5f 73 63 72 61  ce set last_scra
1c70: 70 65 20 3d 20 6e 6f 77 28 29 20 77 68 65 72 65  pe = now() where
1c80: 20 73 6f 75 72 63 65 5f 69 64 20 3d 20 24 31 3b   source_id = $1;
1c90: 22 2c 0a 09 09 09 2a 69 64 29 2e 65 78 65 63 75  ",....*id).execu
1ca0: 74 65 28 26 6d 75 74 20 2a 63 6f 6e 6e 29 2e 61  te(&mut *conn).a
1cb0: 77 61 69 74 3f 3b 0a 09 09 4f 6b 28 66 6f 72 6d  wait?;...Ok(form
1cc0: 61 74 21 28 22 50 6f 73 74 65 64 3a 20 7b 70 6f  at!("Posted: {po
1cd0: 73 74 65 64 7d 22 29 2e 69 6e 74 6f 28 29 29 0a  sted}").into()).
1ce0: 09 7d 0a 0a 09 70 75 62 20 61 73 79 6e 63 20 66  .}...pub async f
1cf0: 6e 20 64 65 6c 65 74 65 20 28 26 73 65 6c 66 2c  n delete (&self,
1d00: 20 73 6f 75 72 63 65 5f 69 64 3a 20 26 69 33 32   source_id: &i32
1d10: 2c 20 6f 77 6e 65 72 3a 20 69 36 34 29 20 2d 3e  , owner: i64) ->
1d20: 20 52 65 73 75 6c 74 3c 43 6f 77 3c 27 5f 2c 20   Result<Cow<'_, 
1d30: 73 74 72 3e 3e 20 7b 0a 09 09 6d 61 74 63 68 20  str>> {...match 
1d40: 73 71 6c 78 3a 3a 71 75 65 72 79 21 28 22 64 65  sqlx::query!("de
1d50: 6c 65 74 65 20 66 72 6f 6d 20 72 73 73 74 67 5f  lete from rsstg_
1d60: 73 6f 75 72 63 65 20 77 68 65 72 65 20 73 6f 75  source where sou
1d70: 72 63 65 5f 69 64 20 3d 20 24 31 20 61 6e 64 20  rce_id = $1 and 
1d80: 6f 77 6e 65 72 20 3d 20 24 32 3b 22 2c 0a 09 09  owner = $2;",...
1d90: 09 73 6f 75 72 63 65 5f 69 64 2c 20 6f 77 6e 65  .source_id, owne
1da0: 72 29 2e 65 78 65 63 75 74 65 28 26 6d 75 74 20  r).execute(&mut 
1db0: 2a 73 65 6c 66 2e 70 6f 6f 6c 2e 61 63 71 75 69  *self.pool.acqui
1dc0: 72 65 28 29 2e 61 77 61 69 74 3f 29 2e 61 77 61  re().await?).awa
1dd0: 69 74 3f 2e 72 6f 77 73 5f 61 66 66 65 63 74 65  it?.rows_affecte
1de0: 64 28 29 20 7b 0a 09 09 09 30 20 3d 3e 20 7b 20  d() {....0 => { 
1df0: 4f 6b 28 22 4e 6f 20 64 61 74 61 20 66 6f 75 6e  Ok("No data foun
1e00: 64 20 66 6f 75 6e 64 2e 22 2e 69 6e 74 6f 28 29  d found.".into()
1e10: 29 20 7d 2c 0a 09 09 09 78 20 3d 3e 20 7b 20 4f  ) },....x => { O
1e20: 6b 28 66 6f 72 6d 61 74 21 28 22 7b 7d 20 73 6f  k(format!("{} so
1e30: 75 72 63 65 73 20 72 65 6d 6f 76 65 64 2e 22 2c  urces removed.",
1e40: 20 78 29 2e 69 6e 74 6f 28 29 29 20 7d 2c 0a 09   x).into()) },..
1e50: 09 7d 0a 09 7d 0a 0a 09 70 75 62 20 61 73 79 6e  .}..}...pub asyn
1e60: 63 20 66 6e 20 63 6c 65 61 6e 20 28 26 73 65 6c  c fn clean (&sel
1e70: 66 2c 20 73 6f 75 72 63 65 5f 69 64 3a 20 26 69  f, source_id: &i
1e80: 33 32 2c 20 6f 77 6e 65 72 3a 20 69 36 34 29 20  32, owner: i64) 
1e90: 2d 3e 20 52 65 73 75 6c 74 3c 43 6f 77 3c 27 5f  -> Result<Cow<'_
1ea0: 2c 20 73 74 72 3e 3e 20 7b 0a 09 09 6d 61 74 63  , str>> {...matc
1eb0: 68 20 73 71 6c 78 3a 3a 71 75 65 72 79 21 28 22  h sqlx::query!("
1ec0: 64 65 6c 65 74 65 20 66 72 6f 6d 20 72 73 73 74  delete from rsst
1ed0: 67 5f 70 6f 73 74 20 70 20 75 73 69 6e 67 20 72  g_post p using r
1ee0: 73 73 74 67 5f 73 6f 75 72 63 65 20 73 20 77 68  sstg_source s wh
1ef0: 65 72 65 20 70 2e 73 6f 75 72 63 65 5f 69 64 20  ere p.source_id 
1f00: 3d 20 24 31 20 61 6e 64 20 6f 77 6e 65 72 20 3d  = $1 and owner =
1f10: 20 24 32 20 61 6e 64 20 70 2e 73 6f 75 72 63 65   $2 and p.source
1f20: 5f 69 64 20 3d 20 73 2e 73 6f 75 72 63 65 5f 69  _id = s.source_i
1f30: 64 3b 22 2c 0a 09 09 09 73 6f 75 72 63 65 5f 69  d;",....source_i
1f40: 64 2c 20 6f 77 6e 65 72 29 2e 65 78 65 63 75 74  d, owner).execut
1f50: 65 28 26 6d 75 74 20 2a 73 65 6c 66 2e 70 6f 6f  e(&mut *self.poo
1f60: 6c 2e 61 63 71 75 69 72 65 28 29 2e 61 77 61 69  l.acquire().awai
1f70: 74 3f 29 2e 61 77 61 69 74 3f 2e 72 6f 77 73 5f  t?).await?.rows_
1f80: 61 66 66 65 63 74 65 64 28 29 20 7b 0a 09 09 09  affected() {....
1f90: 30 20 3d 3e 20 7b 20 4f 6b 28 22 4e 6f 20 64 61  0 => { Ok("No da
1fa0: 74 61 20 66 6f 75 6e 64 20 66 6f 75 6e 64 2e 22  ta found found."
1fb0: 2e 69 6e 74 6f 28 29 29 20 7d 2c 0a 09 09 09 78  .into()) },....x
1fc0: 20 3d 3e 20 7b 20 4f 6b 28 66 6f 72 6d 61 74 21   => { Ok(format!
1fd0: 28 22 7b 78 7d 20 70 6f 73 74 73 20 70 75 72 67  ("{x} posts purg
1fe0: 65 64 2e 22 29 2e 69 6e 74 6f 28 29 29 20 7d 2c  ed.").into()) },
1ff0: 0a 09 09 7d 0a 09 7d 0a 0a 09 70 75 62 20 61 73  ...}..}...pub as
2000: 79 6e 63 20 66 6e 20 65 6e 61 62 6c 65 20 28 26  ync fn enable (&
2010: 73 65 6c 66 2c 20 73 6f 75 72 63 65 5f 69 64 3a  self, source_id:
2020: 20 26 69 33 32 2c 20 6f 77 6e 65 72 3a 20 69 36   &i32, owner: i6
2030: 34 29 20 2d 3e 20 52 65 73 75 6c 74 3c 26 73 74  4) -> Result<&st
2040: 72 3e 20 7b 0a 09 09 6d 61 74 63 68 20 73 71 6c  r> {...match sql
2050: 78 3a 3a 71 75 65 72 79 21 28 22 75 70 64 61 74  x::query!("updat
2060: 65 20 72 73 73 74 67 5f 73 6f 75 72 63 65 20 73  e rsstg_source s
2070: 65 74 20 65 6e 61 62 6c 65 64 20 3d 20 74 72 75  et enabled = tru
2080: 65 20 77 68 65 72 65 20 73 6f 75 72 63 65 5f 69  e where source_i
2090: 64 20 3d 20 24 31 20 61 6e 64 20 6f 77 6e 65 72  d = $1 and owner
20a0: 20 3d 20 24 32 22 2c 0a 09 09 09 73 6f 75 72 63   = $2",....sourc
20b0: 65 5f 69 64 2c 20 6f 77 6e 65 72 29 2e 65 78 65  e_id, owner).exe
20c0: 63 75 74 65 28 26 6d 75 74 20 2a 73 65 6c 66 2e  cute(&mut *self.
20d0: 70 6f 6f 6c 2e 61 63 71 75 69 72 65 28 29 2e 61  pool.acquire().a
20e0: 77 61 69 74 3f 29 2e 61 77 61 69 74 3f 2e 72 6f  wait?).await?.ro
20f0: 77 73 5f 61 66 66 65 63 74 65 64 28 29 20 7b 0a  ws_affected() {.
2100: 09 09 09 31 20 3d 3e 20 7b 20 4f 6b 28 22 53 6f  ...1 => { Ok("So
2110: 75 72 63 65 20 65 6e 61 62 6c 65 64 2e 22 29 20  urce enabled.") 
2120: 7d 2c 0a 09 09 09 30 20 3d 3e 20 7b 20 4f 6b 28  },....0 => { Ok(
2130: 22 53 6f 75 72 63 65 20 6e 6f 74 20 66 6f 75 6e  "Source not foun
2140: 64 2e 22 29 20 7d 2c 0a 09 09 09 5f 20 3d 3e 20  d.") },...._ => 
2150: 7b 20 45 72 72 28 61 6e 79 68 6f 77 21 28 22 44  { Err(anyhow!("D
2160: 61 74 61 62 61 73 65 20 65 72 72 6f 72 2e 22 29  atabase error.")
2170: 29 20 7d 2c 0a 09 09 7d 0a 09 7d 0a 0a 09 70 75  ) },...}..}...pu
2180: 62 20 61 73 79 6e 63 20 66 6e 20 64 69 73 61 62  b async fn disab
2190: 6c 65 20 28 26 73 65 6c 66 2c 20 73 6f 75 72 63  le (&self, sourc
21a0: 65 5f 69 64 3a 20 26 69 33 32 2c 20 6f 77 6e 65  e_id: &i32, owne
21b0: 72 3a 20 69 36 34 29 20 2d 3e 20 52 65 73 75 6c  r: i64) -> Resul
21c0: 74 3c 26 73 74 72 3e 20 7b 0a 09 09 6d 61 74 63  t<&str> {...matc
21d0: 68 20 73 71 6c 78 3a 3a 71 75 65 72 79 21 28 22  h sqlx::query!("
21e0: 75 70 64 61 74 65 20 72 73 73 74 67 5f 73 6f 75  update rsstg_sou
21f0: 72 63 65 20 73 65 74 20 65 6e 61 62 6c 65 64 20  rce set enabled 
2200: 3d 20 66 61 6c 73 65 20 77 68 65 72 65 20 73 6f  = false where so
2210: 75 72 63 65 5f 69 64 20 3d 20 24 31 20 61 6e 64  urce_id = $1 and
2220: 20 6f 77 6e 65 72 20 3d 20 24 32 22 2c 0a 09 09   owner = $2",...
2230: 09 73 6f 75 72 63 65 5f 69 64 2c 20 6f 77 6e 65  .source_id, owne
2240: 72 29 2e 65 78 65 63 75 74 65 28 26 6d 75 74 20  r).execute(&mut 
2250: 2a 73 65 6c 66 2e 70 6f 6f 6c 2e 61 63 71 75 69  *self.pool.acqui
2260: 72 65 28 29 2e 61 77 61 69 74 3f 29 2e 61 77 61  re().await?).awa
2270: 69 74 3f 2e 72 6f 77 73 5f 61 66 66 65 63 74 65  it?.rows_affecte
2280: 64 28 29 20 7b 0a 09 09 09 31 20 3d 3e 20 7b 20  d() {....1 => { 
2290: 4f 6b 28 22 53 6f 75 72 63 65 20 64 69 73 61 62  Ok("Source disab
22a0: 6c 65 64 2e 22 29 20 7d 2c 0a 09 09 09 30 20 3d  led.") },....0 =
22b0: 3e 20 7b 20 4f 6b 28 22 53 6f 75 72 63 65 20 6e  > { Ok("Source n
22c0: 6f 74 20 66 6f 75 6e 64 2e 22 29 20 7d 2c 0a 09  ot found.") },..
22d0: 09 09 5f 20 3d 3e 20 7b 20 45 72 72 28 61 6e 79  .._ => { Err(any
22e0: 68 6f 77 21 28 22 44 61 74 61 62 61 73 65 20 65  how!("Database e
22f0: 72 72 6f 72 2e 22 29 29 20 7d 2c 0a 09 09 7d 0a  rror.")) },...}.
2300: 09 7d 0a 0a 09 70 75 62 20 61 73 79 6e 63 20 66  .}...pub async f
2310: 6e 20 75 70 64 61 74 65 20 28 26 73 65 6c 66 2c  n update (&self,
2320: 20 75 70 64 61 74 65 3a 20 4f 70 74 69 6f 6e 3c   update: Option<
2330: 69 33 32 3e 2c 20 63 68 61 6e 6e 65 6c 3a 20 26  i32>, channel: &
2340: 73 74 72 2c 20 63 68 61 6e 6e 65 6c 5f 69 64 3a  str, channel_id:
2350: 20 69 36 34 2c 20 75 72 6c 3a 20 26 73 74 72 2c   i64, url: &str,
2360: 20 69 76 5f 68 61 73 68 3a 20 4f 70 74 69 6f 6e   iv_hash: Option
2370: 3c 26 73 74 72 3e 2c 20 75 72 6c 5f 72 65 3a 20  <&str>, url_re: 
2380: 4f 70 74 69 6f 6e 3c 26 73 74 72 3e 2c 20 6f 77  Option<&str>, ow
2390: 6e 65 72 3a 20 69 36 34 29 20 2d 3e 20 52 65 73  ner: i64) -> Res
23a0: 75 6c 74 3c 26 73 74 72 3e 20 7b 0a 09 09 6c 65  ult<&str> {...le
23b0: 74 20 6d 75 74 20 63 6f 6e 6e 20 3d 20 73 65 6c  t mut conn = sel
23c0: 66 2e 70 6f 6f 6c 2e 61 63 71 75 69 72 65 28 29  f.pool.acquire()
23d0: 2e 61 77 61 69 74 3f 3b 0a 0a 09 09 6d 61 74 63  .await?;....matc
23e0: 68 20 6d 61 74 63 68 20 75 70 64 61 74 65 20 7b  h match update {
23f0: 0a 09 09 09 09 53 6f 6d 65 28 69 64 29 20 3d 3e  .....Some(id) =>
2400: 20 7b 0a 09 09 09 09 09 73 71 6c 78 3a 3a 71 75   {......sqlx::qu
2410: 65 72 79 21 28 22 75 70 64 61 74 65 20 72 73 73  ery!("update rss
2420: 74 67 5f 73 6f 75 72 63 65 20 73 65 74 20 63 68  tg_source set ch
2430: 61 6e 6e 65 6c 5f 69 64 20 3d 20 24 32 2c 20 75  annel_id = $2, u
2440: 72 6c 20 3d 20 24 33 2c 20 69 76 5f 68 61 73 68  rl = $3, iv_hash
2450: 20 3d 20 24 34 2c 20 6f 77 6e 65 72 20 3d 20 24   = $4, owner = $
2460: 35 2c 20 63 68 61 6e 6e 65 6c 20 3d 20 24 36 2c  5, channel = $6,
2470: 20 75 72 6c 5f 72 65 20 3d 20 24 37 20 77 68 65   url_re = $7 whe
2480: 72 65 20 73 6f 75 72 63 65 5f 69 64 20 3d 20 24  re source_id = $
2490: 31 22 2c 0a 09 09 09 09 09 09 69 64 2c 20 63 68  1",.......id, ch
24a0: 61 6e 6e 65 6c 5f 69 64 2c 20 75 72 6c 2c 20 69  annel_id, url, i
24b0: 76 5f 68 61 73 68 2c 20 6f 77 6e 65 72 2c 20 63  v_hash, owner, c
24c0: 68 61 6e 6e 65 6c 2c 20 75 72 6c 5f 72 65 29 2e  hannel, url_re).
24d0: 65 78 65 63 75 74 65 28 26 6d 75 74 20 2a 63 6f  execute(&mut *co
24e0: 6e 6e 29 2e 61 77 61 69 74 0a 09 09 09 09 7d 2c  nn).await.....},
24f0: 0a 09 09 09 09 4e 6f 6e 65 20 3d 3e 20 7b 0a 09  .....None => {..
2500: 09 09 09 09 73 71 6c 78 3a 3a 71 75 65 72 79 21  ....sqlx::query!
2510: 28 22 69 6e 73 65 72 74 20 69 6e 74 6f 20 72 73  ("insert into rs
2520: 73 74 67 5f 73 6f 75 72 63 65 20 28 63 68 61 6e  stg_source (chan
2530: 6e 65 6c 5f 69 64 2c 20 75 72 6c 2c 20 69 76 5f  nel_id, url, iv_
2540: 68 61 73 68 2c 20 6f 77 6e 65 72 2c 20 63 68 61  hash, owner, cha
2550: 6e 6e 65 6c 2c 20 75 72 6c 5f 72 65 29 20 76 61  nnel, url_re) va
2560: 6c 75 65 73 20 28 24 31 2c 20 24 32 2c 20 24 33  lues ($1, $2, $3
2570: 2c 20 24 34 2c 20 24 35 2c 20 24 36 29 22 2c 0a  , $4, $5, $6)",.
2580: 09 09 09 09 09 09 63 68 61 6e 6e 65 6c 5f 69 64  ......channel_id
2590: 2c 20 75 72 6c 2c 20 69 76 5f 68 61 73 68 2c 20  , url, iv_hash, 
25a0: 6f 77 6e 65 72 2c 20 63 68 61 6e 6e 65 6c 2c 20  owner, channel, 
25b0: 75 72 6c 5f 72 65 29 2e 65 78 65 63 75 74 65 28  url_re).execute(
25c0: 26 6d 75 74 20 2a 63 6f 6e 6e 29 2e 61 77 61 69  &mut *conn).awai
25d0: 74 0a 09 09 09 09 7d 2c 0a 09 09 09 7d 20 7b 0a  t.....},....} {.
25e0: 09 09 09 4f 6b 28 5f 29 20 3d 3e 20 4f 6b 28 6d  ...Ok(_) => Ok(m
25f0: 61 74 63 68 20 75 70 64 61 74 65 20 7b 0a 09 09  atch update {...
2600: 09 09 53 6f 6d 65 28 5f 29 20 3d 3e 20 22 43 68  ..Some(_) => "Ch
2610: 61 6e 6e 65 6c 20 75 70 64 61 74 65 64 2e 22 2c  annel updated.",
2620: 0a 09 09 09 09 4e 6f 6e 65 20 3d 3e 20 22 43 68  .....None => "Ch
2630: 61 6e 6e 65 6c 20 61 64 64 65 64 2e 22 2c 0a 09  annel added.",..
2640: 09 09 7d 29 2c 0a 09 09 09 45 72 72 28 73 71 6c  ..}),....Err(sql
2650: 78 3a 3a 45 72 72 6f 72 3a 3a 44 61 74 61 62 61  x::Error::Databa
2660: 73 65 28 65 72 72 29 29 20 3d 3e 20 7b 0a 09 09  se(err)) => {...
2670: 09 09 6d 61 74 63 68 20 65 72 72 2e 64 6f 77 6e  ..match err.down
2680: 63 61 73 74 3a 3a 3c 73 71 6c 78 3a 3a 70 6f 73  cast::<sqlx::pos
2690: 74 67 72 65 73 3a 3a 50 67 44 61 74 61 62 61 73  tgres::PgDatabas
26a0: 65 45 72 72 6f 72 3e 28 29 2e 72 6f 75 74 69 6e  eError>().routin
26b0: 65 28 29 20 7b 0a 09 09 09 09 09 53 6f 6d 65 28  e() {......Some(
26c0: 22 5f 62 74 5f 63 68 65 63 6b 5f 75 6e 69 71 75  "_bt_check_uniqu
26d0: 65 22 2c 20 29 20 3d 3e 20 7b 0a 09 09 09 09 09  e", ) => {......
26e0: 09 4f 6b 28 22 44 75 70 6c 69 63 61 74 65 20 6b  .Ok("Duplicate k
26f0: 65 79 2e 22 29 0a 09 09 09 09 09 7d 2c 0a 09 09  ey.")......},...
2700: 09 09 09 53 6f 6d 65 28 5f 29 20 3d 3e 20 7b 0a  ...Some(_) => {.
2710: 09 09 09 09 09 09 4f 6b 28 22 44 61 74 61 62 61  ......Ok("Databa
2720: 73 65 20 65 72 72 6f 72 2e 22 29 0a 09 09 09 09  se error.").....
2730: 09 7d 2c 0a 09 09 09 09 09 4e 6f 6e 65 20 3d 3e  .},......None =>
2740: 20 7b 0a 09 09 09 09 09 09 4f 6b 28 22 4e 6f 20   {.......Ok("No 
2750: 64 61 74 61 62 61 73 65 20 65 72 72 6f 72 20 65  database error e
2760: 78 74 72 61 63 74 65 64 2e 22 29 0a 09 09 09 09  xtracted.").....
2770: 09 7d 2c 0a 09 09 09 09 7d 0a 09 09 09 7d 2c 0a  .},.....}....},.
2780: 09 09 09 45 72 72 28 65 72 72 29 20 3d 3e 20 7b  ...Err(err) => {
2790: 0a 09 09 09 09 62 61 69 6c 21 28 22 53 6f 72 72  .....bail!("Sorr
27a0: 79 2c 20 75 6e 6b 6e 6f 77 6e 20 65 72 72 6f 72  y, unknown error
27b0: 3a 5c 6e 7b 65 72 72 3a 23 3f 7d 5c 6e 22 29 3b  :\n{err:#?}\n");
27c0: 0a 09 09 09 7d 2c 0a 09 09 7d 0a 09 7d 0a 0a 09  ....},...}..}...
27d0: 61 73 79 6e 63 20 66 6e 20 61 75 74 6f 66 65 74  async fn autofet
27e0: 63 68 28 26 73 65 6c 66 29 20 2d 3e 20 52 65 73  ch(&self) -> Res
27f0: 75 6c 74 3c 73 74 64 3a 3a 74 69 6d 65 3a 3a 44  ult<std::time::D
2800: 75 72 61 74 69 6f 6e 3e 20 7b 0a 09 09 6c 65 74  uration> {...let
2810: 20 6d 75 74 20 64 65 6c 61 79 20 3d 20 63 68 72   mut delay = chr
2820: 6f 6e 6f 3a 3a 44 75 72 61 74 69 6f 6e 3a 3a 6d  ono::Duration::m
2830: 69 6e 75 74 65 73 28 31 29 3b 0a 09 09 6c 65 74  inutes(1);...let
2840: 20 6e 6f 77 20 3d 20 63 68 72 6f 6e 6f 3a 3a 4c   now = chrono::L
2850: 6f 63 61 6c 3a 3a 6e 6f 77 28 29 3b 0a 09 09 6c  ocal::now();...l
2860: 65 74 20 6d 75 74 20 71 75 65 75 65 20 3d 20 73  et mut queue = s
2870: 71 6c 78 3a 3a 71 75 65 72 79 21 28 72 23 22 73  qlx::query!(r#"s
2880: 65 6c 65 63 74 20 73 6f 75 72 63 65 5f 69 64 2c  elect source_id,
2890: 20 6e 65 78 74 5f 66 65 74 63 68 20 61 73 20 22   next_fetch as "
28a0: 6e 65 78 74 5f 66 65 74 63 68 3a 20 44 61 74 65  next_fetch: Date
28b0: 54 69 6d 65 3c 63 68 72 6f 6e 6f 3a 3a 4c 6f 63  Time<chrono::Loc
28c0: 61 6c 3e 22 2c 20 6f 77 6e 65 72 20 66 72 6f 6d  al>", owner from
28d0: 20 72 73 73 74 67 5f 6f 72 64 65 72 20 6e 61 74   rsstg_order nat
28e0: 75 72 61 6c 20 6c 65 66 74 20 6a 6f 69 6e 20 72  ural left join r
28f0: 73 73 74 67 5f 73 6f 75 72 63 65 20 77 68 65 72  sstg_source wher
2900: 65 20 6e 65 78 74 5f 66 65 74 63 68 20 3c 20 6e  e next_fetch < n
2910: 6f 77 28 29 20 2b 20 69 6e 74 65 72 76 61 6c 20  ow() + interval 
2920: 27 31 20 6d 69 6e 75 74 65 27 3b 22 23 29 0a 09  '1 minute';"#)..
2930: 09 09 2e 66 65 74 63 68 5f 61 6c 6c 28 26 6d 75  ...fetch_all(&mu
2940: 74 20 2a 73 65 6c 66 2e 70 6f 6f 6c 2e 61 63 71  t *self.pool.acq
2950: 75 69 72 65 28 29 2e 61 77 61 69 74 3f 29 2e 61  uire().await?).a
2960: 77 61 69 74 3f 3b 0a 09 09 66 6f 72 20 72 6f 77  wait?;...for row
2970: 20 69 6e 20 71 75 65 75 65 2e 69 74 65 72 28 29   in queue.iter()
2980: 20 7b 0a 09 09 09 69 66 20 6c 65 74 20 53 6f 6d   {....if let Som
2990: 65 28 6e 65 78 74 5f 66 65 74 63 68 29 20 3d 20  e(next_fetch) = 
29a0: 72 6f 77 2e 6e 65 78 74 5f 66 65 74 63 68 20 7b  row.next_fetch {
29b0: 0a 09 09 09 09 69 66 20 6e 65 78 74 5f 66 65 74  .....if next_fet
29c0: 63 68 20 3c 20 6e 6f 77 20 7b 0a 09 09 09 09 09  ch < now {......
29d0: 69 66 20 6c 65 74 20 28 53 6f 6d 65 28 6f 77 6e  if let (Some(own
29e0: 65 72 29 2c 20 53 6f 6d 65 28 73 6f 75 72 63 65  er), Some(source
29f0: 5f 69 64 29 29 20 3d 20 28 72 6f 77 2e 6f 77 6e  _id)) = (row.own
2a00: 65 72 2c 20 72 6f 77 2e 73 6f 75 72 63 65 5f 69  er, row.source_i
2a10: 64 29 20 7b 0a 09 09 09 09 09 09 6c 65 74 20 63  d) {.......let c
2a20: 6c 6f 6e 65 20 3d 20 43 6f 72 65 20 7b 0a 09 09  lone = Core {...
2a30: 09 09 09 09 09 6f 77 6e 65 72 5f 63 68 61 74 3a  .....owner_chat:
2a40: 20 6f 77 6e 65 72 2c 0a 09 09 09 09 09 09 09 2e   owner,.........
2a50: 2e 73 65 6c 66 2e 63 6c 6f 6e 65 28 29 0a 09 09  .self.clone()...
2a60: 09 09 09 09 7d 3b 0a 09 09 09 09 09 09 74 61 73  ....};.......tas
2a70: 6b 3a 3a 73 70 61 77 6e 28 61 73 79 6e 63 20 6d  k::spawn(async m
2a80: 6f 76 65 20 7b 0a 09 09 09 09 09 09 09 69 66 20  ove {........if 
2a90: 6c 65 74 20 45 72 72 28 65 72 72 29 20 3d 20 63  let Err(err) = c
2aa0: 6c 6f 6e 65 2e 63 68 65 63 6b 28 26 73 6f 75 72  lone.check(&sour
2ab0: 63 65 5f 69 64 2c 20 6f 77 6e 65 72 2c 20 74 72  ce_id, owner, tr
2ac0: 75 65 29 2e 61 77 61 69 74 20 7b 0a 09 09 09 09  ue).await {.....
2ad0: 09 09 09 09 69 66 20 6c 65 74 20 45 72 72 28 65  ....if let Err(e
2ae0: 72 72 29 20 3d 20 63 6c 6f 6e 65 2e 73 65 6e 64  rr) = clone.send
2af0: 28 26 66 6f 72 6d 61 74 21 28 22 f0 9f 9b 91 20  (&format!("šŸ›‘ 
2b00: 7b 65 72 72 3a 3f 7d 22 29 2c 20 4e 6f 6e 65 2c  {err:?}"), None,
2b10: 20 4e 6f 6e 65 29 2e 61 77 61 69 74 20 7b 0a 09   None).await {..
2b20: 09 09 09 09 09 09 09 09 65 70 72 69 6e 74 6c 6e  ........eprintln
2b30: 21 28 22 43 68 65 63 6b 20 65 72 72 6f 72 3a 20  !("Check error: 
2b40: 7b 65 72 72 3a 3f 7d 22 29 3b 0a 09 09 09 09 09  {err:?}");......
2b50: 09 09 09 09 2f 2f 20 63 6c 6f 6e 65 2e 64 69 73  ....// clone.dis
2b60: 61 62 6c 65 28 26 73 6f 75 72 63 65 5f 69 64 2c  able(&source_id,
2b70: 20 6f 77 6e 65 72 29 2e 61 77 61 69 74 2e 75 6e   owner).await.un
2b80: 77 72 61 70 28 29 3b 0a 09 09 09 09 09 09 09 09  wrap();.........
2b90: 7d 3b 0a 09 09 09 09 09 09 09 7d 3b 0a 09 09 09  };........};....
2ba0: 09 09 09 7d 29 3b 0a 09 09 09 09 09 7d 0a 09 09  ...});......}...
2bb0: 09 09 7d 20 65 6c 73 65 20 69 66 20 6e 65 78 74  ..} else if next
2bc0: 5f 66 65 74 63 68 20 2d 20 6e 6f 77 20 3c 20 64  _fetch - now < d
2bd0: 65 6c 61 79 20 7b 0a 09 09 09 09 09 64 65 6c 61  elay {......dela
2be0: 79 20 3d 20 6e 65 78 74 5f 66 65 74 63 68 20 2d  y = next_fetch -
2bf0: 20 6e 6f 77 3b 0a 09 09 09 09 7d 0a 09 09 09 7d   now;.....}....}
2c00: 0a 09 09 7d 3b 0a 09 09 71 75 65 75 65 2e 63 6c  ...};...queue.cl
2c10: 65 61 72 28 29 3b 0a 09 09 4f 6b 28 64 65 6c 61  ear();...Ok(dela
2c20: 79 2e 74 6f 5f 73 74 64 28 29 3f 29 0a 09 7d 0a  y.to_std()?)..}.
2c30: 0a 09 70 75 62 20 61 73 79 6e 63 20 66 6e 20 6c  ..pub async fn l
2c40: 69 73 74 20 28 26 73 65 6c 66 2c 20 6f 77 6e 65  ist (&self, owne
2c50: 72 3a 20 69 36 34 29 20 2d 3e 20 52 65 73 75 6c  r: i64) -> Resul
2c60: 74 3c 53 74 72 69 6e 67 3e 20 7b 0a 09 09 6c 65  t<String> {...le
2c70: 74 20 6d 75 74 20 72 65 70 6c 79 3a 20 56 65 63  t mut reply: Vec
2c80: 3c 43 6f 77 3c 73 74 72 3e 3e 20 3d 20 76 65 63  <Cow<str>> = vec
2c90: 21 5b 5d 3b 0a 09 09 72 65 70 6c 79 2e 70 75 73  ![];...reply.pus
2ca0: 68 28 22 43 68 61 6e 6e 65 6c 73 3a 22 2e 69 6e  h("Channels:".in
2cb0: 74 6f 28 29 29 3b 0a 09 09 6c 65 74 20 72 6f 77  to());...let row
2cc0: 73 20 3d 20 73 71 6c 78 3a 3a 71 75 65 72 79 21  s = sqlx::query!
2cd0: 28 22 73 65 6c 65 63 74 20 73 6f 75 72 63 65 5f  ("select source_
2ce0: 69 64 2c 20 63 68 61 6e 6e 65 6c 2c 20 65 6e 61  id, channel, ena
2cf0: 62 6c 65 64 2c 20 75 72 6c 2c 20 69 76 5f 68 61  bled, url, iv_ha
2d00: 73 68 2c 20 75 72 6c 5f 72 65 20 66 72 6f 6d 20  sh, url_re from 
2d10: 72 73 73 74 67 5f 73 6f 75 72 63 65 20 77 68 65  rsstg_source whe
2d20: 72 65 20 6f 77 6e 65 72 20 3d 20 24 31 20 6f 72  re owner = $1 or
2d30: 64 65 72 20 62 79 20 73 6f 75 72 63 65 5f 69 64  der by source_id
2d40: 22 2c 0a 09 09 09 6f 77 6e 65 72 29 2e 66 65 74  ",....owner).fet
2d50: 63 68 5f 61 6c 6c 28 26 6d 75 74 20 2a 73 65 6c  ch_all(&mut *sel
2d60: 66 2e 70 6f 6f 6c 2e 61 63 71 75 69 72 65 28 29  f.pool.acquire()
2d70: 2e 61 77 61 69 74 3f 29 2e 61 77 61 69 74 3f 3b  .await?).await?;
2d80: 0a 09 09 66 6f 72 20 72 6f 77 20 69 6e 20 72 6f  ...for row in ro
2d90: 77 73 2e 69 74 65 72 28 29 20 7b 0a 09 09 09 72  ws.iter() {....r
2da0: 65 70 6c 79 2e 70 75 73 68 28 66 6f 72 6d 61 74  eply.push(format
2db0: 21 28 22 5c 6e 5c 5c 23 ef b8 8f e2 83 a3 20 7b  !("\n\\#ļøāƒ£ {
2dc0: 7d 20 5c 5c 2a ef b8 8f e2 83 a3 20 60 7b 7d 60  } \\*ļøāƒ£ `{}`
2dd0: 20 7b 7d 5c 6e f0 9f 94 97 20 60 7b 7d 60 22 2c   {}\nšŸ”— `{}`",
2de0: 20 72 6f 77 2e 73 6f 75 72 63 65 5f 69 64 2c 20   row.source_id, 
2df0: 72 6f 77 2e 63 68 61 6e 6e 65 6c 2c 0a 09 09 09  row.channel,....
2e00: 09 6d 61 74 63 68 20 72 6f 77 2e 65 6e 61 62 6c  .match row.enabl
2e10: 65 64 20 7b 0a 09 09 09 09 09 74 72 75 65 20 20  ed {......true  
2e20: 3d 3e 20 22 f0 9f 94 84 20 65 6e 61 62 6c 65 64  => "šŸ”„ enabled
2e30: 22 2c 0a 09 09 09 09 09 66 61 6c 73 65 20 3d 3e  ",......false =>
2e40: 20 22 e2 9b 94 20 64 69 73 61 62 6c 65 64 22 2c   "ā›” disabled",
2e50: 0a 09 09 09 09 7d 2c 20 72 6f 77 2e 75 72 6c 29  .....}, row.url)
2e60: 2e 69 6e 74 6f 28 29 29 3b 0a 09 09 09 69 66 20  .into());....if 
2e70: 6c 65 74 20 53 6f 6d 65 28 68 61 73 68 29 20 3d  let Some(hash) =
2e80: 20 26 72 6f 77 2e 69 76 5f 68 61 73 68 20 7b 0a   &row.iv_hash {.
2e90: 09 09 09 09 72 65 70 6c 79 2e 70 75 73 68 28 66  ....reply.push(f
2ea0: 6f 72 6d 61 74 21 28 22 49 56 3a 20 60 7b 68 61  ormat!("IV: `{ha
2eb0: 73 68 7d 60 22 29 2e 69 6e 74 6f 28 29 29 3b 0a  sh}`").into());.
2ec0: 09 09 09 7d 0a 09 09 09 69 66 20 6c 65 74 20 53  ...}....if let S
2ed0: 6f 6d 65 28 72 65 29 20 3d 20 26 72 6f 77 2e 75  ome(re) = &row.u
2ee0: 72 6c 5f 72 65 20 7b 0a 09 09 09 09 72 65 70 6c  rl_re {.....repl
2ef0: 79 2e 70 75 73 68 28 66 6f 72 6d 61 74 21 28 22  y.push(format!("
2f00: 52 45 3a 20 60 7b 72 65 7d 60 22 29 2e 69 6e 74  RE: `{re}`").int
2f10: 6f 28 29 29 3b 0a 09 09 09 7d 0a 09 09 7d 3b 0a  o());....}...};.
2f20: 09 09 4f 6b 28 72 65 70 6c 79 2e 6a 6f 69 6e 28  ..Ok(reply.join(
2f30: 22 5c 6e 22 29 29 0a 09 7d 0a 7d 0a              "\n"))..}.}.