Hex Artifact Content
Logged in as anonymous

Artifact b3dd317a5fe8d3eaace9403014009076d4caac9d278fef98fcc1b7261746ef2c:


0000: 75 73 65 20 61 6e 79 68 6f 77 3a 3a 7b 61 6e 79  use anyhow::{any
0010: 68 6f 77 2c 20 62 61 69 6c 2c 20 43 6f 6e 74 65  how, bail, Conte
0020: 78 74 2c 20 52 65 73 75 6c 74 7d 3b 0a 75 73 65  xt, Result};.use
0030: 20 63 68 72 6f 6e 6f 3a 3a 44 61 74 65 54 69 6d   chrono::DateTim
0040: 65 3b 0a 75 73 65 20 73 71 6c 78 3a 3a 7b 0a 09  e;.use sqlx::{..
0050: 70 6f 73 74 67 72 65 73 3a 3a 50 67 50 6f 6f 6c  postgres::PgPool
0060: 4f 70 74 69 6f 6e 73 2c 0a 09 52 6f 77 2c 0a 7d  Options,..Row,.}
0070: 3b 0a 75 73 65 20 73 74 64 3a 3a 7b 0a 09 62 6f  ;.use std::{..bo
0080: 72 72 6f 77 3a 3a 43 6f 77 2c 0a 09 63 6f 6c 6c  rrow::Cow,..coll
0090: 65 63 74 69 6f 6e 73 3a 3a 7b 0a 09 09 42 54 72  ections::{...BTr
00a0: 65 65 4d 61 70 2c 0a 09 09 48 61 73 68 53 65 74  eeMap,...HashSet
00b0: 2c 0a 09 7d 2c 0a 09 73 79 6e 63 3a 3a 7b 41 72  ,..},..sync::{Ar
00c0: 63 2c 20 4d 75 74 65 78 7d 2c 0a 7d 3b 0a 0a 23  c, Mutex},.};..#
00d0: 5b 64 65 72 69 76 65 28 43 6c 6f 6e 65 29 5d 0a  [derive(Clone)].
00e0: 70 75 62 20 73 74 72 75 63 74 20 43 6f 72 65 20  pub struct Core 
00f0: 7b 0a 09 2f 2f 6f 77 6e 65 72 3a 20 69 36 34 2c  {..//owner: i64,
0100: 0a 09 2f 2f 61 70 69 5f 6b 65 79 3a 20 53 74 72  ..//api_key: Str
0110: 69 6e 67 2c 0a 09 6f 77 6e 65 72 5f 63 68 61 74  ing,..owner_chat
0120: 3a 20 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a  : telegram_bot::
0130: 55 73 65 72 49 64 2c 0a 09 70 75 62 20 74 67 3a  UserId,..pub tg:
0140: 20 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 41   telegram_bot::A
0150: 70 69 2c 0a 09 70 75 62 20 6d 79 3a 20 74 65 6c  pi,..pub my: tel
0160: 65 67 72 61 6d 5f 62 6f 74 3a 3a 55 73 65 72 2c  egram_bot::User,
0170: 0a 09 70 6f 6f 6c 3a 20 73 71 6c 78 3a 3a 50 6f  ..pool: sqlx::Po
0180: 6f 6c 3c 73 71 6c 78 3a 3a 50 6f 73 74 67 72 65  ol<sqlx::Postgre
0190: 73 3e 2c 0a 09 73 6f 75 72 63 65 73 3a 20 41 72  s>,..sources: Ar
01a0: 63 3c 4d 75 74 65 78 3c 48 61 73 68 53 65 74 3c  c<Mutex<HashSet<
01b0: 41 72 63 3c 69 33 32 3e 3e 3e 3e 2c 0a 7d 0a 0a  Arc<i32>>>>,.}..
01c0: 69 6d 70 6c 20 43 6f 72 65 20 7b 0a 09 70 75 62  impl Core {..pub
01d0: 20 61 73 79 6e 63 20 66 6e 20 6e 65 77 28 73 65   async fn new(se
01e0: 74 74 69 6e 67 73 3a 20 63 6f 6e 66 69 67 3a 3a  ttings: config::
01f0: 43 6f 6e 66 69 67 29 20 2d 3e 20 52 65 73 75 6c  Config) -> Resul
0200: 74 3c 41 72 63 3c 43 6f 72 65 3e 3e 20 7b 0a 09  t<Arc<Core>> {..
0210: 09 6c 65 74 20 6f 77 6e 65 72 20 3d 20 73 65 74  .let owner = set
0220: 74 69 6e 67 73 2e 67 65 74 5f 69 6e 74 28 22 6f  tings.get_int("o
0230: 77 6e 65 72 22 29 3f 3b 0a 09 09 6c 65 74 20 61  wner")?;...let a
0240: 70 69 5f 6b 65 79 20 3d 20 73 65 74 74 69 6e 67  pi_key = setting
0250: 73 2e 67 65 74 5f 73 74 72 69 6e 67 28 22 61 70  s.get_string("ap
0260: 69 5f 6b 65 79 22 29 3f 3b 0a 09 09 6c 65 74 20  i_key")?;...let 
0270: 74 67 20 3d 20 74 65 6c 65 67 72 61 6d 5f 62 6f  tg = telegram_bo
0280: 74 3a 3a 41 70 69 3a 3a 6e 65 77 28 26 61 70 69  t::Api::new(&api
0290: 5f 6b 65 79 29 3b 0a 09 09 6c 65 74 20 63 6f 72  _key);...let cor
02a0: 65 20 3d 20 41 72 63 3a 3a 6e 65 77 28 43 6f 72  e = Arc::new(Cor
02b0: 65 20 7b 0a 09 09 09 2f 2f 6f 77 6e 65 72 2c 0a  e {....//owner,.
02c0: 09 09 09 2f 2f 61 70 69 5f 6b 65 79 3a 20 61 70  ...//api_key: ap
02d0: 69 5f 6b 65 79 2e 63 6c 6f 6e 65 28 29 2c 0a 09  i_key.clone(),..
02e0: 09 09 6d 79 3a 20 74 67 2e 73 65 6e 64 28 74 65  ..my: tg.send(te
02f0: 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 47 65 74 4d  legram_bot::GetM
0300: 65 29 2e 61 77 61 69 74 3f 2c 0a 09 09 09 74 67  e).await?,....tg
0310: 2c 0a 09 09 09 6f 77 6e 65 72 5f 63 68 61 74 3a  ,....owner_chat:
0320: 20 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 55   telegram_bot::U
0330: 73 65 72 49 64 3a 3a 6e 65 77 28 6f 77 6e 65 72  serId::new(owner
0340: 29 2c 0a 09 09 09 70 6f 6f 6c 3a 20 50 67 50 6f  ),....pool: PgPo
0350: 6f 6c 4f 70 74 69 6f 6e 73 3a 3a 6e 65 77 28 29  olOptions::new()
0360: 0a 09 09 09 09 2e 6d 61 78 5f 63 6f 6e 6e 65 63  ......max_connec
0370: 74 69 6f 6e 73 28 35 29 0a 09 09 09 09 2e 63 6f  tions(5)......co
0380: 6e 6e 65 63 74 5f 74 69 6d 65 6f 75 74 28 73 74  nnect_timeout(st
0390: 64 3a 3a 74 69 6d 65 3a 3a 44 75 72 61 74 69 6f  d::time::Duratio
03a0: 6e 3a 3a 6e 65 77 28 33 30 30 2c 20 30 29 29 0a  n::new(300, 0)).
03b0: 09 09 09 09 2e 69 64 6c 65 5f 74 69 6d 65 6f 75  .....idle_timeou
03c0: 74 28 73 74 64 3a 3a 74 69 6d 65 3a 3a 44 75 72  t(std::time::Dur
03d0: 61 74 69 6f 6e 3a 3a 6e 65 77 28 36 30 2c 20 30  ation::new(60, 0
03e0: 29 29 0a 09 09 09 09 2e 63 6f 6e 6e 65 63 74 5f  ))......connect_
03f0: 6c 61 7a 79 28 26 73 65 74 74 69 6e 67 73 2e 67  lazy(&settings.g
0400: 65 74 5f 73 74 72 69 6e 67 28 22 70 67 22 29 3f  et_string("pg")?
0410: 29 3f 2c 0a 09 09 09 73 6f 75 72 63 65 73 3a 20  )?,....sources: 
0420: 41 72 63 3a 3a 6e 65 77 28 4d 75 74 65 78 3a 3a  Arc::new(Mutex::
0430: 6e 65 77 28 48 61 73 68 53 65 74 3a 3a 6e 65 77  new(HashSet::new
0440: 28 29 29 29 2c 0a 09 09 7d 29 3b 0a 09 09 6c 65  ())),...});...le
0450: 74 20 63 6c 6f 6e 65 20 3d 20 63 6f 72 65 2e 63  t clone = core.c
0460: 6c 6f 6e 65 28 29 3b 0a 09 09 74 6f 6b 69 6f 3a  lone();...tokio:
0470: 3a 73 70 61 77 6e 28 61 73 79 6e 63 20 6d 6f 76  :spawn(async mov
0480: 65 20 7b 0a 09 09 09 6c 6f 6f 70 20 7b 0a 09 09  e {....loop {...
0490: 09 09 6c 65 74 20 64 65 6c 61 79 20 3d 20 6d 61  ..let delay = ma
04a0: 74 63 68 20 26 63 6c 6f 6e 65 2e 61 75 74 6f 66  tch &clone.autof
04b0: 65 74 63 68 28 29 2e 61 77 61 69 74 20 7b 0a 09  etch().await {..
04c0: 09 09 09 09 45 72 72 28 65 72 72 29 20 3d 3e 20  ....Err(err) => 
04d0: 7b 0a 09 09 09 09 09 09 69 66 20 6c 65 74 20 45  {.......if let E
04e0: 72 72 28 65 72 72 29 20 3d 20 63 6c 6f 6e 65 2e  rr(err) = clone.
04f0: 73 65 6e 64 28 66 6f 72 6d 61 74 21 28 22 f0 9f  send(format!("šŸ
0500: 9b 91 20 7b 3a 3f 7d 22 2c 20 65 72 72 29 2c 20  ›‘ {:?}", err), 
0510: 4e 6f 6e 65 2c 20 4e 6f 6e 65 29 2e 61 77 61 69  None, None).awai
0520: 74 20 7b 0a 09 09 09 09 09 09 09 65 70 72 69 6e  t {........eprin
0530: 74 6c 6e 21 28 22 41 75 74 6f 66 65 74 63 68 20  tln!("Autofetch 
0540: 65 72 72 6f 72 3a 20 7b 7d 22 2c 20 65 72 72 29  error: {}", err)
0550: 3b 0a 09 09 09 09 09 09 7d 3b 0a 09 09 09 09 09  ;.......};......
0560: 09 74 6f 6b 69 6f 3a 3a 74 69 6d 65 3a 3a 44 75  .tokio::time::Du
0570: 72 61 74 69 6f 6e 3a 3a 66 72 6f 6d 5f 73 65 63  ration::from_sec
0580: 73 28 36 30 29 0a 09 09 09 09 09 7d 2c 0a 09 09  s(60)......},...
0590: 09 09 09 4f 6b 28 74 69 6d 65 29 20 3d 3e 20 2a  ...Ok(time) => *
05a0: 74 69 6d 65 2c 0a 09 09 09 09 7d 3b 0a 09 09 09  time,.....};....
05b0: 09 74 6f 6b 69 6f 3a 3a 74 69 6d 65 3a 3a 73 6c  .tokio::time::sl
05c0: 65 65 70 28 64 65 6c 61 79 29 2e 61 77 61 69 74  eep(delay).await
05d0: 3b 0a 09 09 09 7d 0a 09 09 7d 29 3b 0a 09 09 4f  ;....}...});...O
05e0: 6b 28 63 6f 72 65 29 0a 09 7d 0a 0a 09 70 75 62  k(core)..}...pub
05f0: 20 66 6e 20 73 74 72 65 61 6d 28 26 73 65 6c 66   fn stream(&self
0600: 29 20 2d 3e 20 74 65 6c 65 67 72 61 6d 5f 62 6f  ) -> telegram_bo
0610: 74 3a 3a 55 70 64 61 74 65 73 53 74 72 65 61 6d  t::UpdatesStream
0620: 20 7b 0a 09 09 73 65 6c 66 2e 74 67 2e 73 74 72   {...self.tg.str
0630: 65 61 6d 28 29 0a 09 7d 0a 0a 09 70 75 62 20 61  eam()..}...pub a
0640: 73 79 6e 63 20 66 6e 20 73 65 6e 64 3c 27 61 2c  sync fn send<'a,
0650: 20 53 3e 28 26 73 65 6c 66 2c 20 6d 73 67 3a 20   S>(&self, msg: 
0660: 53 2c 20 74 61 72 67 65 74 3a 20 4f 70 74 69 6f  S, target: Optio
0670: 6e 3c 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a  n<telegram_bot::
0680: 55 73 65 72 49 64 3e 2c 20 6d 6f 64 65 3a 20 4f  UserId>, mode: O
0690: 70 74 69 6f 6e 3c 74 65 6c 65 67 72 61 6d 5f 62  ption<telegram_b
06a0: 6f 74 3a 3a 74 79 70 65 73 3a 3a 50 61 72 73 65  ot::types::Parse
06b0: 4d 6f 64 65 3e 29 20 2d 3e 20 52 65 73 75 6c 74  Mode>) -> Result
06c0: 3c 28 29 3e 0a 09 77 68 65 72 65 20 53 3a 20 49  <()>..where S: I
06d0: 6e 74 6f 3c 43 6f 77 3c 27 61 2c 20 73 74 72 3e  nto<Cow<'a, str>
06e0: 3e 20 7b 0a 09 09 6c 65 74 20 6d 6f 64 65 20 3d  > {...let mode =
06f0: 20 6d 6f 64 65 2e 75 6e 77 72 61 70 5f 6f 72 28   mode.unwrap_or(
0700: 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 74 79  telegram_bot::ty
0710: 70 65 73 3a 3a 50 61 72 73 65 4d 6f 64 65 3a 3a  pes::ParseMode::
0720: 48 74 6d 6c 29 3b 0a 09 09 6c 65 74 20 74 61 72  Html);...let tar
0730: 67 65 74 20 3d 20 74 61 72 67 65 74 2e 75 6e 77  get = target.unw
0740: 72 61 70 5f 6f 72 28 73 65 6c 66 2e 6f 77 6e 65  rap_or(self.owne
0750: 72 5f 63 68 61 74 29 3b 0a 09 09 73 65 6c 66 2e  r_chat);...self.
0760: 74 67 2e 73 65 6e 64 28 74 65 6c 65 67 72 61 6d  tg.send(telegram
0770: 5f 62 6f 74 3a 3a 53 65 6e 64 4d 65 73 73 61 67  _bot::SendMessag
0780: 65 3a 3a 6e 65 77 28 74 61 72 67 65 74 2c 20 6d  e::new(target, m
0790: 73 67 29 2e 70 61 72 73 65 5f 6d 6f 64 65 28 6d  sg).parse_mode(m
07a0: 6f 64 65 29 29 2e 61 77 61 69 74 3f 3b 0a 09 09  ode)).await?;...
07b0: 4f 6b 28 28 29 29 0a 09 7d 0a 0a 09 70 75 62 20  Ok(())..}...pub 
07c0: 61 73 79 6e 63 20 66 6e 20 63 68 65 63 6b 3c 53  async fn check<S
07d0: 3e 28 26 73 65 6c 66 2c 20 69 64 3a 20 26 69 33  >(&self, id: &i3
07e0: 32 2c 20 6f 77 6e 65 72 3a 20 53 2c 20 72 65 61  2, owner: S, rea
07f0: 6c 3a 20 62 6f 6f 6c 29 20 2d 3e 20 52 65 73 75  l: bool) -> Resu
0800: 6c 74 3c 43 6f 77 3c 27 5f 2c 20 73 74 72 3e 3e  lt<Cow<'_, str>>
0810: 0a 09 77 68 65 72 65 20 53 3a 20 49 6e 74 6f 3c  ..where S: Into<
0820: 69 36 34 3e 20 7b 0a 09 09 6c 65 74 20 6f 77 6e  i64> {...let own
0830: 65 72 20 3d 20 6f 77 6e 65 72 2e 69 6e 74 6f 28  er = owner.into(
0840: 29 3b 0a 0a 09 09 6c 65 74 20 6d 75 74 20 70 6f  );....let mut po
0850: 73 74 65 64 3a 20 69 33 32 20 3d 20 30 3b 0a 09  sted: i32 = 0;..
0860: 09 6c 65 74 20 69 64 20 3d 20 7b 0a 09 09 09 6c  .let id = {....l
0870: 65 74 20 6d 75 74 20 73 65 74 20 3d 20 73 65 6c  et mut set = sel
0880: 66 2e 73 6f 75 72 63 65 73 2e 6c 6f 63 6b 28 29  f.sources.lock()
0890: 2e 75 6e 77 72 61 70 28 29 3b 0a 09 09 09 6d 61  .unwrap();....ma
08a0: 74 63 68 20 73 65 74 2e 67 65 74 28 69 64 29 20  tch set.get(id) 
08b0: 7b 0a 09 09 09 09 53 6f 6d 65 28 69 64 29 20 3d  {.....Some(id) =
08c0: 3e 20 69 64 2e 63 6c 6f 6e 65 28 29 2c 0a 09 09  > id.clone(),...
08d0: 09 09 4e 6f 6e 65 20 3d 3e 20 7b 0a 09 09 09 09  ..None => {.....
08e0: 09 6c 65 74 20 69 64 20 3d 20 41 72 63 3a 3a 6e  .let id = Arc::n
08f0: 65 77 28 2a 69 64 29 3b 0a 09 09 09 09 09 73 65  ew(*id);......se
0900: 74 2e 69 6e 73 65 72 74 28 69 64 2e 63 6c 6f 6e  t.insert(id.clon
0910: 65 28 29 29 3b 0a 09 09 09 09 09 69 64 2e 63 6c  e());......id.cl
0920: 6f 6e 65 28 29 0a 09 09 09 09 7d 2c 0a 09 09 09  one().....},....
0930: 7d 0a 09 09 7d 3b 0a 09 09 6c 65 74 20 63 6f 75  }...};...let cou
0940: 6e 74 20 3d 20 41 72 63 3a 3a 73 74 72 6f 6e 67  nt = Arc::strong
0950: 5f 63 6f 75 6e 74 28 26 69 64 29 3b 0a 09 09 69  _count(&id);...i
0960: 66 20 63 6f 75 6e 74 20 3d 3d 20 32 20 7b 0a 09  f count == 2 {..
0970: 09 09 6c 65 74 20 6d 75 74 20 63 6f 6e 6e 20 3d  ..let mut conn =
0980: 20 73 65 6c 66 2e 70 6f 6f 6c 2e 61 63 71 75 69   self.pool.acqui
0990: 72 65 28 29 2e 61 77 61 69 74 0a 09 09 09 09 2e  re().await......
09a0: 77 69 74 68 5f 63 6f 6e 74 65 78 74 28 7c 7c 20  with_context(|| 
09b0: 66 6f 72 6d 61 74 21 28 22 51 75 65 72 79 20 71  format!("Query q
09c0: 75 65 75 65 20 66 65 74 63 68 20 63 6f 6e 6e 3a  ueue fetch conn:
09d0: 5c 6e 7b 3a 3f 7d 22 2c 20 26 73 65 6c 66 2e 70  \n{:?}", &self.p
09e0: 6f 6f 6c 29 29 3f 3b 0a 09 09 09 6c 65 74 20 72  ool))?;....let r
09f0: 6f 77 20 3d 20 73 71 6c 78 3a 3a 71 75 65 72 79  ow = sqlx::query
0a00: 28 22 73 65 6c 65 63 74 20 73 6f 75 72 63 65 5f  ("select source_
0a10: 69 64 2c 20 63 68 61 6e 6e 65 6c 5f 69 64 2c 20  id, channel_id, 
0a20: 75 72 6c 2c 20 69 76 5f 68 61 73 68 2c 20 6f 77  url, iv_hash, ow
0a30: 6e 65 72 2c 20 75 72 6c 5f 72 65 20 66 72 6f 6d  ner, url_re from
0a40: 20 72 73 73 74 67 5f 73 6f 75 72 63 65 20 77 68   rsstg_source wh
0a50: 65 72 65 20 73 6f 75 72 63 65 5f 69 64 20 3d 20  ere source_id = 
0a60: 24 31 20 61 6e 64 20 6f 77 6e 65 72 20 3d 20 24  $1 and owner = $
0a70: 32 22 29 0a 09 09 09 09 2e 62 69 6e 64 28 2a 69  2")......bind(*i
0a80: 64 29 0a 09 09 09 09 2e 62 69 6e 64 28 6f 77 6e  d)......bind(own
0a90: 65 72 29 0a 09 09 09 09 2e 66 65 74 63 68 5f 6f  er)......fetch_o
0aa0: 6e 65 28 26 6d 75 74 20 63 6f 6e 6e 29 2e 61 77  ne(&mut conn).aw
0ab0: 61 69 74 0a 09 09 09 09 2e 77 69 74 68 5f 63 6f  ait......with_co
0ac0: 6e 74 65 78 74 28 7c 7c 20 66 6f 72 6d 61 74 21  ntext(|| format!
0ad0: 28 22 51 75 65 72 79 20 73 6f 75 72 63 65 3a 5c  ("Query source:\
0ae0: 6e 7b 3a 3f 7d 22 2c 20 26 73 65 6c 66 2e 70 6f  n{:?}", &self.po
0af0: 6f 6c 29 29 3f 3b 0a 09 09 09 64 72 6f 70 28 63  ol))?;....drop(c
0b00: 6f 6e 6e 29 3b 0a 09 09 09 6c 65 74 20 63 68 61  onn);....let cha
0b10: 6e 6e 65 6c 5f 69 64 3a 20 69 36 34 20 3d 20 72  nnel_id: i64 = r
0b20: 6f 77 2e 74 72 79 5f 67 65 74 28 22 63 68 61 6e  ow.try_get("chan
0b30: 6e 65 6c 5f 69 64 22 29 3f 3b 0a 09 09 09 6c 65  nel_id")?;....le
0b40: 74 20 75 72 6c 3a 20 26 73 74 72 20 3d 20 72 6f  t url: &str = ro
0b50: 77 2e 74 72 79 5f 67 65 74 28 22 75 72 6c 22 29  w.try_get("url")
0b60: 3f 3b 0a 09 09 09 6c 65 74 20 69 76 5f 68 61 73  ?;....let iv_has
0b70: 68 3a 20 4f 70 74 69 6f 6e 3c 26 73 74 72 3e 20  h: Option<&str> 
0b80: 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74 28 22 69  = row.try_get("i
0b90: 76 5f 68 61 73 68 22 29 3f 3b 0a 09 09 09 6c 65  v_hash")?;....le
0ba0: 74 20 75 72 6c 5f 72 65 20 3d 20 6d 61 74 63 68  t url_re = match
0bb0: 20 72 6f 77 2e 74 72 79 5f 67 65 74 28 22 75 72   row.try_get("ur
0bc0: 6c 5f 72 65 22 29 3f 20 7b 0a 09 09 09 09 53 6f  l_re")? {.....So
0bd0: 6d 65 28 78 29 20 3d 3e 20 53 6f 6d 65 28 73 65  me(x) => Some(se
0be0: 64 72 65 67 65 78 3a 3a 52 65 70 6c 61 63 65 43  dregex::ReplaceC
0bf0: 6f 6d 6d 61 6e 64 3a 3a 6e 65 77 28 78 29 3f 29  ommand::new(x)?)
0c00: 2c 0a 09 09 09 09 4e 6f 6e 65 20 3d 3e 20 4e 6f  ,.....None => No
0c10: 6e 65 2c 0a 09 09 09 7d 3b 0a 09 09 09 6c 65 74  ne,....};....let
0c20: 20 64 65 73 74 69 6e 61 74 69 6f 6e 20 3d 20 6d   destination = m
0c30: 61 74 63 68 20 72 65 61 6c 20 7b 0a 09 09 09 09  atch real {.....
0c40: 74 72 75 65 20 3d 3e 20 74 65 6c 65 67 72 61 6d  true => telegram
0c50: 5f 62 6f 74 3a 3a 55 73 65 72 49 64 3a 3a 6e 65  _bot::UserId::ne
0c60: 77 28 63 68 61 6e 6e 65 6c 5f 69 64 29 2c 0a 09  w(channel_id),..
0c70: 09 09 09 66 61 6c 73 65 20 3d 3e 20 74 65 6c 65  ...false => tele
0c80: 67 72 61 6d 5f 62 6f 74 3a 3a 55 73 65 72 49 64  gram_bot::UserId
0c90: 3a 3a 6e 65 77 28 72 6f 77 2e 74 72 79 5f 67 65  ::new(row.try_ge
0ca0: 74 28 22 6f 77 6e 65 72 22 29 3f 29 2c 0a 09 09  t("owner")?),...
0cb0: 09 7d 3b 0a 09 09 09 6c 65 74 20 6d 75 74 20 74  .};....let mut t
0cc0: 68 69 73 5f 66 65 74 63 68 3a 20 4f 70 74 69 6f  his_fetch: Optio
0cd0: 6e 3c 44 61 74 65 54 69 6d 65 3c 63 68 72 6f 6e  n<DateTime<chron
0ce0: 6f 3a 3a 46 69 78 65 64 4f 66 66 73 65 74 3e 3e  o::FixedOffset>>
0cf0: 20 3d 20 4e 6f 6e 65 3b 0a 09 09 09 6c 65 74 20   = None;....let 
0d00: 6d 75 74 20 70 6f 73 74 73 3a 20 42 54 72 65 65  mut posts: BTree
0d10: 4d 61 70 3c 44 61 74 65 54 69 6d 65 3c 63 68 72  Map<DateTime<chr
0d20: 6f 6e 6f 3a 3a 46 69 78 65 64 4f 66 66 73 65 74  ono::FixedOffset
0d30: 3e 2c 20 53 74 72 69 6e 67 3e 20 3d 20 42 54 72  >, String> = BTr
0d40: 65 65 4d 61 70 3a 3a 6e 65 77 28 29 3b 0a 09 09  eeMap::new();...
0d50: 09 6c 65 74 20 72 65 73 70 6f 6e 73 65 20 3d 20  .let response = 
0d60: 72 65 71 77 65 73 74 3a 3a 67 65 74 28 75 72 6c  reqwest::get(url
0d70: 29 2e 61 77 61 69 74 3f 3b 0a 09 09 09 6c 65 74  ).await?;....let
0d80: 20 73 74 61 74 75 73 20 3d 20 72 65 73 70 6f 6e   status = respon
0d90: 73 65 2e 73 74 61 74 75 73 28 29 3b 0a 09 09 09  se.status();....
0da0: 6c 65 74 20 63 6f 6e 74 65 6e 74 20 3d 20 72 65  let content = re
0db0: 73 70 6f 6e 73 65 2e 62 79 74 65 73 28 29 2e 61  sponse.bytes().a
0dc0: 77 61 69 74 3f 3b 0a 09 09 09 6d 61 74 63 68 20  wait?;....match 
0dd0: 72 73 73 3a 3a 43 68 61 6e 6e 65 6c 3a 3a 72 65  rss::Channel::re
0de0: 61 64 5f 66 72 6f 6d 28 26 63 6f 6e 74 65 6e 74  ad_from(&content
0df0: 5b 2e 2e 5d 29 20 7b 0a 09 09 09 09 4f 6b 28 66  [..]) {.....Ok(f
0e00: 65 65 64 29 20 3d 3e 20 7b 0a 09 09 09 09 09 66  eed) => {......f
0e10: 6f 72 20 69 74 65 6d 20 69 6e 20 66 65 65 64 2e  or item in feed.
0e20: 69 74 65 6d 73 28 29 20 7b 0a 09 09 09 09 09 09  items() {.......
0e30: 69 66 20 6c 65 74 20 53 6f 6d 65 28 6c 69 6e 6b  if let Some(link
0e40: 29 20 3d 20 69 74 65 6d 2e 6c 69 6e 6b 28 29 20  ) = item.link() 
0e50: 7b 0a 09 09 09 09 09 09 09 6c 65 74 20 64 61 74  {........let dat
0e60: 65 20 3d 20 6d 61 74 63 68 20 69 74 65 6d 2e 70  e = match item.p
0e70: 75 62 5f 64 61 74 65 28 29 20 7b 0a 09 09 09 09  ub_date() {.....
0e80: 09 09 09 09 53 6f 6d 65 28 66 65 65 64 5f 64 61  ....Some(feed_da
0e90: 74 65 29 20 3d 3e 20 44 61 74 65 54 69 6d 65 3a  te) => DateTime:
0ea0: 3a 70 61 72 73 65 5f 66 72 6f 6d 5f 72 66 63 32  :parse_from_rfc2
0eb0: 38 32 32 28 66 65 65 64 5f 64 61 74 65 29 2c 0a  822(feed_date),.
0ec0: 09 09 09 09 09 09 09 09 4e 6f 6e 65 20 3d 3e 20  ........None => 
0ed0: 44 61 74 65 54 69 6d 65 3a 3a 70 61 72 73 65 5f  DateTime::parse_
0ee0: 66 72 6f 6d 5f 72 66 63 33 33 33 39 28 26 69 74  from_rfc3339(&it
0ef0: 65 6d 2e 64 75 62 6c 69 6e 5f 63 6f 72 65 5f 65  em.dublin_core_e
0f00: 78 74 28 29 2e 75 6e 77 72 61 70 28 29 2e 64 61  xt().unwrap().da
0f10: 74 65 73 28 29 5b 30 5d 29 2c 0a 09 09 09 09 09  tes()[0]),......
0f20: 09 09 7d 3f 3b 0a 09 09 09 09 09 09 09 6c 65 74  ..}?;........let
0f30: 20 75 72 6c 20 3d 20 6c 69 6e 6b 3b 0a 09 09 09   url = link;....
0f40: 09 09 09 09 70 6f 73 74 73 2e 69 6e 73 65 72 74  ....posts.insert
0f50: 28 64 61 74 65 2c 20 75 72 6c 2e 74 6f 5f 73 74  (date, url.to_st
0f60: 72 69 6e 67 28 29 29 3b 0a 09 09 09 09 09 09 7d  ring());.......}
0f70: 0a 09 09 09 09 09 7d 3b 0a 09 09 09 09 7d 2c 0a  ......};.....},.
0f80: 09 09 09 09 45 72 72 28 65 72 72 29 20 3d 3e 20  ....Err(err) => 
0f90: 6d 61 74 63 68 20 65 72 72 20 7b 0a 09 09 09 09  match err {.....
0fa0: 09 72 73 73 3a 3a 45 72 72 6f 72 3a 3a 49 6e 76  .rss::Error::Inv
0fb0: 61 6c 69 64 53 74 61 72 74 54 61 67 20 3d 3e 20  alidStartTag => 
0fc0: 7b 0a 09 09 09 09 09 09 6c 65 74 20 66 65 65 64  {.......let feed
0fd0: 20 3d 20 61 74 6f 6d 5f 73 79 6e 64 69 63 61 74   = atom_syndicat
0fe0: 69 6f 6e 3a 3a 46 65 65 64 3a 3a 72 65 61 64 5f  ion::Feed::read_
0ff0: 66 72 6f 6d 28 26 63 6f 6e 74 65 6e 74 5b 2e 2e  from(&content[..
1000: 5d 29 0a 09 09 09 09 09 09 09 2e 77 69 74 68 5f  ]).........with_
1010: 63 6f 6e 74 65 78 74 28 7c 7c 20 66 6f 72 6d 61  context(|| forma
1020: 74 21 28 22 50 72 6f 62 6c 65 6d 20 6f 70 65 6e  t!("Problem open
1030: 69 6e 67 20 66 65 65 64 20 75 72 6c 3a 5c 6e 7b  ing feed url:\n{
1040: 7d 5c 6e 7b 7d 22 2c 20 26 75 72 6c 2c 20 73 74  }\n{}", &url, st
1050: 61 74 75 73 29 29 3f 3b 0a 09 09 09 09 09 09 66  atus))?;.......f
1060: 6f 72 20 69 74 65 6d 20 69 6e 20 66 65 65 64 2e  or item in feed.
1070: 65 6e 74 72 69 65 73 28 29 20 7b 0a 09 09 09 09  entries() {.....
1080: 09 09 09 6c 65 74 20 64 61 74 65 20 3d 20 69 74  ...let date = it
1090: 65 6d 2e 70 75 62 6c 69 73 68 65 64 28 29 2e 75  em.published().u
10a0: 6e 77 72 61 70 28 29 3b 0a 09 09 09 09 09 09 09  nwrap();........
10b0: 6c 65 74 20 75 72 6c 20 3d 20 69 74 65 6d 2e 6c  let url = item.l
10c0: 69 6e 6b 73 28 29 5b 30 5d 2e 68 72 65 66 28 29  inks()[0].href()
10d0: 3b 0a 09 09 09 09 09 09 09 70 6f 73 74 73 2e 69  ;........posts.i
10e0: 6e 73 65 72 74 28 2a 64 61 74 65 2c 20 75 72 6c  nsert(*date, url
10f0: 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 3b 0a 09  .to_string());..
1100: 09 09 09 09 09 7d 3b 0a 09 09 09 09 09 7d 2c 0a  .....};......},.
1110: 09 09 09 09 09 72 73 73 3a 3a 45 72 72 6f 72 3a  .....rss::Error:
1120: 3a 45 6f 66 20 3d 3e 20 28 29 2c 0a 09 09 09 09  :Eof => (),.....
1130: 09 5f 20 3d 3e 20 62 61 69 6c 21 28 22 55 6e 73  ._ => bail!("Uns
1140: 75 70 70 6f 72 74 65 64 20 6f 72 20 6d 61 6e 67  upported or mang
1150: 6c 65 64 20 63 6f 6e 74 65 6e 74 3a 5c 6e 7b 3a  led content:\n{:
1160: 3f 7d 5c 6e 7b 3a 23 3f 7d 5c 6e 7b 3a 23 3f 7d  ?}\n{:#?}\n{:#?}
1170: 5c 6e 22 2c 20 26 75 72 6c 2c 20 65 72 72 2c 20  \n", &url, err, 
1180: 73 74 61 74 75 73 29 0a 09 09 09 09 7d 0a 09 09  status).....}...
1190: 09 7d 3b 0a 09 09 09 66 6f 72 20 28 64 61 74 65  .};....for (date
11a0: 2c 20 75 72 6c 29 20 69 6e 20 70 6f 73 74 73 2e  , url) in posts.
11b0: 69 74 65 72 28 29 20 7b 0a 09 09 09 09 6c 65 74  iter() {.....let
11c0: 20 6d 75 74 20 63 6f 6e 6e 20 3d 20 73 65 6c 66   mut conn = self
11d0: 2e 70 6f 6f 6c 2e 61 63 71 75 69 72 65 28 29 2e  .pool.acquire().
11e0: 61 77 61 69 74 0a 09 09 09 09 09 2e 77 69 74 68  await.......with
11f0: 5f 63 6f 6e 74 65 78 74 28 7c 7c 20 66 6f 72 6d  _context(|| form
1200: 61 74 21 28 22 43 68 65 63 6b 20 70 6f 73 74 20  at!("Check post 
1210: 66 65 74 63 68 20 63 6f 6e 6e 3a 5c 6e 7b 3a 3f  fetch conn:\n{:?
1220: 7d 22 2c 20 26 73 65 6c 66 2e 70 6f 6f 6c 29 29  }", &self.pool))
1230: 3f 3b 0a 09 09 09 09 6c 65 74 20 70 6f 73 74 5f  ?;.....let post_
1240: 75 72 6c 3a 20 43 6f 77 3c 73 74 72 3e 20 3d 20  url: Cow<str> = 
1250: 6d 61 74 63 68 20 75 72 6c 5f 72 65 20 7b 0a 09  match url_re {..
1260: 09 09 09 09 53 6f 6d 65 28 72 65 66 20 78 29 20  ....Some(ref x) 
1270: 3d 3e 20 78 2e 65 78 65 63 75 74 65 28 75 72 6c  => x.execute(url
1280: 29 2c 0a 09 09 09 09 09 4e 6f 6e 65 20 3d 3e 20  ),......None => 
1290: 75 72 6c 2e 69 6e 74 6f 28 29 2c 0a 09 09 09 09  url.into(),.....
12a0: 7d 3b 0a 09 09 09 09 6c 65 74 20 72 6f 77 20 3d  };.....let row =
12b0: 20 73 71 6c 78 3a 3a 71 75 65 72 79 28 22 73 65   sqlx::query("se
12c0: 6c 65 63 74 20 65 78 69 73 74 73 28 73 65 6c 65  lect exists(sele
12d0: 63 74 20 74 72 75 65 20 66 72 6f 6d 20 72 73 73  ct true from rss
12e0: 74 67 5f 70 6f 73 74 20 77 68 65 72 65 20 75 72  tg_post where ur
12f0: 6c 20 3d 20 24 31 20 61 6e 64 20 73 6f 75 72 63  l = $1 and sourc
1300: 65 5f 69 64 20 3d 20 24 32 29 20 61 73 20 65 78  e_id = $2) as ex
1310: 69 73 74 73 3b 22 29 0a 09 09 09 09 09 2e 62 69  ists;").......bi
1320: 6e 64 28 26 2a 70 6f 73 74 5f 75 72 6c 29 0a 09  nd(&*post_url)..
1330: 09 09 09 09 2e 62 69 6e 64 28 2a 69 64 29 0a 09  .....bind(*id)..
1340: 09 09 09 09 2e 66 65 74 63 68 5f 6f 6e 65 28 26  .....fetch_one(&
1350: 6d 75 74 20 63 6f 6e 6e 29 2e 61 77 61 69 74 0a  mut conn).await.
1360: 09 09 09 09 09 2e 77 69 74 68 5f 63 6f 6e 74 65  ......with_conte
1370: 78 74 28 7c 7c 20 66 6f 72 6d 61 74 21 28 22 43  xt(|| format!("C
1380: 68 65 63 6b 20 70 6f 73 74 3a 5c 6e 7b 3a 3f 7d  heck post:\n{:?}
1390: 22 2c 20 26 63 6f 6e 6e 29 29 3f 3b 0a 09 09 09  ", &conn))?;....
13a0: 09 6c 65 74 20 65 78 69 73 74 73 3a 20 62 6f 6f  .let exists: boo
13b0: 6c 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74 28  l = row.try_get(
13c0: 22 65 78 69 73 74 73 22 29 3f 3b 0a 09 09 09 09  "exists")?;.....
13d0: 69 66 20 21 20 65 78 69 73 74 73 20 7b 0a 09 09  if ! exists {...
13e0: 09 09 09 69 66 20 74 68 69 73 5f 66 65 74 63 68  ...if this_fetch
13f0: 20 3d 3d 20 4e 6f 6e 65 20 7c 7c 20 2a 64 61 74   == None || *dat
1400: 65 20 3e 20 74 68 69 73 5f 66 65 74 63 68 2e 75  e > this_fetch.u
1410: 6e 77 72 61 70 28 29 20 7b 0a 09 09 09 09 09 09  nwrap() {.......
1420: 74 68 69 73 5f 66 65 74 63 68 20 3d 20 53 6f 6d  this_fetch = Som
1430: 65 28 2a 64 61 74 65 29 3b 0a 09 09 09 09 09 7d  e(*date);......}
1440: 3b 0a 09 09 09 09 09 73 65 6c 66 2e 74 67 2e 73  ;......self.tg.s
1450: 65 6e 64 28 20 6d 61 74 63 68 20 69 76 5f 68 61  end( match iv_ha
1460: 73 68 20 7b 0a 09 09 09 09 09 09 09 53 6f 6d 65  sh {........Some
1470: 28 68 61 73 68 29 20 3d 3e 20 74 65 6c 65 67 72  (hash) => telegr
1480: 61 6d 5f 62 6f 74 3a 3a 53 65 6e 64 4d 65 73 73  am_bot::SendMess
1490: 61 67 65 3a 3a 6e 65 77 28 64 65 73 74 69 6e 61  age::new(destina
14a0: 74 69 6f 6e 2c 20 66 6f 72 6d 61 74 21 28 22 3c  tion, format!("<
14b0: 61 20 68 72 65 66 3d 5c 22 68 74 74 70 73 3a 2f  a href=\"https:/
14c0: 2f 74 2e 6d 65 2f 69 76 3f 75 72 6c 3d 7b 7d 26  /t.me/iv?url={}&
14d0: 72 68 61 73 68 3d 7b 7d 5c 22 3e 20 3c 2f 61 3e  rhash={}\"> </a>
14e0: 7b 30 7d 22 2c 20 26 70 6f 73 74 5f 75 72 6c 2c  {0}", &post_url,
14f0: 20 68 61 73 68 29 29 2c 0a 09 09 09 09 09 09 09   hash)),........
1500: 4e 6f 6e 65 20 3d 3e 20 74 65 6c 65 67 72 61 6d  None => telegram
1510: 5f 62 6f 74 3a 3a 53 65 6e 64 4d 65 73 73 61 67  _bot::SendMessag
1520: 65 3a 3a 6e 65 77 28 64 65 73 74 69 6e 61 74 69  e::new(destinati
1530: 6f 6e 2c 20 66 6f 72 6d 61 74 21 28 22 7b 7d 22  on, format!("{}"
1540: 2c 20 70 6f 73 74 5f 75 72 6c 29 29 2c 0a 09 09  , post_url)),...
1550: 09 09 09 09 7d 2e 70 61 72 73 65 5f 6d 6f 64 65  ....}.parse_mode
1560: 28 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 74  (telegram_bot::t
1570: 79 70 65 73 3a 3a 50 61 72 73 65 4d 6f 64 65 3a  ypes::ParseMode:
1580: 3a 48 74 6d 6c 29 29 2e 61 77 61 69 74 0a 09 09  :Html)).await...
1590: 09 09 09 09 2e 63 6f 6e 74 65 78 74 28 22 43 61  .....context("Ca
15a0: 6e 27 74 20 70 6f 73 74 20 6d 65 73 73 61 67 65  n't post message
15b0: 3a 22 29 3f 3b 0a 09 09 09 09 09 73 71 6c 78 3a  :")?;......sqlx:
15c0: 3a 71 75 65 72 79 28 22 69 6e 73 65 72 74 20 69  :query("insert i
15d0: 6e 74 6f 20 72 73 73 74 67 5f 70 6f 73 74 20 28  nto rsstg_post (
15e0: 73 6f 75 72 63 65 5f 69 64 2c 20 70 6f 73 74 65  source_id, poste
15f0: 64 2c 20 75 72 6c 29 20 76 61 6c 75 65 73 20 28  d, url) values (
1600: 24 31 2c 20 24 32 2c 20 24 33 29 3b 22 29 0a 09  $1, $2, $3);")..
1610: 09 09 09 09 09 2e 62 69 6e 64 28 2a 69 64 29 0a  ......bind(*id).
1620: 09 09 09 09 09 09 2e 62 69 6e 64 28 64 61 74 65  .......bind(date
1630: 29 0a 09 09 09 09 09 09 2e 62 69 6e 64 28 26 2a  )........bind(&*
1640: 70 6f 73 74 5f 75 72 6c 29 0a 09 09 09 09 09 09  post_url).......
1650: 2e 65 78 65 63 75 74 65 28 26 6d 75 74 20 63 6f  .execute(&mut co
1660: 6e 6e 29 2e 61 77 61 69 74 0a 09 09 09 09 09 09  nn).await.......
1670: 2e 77 69 74 68 5f 63 6f 6e 74 65 78 74 28 7c 7c  .with_context(||
1680: 20 66 6f 72 6d 61 74 21 28 22 52 65 63 6f 72 64   format!("Record
1690: 20 70 6f 73 74 3a 5c 6e 7b 3a 3f 7d 22 2c 20 26   post:\n{:?}", &
16a0: 63 6f 6e 6e 29 29 3f 3b 0a 09 09 09 09 09 64 72  conn))?;......dr
16b0: 6f 70 28 63 6f 6e 6e 29 3b 0a 09 09 09 09 09 74  op(conn);......t
16c0: 6f 6b 69 6f 3a 3a 74 69 6d 65 3a 3a 73 6c 65 65  okio::time::slee
16d0: 70 28 73 74 64 3a 3a 74 69 6d 65 3a 3a 44 75 72  p(std::time::Dur
16e0: 61 74 69 6f 6e 3a 3a 6e 65 77 28 34 2c 20 30 29  ation::new(4, 0)
16f0: 29 2e 61 77 61 69 74 3b 0a 09 09 09 09 7d 3b 0a  ).await;.....};.
1700: 09 09 09 09 70 6f 73 74 65 64 20 2b 3d 20 31 3b  ....posted += 1;
1710: 0a 09 09 09 7d 3b 0a 09 09 09 70 6f 73 74 73 2e  ....};....posts.
1720: 63 6c 65 61 72 28 29 3b 0a 09 09 7d 3b 0a 09 09  clear();...};...
1730: 6c 65 74 20 6d 75 74 20 63 6f 6e 6e 20 3d 20 73  let mut conn = s
1740: 65 6c 66 2e 70 6f 6f 6c 2e 61 63 71 75 69 72 65  elf.pool.acquire
1750: 28 29 2e 61 77 61 69 74 0a 09 09 09 2e 77 69 74  ().await.....wit
1760: 68 5f 63 6f 6e 74 65 78 74 28 7c 7c 20 66 6f 72  h_context(|| for
1770: 6d 61 74 21 28 22 55 70 64 61 74 65 20 73 63 72  mat!("Update scr
1780: 61 70 65 20 66 65 74 63 68 20 63 6f 6e 6e 3a 5c  ape fetch conn:\
1790: 6e 7b 3a 3f 7d 22 2c 20 26 73 65 6c 66 2e 70 6f  n{:?}", &self.po
17a0: 6f 6c 29 29 3f 3b 0a 09 09 73 71 6c 78 3a 3a 71  ol))?;...sqlx::q
17b0: 75 65 72 79 28 22 75 70 64 61 74 65 20 72 73 73  uery("update rss
17c0: 74 67 5f 73 6f 75 72 63 65 20 73 65 74 20 6c 61  tg_source set la
17d0: 73 74 5f 73 63 72 61 70 65 20 3d 20 6e 6f 77 28  st_scrape = now(
17e0: 29 20 77 68 65 72 65 20 73 6f 75 72 63 65 5f 69  ) where source_i
17f0: 64 20 3d 20 24 31 3b 22 29 0a 09 09 09 2e 62 69  d = $1;").....bi
1800: 6e 64 28 2a 69 64 29 0a 09 09 09 2e 65 78 65 63  nd(*id).....exec
1810: 75 74 65 28 26 6d 75 74 20 63 6f 6e 6e 29 2e 61  ute(&mut conn).a
1820: 77 61 69 74 0a 09 09 09 2e 77 69 74 68 5f 63 6f  wait.....with_co
1830: 6e 74 65 78 74 28 7c 7c 20 66 6f 72 6d 61 74 21  ntext(|| format!
1840: 28 22 55 70 64 61 74 65 20 73 63 72 61 70 65 3a  ("Update scrape:
1850: 5c 6e 7b 3a 3f 7d 22 2c 20 26 63 6f 6e 6e 29 29  \n{:?}", &conn))
1860: 3f 3b 0a 09 09 4f 6b 28 66 6f 72 6d 61 74 21 28  ?;...Ok(format!(
1870: 22 50 6f 73 74 65 64 3a 20 7b 7d 22 2c 20 26 70  "Posted: {}", &p
1880: 6f 73 74 65 64 29 2e 69 6e 74 6f 28 29 29 0a 09  osted).into())..
1890: 7d 0a 0a 09 70 75 62 20 61 73 79 6e 63 20 66 6e  }...pub async fn
18a0: 20 64 65 6c 65 74 65 3c 53 3e 28 26 73 65 6c 66   delete<S>(&self
18b0: 2c 20 73 6f 75 72 63 65 5f 69 64 3a 20 26 69 33  , source_id: &i3
18c0: 32 2c 20 6f 77 6e 65 72 3a 20 53 29 20 2d 3e 20  2, owner: S) -> 
18d0: 52 65 73 75 6c 74 3c 43 6f 77 3c 27 5f 2c 20 73  Result<Cow<'_, s
18e0: 74 72 3e 3e 0a 09 77 68 65 72 65 20 53 3a 20 49  tr>>..where S: I
18f0: 6e 74 6f 3c 69 36 34 3e 20 7b 0a 09 09 6c 65 74  nto<i64> {...let
1900: 20 6f 77 6e 65 72 20 3d 20 6f 77 6e 65 72 2e 69   owner = owner.i
1910: 6e 74 6f 28 29 3b 0a 0a 09 09 6c 65 74 20 6d 75  nto();....let mu
1920: 74 20 63 6f 6e 6e 20 3d 20 73 65 6c 66 2e 70 6f  t conn = self.po
1930: 6f 6c 2e 61 63 71 75 69 72 65 28 29 2e 61 77 61  ol.acquire().awa
1940: 69 74 0a 09 09 09 2e 77 69 74 68 5f 63 6f 6e 74  it.....with_cont
1950: 65 78 74 28 7c 7c 20 66 6f 72 6d 61 74 21 28 22  ext(|| format!("
1960: 44 65 6c 65 74 65 20 66 65 74 63 68 20 63 6f 6e  Delete fetch con
1970: 6e 3a 5c 6e 7b 3a 3f 7d 22 2c 20 26 73 65 6c 66  n:\n{:?}", &self
1980: 2e 70 6f 6f 6c 29 29 3f 3b 0a 09 09 6d 61 74 63  .pool))?;...matc
1990: 68 20 73 71 6c 78 3a 3a 71 75 65 72 79 28 22 64  h sqlx::query("d
19a0: 65 6c 65 74 65 20 66 72 6f 6d 20 72 73 73 74 67  elete from rsstg
19b0: 5f 73 6f 75 72 63 65 20 77 68 65 72 65 20 73 6f  _source where so
19c0: 75 72 63 65 5f 69 64 20 3d 20 24 31 20 61 6e 64  urce_id = $1 and
19d0: 20 6f 77 6e 65 72 20 3d 20 24 32 3b 22 29 0a 09   owner = $2;")..
19e0: 09 09 2e 62 69 6e 64 28 73 6f 75 72 63 65 5f 69  ...bind(source_i
19f0: 64 29 0a 09 09 09 2e 62 69 6e 64 28 6f 77 6e 65  d).....bind(owne
1a00: 72 29 0a 09 09 09 2e 65 78 65 63 75 74 65 28 26  r).....execute(&
1a10: 6d 75 74 20 63 6f 6e 6e 29 2e 61 77 61 69 74 0a  mut conn).await.
1a20: 09 09 09 2e 77 69 74 68 5f 63 6f 6e 74 65 78 74  ....with_context
1a30: 28 7c 7c 20 66 6f 72 6d 61 74 21 28 22 44 65 6c  (|| format!("Del
1a40: 65 74 65 20 73 6f 75 72 63 65 20 72 75 6c 65 3a  ete source rule:
1a50: 5c 6e 7b 3a 3f 7d 22 2c 20 26 73 65 6c 66 2e 70  \n{:?}", &self.p
1a60: 6f 6f 6c 29 29 3f 0a 09 09 09 2e 72 6f 77 73 5f  ool))?.....rows_
1a70: 61 66 66 65 63 74 65 64 28 29 20 7b 0a 09 09 09  affected() {....
1a80: 30 20 3d 3e 20 7b 20 4f 6b 28 22 4e 6f 20 64 61  0 => { Ok("No da
1a90: 74 61 20 66 6f 75 6e 64 20 66 6f 75 6e 64 2e 22  ta found found."
1aa0: 2e 69 6e 74 6f 28 29 29 20 7d 2c 0a 09 09 09 78  .into()) },....x
1ab0: 20 3d 3e 20 7b 20 4f 6b 28 66 6f 72 6d 61 74 21   => { Ok(format!
1ac0: 28 22 7b 7d 20 73 6f 75 72 63 65 73 20 72 65 6d  ("{} sources rem
1ad0: 6f 76 65 64 2e 22 2c 20 78 29 2e 69 6e 74 6f 28  oved.", x).into(
1ae0: 29 29 20 7d 2c 0a 09 09 7d 0a 09 7d 0a 0a 09 70  )) },...}..}...p
1af0: 75 62 20 61 73 79 6e 63 20 66 6e 20 63 6c 65 61  ub async fn clea
1b00: 6e 3c 53 3e 28 26 73 65 6c 66 2c 20 73 6f 75 72  n<S>(&self, sour
1b10: 63 65 5f 69 64 3a 20 26 69 33 32 2c 20 6f 77 6e  ce_id: &i32, own
1b20: 65 72 3a 20 53 29 20 2d 3e 20 52 65 73 75 6c 74  er: S) -> Result
1b30: 3c 43 6f 77 3c 27 5f 2c 20 73 74 72 3e 3e 0a 09  <Cow<'_, str>>..
1b40: 77 68 65 72 65 20 53 3a 20 49 6e 74 6f 3c 69 36  where S: Into<i6
1b50: 34 3e 20 7b 0a 09 09 6c 65 74 20 6f 77 6e 65 72  4> {...let owner
1b60: 20 3d 20 6f 77 6e 65 72 2e 69 6e 74 6f 28 29 3b   = owner.into();
1b70: 0a 0a 09 09 6c 65 74 20 6d 75 74 20 63 6f 6e 6e  ....let mut conn
1b80: 20 3d 20 73 65 6c 66 2e 70 6f 6f 6c 2e 61 63 71   = self.pool.acq
1b90: 75 69 72 65 28 29 2e 61 77 61 69 74 0a 09 09 09  uire().await....
1ba0: 2e 77 69 74 68 5f 63 6f 6e 74 65 78 74 28 7c 7c  .with_context(||
1bb0: 20 66 6f 72 6d 61 74 21 28 22 43 6c 65 61 6e 20   format!("Clean 
1bc0: 66 65 74 63 68 20 63 6f 6e 6e 3a 5c 6e 7b 3a 3f  fetch conn:\n{:?
1bd0: 7d 22 2c 20 26 73 65 6c 66 2e 70 6f 6f 6c 29 29  }", &self.pool))
1be0: 3f 3b 0a 09 09 6d 61 74 63 68 20 73 71 6c 78 3a  ?;...match sqlx:
1bf0: 3a 71 75 65 72 79 28 22 64 65 6c 65 74 65 20 66  :query("delete f
1c00: 72 6f 6d 20 72 73 73 74 67 5f 70 6f 73 74 20 70  rom rsstg_post p
1c10: 20 75 73 69 6e 67 20 72 73 73 74 67 5f 73 6f 75   using rsstg_sou
1c20: 72 63 65 20 73 20 77 68 65 72 65 20 70 2e 73 6f  rce s where p.so
1c30: 75 72 63 65 5f 69 64 20 3d 20 24 31 20 61 6e 64  urce_id = $1 and
1c40: 20 6f 77 6e 65 72 20 3d 20 24 32 20 61 6e 64 20   owner = $2 and 
1c50: 70 2e 73 6f 75 72 63 65 5f 69 64 20 3d 20 73 2e  p.source_id = s.
1c60: 73 6f 75 72 63 65 5f 69 64 3b 22 29 0a 09 09 09  source_id;")....
1c70: 2e 62 69 6e 64 28 73 6f 75 72 63 65 5f 69 64 29  .bind(source_id)
1c80: 0a 09 09 09 2e 62 69 6e 64 28 6f 77 6e 65 72 29  .....bind(owner)
1c90: 0a 09 09 09 2e 65 78 65 63 75 74 65 28 26 6d 75  .....execute(&mu
1ca0: 74 20 63 6f 6e 6e 29 2e 61 77 61 69 74 0a 09 09  t conn).await...
1cb0: 09 2e 77 69 74 68 5f 63 6f 6e 74 65 78 74 28 7c  ..with_context(|
1cc0: 7c 20 66 6f 72 6d 61 74 21 28 22 43 6c 65 61 6e  | format!("Clean
1cd0: 20 73 65 65 6e 20 70 6f 73 74 73 3a 5c 6e 7b 3a   seen posts:\n{:
1ce0: 3f 7d 22 2c 20 26 73 65 6c 66 2e 70 6f 6f 6c 29  ?}", &self.pool)
1cf0: 29 3f 0a 09 09 09 2e 72 6f 77 73 5f 61 66 66 65  )?.....rows_affe
1d00: 63 74 65 64 28 29 20 7b 0a 09 09 09 30 20 3d 3e  cted() {....0 =>
1d10: 20 7b 20 4f 6b 28 22 4e 6f 20 64 61 74 61 20 66   { Ok("No data f
1d20: 6f 75 6e 64 20 66 6f 75 6e 64 2e 22 2e 69 6e 74  ound found.".int
1d30: 6f 28 29 29 20 7d 2c 0a 09 09 09 78 20 3d 3e 20  o()) },....x => 
1d40: 7b 20 4f 6b 28 66 6f 72 6d 61 74 21 28 22 7b 7d  { Ok(format!("{}
1d50: 20 70 6f 73 74 73 20 70 75 72 67 65 64 2e 22 2c   posts purged.",
1d60: 20 78 29 2e 69 6e 74 6f 28 29 29 20 7d 2c 0a 09   x).into()) },..
1d70: 09 7d 0a 09 7d 0a 0a 09 70 75 62 20 61 73 79 6e  .}..}...pub asyn
1d80: 63 20 66 6e 20 65 6e 61 62 6c 65 3c 53 3e 28 26  c fn enable<S>(&
1d90: 73 65 6c 66 2c 20 73 6f 75 72 63 65 5f 69 64 3a  self, source_id:
1da0: 20 26 69 33 32 2c 20 6f 77 6e 65 72 3a 20 53 29   &i32, owner: S)
1db0: 20 2d 3e 20 52 65 73 75 6c 74 3c 26 73 74 72 3e   -> Result<&str>
1dc0: 0a 09 77 68 65 72 65 20 53 3a 20 49 6e 74 6f 3c  ..where S: Into<
1dd0: 69 36 34 3e 20 7b 0a 09 09 6c 65 74 20 6f 77 6e  i64> {...let own
1de0: 65 72 20 3d 20 6f 77 6e 65 72 2e 69 6e 74 6f 28  er = owner.into(
1df0: 29 3b 0a 0a 09 09 6c 65 74 20 6d 75 74 20 63 6f  );....let mut co
1e00: 6e 6e 20 3d 20 73 65 6c 66 2e 70 6f 6f 6c 2e 61  nn = self.pool.a
1e10: 63 71 75 69 72 65 28 29 2e 61 77 61 69 74 0a 09  cquire().await..
1e20: 09 09 2e 77 69 74 68 5f 63 6f 6e 74 65 78 74 28  ...with_context(
1e30: 7c 7c 20 66 6f 72 6d 61 74 21 28 22 45 6e 61 62  || format!("Enab
1e40: 6c 65 20 66 65 74 63 68 20 63 6f 6e 6e 3a 5c 6e  le fetch conn:\n
1e50: 7b 3a 3f 7d 22 2c 20 26 73 65 6c 66 2e 70 6f 6f  {:?}", &self.poo
1e60: 6c 29 29 3f 3b 0a 09 09 6d 61 74 63 68 20 73 71  l))?;...match sq
1e70: 6c 78 3a 3a 71 75 65 72 79 28 22 75 70 64 61 74  lx::query("updat
1e80: 65 20 72 73 73 74 67 5f 73 6f 75 72 63 65 20 73  e rsstg_source s
1e90: 65 74 20 65 6e 61 62 6c 65 64 20 3d 20 74 72 75  et enabled = tru
1ea0: 65 20 77 68 65 72 65 20 73 6f 75 72 63 65 5f 69  e where source_i
1eb0: 64 20 3d 20 24 31 20 61 6e 64 20 6f 77 6e 65 72  d = $1 and owner
1ec0: 20 3d 20 24 32 22 29 0a 09 09 09 2e 62 69 6e 64   = $2").....bind
1ed0: 28 73 6f 75 72 63 65 5f 69 64 29 0a 09 09 09 2e  (source_id).....
1ee0: 62 69 6e 64 28 6f 77 6e 65 72 29 0a 09 09 09 2e  bind(owner).....
1ef0: 65 78 65 63 75 74 65 28 26 6d 75 74 20 63 6f 6e  execute(&mut con
1f00: 6e 29 2e 61 77 61 69 74 0a 09 09 09 2e 77 69 74  n).await.....wit
1f10: 68 5f 63 6f 6e 74 65 78 74 28 7c 7c 20 66 6f 72  h_context(|| for
1f20: 6d 61 74 21 28 22 45 6e 61 62 6c 65 20 73 6f 75  mat!("Enable sou
1f30: 72 63 65 3a 5c 6e 7b 3a 3f 7d 22 2c 20 26 73 65  rce:\n{:?}", &se
1f40: 6c 66 2e 70 6f 6f 6c 29 29 3f 0a 09 09 09 2e 72  lf.pool))?.....r
1f50: 6f 77 73 5f 61 66 66 65 63 74 65 64 28 29 20 7b  ows_affected() {
1f60: 0a 09 09 09 31 20 3d 3e 20 7b 20 4f 6b 28 22 53  ....1 => { Ok("S
1f70: 6f 75 72 63 65 20 65 6e 61 62 6c 65 64 2e 22 29  ource enabled.")
1f80: 20 7d 2c 0a 09 09 09 30 20 3d 3e 20 7b 20 4f 6b   },....0 => { Ok
1f90: 28 22 53 6f 75 72 63 65 20 6e 6f 74 20 66 6f 75  ("Source not fou
1fa0: 6e 64 2e 22 29 20 7d 2c 0a 09 09 09 5f 20 3d 3e  nd.") },...._ =>
1fb0: 20 7b 20 45 72 72 28 61 6e 79 68 6f 77 21 28 22   { Err(anyhow!("
1fc0: 44 61 74 61 62 61 73 65 20 65 72 72 6f 72 2e 22  Database error."
1fd0: 29 29 20 7d 2c 0a 09 09 7d 0a 09 7d 0a 0a 09 70  )) },...}..}...p
1fe0: 75 62 20 61 73 79 6e 63 20 66 6e 20 64 69 73 61  ub async fn disa
1ff0: 62 6c 65 3c 53 3e 28 26 73 65 6c 66 2c 20 73 6f  ble<S>(&self, so
2000: 75 72 63 65 5f 69 64 3a 20 26 69 33 32 2c 20 6f  urce_id: &i32, o
2010: 77 6e 65 72 3a 20 53 29 20 2d 3e 20 52 65 73 75  wner: S) -> Resu
2020: 6c 74 3c 26 73 74 72 3e 0a 09 77 68 65 72 65 20  lt<&str>..where 
2030: 53 3a 20 49 6e 74 6f 3c 69 36 34 3e 20 7b 0a 09  S: Into<i64> {..
2040: 09 6c 65 74 20 6f 77 6e 65 72 20 3d 20 6f 77 6e  .let owner = own
2050: 65 72 2e 69 6e 74 6f 28 29 3b 0a 0a 09 09 6c 65  er.into();....le
2060: 74 20 6d 75 74 20 63 6f 6e 6e 20 3d 20 73 65 6c  t mut conn = sel
2070: 66 2e 70 6f 6f 6c 2e 61 63 71 75 69 72 65 28 29  f.pool.acquire()
2080: 2e 61 77 61 69 74 0a 09 09 09 2e 77 69 74 68 5f  .await.....with_
2090: 63 6f 6e 74 65 78 74 28 7c 7c 20 66 6f 72 6d 61  context(|| forma
20a0: 74 21 28 22 44 69 73 61 62 6c 65 20 66 65 74 63  t!("Disable fetc
20b0: 68 20 63 6f 6e 6e 3a 5c 6e 7b 3a 3f 7d 22 2c 20  h conn:\n{:?}", 
20c0: 26 73 65 6c 66 2e 70 6f 6f 6c 29 29 3f 3b 0a 09  &self.pool))?;..
20d0: 09 6d 61 74 63 68 20 73 71 6c 78 3a 3a 71 75 65  .match sqlx::que
20e0: 72 79 28 22 75 70 64 61 74 65 20 72 73 73 74 67  ry("update rsstg
20f0: 5f 73 6f 75 72 63 65 20 73 65 74 20 65 6e 61 62  _source set enab
2100: 6c 65 64 20 3d 20 66 61 6c 73 65 20 77 68 65 72  led = false wher
2110: 65 20 73 6f 75 72 63 65 5f 69 64 20 3d 20 24 31  e source_id = $1
2120: 20 61 6e 64 20 6f 77 6e 65 72 20 3d 20 24 32 22   and owner = $2"
2130: 29 0a 09 09 09 2e 62 69 6e 64 28 73 6f 75 72 63  ).....bind(sourc
2140: 65 5f 69 64 29 0a 09 09 09 2e 62 69 6e 64 28 6f  e_id).....bind(o
2150: 77 6e 65 72 29 0a 09 09 09 2e 65 78 65 63 75 74  wner).....execut
2160: 65 28 26 6d 75 74 20 63 6f 6e 6e 29 2e 61 77 61  e(&mut conn).awa
2170: 69 74 0a 09 09 09 2e 77 69 74 68 5f 63 6f 6e 74  it.....with_cont
2180: 65 78 74 28 7c 7c 20 66 6f 72 6d 61 74 21 28 22  ext(|| format!("
2190: 44 69 73 61 62 6c 65 20 73 6f 75 72 63 65 3a 5c  Disable source:\
21a0: 6e 7b 3a 3f 7d 22 2c 20 26 73 65 6c 66 2e 70 6f  n{:?}", &self.po
21b0: 6f 6c 29 29 3f 0a 09 09 09 2e 72 6f 77 73 5f 61  ol))?.....rows_a
21c0: 66 66 65 63 74 65 64 28 29 20 7b 0a 09 09 09 31  ffected() {....1
21d0: 20 3d 3e 20 7b 20 4f 6b 28 22 53 6f 75 72 63 65   => { Ok("Source
21e0: 20 64 69 73 61 62 6c 65 64 2e 22 29 20 7d 2c 0a   disabled.") },.
21f0: 09 09 09 30 20 3d 3e 20 7b 20 4f 6b 28 22 53 6f  ...0 => { Ok("So
2200: 75 72 63 65 20 6e 6f 74 20 66 6f 75 6e 64 2e 22  urce not found."
2210: 29 20 7d 2c 0a 09 09 09 5f 20 3d 3e 20 7b 20 45  ) },...._ => { E
2220: 72 72 28 61 6e 79 68 6f 77 21 28 22 44 61 74 61  rr(anyhow!("Data
2230: 62 61 73 65 20 65 72 72 6f 72 2e 22 29 29 20 7d  base error.")) }
2240: 2c 0a 09 09 7d 0a 09 7d 0a 0a 09 70 75 62 20 61  ,...}..}...pub a
2250: 73 79 6e 63 20 66 6e 20 75 70 64 61 74 65 3c 53  sync fn update<S
2260: 3e 28 26 73 65 6c 66 2c 20 75 70 64 61 74 65 3a  >(&self, update:
2270: 20 4f 70 74 69 6f 6e 3c 69 33 32 3e 2c 20 63 68   Option<i32>, ch
2280: 61 6e 6e 65 6c 3a 20 26 73 74 72 2c 20 63 68 61  annel: &str, cha
2290: 6e 6e 65 6c 5f 69 64 3a 20 69 36 34 2c 20 75 72  nnel_id: i64, ur
22a0: 6c 3a 20 26 73 74 72 2c 20 69 76 5f 68 61 73 68  l: &str, iv_hash
22b0: 3a 20 4f 70 74 69 6f 6e 3c 26 73 74 72 3e 2c 20  : Option<&str>, 
22c0: 75 72 6c 5f 72 65 3a 20 4f 70 74 69 6f 6e 3c 26  url_re: Option<&
22d0: 73 74 72 3e 2c 20 6f 77 6e 65 72 3a 20 53 29 20  str>, owner: S) 
22e0: 2d 3e 20 52 65 73 75 6c 74 3c 26 73 74 72 3e 0a  -> Result<&str>.
22f0: 09 77 68 65 72 65 20 53 3a 20 49 6e 74 6f 3c 69  .where S: Into<i
2300: 36 34 3e 20 7b 0a 09 09 6c 65 74 20 6f 77 6e 65  64> {...let owne
2310: 72 20 3d 20 6f 77 6e 65 72 2e 69 6e 74 6f 28 29  r = owner.into()
2320: 3b 0a 0a 09 09 6c 65 74 20 6d 75 74 20 63 6f 6e  ;....let mut con
2330: 6e 20 3d 20 73 65 6c 66 2e 70 6f 6f 6c 2e 61 63  n = self.pool.ac
2340: 71 75 69 72 65 28 29 2e 61 77 61 69 74 0a 09 09  quire().await...
2350: 09 2e 77 69 74 68 5f 63 6f 6e 74 65 78 74 28 7c  ..with_context(|
2360: 7c 20 66 6f 72 6d 61 74 21 28 22 55 70 64 61 74  | format!("Updat
2370: 65 20 66 65 74 63 68 20 63 6f 6e 6e 3a 5c 6e 7b  e fetch conn:\n{
2380: 3a 3f 7d 22 2c 20 26 73 65 6c 66 2e 70 6f 6f 6c  :?}", &self.pool
2390: 29 29 3f 3b 0a 0a 09 09 6d 61 74 63 68 20 6d 61  ))?;....match ma
23a0: 74 63 68 20 75 70 64 61 74 65 20 7b 0a 09 09 09  tch update {....
23b0: 09 53 6f 6d 65 28 69 64 29 20 3d 3e 20 7b 0a 09  .Some(id) => {..
23c0: 09 09 09 09 73 71 6c 78 3a 3a 71 75 65 72 79 28  ....sqlx::query(
23d0: 22 75 70 64 61 74 65 20 72 73 73 74 67 5f 73 6f  "update rsstg_so
23e0: 75 72 63 65 20 73 65 74 20 63 68 61 6e 6e 65 6c  urce set channel
23f0: 5f 69 64 20 3d 20 24 32 2c 20 75 72 6c 20 3d 20  _id = $2, url = 
2400: 24 33 2c 20 69 76 5f 68 61 73 68 20 3d 20 24 34  $3, iv_hash = $4
2410: 2c 20 6f 77 6e 65 72 20 3d 20 24 35 2c 20 63 68  , owner = $5, ch
2420: 61 6e 6e 65 6c 20 3d 20 24 36 2c 20 75 72 6c 5f  annel = $6, url_
2430: 72 65 20 3d 20 24 37 20 77 68 65 72 65 20 73 6f  re = $7 where so
2440: 75 72 63 65 5f 69 64 20 3d 20 24 31 22 29 2e 62  urce_id = $1").b
2450: 69 6e 64 28 69 64 29 0a 09 09 09 09 7d 2c 0a 09  ind(id).....},..
2460: 09 09 09 4e 6f 6e 65 20 3d 3e 20 7b 0a 09 09 09  ...None => {....
2470: 09 09 73 71 6c 78 3a 3a 71 75 65 72 79 28 22 69  ..sqlx::query("i
2480: 6e 73 65 72 74 20 69 6e 74 6f 20 72 73 73 74 67  nsert into rsstg
2490: 5f 73 6f 75 72 63 65 20 28 63 68 61 6e 6e 65 6c  _source (channel
24a0: 5f 69 64 2c 20 75 72 6c 2c 20 69 76 5f 68 61 73  _id, url, iv_has
24b0: 68 2c 20 6f 77 6e 65 72 2c 20 63 68 61 6e 6e 65  h, owner, channe
24c0: 6c 2c 20 75 72 6c 5f 72 65 29 20 76 61 6c 75 65  l, url_re) value
24d0: 73 20 28 24 31 2c 20 24 32 2c 20 24 33 2c 20 24  s ($1, $2, $3, $
24e0: 34 2c 20 24 35 2c 20 24 36 29 22 29 0a 09 09 09  4, $5, $6)")....
24f0: 09 7d 2c 0a 09 09 09 7d 0a 09 09 09 2e 62 69 6e  .},....}.....bin
2500: 64 28 63 68 61 6e 6e 65 6c 5f 69 64 29 0a 09 09  d(channel_id)...
2510: 09 2e 62 69 6e 64 28 75 72 6c 29 0a 09 09 09 2e  ..bind(url).....
2520: 62 69 6e 64 28 69 76 5f 68 61 73 68 29 0a 09 09  bind(iv_hash)...
2530: 09 2e 62 69 6e 64 28 6f 77 6e 65 72 29 0a 09 09  ..bind(owner)...
2540: 09 2e 62 69 6e 64 28 63 68 61 6e 6e 65 6c 29 0a  ..bind(channel).
2550: 09 09 09 2e 62 69 6e 64 28 75 72 6c 5f 72 65 29  ....bind(url_re)
2560: 0a 09 09 09 2e 65 78 65 63 75 74 65 28 26 6d 75  .....execute(&mu
2570: 74 20 63 6f 6e 6e 29 2e 61 77 61 69 74 20 7b 0a  t conn).await {.
2580: 09 09 09 4f 6b 28 5f 29 20 3d 3e 20 4f 6b 28 6d  ...Ok(_) => Ok(m
2590: 61 74 63 68 20 75 70 64 61 74 65 20 7b 0a 09 09  atch update {...
25a0: 09 09 53 6f 6d 65 28 5f 29 20 3d 3e 20 22 43 68  ..Some(_) => "Ch
25b0: 61 6e 6e 65 6c 20 75 70 64 61 74 65 64 2e 22 2c  annel updated.",
25c0: 0a 09 09 09 09 4e 6f 6e 65 20 3d 3e 20 22 43 68  .....None => "Ch
25d0: 61 6e 6e 65 6c 20 61 64 64 65 64 2e 22 2c 0a 09  annel added.",..
25e0: 09 09 7d 29 2c 0a 09 09 09 45 72 72 28 73 71 6c  ..}),....Err(sql
25f0: 78 3a 3a 45 72 72 6f 72 3a 3a 44 61 74 61 62 61  x::Error::Databa
2600: 73 65 28 65 72 72 29 29 20 3d 3e 20 7b 0a 09 09  se(err)) => {...
2610: 09 09 6d 61 74 63 68 20 65 72 72 2e 64 6f 77 6e  ..match err.down
2620: 63 61 73 74 3a 3a 3c 73 71 6c 78 3a 3a 70 6f 73  cast::<sqlx::pos
2630: 74 67 72 65 73 3a 3a 50 67 44 61 74 61 62 61 73  tgres::PgDatabas
2640: 65 45 72 72 6f 72 3e 28 29 2e 72 6f 75 74 69 6e  eError>().routin
2650: 65 28 29 20 7b 0a 09 09 09 09 09 53 6f 6d 65 28  e() {......Some(
2660: 22 5f 62 74 5f 63 68 65 63 6b 5f 75 6e 69 71 75  "_bt_check_uniqu
2670: 65 22 2c 20 29 20 3d 3e 20 7b 0a 09 09 09 09 09  e", ) => {......
2680: 09 4f 6b 28 22 44 75 70 6c 69 63 61 74 65 20 6b  .Ok("Duplicate k
2690: 65 79 2e 22 29 0a 09 09 09 09 09 7d 2c 0a 09 09  ey.")......},...
26a0: 09 09 09 53 6f 6d 65 28 5f 29 20 3d 3e 20 7b 0a  ...Some(_) => {.
26b0: 09 09 09 09 09 09 4f 6b 28 22 44 61 74 61 62 61  ......Ok("Databa
26c0: 73 65 20 65 72 72 6f 72 2e 22 29 0a 09 09 09 09  se error.").....
26d0: 09 7d 2c 0a 09 09 09 09 09 4e 6f 6e 65 20 3d 3e  .},......None =>
26e0: 20 7b 0a 09 09 09 09 09 09 4f 6b 28 22 4e 6f 20   {.......Ok("No 
26f0: 64 61 74 61 62 61 73 65 20 65 72 72 6f 72 20 65  database error e
2700: 78 74 72 61 63 74 65 64 2e 22 29 0a 09 09 09 09  xtracted.").....
2710: 09 7d 2c 0a 09 09 09 09 7d 0a 09 09 09 7d 2c 0a  .},.....}....},.
2720: 09 09 09 45 72 72 28 65 72 72 29 20 3d 3e 20 7b  ...Err(err) => {
2730: 0a 09 09 09 09 62 61 69 6c 21 28 22 53 6f 72 72  .....bail!("Sorr
2740: 79 2c 20 75 6e 6b 6e 6f 77 6e 20 65 72 72 6f 72  y, unknown error
2750: 3a 5c 6e 7b 3a 23 3f 7d 5c 6e 22 2c 20 65 72 72  :\n{:#?}\n", err
2760: 29 3b 0a 09 09 09 7d 2c 0a 09 09 7d 0a 09 7d 0a  );....},...}..}.
2770: 0a 09 61 73 79 6e 63 20 66 6e 20 61 75 74 6f 66  ..async fn autof
2780: 65 74 63 68 28 26 73 65 6c 66 29 20 2d 3e 20 52  etch(&self) -> R
2790: 65 73 75 6c 74 3c 73 74 64 3a 3a 74 69 6d 65 3a  esult<std::time:
27a0: 3a 44 75 72 61 74 69 6f 6e 3e 20 7b 0a 09 09 6c  :Duration> {...l
27b0: 65 74 20 6d 75 74 20 64 65 6c 61 79 20 3d 20 63  et mut delay = c
27c0: 68 72 6f 6e 6f 3a 3a 44 75 72 61 74 69 6f 6e 3a  hrono::Duration:
27d0: 3a 6d 69 6e 75 74 65 73 28 31 29 3b 0a 09 09 6c  :minutes(1);...l
27e0: 65 74 20 6d 75 74 20 63 6f 6e 6e 20 3d 20 73 65  et mut conn = se
27f0: 6c 66 2e 70 6f 6f 6c 2e 61 63 71 75 69 72 65 28  lf.pool.acquire(
2800: 29 2e 61 77 61 69 74 0a 09 09 09 2e 77 69 74 68  ).await.....with
2810: 5f 63 6f 6e 74 65 78 74 28 7c 7c 20 66 6f 72 6d  _context(|| form
2820: 61 74 21 28 22 41 75 74 6f 66 65 74 63 68 20 66  at!("Autofetch f
2830: 65 74 63 68 20 63 6f 6e 6e 3a 5c 6e 7b 3a 3f 7d  etch conn:\n{:?}
2840: 22 2c 20 26 73 65 6c 66 2e 70 6f 6f 6c 29 29 3f  ", &self.pool))?
2850: 3b 0a 09 09 6c 65 74 20 6e 6f 77 20 3d 20 63 68  ;...let now = ch
2860: 72 6f 6e 6f 3a 3a 4c 6f 63 61 6c 3a 3a 6e 6f 77  rono::Local::now
2870: 28 29 3b 0a 09 09 6c 65 74 20 6d 75 74 20 71 75  ();...let mut qu
2880: 65 75 65 20 3d 20 73 71 6c 78 3a 3a 71 75 65 72  eue = sqlx::quer
2890: 79 28 22 73 65 6c 65 63 74 20 73 6f 75 72 63 65  y("select source
28a0: 5f 69 64 2c 20 6e 65 78 74 5f 66 65 74 63 68 2c  _id, next_fetch,
28b0: 20 6f 77 6e 65 72 20 66 72 6f 6d 20 72 73 73 74   owner from rsst
28c0: 67 5f 6f 72 64 65 72 20 6e 61 74 75 72 61 6c 20  g_order natural 
28d0: 6c 65 66 74 20 6a 6f 69 6e 20 72 73 73 74 67 5f  left join rsstg_
28e0: 73 6f 75 72 63 65 20 77 68 65 72 65 20 6e 65 78  source where nex
28f0: 74 5f 66 65 74 63 68 20 3c 20 6e 6f 77 28 29 20  t_fetch < now() 
2900: 2b 20 69 6e 74 65 72 76 61 6c 20 27 31 20 6d 69  + interval '1 mi
2910: 6e 75 74 65 27 3b 22 29 0a 09 09 09 2e 66 65 74  nute';").....fet
2920: 63 68 5f 61 6c 6c 28 26 6d 75 74 20 63 6f 6e 6e  ch_all(&mut conn
2930: 29 2e 61 77 61 69 74 3f 3b 0a 09 09 66 6f 72 20  ).await?;...for 
2940: 72 6f 77 20 69 6e 20 71 75 65 75 65 2e 69 74 65  row in queue.ite
2950: 72 28 29 20 7b 0a 09 09 09 6c 65 74 20 73 6f 75  r() {....let sou
2960: 72 63 65 5f 69 64 3a 20 69 33 32 20 3d 20 72 6f  rce_id: i32 = ro
2970: 77 2e 74 72 79 5f 67 65 74 28 22 73 6f 75 72 63  w.try_get("sourc
2980: 65 5f 69 64 22 29 3f 3b 0a 09 09 09 6c 65 74 20  e_id")?;....let 
2990: 6f 77 6e 65 72 3a 20 69 36 34 20 3d 20 72 6f 77  owner: i64 = row
29a0: 2e 74 72 79 5f 67 65 74 28 22 6f 77 6e 65 72 22  .try_get("owner"
29b0: 29 3f 3b 0a 09 09 09 6c 65 74 20 6e 65 78 74 5f  )?;....let next_
29c0: 66 65 74 63 68 3a 20 44 61 74 65 54 69 6d 65 3c  fetch: DateTime<
29d0: 63 68 72 6f 6e 6f 3a 3a 4c 6f 63 61 6c 3e 20 3d  chrono::Local> =
29e0: 20 72 6f 77 2e 74 72 79 5f 67 65 74 28 22 6e 65   row.try_get("ne
29f0: 78 74 5f 66 65 74 63 68 22 29 3f 3b 0a 09 09 09  xt_fetch")?;....
2a00: 69 66 20 6e 65 78 74 5f 66 65 74 63 68 20 3c 20  if next_fetch < 
2a10: 6e 6f 77 20 7b 0a 09 09 09 09 6c 65 74 20 63 6c  now {.....let cl
2a20: 6f 6e 65 20 3d 20 43 6f 72 65 20 7b 0a 09 09 09  one = Core {....
2a30: 09 09 6f 77 6e 65 72 5f 63 68 61 74 3a 20 74 65  ..owner_chat: te
2a40: 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 55 73 65 72  legram_bot::User
2a50: 49 64 3a 3a 6e 65 77 28 6f 77 6e 65 72 29 2c 0a  Id::new(owner),.
2a60: 09 09 09 09 09 2e 2e 73 65 6c 66 2e 63 6c 6f 6e  .......self.clon
2a70: 65 28 29 0a 09 09 09 09 7d 3b 0a 09 09 09 09 74  e().....};.....t
2a80: 6f 6b 69 6f 3a 3a 73 70 61 77 6e 28 61 73 79 6e  okio::spawn(asyn
2a90: 63 20 6d 6f 76 65 20 7b 0a 09 09 09 09 09 69 66  c move {......if
2aa0: 20 6c 65 74 20 45 72 72 28 65 72 72 29 20 3d 20   let Err(err) = 
2ab0: 63 6c 6f 6e 65 2e 63 68 65 63 6b 28 26 73 6f 75  clone.check(&sou
2ac0: 72 63 65 5f 69 64 2c 20 6f 77 6e 65 72 2c 20 74  rce_id, owner, t
2ad0: 72 75 65 29 2e 61 77 61 69 74 20 7b 0a 09 09 09  rue).await {....
2ae0: 09 09 09 69 66 20 6c 65 74 20 45 72 72 28 65 72  ...if let Err(er
2af0: 72 29 20 3d 20 63 6c 6f 6e 65 2e 73 65 6e 64 28  r) = clone.send(
2b00: 26 66 6f 72 6d 61 74 21 28 22 f0 9f 9b 91 20 7b  &format!("šŸ›‘ {
2b10: 3a 3f 7d 22 2c 20 65 72 72 29 2c 20 4e 6f 6e 65  :?}", err), None
2b20: 2c 20 4e 6f 6e 65 29 2e 61 77 61 69 74 20 7b 0a  , None).await {.
2b30: 09 09 09 09 09 09 09 65 70 72 69 6e 74 6c 6e 21  .......eprintln!
2b40: 28 22 43 68 65 63 6b 20 65 72 72 6f 72 3a 20 7b  ("Check error: {
2b50: 7d 22 2c 20 65 72 72 29 3b 0a 09 09 09 09 09 09  }", err);.......
2b60: 7d 3b 0a 09 09 09 09 09 7d 3b 0a 09 09 09 09 7d  };......};.....}
2b70: 29 3b 0a 09 09 09 7d 20 65 6c 73 65 20 69 66 20  );....} else if 
2b80: 6e 65 78 74 5f 66 65 74 63 68 20 2d 20 6e 6f 77  next_fetch - now
2b90: 20 3c 20 64 65 6c 61 79 20 7b 0a 09 09 09 09 64   < delay {.....d
2ba0: 65 6c 61 79 20 3d 20 6e 65 78 74 5f 66 65 74 63  elay = next_fetc
2bb0: 68 20 2d 20 6e 6f 77 3b 0a 09 09 09 7d 0a 09 09  h - now;....}...
2bc0: 7d 3b 0a 09 09 71 75 65 75 65 2e 63 6c 65 61 72  };...queue.clear
2bd0: 28 29 3b 0a 09 09 4f 6b 28 64 65 6c 61 79 2e 74  ();...Ok(delay.t
2be0: 6f 5f 73 74 64 28 29 3f 29 0a 09 7d 0a 0a 09 70  o_std()?)..}...p
2bf0: 75 62 20 61 73 79 6e 63 20 66 6e 20 6c 69 73 74  ub async fn list
2c00: 3c 53 3e 28 26 73 65 6c 66 2c 20 6f 77 6e 65 72  <S>(&self, owner
2c10: 3a 20 53 29 20 2d 3e 20 52 65 73 75 6c 74 3c 53  : S) -> Result<S
2c20: 74 72 69 6e 67 3e 0a 09 77 68 65 72 65 20 53 3a  tring>..where S:
2c30: 20 49 6e 74 6f 3c 69 36 34 3e 20 7b 0a 09 09 6c   Into<i64> {...l
2c40: 65 74 20 6f 77 6e 65 72 20 3d 20 6f 77 6e 65 72  et owner = owner
2c50: 2e 69 6e 74 6f 28 29 3b 0a 0a 09 09 6c 65 74 20  .into();....let 
2c60: 6d 75 74 20 72 65 70 6c 79 3a 20 56 65 63 3c 43  mut reply: Vec<C
2c70: 6f 77 3c 73 74 72 3e 3e 20 3d 20 76 65 63 21 5b  ow<str>> = vec![
2c80: 5d 3b 0a 09 09 6c 65 74 20 6d 75 74 20 63 6f 6e  ];...let mut con
2c90: 6e 20 3d 20 73 65 6c 66 2e 70 6f 6f 6c 2e 61 63  n = self.pool.ac
2ca0: 71 75 69 72 65 28 29 2e 61 77 61 69 74 0a 09 09  quire().await...
2cb0: 09 2e 77 69 74 68 5f 63 6f 6e 74 65 78 74 28 7c  ..with_context(|
2cc0: 7c 20 66 6f 72 6d 61 74 21 28 22 4c 69 73 74 20  | format!("List 
2cd0: 66 65 74 63 68 20 63 6f 6e 6e 3a 5c 6e 7b 3a 3f  fetch conn:\n{:?
2ce0: 7d 22 2c 20 26 73 65 6c 66 2e 70 6f 6f 6c 29 29  }", &self.pool))
2cf0: 3f 3b 0a 09 09 72 65 70 6c 79 2e 70 75 73 68 28  ?;...reply.push(
2d00: 22 43 68 61 6e 6e 65 6c 73 3a 22 2e 69 6e 74 6f  "Channels:".into
2d10: 28 29 29 3b 0a 09 09 6c 65 74 20 72 6f 77 73 20  ());...let rows 
2d20: 3d 20 73 71 6c 78 3a 3a 71 75 65 72 79 28 22 73  = sqlx::query("s
2d30: 65 6c 65 63 74 20 73 6f 75 72 63 65 5f 69 64 2c  elect source_id,
2d40: 20 63 68 61 6e 6e 65 6c 2c 20 65 6e 61 62 6c 65   channel, enable
2d50: 64 2c 20 75 72 6c 2c 20 69 76 5f 68 61 73 68 2c  d, url, iv_hash,
2d60: 20 75 72 6c 5f 72 65 20 66 72 6f 6d 20 72 73 73   url_re from rss
2d70: 74 67 5f 73 6f 75 72 63 65 20 77 68 65 72 65 20  tg_source where 
2d80: 6f 77 6e 65 72 20 3d 20 24 31 20 6f 72 64 65 72  owner = $1 order
2d90: 20 62 79 20 73 6f 75 72 63 65 5f 69 64 22 29 0a   by source_id").
2da0: 09 09 09 2e 62 69 6e 64 28 6f 77 6e 65 72 29 0a  ....bind(owner).
2db0: 09 09 09 2e 66 65 74 63 68 5f 61 6c 6c 28 26 6d  ....fetch_all(&m
2dc0: 75 74 20 63 6f 6e 6e 29 2e 61 77 61 69 74 3f 3b  ut conn).await?;
2dd0: 0a 09 09 66 6f 72 20 72 6f 77 20 69 6e 20 72 6f  ...for row in ro
2de0: 77 73 2e 69 74 65 72 28 29 20 7b 0a 09 09 09 6c  ws.iter() {....l
2df0: 65 74 20 73 6f 75 72 63 65 5f 69 64 3a 20 69 33  et source_id: i3
2e00: 32 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74 28  2 = row.try_get(
2e10: 22 73 6f 75 72 63 65 5f 69 64 22 29 3f 3b 0a 09  "source_id")?;..
2e20: 09 09 6c 65 74 20 75 73 65 72 6e 61 6d 65 3a 20  ..let username: 
2e30: 26 73 74 72 20 3d 20 72 6f 77 2e 74 72 79 5f 67  &str = row.try_g
2e40: 65 74 28 22 63 68 61 6e 6e 65 6c 22 29 3f 3b 0a  et("channel")?;.
2e50: 09 09 09 6c 65 74 20 65 6e 61 62 6c 65 64 3a 20  ...let enabled: 
2e60: 62 6f 6f 6c 20 3d 20 72 6f 77 2e 74 72 79 5f 67  bool = row.try_g
2e70: 65 74 28 22 65 6e 61 62 6c 65 64 22 29 3f 3b 0a  et("enabled")?;.
2e80: 09 09 09 6c 65 74 20 75 72 6c 3a 20 26 73 74 72  ...let url: &str
2e90: 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74 28 22   = row.try_get("
2ea0: 75 72 6c 22 29 3f 3b 0a 09 09 09 6c 65 74 20 69  url")?;....let i
2eb0: 76 5f 68 61 73 68 3a 20 4f 70 74 69 6f 6e 3c 26  v_hash: Option<&
2ec0: 73 74 72 3e 20 3d 20 72 6f 77 2e 74 72 79 5f 67  str> = row.try_g
2ed0: 65 74 28 22 69 76 5f 68 61 73 68 22 29 3f 3b 0a  et("iv_hash")?;.
2ee0: 09 09 09 6c 65 74 20 75 72 6c 5f 72 65 3a 20 4f  ...let url_re: O
2ef0: 70 74 69 6f 6e 3c 26 73 74 72 3e 20 3d 20 72 6f  ption<&str> = ro
2f00: 77 2e 74 72 79 5f 67 65 74 28 22 75 72 6c 5f 72  w.try_get("url_r
2f10: 65 22 29 3f 3b 0a 09 09 09 72 65 70 6c 79 2e 70  e")?;....reply.p
2f20: 75 73 68 28 66 6f 72 6d 61 74 21 28 22 5c 6e 5c  ush(format!("\n\
2f30: 5c 23 ef b8 8f e2 83 a3 20 7b 7d 20 5c 5c 2a ef  \#ļøāƒ£ {} \\*ļ
2f40: b8 8f e2 83 a3 20 60 7b 7d 60 20 7b 7d 5c 6e f0  øāƒ£ `{}` {}\nš
2f50: 9f 94 97 20 60 7b 7d 60 22 2c 20 73 6f 75 72 63  Ÿ”— `{}`", sourc
2f60: 65 5f 69 64 2c 20 75 73 65 72 6e 61 6d 65 2c 20  e_id, username, 
2f70: 20 0a 09 09 09 09 6d 61 74 63 68 20 65 6e 61 62   .....match enab
2f80: 6c 65 64 20 7b 0a 09 09 09 09 09 74 72 75 65 20  led {......true 
2f90: 20 3d 3e 20 22 f0 9f 94 84 20 65 6e 61 62 6c 65   => "šŸ”„ enable
2fa0: 64 22 2c 0a 09 09 09 09 09 66 61 6c 73 65 20 3d  d",......false =
2fb0: 3e 20 22 e2 9b 94 20 64 69 73 61 62 6c 65 64 22  > "ā›” disabled"
2fc0: 2c 0a 09 09 09 09 7d 2c 20 75 72 6c 29 2e 69 6e  ,.....}, url).in
2fd0: 74 6f 28 29 29 3b 0a 09 09 09 69 66 20 6c 65 74  to());....if let
2fe0: 20 53 6f 6d 65 28 68 61 73 68 29 20 3d 20 69 76   Some(hash) = iv
2ff0: 5f 68 61 73 68 20 7b 0a 09 09 09 09 72 65 70 6c  _hash {.....repl
3000: 79 2e 70 75 73 68 28 66 6f 72 6d 61 74 21 28 22  y.push(format!("
3010: 49 56 3a 20 60 7b 7d 60 22 2c 20 68 61 73 68 29  IV: `{}`", hash)
3020: 2e 69 6e 74 6f 28 29 29 3b 0a 09 09 09 7d 0a 09  .into());....}..
3030: 09 09 69 66 20 6c 65 74 20 53 6f 6d 65 28 72 65  ..if let Some(re
3040: 29 20 3d 20 75 72 6c 5f 72 65 20 7b 0a 09 09 09  ) = url_re {....
3050: 09 72 65 70 6c 79 2e 70 75 73 68 28 66 6f 72 6d  .reply.push(form
3060: 61 74 21 28 22 52 45 3a 20 60 7b 7d 60 22 2c 20  at!("RE: `{}`", 
3070: 72 65 29 2e 69 6e 74 6f 28 29 29 3b 0a 09 09 09  re).into());....
3080: 7d 0a 09 09 7d 3b 0a 09 09 4f 6b 28 72 65 70 6c  }...};...Ok(repl
3090: 79 2e 6a 6f 69 6e 28 22 5c 6e 22 29 29 0a 09 7d  y.join("\n"))..}
30a0: 0a 7d 0a                                         .}.