Hex Artifact Content
Logged in as anonymous

Artifact 363e6b408a2b3e5cdf42e5b681dc1dfcb3b6460b4b3c0e5bb91eea4d94f130c8:


0000: 75 73 65 20 73 74 64 3a 3a 63 6f 6c 6c 65 63 74  use std::collect
0010: 69 6f 6e 73 3a 3a 42 54 72 65 65 4d 61 70 3b 0a  ions::BTreeMap;.
0020: 0a 75 73 65 20 63 6f 6e 66 69 67 3b 0a 0a 75 73  .use config;..us
0030: 65 20 74 6f 6b 69 6f 3b 0a 75 73 65 20 72 73 73  e tokio;.use rss
0040: 3b 0a 75 73 65 20 63 68 72 6f 6e 6f 3a 3a 44 61  ;.use chrono::Da
0050: 74 65 54 69 6d 65 3b 0a 0a 75 73 65 20 72 65 67  teTime;..use reg
0060: 65 78 3a 3a 52 65 67 65 78 3b 0a 0a 75 73 65 20  ex::Regex;..use 
0070: 74 6f 6b 69 6f 3a 3a 73 74 72 65 61 6d 3a 3a 53  tokio::stream::S
0080: 74 72 65 61 6d 45 78 74 3b 0a 75 73 65 20 74 65  treamExt;.use te
0090: 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 2a 3b 0a 0a  legram_bot::*;..
00a0: 75 73 65 20 73 71 6c 78 3a 3a 70 6f 73 74 67 72  use sqlx::postgr
00b0: 65 73 3a 3a 50 67 50 6f 6f 6c 4f 70 74 69 6f 6e  es::PgPoolOption
00c0: 73 3b 0a 75 73 65 20 73 71 6c 78 3a 3a 52 6f 77  s;.use sqlx::Row
00d0: 3b 0a 0a 74 79 70 65 20 52 65 73 75 6c 74 3c 54  ;..type Result<T
00e0: 3e 20 3d 20 73 74 64 3a 3a 72 65 73 75 6c 74 3a  > = std::result:
00f0: 3a 52 65 73 75 6c 74 3c 54 2c 20 42 6f 78 3c 64  :Result<T, Box<d
0100: 79 6e 20 73 74 64 3a 3a 65 72 72 6f 72 3a 3a 45  yn std::error::E
0110: 72 72 6f 72 3e 3e 3b 0a 0a 23 5b 64 65 72 69 76  rror>>;..#[deriv
0120: 65 28 43 6c 6f 6e 65 29 5d 0a 73 74 72 75 63 74  e(Clone)].struct
0130: 20 43 6f 72 65 20 7b 0a 09 6f 77 6e 65 72 3a 20   Core {..owner: 
0140: 69 36 34 2c 0a 09 61 70 69 5f 6b 65 79 3a 20 53  i64,..api_key: S
0150: 74 72 69 6e 67 2c 0a 09 6f 77 6e 65 72 5f 63 68  tring,..owner_ch
0160: 61 74 3a 20 55 73 65 72 49 64 2c 0a 09 74 67 3a  at: UserId,..tg:
0170: 20 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 41   telegram_bot::A
0180: 70 69 2c 0a 09 6d 79 3a 20 55 73 65 72 2c 0a 09  pi,..my: User,..
0190: 70 6f 6f 6c 3a 20 73 71 6c 78 3a 3a 50 6f 6f 6c  pool: sqlx::Pool
01a0: 3c 73 71 6c 78 3a 3a 50 6f 73 74 67 72 65 73 3e  <sqlx::Postgres>
01b0: 2c 0a 7d 0a 0a 69 6d 70 6c 20 43 6f 72 65 20 7b  ,.}..impl Core {
01c0: 0a 09 61 73 79 6e 63 20 66 6e 20 6e 65 77 28 73  ..async fn new(s
01d0: 65 74 74 69 6e 67 73 3a 20 63 6f 6e 66 69 67 3a  ettings: config:
01e0: 3a 43 6f 6e 66 69 67 29 20 2d 3e 20 52 65 73 75  :Config) -> Resu
01f0: 6c 74 3c 43 6f 72 65 3e 20 7b 0a 09 09 6c 65 74  lt<Core> {...let
0200: 20 6f 77 6e 65 72 20 3d 20 73 65 74 74 69 6e 67   owner = setting
0210: 73 2e 67 65 74 5f 69 6e 74 28 22 6f 77 6e 65 72  s.get_int("owner
0220: 22 29 3f 3b 0a 09 09 6c 65 74 20 61 70 69 5f 6b  ")?;...let api_k
0230: 65 79 20 3d 20 73 65 74 74 69 6e 67 73 2e 67 65  ey = settings.ge
0240: 74 5f 73 74 72 28 22 61 70 69 5f 6b 65 79 22 29  t_str("api_key")
0250: 3f 3b 0a 09 09 6c 65 74 20 74 67 20 3d 20 41 70  ?;...let tg = Ap
0260: 69 3a 3a 6e 65 77 28 26 61 70 69 5f 6b 65 79 29  i::new(&api_key)
0270: 3b 0a 09 09 6c 65 74 20 63 6f 72 65 20 3d 20 43  ;...let core = C
0280: 6f 72 65 20 7b 0a 09 09 09 6f 77 6e 65 72 3a 20  ore {....owner: 
0290: 6f 77 6e 65 72 2c 0a 09 09 09 61 70 69 5f 6b 65  owner,....api_ke
02a0: 79 3a 20 61 70 69 5f 6b 65 79 2e 63 6c 6f 6e 65  y: api_key.clone
02b0: 28 29 2c 0a 09 09 09 6d 79 3a 20 74 67 2e 73 65  (),....my: tg.se
02c0: 6e 64 28 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a  nd(telegram_bot:
02d0: 3a 47 65 74 4d 65 29 2e 61 77 61 69 74 3f 2c 0a  :GetMe).await?,.
02e0: 09 09 09 74 67 3a 20 74 67 2c 0a 09 09 09 6f 77  ...tg: tg,....ow
02f0: 6e 65 72 5f 63 68 61 74 3a 20 55 73 65 72 49 64  ner_chat: UserId
0300: 3a 3a 6e 65 77 28 6f 77 6e 65 72 29 2c 0a 09 09  ::new(owner),...
0310: 09 70 6f 6f 6c 3a 20 50 67 50 6f 6f 6c 4f 70 74  .pool: PgPoolOpt
0320: 69 6f 6e 73 3a 3a 6e 65 77 28 29 2e 6d 61 78 5f  ions::new().max_
0330: 63 6f 6e 6e 65 63 74 69 6f 6e 73 28 35 29 2e 63  connections(5).c
0340: 6f 6e 6e 65 63 74 28 26 73 65 74 74 69 6e 67 73  onnect(&settings
0350: 2e 67 65 74 5f 73 74 72 28 22 70 67 22 29 3f 29  .get_str("pg")?)
0360: 2e 61 77 61 69 74 3f 2c 0a 09 09 7d 3b 0a 09 09  .await?,...};...
0370: 6c 65 74 20 63 6c 6f 6e 65 20 3d 20 63 6f 72 65  let clone = core
0380: 2e 63 6c 6f 6e 65 28 29 3b 0a 09 09 74 6f 6b 69  .clone();...toki
0390: 6f 3a 3a 73 70 61 77 6e 28 61 73 79 6e 63 20 6d  o::spawn(async m
03a0: 6f 76 65 20 7b 0a 09 09 09 69 66 20 6c 65 74 20  ove {....if let 
03b0: 45 72 72 28 65 72 72 29 20 3d 20 63 6c 6f 6e 65  Err(err) = clone
03c0: 2e 61 75 74 6f 66 65 74 63 68 28 29 2e 61 77 61  .autofetch().awa
03d0: 69 74 20 7b 0a 09 09 09 09 65 70 72 69 6e 74 6c  it {.....eprintl
03e0: 6e 21 28 22 63 6f 6e 6e 65 63 74 69 6f 6e 20 65  n!("connection e
03f0: 72 72 6f 72 3a 20 7b 7d 22 2c 20 65 72 72 29 3b  rror: {}", err);
0400: 0a 09 09 09 7d 0a 09 09 7d 29 3b 0a 09 09 4f 6b  ....}...});...Ok
0410: 28 63 6f 72 65 29 0a 09 7d 0a 0a 09 66 6e 20 73  (core)..}...fn s
0420: 74 72 65 61 6d 28 26 73 65 6c 66 29 20 2d 3e 20  tream(&self) -> 
0430: 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 55 70  telegram_bot::Up
0440: 64 61 74 65 73 53 74 72 65 61 6d 20 7b 0a 09 09  datesStream {...
0450: 73 65 6c 66 2e 74 67 2e 73 74 72 65 61 6d 28 29  self.tg.stream()
0460: 0a 09 7d 0a 0a 09 66 6e 20 64 65 62 75 67 28 26  ..}...fn debug(&
0470: 73 65 6c 66 2c 20 6d 73 67 3a 20 26 73 74 72 29  self, msg: &str)
0480: 20 2d 3e 20 52 65 73 75 6c 74 3c 28 29 3e 20 7b   -> Result<()> {
0490: 0a 09 09 73 65 6c 66 2e 74 67 2e 73 70 61 77 6e  ...self.tg.spawn
04a0: 28 53 65 6e 64 4d 65 73 73 61 67 65 3a 3a 6e 65  (SendMessage::ne
04b0: 77 28 73 65 6c 66 2e 6f 77 6e 65 72 5f 63 68 61  w(self.owner_cha
04c0: 74 2c 20 6d 73 67 29 29 3b 0a 09 09 4f 6b 28 28  t, msg));...Ok((
04d0: 29 29 0a 09 7d 0a 0a 09 61 73 79 6e 63 20 66 6e  ))..}...async fn
04e0: 20 63 68 65 63 6b 28 26 73 65 6c 66 2c 20 69 64   check(&self, id
04f0: 3a 20 26 69 33 32 2c 20 72 65 61 6c 3a 20 4f 70  : &i32, real: Op
0500: 74 69 6f 6e 3c 62 6f 6f 6c 3e 29 20 2d 3e 20 52  tion<bool>) -> R
0510: 65 73 75 6c 74 3c 28 29 3e 20 7b 0a 09 09 6d 61  esult<()> {...ma
0520: 74 63 68 20 73 71 6c 78 3a 3a 71 75 65 72 79 28  tch sqlx::query(
0530: 22 73 65 6c 65 63 74 20 73 6f 75 72 63 65 5f 69  "select source_i
0540: 64 2c 20 63 68 61 6e 6e 65 6c 5f 69 64 2c 20 75  d, channel_id, u
0550: 72 6c 2c 20 69 76 5f 68 61 73 68 2c 20 6f 77 6e  rl, iv_hash, own
0560: 65 72 20 66 72 6f 6d 20 72 73 73 74 67 5f 73 6f  er from rsstg_so
0570: 75 72 63 65 20 77 68 65 72 65 20 73 6f 75 72 63  urce where sourc
0580: 65 5f 69 64 20 3d 20 24 31 22 29 0a 09 09 09 2e  e_id = $1").....
0590: 62 69 6e 64 28 69 64 29 0a 09 09 09 2e 66 65 74  bind(id).....fet
05a0: 63 68 5f 6f 6e 65 28 26 73 65 6c 66 2e 70 6f 6f  ch_one(&self.poo
05b0: 6c 29 2e 61 77 61 69 74 20 7b 0a 09 09 09 4f 6b  l).await {....Ok
05c0: 28 72 6f 77 29 20 3d 3e 20 7b 0a 09 09 09 09 6c  (row) => {.....l
05d0: 65 74 20 63 68 61 6e 6e 65 6c 5f 69 64 3a 20 69  et channel_id: i
05e0: 36 34 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74  64 = row.try_get
05f0: 28 22 63 68 61 6e 6e 65 6c 5f 69 64 22 29 3f 3b  ("channel_id")?;
0600: 0a 09 09 09 09 6c 65 74 20 64 65 73 74 69 6e 61  .....let destina
0610: 74 69 6f 6e 20 3d 20 6d 61 74 63 68 20 72 65 61  tion = match rea
0620: 6c 20 7b 0a 09 09 09 09 09 53 6f 6d 65 28 74 72  l {......Some(tr
0630: 75 65 29 20 3d 3e 20 55 73 65 72 49 64 3a 3a 6e  ue) => UserId::n
0640: 65 77 28 63 68 61 6e 6e 65 6c 5f 69 64 29 2c 0a  ew(channel_id),.
0650: 09 09 09 09 09 53 6f 6d 65 28 66 61 6c 73 65 29  .....Some(false)
0660: 20 7c 20 4e 6f 6e 65 20 3d 3e 20 55 73 65 72 49   | None => UserI
0670: 64 3a 3a 6e 65 77 28 72 6f 77 2e 74 72 79 5f 67  d::new(row.try_g
0680: 65 74 28 22 6f 77 6e 65 72 22 29 3f 29 2c 0a 09  et("owner")?),..
0690: 09 09 09 7d 3b 0a 09 09 09 09 6c 65 74 20 75 72  ...};.....let ur
06a0: 6c 3a 20 26 73 74 72 20 3d 20 72 6f 77 2e 74 72  l: &str = row.tr
06b0: 79 5f 67 65 74 28 22 75 72 6c 22 29 3f 3b 0a 09  y_get("url")?;..
06c0: 09 09 09 6c 65 74 20 6d 75 74 20 74 68 69 73 5f  ...let mut this_
06d0: 66 65 74 63 68 3a 20 4f 70 74 69 6f 6e 3c 44 61  fetch: Option<Da
06e0: 74 65 54 69 6d 65 3c 63 68 72 6f 6e 6f 3a 3a 46  teTime<chrono::F
06f0: 69 78 65 64 4f 66 66 73 65 74 3e 3e 20 3d 20 4e  ixedOffset>> = N
0700: 6f 6e 65 3b 0a 09 09 09 09 6c 65 74 20 69 76 5f  one;.....let iv_
0710: 68 61 73 68 3a 20 4f 70 74 69 6f 6e 3c 26 73 74  hash: Option<&st
0720: 72 3e 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74  r> = row.try_get
0730: 28 22 69 76 5f 68 61 73 68 22 29 3f 3b 0a 09 09  ("iv_hash")?;...
0740: 09 09 6c 65 74 20 6d 75 74 20 70 6f 73 74 73 3a  ..let mut posts:
0750: 20 42 54 72 65 65 4d 61 70 3c 44 61 74 65 54 69   BTreeMap<DateTi
0760: 6d 65 3c 63 68 72 6f 6e 6f 3a 3a 46 69 78 65 64  me<chrono::Fixed
0770: 4f 66 66 73 65 74 3e 2c 20 53 74 72 69 6e 67 3e  Offset>, String>
0780: 20 3d 20 42 54 72 65 65 4d 61 70 3a 3a 6e 65 77   = BTreeMap::new
0790: 28 29 3b 0a 09 09 09 09 6d 61 74 63 68 20 72 73  ();.....match rs
07a0: 73 3a 3a 43 68 61 6e 6e 65 6c 3a 3a 66 72 6f 6d  s::Channel::from
07b0: 5f 75 72 6c 28 75 72 6c 29 20 7b 0a 09 09 09 09  _url(url) {.....
07c0: 09 4f 6b 28 66 65 65 64 29 20 3d 3e 20 7b 0a 09  .Ok(feed) => {..
07d0: 09 09 09 09 09 73 65 6c 66 2e 64 65 62 75 67 28  .....self.debug(
07e0: 26 66 6f 72 6d 61 74 21 28 22 23 20 74 69 74 6c  &format!("# titl
07f0: 65 3a 7b 3a 3f 7d 20 74 74 6c 3a 7b 3a 3f 7d 20  e:{:?} ttl:{:?} 
0800: 68 6f 75 72 73 3a 7b 3a 3f 7d 20 64 61 79 73 3a  hours:{:?} days:
0810: 7b 3a 3f 7d 22 2c 20 66 65 65 64 2e 74 69 74 6c  {:?}", feed.titl
0820: 65 28 29 2c 20 66 65 65 64 2e 74 74 6c 28 29 2c  e(), feed.ttl(),
0830: 20 66 65 65 64 2e 73 6b 69 70 5f 68 6f 75 72 73   feed.skip_hours
0840: 28 29 2c 20 66 65 65 64 2e 73 6b 69 70 5f 64 61  (), feed.skip_da
0850: 79 73 28 29 29 29 3f 3b 0a 09 09 09 09 09 09 66  ys()))?;.......f
0860: 6f 72 20 69 74 65 6d 20 69 6e 20 66 65 65 64 2e  or item in feed.
0870: 69 74 65 6d 73 28 29 20 7b 0a 09 09 09 09 09 09  items() {.......
0880: 09 6c 65 74 20 64 61 74 65 20 3d 20 6d 61 74 63  .let date = matc
0890: 68 20 69 74 65 6d 2e 70 75 62 5f 64 61 74 65 28  h item.pub_date(
08a0: 29 20 7b 0a 09 09 09 09 09 09 09 09 53 6f 6d 65  ) {.........Some
08b0: 28 66 65 65 64 5f 64 61 74 65 29 20 3d 3e 20 44  (feed_date) => D
08c0: 61 74 65 54 69 6d 65 3a 3a 70 61 72 73 65 5f 66  ateTime::parse_f
08d0: 72 6f 6d 5f 72 66 63 32 38 32 32 28 66 65 65 64  rom_rfc2822(feed
08e0: 5f 64 61 74 65 29 2c 0a 09 09 09 09 09 09 09 09  _date),.........
08f0: 4e 6f 6e 65 20 3d 3e 20 44 61 74 65 54 69 6d 65  None => DateTime
0900: 3a 3a 70 61 72 73 65 5f 66 72 6f 6d 5f 72 66 63  ::parse_from_rfc
0910: 33 33 33 39 28 26 69 74 65 6d 2e 64 75 62 6c 69  3339(&item.dubli
0920: 6e 5f 63 6f 72 65 5f 65 78 74 28 29 2e 75 6e 77  n_core_ext().unw
0930: 72 61 70 28 29 2e 64 61 74 65 73 28 29 5b 30 5d  rap().dates()[0]
0940: 29 2c 0a 09 09 09 09 09 09 09 7d 3f 3b 0a 09 09  ),........}?;...
0950: 09 09 09 09 09 6c 65 74 20 75 72 6c 20 3d 20 69  .....let url = i
0960: 74 65 6d 2e 6c 69 6e 6b 28 29 2e 75 6e 77 72 61  tem.link().unwra
0970: 70 28 29 2e 74 6f 5f 73 74 72 69 6e 67 28 29 3b  p().to_string();
0980: 0a 09 09 09 09 09 09 09 70 6f 73 74 73 2e 69 6e  ........posts.in
0990: 73 65 72 74 28 64 61 74 65 2e 63 6c 6f 6e 65 28  sert(date.clone(
09a0: 29 2c 20 75 72 6c 2e 63 6c 6f 6e 65 28 29 29 3b  ), url.clone());
09b0: 0a 09 09 09 09 09 09 7d 3b 0a 09 09 09 09 09 09  .......};.......
09c0: 66 6f 72 20 28 64 61 74 65 2c 20 75 72 6c 29 20  for (date, url) 
09d0: 69 6e 20 70 6f 73 74 73 2e 69 74 65 72 28 29 20  in posts.iter() 
09e0: 7b 0a 09 09 09 09 09 09 09 6d 61 74 63 68 20 73  {........match s
09f0: 71 6c 78 3a 3a 71 75 65 72 79 28 22 73 65 6c 65  qlx::query("sele
0a00: 63 74 20 65 78 69 73 74 73 28 73 65 6c 65 63 74  ct exists(select
0a10: 20 74 72 75 65 20 66 72 6f 6d 20 72 73 73 74 67   true from rsstg
0a20: 5f 70 6f 73 74 20 77 68 65 72 65 20 75 72 6c 20  _post where url 
0a30: 3d 20 24 31 20 61 6e 64 20 73 6f 75 72 63 65 5f  = $1 and source_
0a40: 69 64 20 3d 20 24 32 29 20 61 73 20 65 78 69 73  id = $2) as exis
0a50: 74 73 3b 22 29 0a 09 09 09 09 09 09 09 09 2e 62  ts;")..........b
0a60: 69 6e 64 28 26 75 72 6c 29 0a 09 09 09 09 09 09  ind(&url).......
0a70: 09 09 2e 62 69 6e 64 28 69 64 29 0a 09 09 09 09  ...bind(id).....
0a80: 09 09 09 09 2e 66 65 74 63 68 5f 6f 6e 65 28 26  .....fetch_one(&
0a90: 73 65 6c 66 2e 70 6f 6f 6c 29 2e 61 77 61 69 74  self.pool).await
0aa0: 20 7b 0a 09 09 09 09 09 09 09 09 4f 6b 28 72 6f   {.........Ok(ro
0ab0: 77 29 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09  w) => {.........
0ac0: 09 6c 65 74 20 65 78 69 73 74 73 3a 20 62 6f 6f  .let exists: boo
0ad0: 6c 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74 28  l = row.try_get(
0ae0: 22 65 78 69 73 74 73 22 29 3f 3b 0a 09 09 09 09  "exists")?;.....
0af0: 09 09 09 09 09 69 66 20 21 20 65 78 69 73 74 73  .....if ! exists
0b00: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 69 66 20   {...........if 
0b10: 74 68 69 73 5f 66 65 74 63 68 20 3d 3d 20 4e 6f  this_fetch == No
0b20: 6e 65 20 7c 7c 20 2a 64 61 74 65 20 3e 20 74 68  ne || *date > th
0b30: 69 73 5f 66 65 74 63 68 2e 75 6e 77 72 61 70 28  is_fetch.unwrap(
0b40: 29 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 74  ) {............t
0b50: 68 69 73 5f 66 65 74 63 68 20 3d 20 53 6f 6d 65  his_fetch = Some
0b60: 28 2a 64 61 74 65 29 3b 0a 09 09 09 09 09 09 09  (*date);........
0b70: 09 09 09 7d 0a 09 09 09 09 09 09 09 09 09 09 6d  ...}...........m
0b80: 61 74 63 68 20 73 65 6c 66 2e 74 67 2e 73 65 6e  atch self.tg.sen
0b90: 64 28 20 6d 61 74 63 68 20 69 76 5f 68 61 73 68  d( match iv_hash
0ba0: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09 53   {.............S
0bb0: 6f 6d 65 28 78 29 20 3d 3e 20 53 65 6e 64 4d 65  ome(x) => SendMe
0bc0: 73 73 61 67 65 3a 3a 6e 65 77 28 64 65 73 74 69  ssage::new(desti
0bd0: 6e 61 74 69 6f 6e 2c 20 66 6f 72 6d 61 74 21 28  nation, format!(
0be0: 22 3c 61 20 68 72 65 66 3d 5c 22 68 74 74 70 73  "<a href=\"https
0bf0: 3a 2f 2f 74 2e 6d 65 2f 69 76 3f 75 72 6c 3d 7b  ://t.me/iv?url={
0c00: 7d 26 72 68 61 73 68 3d 7b 7d 5c 22 3e 20 3c 2f  }&rhash={}\"> </
0c10: 61 3e 7b 30 7d 22 2c 20 75 72 6c 2c 20 78 29 29  a>{0}", url, x))
0c20: 2c 0a 09 09 09 09 09 09 09 09 09 09 09 09 4e 6f  ,.............No
0c30: 6e 65 20 3d 3e 20 53 65 6e 64 4d 65 73 73 61 67  ne => SendMessag
0c40: 65 3a 3a 6e 65 77 28 64 65 73 74 69 6e 61 74 69  e::new(destinati
0c50: 6f 6e 2c 20 66 6f 72 6d 61 74 21 28 22 7b 7d 22  on, format!("{}"
0c60: 2c 20 75 72 6c 29 29 2c 0a 09 09 09 09 09 09 09  , url)),........
0c70: 09 09 09 09 7d 2e 70 61 72 73 65 5f 6d 6f 64 65  ....}.parse_mode
0c80: 28 74 79 70 65 73 3a 3a 50 61 72 73 65 4d 6f 64  (types::ParseMod
0c90: 65 3a 3a 48 74 6d 6c 29 29 2e 61 77 61 69 74 20  e::Html)).await 
0ca0: 7b 0a 09 09 09 09 09 09 09 09 09 09 09 4f 6b 28  {............Ok(
0cb0: 5f 29 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09  _) => {.........
0cc0: 09 09 09 09 6d 61 74 63 68 20 73 71 6c 78 3a 3a  ....match sqlx::
0cd0: 71 75 65 72 79 28 22 69 6e 73 65 72 74 20 69 6e  query("insert in
0ce0: 74 6f 20 72 73 73 74 67 5f 70 6f 73 74 20 28 73  to rsstg_post (s
0cf0: 6f 75 72 63 65 5f 69 64 2c 20 70 6f 73 74 65 64  ource_id, posted
0d00: 2c 20 75 72 6c 29 20 76 61 6c 75 65 73 20 28 24  , url) values ($
0d10: 31 2c 20 24 32 2c 20 24 33 29 3b 22 29 0a 09 09  1, $2, $3);")...
0d20: 09 09 09 09 09 09 09 09 09 09 09 2e 62 69 6e 64  ............bind
0d30: 28 69 64 29 0a 09 09 09 09 09 09 09 09 09 09 09  (id)............
0d40: 09 09 2e 62 69 6e 64 28 64 61 74 65 29 0a 09 09  ...bind(date)...
0d50: 09 09 09 09 09 09 09 09 09 09 09 2e 62 69 6e 64  ............bind
0d60: 28 75 72 6c 29 0a 09 09 09 09 09 09 09 09 09 09  (url)...........
0d70: 09 09 09 2e 65 78 65 63 75 74 65 28 26 73 65 6c  ....execute(&sel
0d80: 66 2e 70 6f 6f 6c 29 2e 61 77 61 69 74 20 7b 0a  f.pool).await {.
0d90: 09 09 09 09 09 09 09 09 09 09 09 09 09 09 4f 6b  ..............Ok
0da0: 28 5f 29 20 3d 3e 20 7b 7d 2c 0a 09 09 09 09 09  (_) => {},......
0db0: 09 09 09 09 09 09 09 09 09 45 72 72 28 65 72 72  .........Err(err
0dc0: 29 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09 09  ) => {..........
0dd0: 09 09 09 09 09 09 73 65 6c 66 2e 64 65 62 75 67  ......self.debug
0de0: 28 26 65 72 72 2e 74 6f 5f 73 74 72 69 6e 67 28  (&err.to_string(
0df0: 29 29 3f 3b 0a 09 09 09 09 09 09 09 09 09 09 09  ))?;............
0e00: 09 09 09 7d 2c 0a 09 09 09 09 09 09 09 09 09 09  ...},...........
0e10: 09 09 7d 3b 0a 09 09 09 09 09 09 09 09 09 09 09  ..};............
0e20: 7d 2c 0a 09 09 09 09 09 09 09 09 09 09 09 45 72  },............Er
0e30: 72 28 65 72 72 29 20 3d 3e 20 7b 0a 09 09 09 09  r(err) => {.....
0e40: 09 09 09 09 09 09 09 09 73 65 6c 66 2e 64 65 62  ........self.deb
0e50: 75 67 28 26 65 72 72 2e 74 6f 5f 73 74 72 69 6e  ug(&err.to_strin
0e60: 67 28 29 29 3f 3b 0a 09 09 09 09 09 09 09 09 09  g())?;..........
0e70: 09 09 7d 2c 0a 09 09 09 09 09 09 09 09 09 09 7d  ..},...........}
0e80: 3b 0a 09 09 09 09 09 09 09 09 09 09 74 6f 6b 69  ;...........toki
0e90: 6f 3a 3a 74 69 6d 65 3a 3a 64 65 6c 61 79 5f 66  o::time::delay_f
0ea0: 6f 72 28 73 74 64 3a 3a 74 69 6d 65 3a 3a 44 75  or(std::time::Du
0eb0: 72 61 74 69 6f 6e 3a 3a 6e 65 77 28 34 2c 20 30  ration::new(4, 0
0ec0: 29 29 2e 61 77 61 69 74 3b 0a 09 09 09 09 09 09  )).await;.......
0ed0: 09 09 09 7d 0a 09 09 09 09 09 09 09 09 7d 2c 0a  ...}.........},.
0ee0: 09 09 09 09 09 09 09 09 45 72 72 28 65 72 72 29  ........Err(err)
0ef0: 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09 09 73   => {..........s
0f00: 65 6c 66 2e 64 65 62 75 67 28 26 65 72 72 2e 74  elf.debug(&err.t
0f10: 6f 5f 73 74 72 69 6e 67 28 29 29 3f 3b 0a 09 09  o_string())?;...
0f20: 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 09 09  ......},........
0f30: 7d 3b 0a 09 09 09 09 09 09 7d 3b 0a 09 09 09 09  };.......};.....
0f40: 09 09 70 6f 73 74 73 2e 63 6c 65 61 72 28 29 3b  ..posts.clear();
0f50: 0a 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 45 72  ......},......Er
0f60: 72 28 65 72 72 29 20 3d 3e 20 7b 0a 09 09 09 09  r(err) => {.....
0f70: 09 09 73 65 6c 66 2e 64 65 62 75 67 28 26 65 72  ..self.debug(&er
0f80: 72 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 3f 3b  r.to_string())?;
0f90: 0a 09 09 09 09 09 7d 2c 0a 09 09 09 09 7d 3b 0a  ......},.....};.
0fa0: 09 09 09 09 6d 61 74 63 68 20 73 71 6c 78 3a 3a  ....match sqlx::
0fb0: 71 75 65 72 79 28 22 75 70 64 61 74 65 20 72 73  query("update rs
0fc0: 73 74 67 5f 73 6f 75 72 63 65 20 73 65 74 20 6c  stg_source set l
0fd0: 61 73 74 5f 73 63 72 61 70 65 20 3d 20 6e 6f 77  ast_scrape = now
0fe0: 28 29 20 77 68 65 72 65 20 73 6f 75 72 63 65 5f  () where source_
0ff0: 69 64 20 3d 20 24 31 3b 22 29 0a 09 09 09 09 09  id = $1;")......
1000: 2e 62 69 6e 64 28 69 64 29 0a 09 09 09 09 09 2e  .bind(id).......
1010: 65 78 65 63 75 74 65 28 26 73 65 6c 66 2e 70 6f  execute(&self.po
1020: 6f 6c 29 2e 61 77 61 69 74 20 7b 0a 09 09 09 09  ol).await {.....
1030: 09 4f 6b 28 5f 29 20 3d 3e 20 7b 7d 2c 0a 09 09  .Ok(_) => {},...
1040: 09 09 09 45 72 72 28 65 72 72 29 20 3d 3e 20 7b  ...Err(err) => {
1050: 0a 09 09 09 09 09 09 73 65 6c 66 2e 64 65 62 75  .......self.debu
1060: 67 28 26 65 72 72 2e 74 6f 5f 73 74 72 69 6e 67  g(&err.to_string
1070: 28 29 29 3f 3b 0a 09 09 09 09 09 7d 2c 0a 09 09  ())?;......},...
1080: 09 09 7d 3b 0a 09 09 09 7d 2c 0a 09 09 09 45 72  ..};....},....Er
1090: 72 28 65 72 72 29 20 3d 3e 20 7b 0a 09 09 09 09  r(err) => {.....
10a0: 73 65 6c 66 2e 64 65 62 75 67 28 26 65 72 72 2e  self.debug(&err.
10b0: 74 6f 5f 73 74 72 69 6e 67 28 29 29 3f 3b 0a 09  to_string())?;..
10c0: 09 09 7d 2c 0a 09 09 7d 3b 0a 09 09 4f 6b 28 28  ..},...};...Ok((
10d0: 29 29 0a 09 7d 0a 0a 09 61 73 79 6e 63 20 66 6e  ))..}...async fn
10e0: 20 63 6c 65 61 6e 28 26 73 65 6c 66 2c 20 73 6f   clean(&self, so
10f0: 75 72 63 65 5f 69 64 3a 20 69 33 32 29 20 2d 3e  urce_id: i32) ->
1100: 20 52 65 73 75 6c 74 3c 28 29 3e 20 7b 0a 09 09   Result<()> {...
1110: 6d 61 74 63 68 20 73 71 6c 78 3a 3a 71 75 65 72  match sqlx::quer
1120: 79 28 22 64 65 6c 65 74 65 20 66 72 6f 6d 20 72  y("delete from r
1130: 73 73 74 67 5f 70 6f 73 74 20 77 68 65 72 65 20  sstg_post where 
1140: 73 6f 75 72 63 65 5f 69 64 20 3d 20 24 31 3b 22  source_id = $1;"
1150: 29 0a 09 09 09 2e 62 69 6e 64 28 73 6f 75 72 63  ).....bind(sourc
1160: 65 5f 69 64 29 0a 09 09 09 2e 65 78 65 63 75 74  e_id).....execut
1170: 65 28 26 73 65 6c 66 2e 70 6f 6f 6c 29 2e 61 77  e(&self.pool).aw
1180: 61 69 74 20 7b 0a 09 09 09 4f 6b 28 5f 29 20 3d  ait {....Ok(_) =
1190: 3e 20 7b 7d 2c 0a 09 09 09 45 72 72 28 65 72 72  > {},....Err(err
11a0: 29 20 3d 3e 20 7b 0a 09 09 09 09 73 65 6c 66 2e  ) => {.....self.
11b0: 64 65 62 75 67 28 26 65 72 72 2e 74 6f 5f 73 74  debug(&err.to_st
11c0: 72 69 6e 67 28 29 29 3f 3b 0a 09 09 09 7d 2c 0a  ring())?;....},.
11d0: 09 09 7d 3b 0a 09 09 4f 6b 28 28 29 29 0a 09 7d  ..};...Ok(())..}
11e0: 0a 0a 09 61 73 79 6e 63 20 66 6e 20 65 6e 61 62  ...async fn enab
11f0: 6c 65 28 26 73 65 6c 66 2c 20 73 6f 75 72 63 65  le(&self, source
1200: 5f 69 64 3a 20 26 69 33 32 29 20 2d 3e 20 52 65  _id: &i32) -> Re
1210: 73 75 6c 74 3c 28 29 3e 20 7b 0a 09 09 6d 61 74  sult<()> {...mat
1220: 63 68 20 73 71 6c 78 3a 3a 71 75 65 72 79 28 22  ch sqlx::query("
1230: 75 70 64 61 74 65 20 72 73 73 74 67 5f 73 6f 75  update rsstg_sou
1240: 72 63 65 20 73 65 74 20 65 6e 61 62 6c 65 64 20  rce set enabled 
1250: 3d 20 74 72 75 65 20 77 68 65 72 65 20 73 6f 75  = true where sou
1260: 72 63 65 5f 69 64 20 3d 20 24 31 22 29 0a 09 09  rce_id = $1")...
1270: 09 2e 62 69 6e 64 28 73 6f 75 72 63 65 5f 69 64  ..bind(source_id
1280: 29 0a 09 09 09 2e 65 78 65 63 75 74 65 28 26 73  ).....execute(&s
1290: 65 6c 66 2e 70 6f 6f 6c 29 2e 61 77 61 69 74 20  elf.pool).await 
12a0: 7b 0a 09 09 09 4f 6b 28 5f 29 20 3d 3e 20 7b 7d  {....Ok(_) => {}
12b0: 2c 0a 09 09 09 45 72 72 28 65 72 72 29 20 3d 3e  ,....Err(err) =>
12c0: 20 7b 0a 09 09 09 09 73 65 6c 66 2e 64 65 62 75   {.....self.debu
12d0: 67 28 26 65 72 72 2e 74 6f 5f 73 74 72 69 6e 67  g(&err.to_string
12e0: 28 29 29 3f 3b 0a 09 09 09 7d 2c 0a 09 09 7d 0a  ())?;....},...}.
12f0: 09 09 4f 6b 28 28 29 29 0a 09 7d 0a 0a 09 61 73  ..Ok(())..}...as
1300: 79 6e 63 20 66 6e 20 64 69 73 61 62 6c 65 28 26  ync fn disable(&
1310: 73 65 6c 66 2c 20 73 6f 75 72 63 65 5f 69 64 3a  self, source_id:
1320: 20 26 69 33 32 29 20 2d 3e 20 52 65 73 75 6c 74   &i32) -> Result
1330: 3c 28 29 3e 20 7b 0a 09 09 6d 61 74 63 68 20 73  <()> {...match s
1340: 71 6c 78 3a 3a 71 75 65 72 79 28 22 75 70 64 61  qlx::query("upda
1350: 74 65 20 72 73 73 74 67 5f 73 6f 75 72 63 65 20  te rsstg_source 
1360: 73 65 74 20 65 6e 61 62 6c 65 64 20 3d 20 66 61  set enabled = fa
1370: 6c 73 65 20 77 68 65 72 65 20 73 6f 75 72 63 65  lse where source
1380: 5f 69 64 20 3d 20 24 31 22 29 0a 09 09 09 2e 62  _id = $1").....b
1390: 69 6e 64 28 73 6f 75 72 63 65 5f 69 64 29 0a 09  ind(source_id)..
13a0: 09 09 2e 65 78 65 63 75 74 65 28 26 73 65 6c 66  ...execute(&self
13b0: 2e 70 6f 6f 6c 29 2e 61 77 61 69 74 20 7b 0a 09  .pool).await {..
13c0: 09 09 4f 6b 28 5f 29 20 3d 3e 20 7b 7d 2c 0a 09  ..Ok(_) => {},..
13d0: 09 09 45 72 72 28 65 72 72 29 20 3d 3e 20 7b 0a  ..Err(err) => {.
13e0: 09 09 09 09 73 65 6c 66 2e 64 65 62 75 67 28 26  ....self.debug(&
13f0: 65 72 72 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29  err.to_string())
1400: 3f 3b 0a 09 09 09 7d 2c 0a 09 09 7d 0a 09 09 4f  ?;....},...}...O
1410: 6b 28 28 29 29 0a 09 7d 0a 0a 09 61 73 79 6e 63  k(())..}...async
1420: 20 66 6e 20 61 75 74 6f 66 65 74 63 68 28 26 73   fn autofetch(&s
1430: 65 6c 66 29 20 2d 3e 20 52 65 73 75 6c 74 3c 28  elf) -> Result<(
1440: 29 3e 20 7b 0a 09 09 6c 65 74 20 6d 75 74 20 64  )> {...let mut d
1450: 65 6c 61 79 20 3d 20 63 68 72 6f 6e 6f 3a 3a 44  elay = chrono::D
1460: 75 72 61 74 69 6f 6e 3a 3a 6d 69 6e 75 74 65 73  uration::minutes
1470: 28 35 29 3b 0a 09 09 6c 65 74 20 6d 75 74 20 6e  (5);...let mut n
1480: 65 78 74 5f 66 65 74 63 68 3a 20 44 61 74 65 54  ext_fetch: DateT
1490: 69 6d 65 3c 63 68 72 6f 6e 6f 3a 3a 4c 6f 63 61  ime<chrono::Loca
14a0: 6c 3e 3b 0a 09 09 6c 65 74 20 6d 75 74 20 6e 6f  l>;...let mut no
14b0: 77 3b 0a 09 09 6c 6f 6f 70 20 7b 0a 09 09 09 73  w;...loop {....s
14c0: 65 6c 66 2e 64 65 62 75 67 28 22 63 79 63 6c 65  elf.debug("cycle
14d0: 22 29 3f 3b 0a 09 09 09 6e 6f 77 20 3d 20 63 68  ")?;....now = ch
14e0: 72 6f 6e 6f 3a 3a 4c 6f 63 61 6c 3a 3a 6e 6f 77  rono::Local::now
14f0: 28 29 3b 0a 09 09 09 6c 65 74 20 6d 75 74 20 72  ();....let mut r
1500: 6f 77 73 20 3d 20 73 71 6c 78 3a 3a 71 75 65 72  ows = sqlx::quer
1510: 79 28 22 73 65 6c 65 63 74 20 73 6f 75 72 63 65  y("select source
1520: 5f 69 64 2c 20 6e 65 78 74 5f 66 65 74 63 68 20  _id, next_fetch 
1530: 66 72 6f 6d 20 72 73 73 74 67 5f 6f 72 64 65 72  from rsstg_order
1540: 20 6e 61 74 75 72 61 6c 20 6c 65 66 74 20 6a 6f   natural left jo
1550: 69 6e 20 72 73 73 74 67 5f 73 6f 75 72 63 65 20  in rsstg_source 
1560: 6e 61 74 75 72 61 6c 20 6c 65 66 74 20 6a 6f 69  natural left joi
1570: 6e 20 72 73 73 74 67 5f 63 68 61 6e 6e 65 6c 20  n rsstg_channel 
1580: 77 68 65 72 65 20 6e 65 78 74 5f 66 65 74 63 68  where next_fetch
1590: 20 3c 20 6e 6f 77 28 29 3b 22 29 0a 09 09 09 09   < now();").....
15a0: 2e 66 65 74 63 68 28 26 73 65 6c 66 2e 70 6f 6f  .fetch(&self.poo
15b0: 6c 29 3b 0a 09 09 09 77 68 69 6c 65 20 6c 65 74  l);....while let
15c0: 20 53 6f 6d 65 28 72 6f 77 29 20 3d 20 72 6f 77   Some(row) = row
15d0: 73 2e 74 72 79 5f 6e 65 78 74 28 29 2e 61 77 61  s.try_next().awa
15e0: 69 74 2e 75 6e 77 72 61 70 28 29 20 7b 0a 09 09  it.unwrap() {...
15f0: 09 09 6c 65 74 20 73 6f 75 72 63 65 5f 69 64 3a  ..let source_id:
1600: 20 69 33 32 20 3d 20 72 6f 77 2e 74 72 79 5f 67   i32 = row.try_g
1610: 65 74 28 22 73 6f 75 72 63 65 5f 69 64 22 29 3f  et("source_id")?
1620: 3b 0a 09 09 09 09 6e 65 78 74 5f 66 65 74 63 68  ;.....next_fetch
1630: 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74 28 22   = row.try_get("
1640: 6e 65 78 74 5f 66 65 74 63 68 22 29 3f 3b 0a 09  next_fetch")?;..
1650: 09 09 09 69 66 20 6e 65 78 74 5f 66 65 74 63 68  ...if next_fetch
1660: 20 3c 20 6e 6f 77 20 7b 0a 09 09 09 09 09 6d 61   < now {......ma
1670: 74 63 68 20 73 71 6c 78 3a 3a 71 75 65 72 79 28  tch sqlx::query(
1680: 22 75 70 64 61 74 65 20 72 73 73 74 67 5f 73 6f  "update rsstg_so
1690: 75 72 63 65 20 73 65 74 20 6c 61 73 74 5f 73 63  urce set last_sc
16a0: 72 61 70 65 20 3d 20 6e 6f 77 28 29 20 2b 20 69  rape = now() + i
16b0: 6e 74 65 72 76 61 6c 20 27 31 20 68 6f 75 72 27  nterval '1 hour'
16c0: 20 77 68 65 72 65 20 73 6f 75 72 63 65 5f 69 64   where source_id
16d0: 20 3d 20 24 31 3b 22 29 0a 09 09 09 09 09 09 2e   = $1;")........
16e0: 62 69 6e 64 28 73 6f 75 72 63 65 5f 69 64 29 0a  bind(source_id).
16f0: 09 09 09 09 09 09 2e 65 78 65 63 75 74 65 28 26  .......execute(&
1700: 73 65 6c 66 2e 70 6f 6f 6c 29 2e 61 77 61 69 74  self.pool).await
1710: 20 7b 0a 09 09 09 09 09 09 4f 6b 28 5f 29 20 3d   {.......Ok(_) =
1720: 3e 20 7b 7d 2c 0a 09 09 09 09 09 09 45 72 72 28  > {},.......Err(
1730: 65 72 72 29 20 3d 3e 20 7b 0a 09 09 09 09 09 09  err) => {.......
1740: 09 73 65 6c 66 2e 64 65 62 75 67 28 26 65 72 72  .self.debug(&err
1750: 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 3f 3b 0a  .to_string())?;.
1760: 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 7d 3b  ......},......};
1770: 0a 09 09 09 09 09 6c 65 74 20 63 6c 6f 6e 65 20  ......let clone 
1780: 3d 20 73 65 6c 66 2e 63 6c 6f 6e 65 28 29 3b 0a  = self.clone();.
1790: 09 09 09 09 09 74 6f 6b 69 6f 3a 3a 73 70 61 77  .....tokio::spaw
17a0: 6e 28 61 73 79 6e 63 20 6d 6f 76 65 20 7b 0a 09  n(async move {..
17b0: 09 09 09 09 09 69 66 20 6c 65 74 20 45 72 72 28  .....if let Err(
17c0: 65 72 72 29 20 3d 20 63 6c 6f 6e 65 2e 63 68 65  err) = clone.che
17d0: 63 6b 28 26 73 6f 75 72 63 65 5f 69 64 2e 63 6c  ck(&source_id.cl
17e0: 6f 6e 65 28 29 2c 20 53 6f 6d 65 28 74 72 75 65  one(), Some(true
17f0: 29 29 2e 61 77 61 69 74 20 7b 0a 09 09 09 09 09  )).await {......
1800: 09 09 65 70 72 69 6e 74 6c 6e 21 28 22 63 6f 6e  ..eprintln!("con
1810: 6e 65 63 74 69 6f 6e 20 65 72 72 6f 72 3a 20 7b  nection error: {
1820: 7d 22 2c 20 65 72 72 29 3b 0a 09 09 09 09 09 09  }", err);.......
1830: 7d 0a 09 09 09 09 09 7d 29 3b 0a 09 09 09 09 7d  }......});.....}
1840: 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 69 66 20   else {......if 
1850: 6e 65 78 74 5f 66 65 74 63 68 20 2d 20 6e 6f 77  next_fetch - now
1860: 20 3c 20 64 65 6c 61 79 20 7b 0a 09 09 09 09 09   < delay {......
1870: 09 64 65 6c 61 79 20 3d 20 6e 65 78 74 5f 66 65  .delay = next_fe
1880: 74 63 68 20 2d 20 6e 6f 77 3b 0a 09 09 09 09 09  tch - now;......
1890: 7d 0a 09 09 09 09 7d 0a 09 09 09 7d 3b 0a 09 09  }.....}....};...
18a0: 09 74 6f 6b 69 6f 3a 3a 74 69 6d 65 3a 3a 64 65  .tokio::time::de
18b0: 6c 61 79 5f 66 6f 72 28 64 65 6c 61 79 2e 74 6f  lay_for(delay.to
18c0: 5f 73 74 64 28 29 3f 29 2e 61 77 61 69 74 3b 0a  _std()?).await;.
18d0: 09 09 09 64 65 6c 61 79 20 3d 20 63 68 72 6f 6e  ...delay = chron
18e0: 6f 3a 3a 44 75 72 61 74 69 6f 6e 3a 3a 6d 69 6e  o::Duration::min
18f0: 75 74 65 73 28 35 29 3b 0a 09 09 7d 0a 09 09 2f  utes(5);...}.../
1900: 2f 4f 6b 28 28 29 29 0a 09 7d 0a 0a 7d 0a 0a 23  /Ok(())..}..}..#
1910: 5b 74 6f 6b 69 6f 3a 3a 6d 61 69 6e 28 62 61 73  [tokio::main(bas
1920: 69 63 5f 73 63 68 65 64 75 6c 65 72 29 5d 0a 61  ic_scheduler)].a
1930: 73 79 6e 63 20 66 6e 20 6d 61 69 6e 28 29 20 2d  sync fn main() -
1940: 3e 20 52 65 73 75 6c 74 3c 28 29 3e 20 7b 0a 09  > Result<()> {..
1950: 6c 65 74 20 6d 75 74 20 73 65 74 74 69 6e 67 73  let mut settings
1960: 20 3d 20 63 6f 6e 66 69 67 3a 3a 43 6f 6e 66 69   = config::Confi
1970: 67 3a 3a 64 65 66 61 75 6c 74 28 29 3b 0a 09 73  g::default();..s
1980: 65 74 74 69 6e 67 73 2e 6d 65 72 67 65 28 63 6f  ettings.merge(co
1990: 6e 66 69 67 3a 3a 46 69 6c 65 3a 3a 77 69 74 68  nfig::File::with
19a0: 5f 6e 61 6d 65 28 22 72 73 73 74 67 22 29 29 3f  _name("rsstg"))?
19b0: 3b 0a 0a 09 6c 65 74 20 72 65 5f 75 73 65 72 6e  ;...let re_usern
19c0: 61 6d 65 20 3d 20 52 65 67 65 78 3a 3a 6e 65 77  ame = Regex::new
19d0: 28 72 22 5e 40 5b 61 2d 7a 41 2d 5a 5d 5b 61 2d  (r"^@[a-zA-Z][a-
19e0: 7a 41 2d 5a 30 2d 39 5f 5d 2b 24 22 29 3f 3b 0a  zA-Z0-9_]+$")?;.
19f0: 09 6c 65 74 20 72 65 5f 6c 69 6e 6b 20 3d 20 52  .let re_link = R
1a00: 65 67 65 78 3a 3a 6e 65 77 28 72 22 5e 68 74 74  egex::new(r"^htt
1a10: 70 73 3f 3a 2f 2f 5b 61 2d 7a 41 2d 5a 2e 30 2d  ps?://[a-zA-Z.0-
1a20: 39 2d 5d 2b 2f 5b 2d 5f 61 2d 7a 41 2d 5a 2e 30  9-]+/[-_a-zA-Z.0
1a30: 2d 39 2f 3f 3d 5d 2b 24 22 29 3f 3b 0a 09 6c 65  -9/?=]+$")?;..le
1a40: 74 20 72 65 5f 69 76 5f 68 61 73 68 20 3d 20 52  t re_iv_hash = R
1a50: 65 67 65 78 3a 3a 6e 65 77 28 72 22 5e 5b 61 2d  egex::new(r"^[a-
1a60: 66 30 2d 39 5d 7b 31 34 7d 24 22 29 3f 3b 0a 0a  f0-9]{14}$")?;..
1a70: 09 6c 65 74 20 63 6f 72 65 20 3d 20 43 6f 72 65  .let core = Core
1a80: 3a 3a 6e 65 77 28 73 65 74 74 69 6e 67 73 29 2e  ::new(settings).
1a90: 61 77 61 69 74 3f 3b 0a 0a 09 6c 65 74 20 6d 75  await?;...let mu
1aa0: 74 20 73 74 72 65 61 6d 20 3d 20 63 6f 72 65 2e  t stream = core.
1ab0: 73 74 72 65 61 6d 28 29 3b 0a 0a 09 77 68 69 6c  stream();...whil
1ac0: 65 20 6c 65 74 20 53 6f 6d 65 28 75 70 64 61 74  e let Some(updat
1ad0: 65 29 20 3d 20 73 74 72 65 61 6d 2e 6e 65 78 74  e) = stream.next
1ae0: 28 29 2e 61 77 61 69 74 20 7b 0a 09 09 6c 65 74  ().await {...let
1af0: 20 75 70 64 61 74 65 20 3d 20 75 70 64 61 74 65   update = update
1b00: 3f 3b 0a 09 09 6d 61 74 63 68 20 75 70 64 61 74  ?;...match updat
1b10: 65 2e 6b 69 6e 64 20 7b 0a 09 09 09 55 70 64 61  e.kind {....Upda
1b20: 74 65 4b 69 6e 64 3a 3a 4d 65 73 73 61 67 65 28  teKind::Message(
1b30: 6d 65 73 73 61 67 65 29 20 3d 3e 20 7b 0a 09 09  message) => {...
1b40: 09 09 6c 65 74 20 6d 75 74 20 72 65 70 6c 79 3a  ..let mut reply:
1b50: 20 56 65 63 3c 53 74 72 69 6e 67 3e 20 3d 20 76   Vec<String> = v
1b60: 65 63 21 5b 5d 3b 0a 09 09 09 09 6d 61 74 63 68  ec![];.....match
1b70: 20 6d 65 73 73 61 67 65 2e 6b 69 6e 64 20 7b 0a   message.kind {.
1b80: 09 09 09 09 09 4d 65 73 73 61 67 65 4b 69 6e 64  .....MessageKind
1b90: 3a 3a 54 65 78 74 20 7b 20 72 65 66 20 64 61 74  ::Text { ref dat
1ba0: 61 2c 20 2e 2e 20 7d 20 3d 3e 20 7b 0a 09 09 09  a, .. } => {....
1bb0: 09 09 09 6c 65 74 20 6d 75 74 20 77 6f 72 64 73  ...let mut words
1bc0: 20 3d 20 64 61 74 61 2e 73 70 6c 69 74 5f 77 68   = data.split_wh
1bd0: 69 74 65 73 70 61 63 65 28 29 3b 0a 09 09 09 09  itespace();.....
1be0: 09 09 6c 65 74 20 63 6d 64 20 3d 20 77 6f 72 64  ..let cmd = word
1bf0: 73 2e 6e 65 78 74 28 29 2e 75 6e 77 72 61 70 28  s.next().unwrap(
1c00: 29 3b 0a 09 09 09 09 09 09 6d 61 74 63 68 20 63  );.......match c
1c10: 6d 64 20 7b 0a 0a 2f 2f 20 73 74 61 72 74 0a 0a  md {..// start..
1c20: 09 09 09 09 09 09 09 22 2f 73 74 61 72 74 22 20  ......."/start" 
1c30: 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09 72 65 70  => {.........rep
1c40: 6c 79 2e 70 75 73 68 28 22 4e 6f 74 20 69 6e 20  ly.push("Not in 
1c50: 73 65 72 76 69 63 65 20 79 65 74 5c 5c 2e 20 54  service yet\\. T
1c60: 72 79 20 6c 61 74 65 72 5c 5c 2e 22 2e 74 6f 5f  ry later\\.".to_
1c70: 73 74 72 69 6e 67 28 29 29 3b 0a 09 09 09 09 09  string());......
1c80: 09 09 7d 2c 0a 0a 2f 2f 20 6c 69 73 74 0a 0a 09  ..},..// list...
1c90: 09 09 09 09 09 09 22 2f 6c 69 73 74 22 20 3d 3e  ......"/list" =>
1ca0: 20 7b 0a 09 09 09 09 09 09 09 09 72 65 70 6c 79   {.........reply
1cb0: 2e 70 75 73 68 28 22 43 68 61 6e 6e 65 6c 73 3a  .push("Channels:
1cc0: 22 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 3b 0a  ".to_string());.
1cd0: 09 09 09 09 09 09 09 09 6c 65 74 20 6d 75 74 20  ........let mut 
1ce0: 72 6f 77 73 20 3d 20 73 71 6c 78 3a 3a 71 75 65  rows = sqlx::que
1cf0: 72 79 28 22 73 65 6c 65 63 74 20 73 6f 75 72 63  ry("select sourc
1d00: 65 5f 69 64 2c 20 75 73 65 72 6e 61 6d 65 2c 20  e_id, username, 
1d10: 65 6e 61 62 6c 65 64 2c 20 75 72 6c 2c 20 69 76  enabled, url, iv
1d20: 5f 68 61 73 68 20 66 72 6f 6d 20 72 73 73 74 67  _hash from rsstg
1d30: 5f 73 6f 75 72 63 65 20 6c 65 66 74 20 6a 6f 69  _source left joi
1d40: 6e 20 72 73 73 74 67 5f 63 68 61 6e 6e 65 6c 20  n rsstg_channel 
1d50: 75 73 69 6e 67 20 28 63 68 61 6e 6e 65 6c 5f 69  using (channel_i
1d60: 64 29 20 77 68 65 72 65 20 6f 77 6e 65 72 20 3d  d) where owner =
1d70: 20 24 31 20 6f 72 64 65 72 20 62 79 20 73 6f 75   $1 order by sou
1d80: 72 63 65 5f 69 64 22 29 0a 09 09 09 09 09 09 09  rce_id")........
1d90: 09 09 2e 62 69 6e 64 28 69 36 34 3a 3a 66 72 6f  ...bind(i64::fro
1da0: 6d 28 6d 65 73 73 61 67 65 2e 66 72 6f 6d 2e 69  m(message.from.i
1db0: 64 29 29 0a 09 09 09 09 09 09 09 09 09 2e 66 65  d))...........fe
1dc0: 74 63 68 28 26 63 6f 72 65 2e 70 6f 6f 6c 29 3b  tch(&core.pool);
1dd0: 0a 09 09 09 09 09 09 09 09 77 68 69 6c 65 20 6c  .........while l
1de0: 65 74 20 53 6f 6d 65 28 72 6f 77 29 20 3d 20 72  et Some(row) = r
1df0: 6f 77 73 2e 74 72 79 5f 6e 65 78 74 28 29 2e 61  ows.try_next().a
1e00: 77 61 69 74 3f 20 7b 0a 09 09 09 09 09 09 09 09  wait? {.........
1e10: 09 6c 65 74 20 73 6f 75 72 63 65 5f 69 64 3a 20  .let source_id: 
1e20: 69 33 32 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65  i32 = row.try_ge
1e30: 74 28 22 73 6f 75 72 63 65 5f 69 64 22 29 3f 3b  t("source_id")?;
1e40: 0a 09 09 09 09 09 09 09 09 09 6c 65 74 20 75 73  ..........let us
1e50: 65 72 6e 61 6d 65 3a 20 26 73 74 72 20 3d 20 72  ername: &str = r
1e60: 6f 77 2e 74 72 79 5f 67 65 74 28 22 75 73 65 72  ow.try_get("user
1e70: 6e 61 6d 65 22 29 3f 3b 0a 09 09 09 09 09 09 09  name")?;........
1e80: 09 09 6c 65 74 20 65 6e 61 62 6c 65 64 3a 20 62  ..let enabled: b
1e90: 6f 6f 6c 20 3d 20 72 6f 77 2e 74 72 79 5f 67 65  ool = row.try_ge
1ea0: 74 28 22 65 6e 61 62 6c 65 64 22 29 3f 3b 0a 09  t("enabled")?;..
1eb0: 09 09 09 09 09 09 09 09 6c 65 74 20 75 72 6c 3a  ........let url:
1ec0: 20 26 73 74 72 20 3d 20 72 6f 77 2e 74 72 79 5f   &str = row.try_
1ed0: 67 65 74 28 22 75 72 6c 22 29 3f 3b 0a 09 09 09  get("url")?;....
1ee0: 09 09 09 09 09 09 6c 65 74 20 69 76 5f 68 61 73  ......let iv_has
1ef0: 68 3a 20 4f 70 74 69 6f 6e 3c 26 73 74 72 3e 20  h: Option<&str> 
1f00: 3d 20 72 6f 77 2e 74 72 79 5f 67 65 74 28 22 69  = row.try_get("i
1f10: 76 5f 68 61 73 68 22 29 3f 3b 0a 09 09 09 09 09  v_hash")?;......
1f20: 09 09 09 09 72 65 70 6c 79 2e 70 75 73 68 28 66  ....reply.push(f
1f30: 6f 72 6d 61 74 21 28 22 5c 6e 5c 5c 23 ef b8 8f  ormat!("\n\\#️
1f40: e2 83 a3 20 7b 7d 20 5c 5c 2a ef b8 8f e2 83 a3  ⃣ {} \\*️⃣
1f50: 20 60 7b 7d 60 20 7b 7d 5c 6e f0 9f 94 97 20 60   `{}` {}\n🔗 `
1f60: 7b 7d 60 22 2c 20 73 6f 75 72 63 65 5f 69 64 2c  {}`", source_id,
1f70: 20 75 73 65 72 6e 61 6d 65 2c 20 20 0a 09 09 09   username,  ....
1f80: 09 09 09 09 09 09 09 6d 61 74 63 68 20 65 6e 61  .......match ena
1f90: 62 6c 65 64 20 7b 0a 09 09 09 09 09 09 09 09 09  bled {..........
1fa0: 09 09 74 72 75 65 20 20 3d 3e 20 22 f0 9f 94 84  ..true  => "🔄
1fb0: 20 65 6e 61 62 6c 65 64 22 2c 0a 09 09 09 09 09   enabled",......
1fc0: 09 09 09 09 09 09 66 61 6c 73 65 20 3d 3e 20 22  ......false => "
1fd0: e2 9b 94 20 64 69 73 61 62 6c 65 64 22 2c 0a 09  ⛔ disabled",..
1fe0: 09 09 09 09 09 09 09 09 09 7d 2c 20 75 72 6c 29  .........}, url)
1ff0: 29 3b 0a 09 09 09 09 09 09 09 09 09 69 66 20 6c  );..........if l
2000: 65 74 20 53 6f 6d 65 28 68 61 73 68 29 20 3d 20  et Some(hash) = 
2010: 69 76 5f 68 61 73 68 20 7b 0a 09 09 09 09 09 09  iv_hash {.......
2020: 09 09 09 09 72 65 70 6c 79 2e 70 75 73 68 28 66  ....reply.push(f
2030: 6f 72 6d 61 74 21 28 22 49 56 20 60 7b 7d 60 22  ormat!("IV `{}`"
2040: 2c 20 68 61 73 68 29 29 3b 0a 09 09 09 09 09 09  , hash));.......
2050: 09 09 09 7d 0a 09 09 09 09 09 09 09 09 7d 0a 09  ...}.........}..
2060: 09 09 09 09 09 09 7d 2c 0a 0a 2f 2f 20 61 64 64  ......},..// add
2070: 0a 0a 09 09 09 09 09 09 09 22 2f 61 64 64 22 20  ........."/add" 
2080: 7c 20 22 2f 75 70 64 61 74 65 22 20 3d 3e 20 7b  | "/update" => {
2090: 0a 09 09 09 09 09 09 09 09 6c 65 74 20 6d 75 74  .........let mut
20a0: 20 73 6f 75 72 63 65 5f 69 64 3a 20 69 33 32 20   source_id: i32 
20b0: 3d 20 30 3b 0a 09 09 09 09 09 09 09 09 69 66 20  = 0;.........if 
20c0: 63 6d 64 20 3d 3d 20 22 2f 75 70 64 61 74 65 22  cmd == "/update"
20d0: 20 7b 0a 09 09 09 09 09 09 09 09 09 73 6f 75 72   {..........sour
20e0: 63 65 5f 69 64 20 3d 20 77 6f 72 64 73 2e 6e 65  ce_id = words.ne
20f0: 78 74 28 29 2e 75 6e 77 72 61 70 28 29 2e 70 61  xt().unwrap().pa
2100: 72 73 65 3a 3a 3c 69 33 32 3e 28 29 3f 3b 0a 09  rse::<i32>()?;..
2110: 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09 09  .......}........
2120: 09 6c 65 74 20 28 63 68 61 6e 6e 65 6c 2c 20 75  .let (channel, u
2130: 72 6c 2c 20 69 76 5f 68 61 73 68 29 20 3d 20 28  rl, iv_hash) = (
2140: 77 6f 72 64 73 2e 6e 65 78 74 28 29 2e 75 6e 77  words.next().unw
2150: 72 61 70 28 29 2c 20 77 6f 72 64 73 2e 6e 65 78  rap(), words.nex
2160: 74 28 29 2e 75 6e 77 72 61 70 28 29 2c 20 77 6f  t().unwrap(), wo
2170: 72 64 73 2e 6e 65 78 74 28 29 29 3b 0a 09 09 09  rds.next());....
2180: 09 09 09 09 09 6c 65 74 20 6f 6b 5f 6c 69 6e 6b  .....let ok_link
2190: 20 3d 20 72 65 5f 6c 69 6e 6b 2e 69 73 5f 6d 61   = re_link.is_ma
21a0: 74 63 68 28 26 75 72 6c 29 3b 0a 09 09 09 09 09  tch(&url);......
21b0: 09 09 09 6c 65 74 20 6f 6b 5f 68 61 73 68 20 3d  ...let ok_hash =
21c0: 20 6d 61 74 63 68 20 69 76 5f 68 61 73 68 20 7b   match iv_hash {
21d0: 0a 09 09 09 09 09 09 09 09 09 53 6f 6d 65 28 68  ..........Some(h
21e0: 61 73 68 29 20 3d 3e 20 72 65 5f 69 76 5f 68 61  ash) => re_iv_ha
21f0: 73 68 2e 69 73 5f 6d 61 74 63 68 28 26 68 61 73  sh.is_match(&has
2200: 68 29 2c 0a 09 09 09 09 09 09 09 09 09 4e 6f 6e  h),..........Non
2210: 65 20 3d 3e 20 74 72 75 65 2c 0a 09 09 09 09 09  e => true,......
2220: 09 09 09 7d 3b 0a 09 09 09 09 09 09 09 09 69 66  ...};.........if
2230: 20 21 20 6f 6b 5f 6c 69 6e 6b 20 7b 0a 09 09 09   ! ok_link {....
2240: 09 09 09 09 09 09 72 65 70 6c 79 2e 70 75 73 68  ......reply.push
2250: 28 22 4c 69 6e 6b 20 73 68 6f 75 6c 64 20 62 65  ("Link should be
2260: 20 6c 69 6e 6b 20 74 6f 20 61 74 6f 6d 2f 72 73   link to atom/rs
2270: 73 20 66 65 65 64 2c 20 73 6f 6d 65 74 68 69 6e  s feed, somethin
2280: 67 20 6c 69 6b 65 20 5c 22 68 74 74 70 73 3a 2f  g like \"https:/
2290: 2f 64 6f 6d 61 69 6e 2f 70 61 74 68 5c 22 5c 5c  /domain/path\"\\
22a0: 2e 22 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 3b  .".to_string());
22b0: 0a 09 09 09 09 09 09 09 09 09 63 6f 72 65 2e 64  ..........core.d
22c0: 65 62 75 67 28 26 66 6f 72 6d 61 74 21 28 22 55  ebug(&format!("U
22d0: 72 6c 3a 20 7b 3a 3f 7d 22 2c 20 26 75 72 6c 29  rl: {:?}", &url)
22e0: 29 3f 3b 0a 09 09 09 09 09 09 09 09 7d 0a 09 09  )?;.........}...
22f0: 09 09 09 09 09 09 69 66 20 21 20 6f 6b 5f 68 61  ......if ! ok_ha
2300: 73 68 20 7b 0a 09 09 09 09 09 09 09 09 09 72 65  sh {..........re
2310: 70 6c 79 2e 70 75 73 68 28 22 49 56 20 68 61 73  ply.push("IV has
2320: 68 20 73 68 6f 75 6c 64 20 62 65 20 31 34 20 68  h should be 14 h
2330: 65 78 20 64 69 67 69 74 73 2e 22 2e 74 6f 5f 73  ex digits.".to_s
2340: 74 72 69 6e 67 28 29 29 3b 0a 09 09 09 09 09 09  tring());.......
2350: 09 09 09 63 6f 72 65 2e 64 65 62 75 67 28 26 66  ...core.debug(&f
2360: 6f 72 6d 61 74 21 28 22 49 56 3a 20 7b 3a 3f 7d  ormat!("IV: {:?}
2370: 22 2c 20 26 69 76 5f 68 61 73 68 29 29 3f 3b 0a  ", &iv_hash))?;.
2380: 09 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09  ........}.......
2390: 09 09 69 66 20 6f 6b 5f 6c 69 6e 6b 20 26 26 20  ..if ok_link && 
23a0: 6f 6b 5f 68 61 73 68 20 7b 0a 09 09 09 09 09 09  ok_hash {.......
23b0: 09 09 09 6c 65 74 20 63 68 61 6e 3a 20 4f 70 74  ...let chan: Opt
23c0: 69 6f 6e 3c 69 36 34 3e 20 3d 20 6d 61 74 63 68  ion<i64> = match
23d0: 20 73 71 6c 78 3a 3a 71 75 65 72 79 28 22 73 65   sqlx::query("se
23e0: 6c 65 63 74 20 63 68 61 6e 6e 65 6c 5f 69 64 20  lect channel_id 
23f0: 66 72 6f 6d 20 72 73 73 74 67 5f 63 68 61 6e 6e  from rsstg_chann
2400: 65 6c 20 77 68 65 72 65 20 75 73 65 72 6e 61 6d  el where usernam
2410: 65 20 3d 20 24 31 22 29 0a 09 09 09 09 09 09 09  e = $1")........
2420: 09 09 09 2e 62 69 6e 64 28 63 68 61 6e 6e 65 6c  ....bind(channel
2430: 29 0a 09 09 09 09 09 09 09 09 09 09 2e 66 65 74  )............fet
2440: 63 68 5f 6f 6e 65 28 26 63 6f 72 65 2e 70 6f 6f  ch_one(&core.poo
2450: 6c 29 2e 61 77 61 69 74 20 7b 0a 09 09 09 09 09  l).await {......
2460: 09 09 09 09 09 09 4f 6b 28 63 68 61 6e 29 20 3d  ......Ok(chan) =
2470: 3e 20 53 6f 6d 65 28 63 68 61 6e 2e 74 72 79 5f  > Some(chan.try_
2480: 67 65 74 28 22 63 68 61 6e 6e 65 6c 5f 69 64 22  get("channel_id"
2490: 29 3f 29 2c 0a 09 09 09 09 09 09 09 09 09 09 09  )?),............
24a0: 45 72 72 28 73 71 6c 78 3a 3a 45 72 72 6f 72 3a  Err(sqlx::Error:
24b0: 3a 52 6f 77 4e 6f 74 46 6f 75 6e 64 29 20 3d 3e  :RowNotFound) =>
24c0: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09 72   {.............r
24d0: 65 70 6c 79 2e 70 75 73 68 28 22 53 6f 72 72 79  eply.push("Sorry
24e0: 2c 20 49 20 64 6f 6e 27 74 20 6b 6e 6f 77 20 61  , I don't know a
24f0: 62 6f 75 74 20 74 68 61 74 20 63 68 61 6e 6e 65  bout that channe
2500: 6c 2e 20 50 6c 65 61 73 65 2c 20 61 64 64 20 61  l. Please, add a
2510: 20 63 68 61 6e 6e 65 6c 20 77 69 74 68 20 2f 61   channel with /a
2520: 64 64 63 68 61 6e 2e 22 2e 74 6f 5f 73 74 72 69  ddchan.".to_stri
2530: 6e 67 28 29 29 3b 0a 09 09 09 09 09 09 09 09 09  ng());..........
2540: 09 09 09 4e 6f 6e 65 0a 09 09 09 09 09 09 09 09  ...None.........
2550: 09 09 09 7d 2c 0a 09 09 09 09 09 09 09 09 09 09  ...},...........
2560: 09 45 72 72 28 65 72 72 29 20 3d 3e 20 7b 0a 09  .Err(err) => {..
2570: 09 09 09 09 09 09 09 09 09 09 09 72 65 70 6c 79  ...........reply
2580: 2e 70 75 73 68 28 22 53 6f 72 72 79 2c 20 75 6e  .push("Sorry, un
2590: 6b 6e 6f 77 6e 20 65 72 72 6f 72 5c 5c 2e 22 2e  known error\\.".
25a0: 74 6f 5f 73 74 72 69 6e 67 28 29 29 3b 0a 09 09  to_string());...
25b0: 09 09 09 09 09 09 09 09 09 09 63 6f 72 65 2e 64  ..........core.d
25c0: 65 62 75 67 28 26 66 6f 72 6d 61 74 21 28 22 53  ebug(&format!("S
25d0: 6f 72 72 79 2c 20 75 6e 6b 6e 6f 77 6e 20 65 72  orry, unknown er
25e0: 72 6f 72 3a 20 7b 3a 23 3f 7d 5c 6e 22 2c 20 65  ror: {:#?}\n", e
25f0: 72 72 29 29 3f 3b 0a 09 09 09 09 09 09 09 09 09  rr))?;..........
2600: 09 09 09 4e 6f 6e 65 0a 09 09 09 09 09 09 09 09  ...None.........
2610: 09 09 09 7d 2c 0a 09 09 09 09 09 09 09 09 09 7d  ...},..........}
2620: 3b 0a 09 09 09 09 09 09 09 09 09 69 66 20 6c 65  ;..........if le
2630: 74 20 53 6f 6d 65 28 63 68 61 6e 29 20 3d 20 63  t Some(chan) = c
2640: 68 61 6e 20 7b 0a 09 09 09 09 09 09 09 09 09 09  han {...........
2650: 6d 61 74 63 68 20 69 66 20 63 6d 64 20 3d 3d 20  match if cmd == 
2660: 22 2f 75 70 64 61 74 65 22 20 7b 0a 09 09 09 09  "/update" {.....
2670: 09 09 09 09 09 09 09 09 73 71 6c 78 3a 3a 71 75  ........sqlx::qu
2680: 65 72 79 28 22 75 70 64 61 74 65 20 72 73 73 74  ery("update rsst
2690: 67 5f 73 6f 75 72 63 65 20 73 65 74 20 63 68 61  g_source set cha
26a0: 6e 6e 65 6c 5f 69 64 20 3d 20 24 32 2c 20 75 72  nnel_id = $2, ur
26b0: 6c 20 3d 20 24 33 2c 20 69 76 5f 68 61 73 68 20  l = $3, iv_hash 
26c0: 3d 20 24 34 2c 20 6f 77 6e 65 72 20 3d 20 24 34  = $4, owner = $4
26d0: 20 77 68 65 72 65 20 73 6f 75 72 63 65 5f 69 64   where source_id
26e0: 20 3d 20 24 31 22 29 2e 62 69 6e 64 28 73 6f 75   = $1").bind(sou
26f0: 72 63 65 5f 69 64 29 0a 09 09 09 09 09 09 09 09  rce_id).........
2700: 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09  ...} else {.....
2710: 09 09 09 09 09 09 09 09 73 71 6c 78 3a 3a 71 75  ........sqlx::qu
2720: 65 72 79 28 22 69 6e 73 65 72 74 20 69 6e 74 6f  ery("insert into
2730: 20 72 73 73 74 67 5f 73 6f 75 72 63 65 20 28 63   rsstg_source (c
2740: 68 61 6e 6e 65 6c 5f 69 64 2c 20 75 72 6c 2c 20  hannel_id, url, 
2750: 69 76 5f 68 61 73 68 2c 20 6f 77 6e 65 72 29 20  iv_hash, owner) 
2760: 76 61 6c 75 65 73 20 28 24 31 2c 20 24 32 2c 20  values ($1, $2, 
2770: 24 33 2c 20 24 34 29 22 29 0a 09 09 09 09 09 09  $3, $4)").......
2780: 09 09 09 09 09 7d 0a 09 09 09 09 09 09 09 09 09  .....}..........
2790: 09 09 2e 62 69 6e 64 28 63 68 61 6e 29 0a 09 09  ...bind(chan)...
27a0: 09 09 09 09 09 09 09 09 09 2e 62 69 6e 64 28 75  ..........bind(u
27b0: 72 6c 29 0a 09 09 09 09 09 09 09 09 09 09 09 2e  rl).............
27c0: 62 69 6e 64 28 69 76 5f 68 61 73 68 29 0a 09 09  bind(iv_hash)...
27d0: 09 09 09 09 09 09 09 09 09 2e 62 69 6e 64 28 69  ..........bind(i
27e0: 36 34 3a 3a 66 72 6f 6d 28 6d 65 73 73 61 67 65  64::from(message
27f0: 2e 66 72 6f 6d 2e 69 64 29 29 0a 09 09 09 09 09  .from.id))......
2800: 09 09 09 09 09 09 2e 65 78 65 63 75 74 65 28 26  .......execute(&
2810: 63 6f 72 65 2e 70 6f 6f 6c 29 2e 61 77 61 69 74  core.pool).await
2820: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 4f 6b   {............Ok
2830: 28 5f 29 20 3d 3e 20 72 65 70 6c 79 2e 70 75 73  (_) => reply.pus
2840: 68 28 22 43 68 61 6e 6e 65 6c 20 61 64 64 65 64  h("Channel added
2850: 5c 5c 2e 22 2e 74 6f 5f 73 74 72 69 6e 67 28 29  \\.".to_string()
2860: 29 2c 0a 09 09 09 09 09 09 09 09 09 09 09 45 72  ),............Er
2870: 72 28 73 71 6c 78 3a 3a 45 72 72 6f 72 3a 3a 44  r(sqlx::Error::D
2880: 61 74 61 62 61 73 65 28 65 72 72 29 29 20 3d 3e  atabase(err)) =>
2890: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09 6d   {.............m
28a0: 61 74 63 68 20 65 72 72 2e 64 6f 77 6e 63 61 73  atch err.downcas
28b0: 74 3a 3a 3c 73 71 6c 78 3a 3a 70 6f 73 74 67 72  t::<sqlx::postgr
28c0: 65 73 3a 3a 50 67 44 61 74 61 62 61 73 65 45 72  es::PgDatabaseEr
28d0: 72 6f 72 3e 28 29 2e 72 6f 75 74 69 6e 65 28 29  ror>().routine()
28e0: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09 09   {..............
28f0: 53 6f 6d 65 28 22 5f 62 74 5f 63 68 65 63 6b 5f  Some("_bt_check_
2900: 75 6e 69 71 75 65 22 2c 20 29 20 3d 3e 20 7b 0a  unique", ) => {.
2910: 09 09 09 09 09 09 09 09 09 09 09 09 09 09 72 65  ..............re
2920: 70 6c 79 2e 70 75 73 68 28 22 44 75 70 6c 69 63  ply.push("Duplic
2930: 61 74 65 20 6b 65 79 5c 5c 2e 22 2e 74 6f 5f 73  ate key\\.".to_s
2940: 74 72 69 6e 67 28 29 29 3b 0a 09 09 09 09 09 09  tring());.......
2950: 09 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 09  .......},.......
2960: 09 09 09 09 09 09 09 53 6f 6d 65 28 5f 29 20 3d  .......Some(_) =
2970: 3e 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09  > {.............
2980: 09 09 72 65 70 6c 79 2e 70 75 73 68 28 22 44 61  ..reply.push("Da
2990: 74 61 62 61 73 65 20 65 72 72 6f 72 5c 5c 2e 22  tabase error\\."
29a0: 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 3b 0a 09  .to_string());..
29b0: 09 09 09 09 09 09 09 09 09 09 09 09 7d 2c 0a 09  ............},..
29c0: 09 09 09 09 09 09 09 09 09 09 09 09 4e 6f 6e 65  ............None
29d0: 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09 09 09   => {...........
29e0: 09 09 09 09 72 65 70 6c 79 2e 70 75 73 68 28 22  ....reply.push("
29f0: 4e 6f 20 64 61 74 61 62 61 73 65 20 65 72 72 6f  No database erro
2a00: 72 20 65 78 74 72 61 63 74 65 64 5c 5c 2e 22 2e  r extracted\\.".
2a10: 74 6f 5f 73 74 72 69 6e 67 28 29 29 3b 0a 09 09  to_string());...
2a20: 09 09 09 09 09 09 09 09 09 09 09 7d 2c 0a 09 09  ...........},...
2a30: 09 09 09 09 09 09 09 09 09 09 7d 3b 0a 09 09 09  ..........};....
2a40: 09 09 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09  ........},......
2a50: 09 09 09 09 09 09 45 72 72 28 65 72 72 29 20 3d  ......Err(err) =
2a60: 3e 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09  > {.............
2a70: 72 65 70 6c 79 2e 70 75 73 68 28 22 53 6f 72 72  reply.push("Sorr
2a80: 79 2c 20 75 6e 6b 6e 6f 77 6e 20 65 72 72 6f 72  y, unknown error
2a90: 5c 5c 2e 22 2e 74 6f 5f 73 74 72 69 6e 67 28 29  \\.".to_string()
2aa0: 29 3b 0a 09 09 09 09 09 09 09 09 09 09 09 09 63  );.............c
2ab0: 6f 72 65 2e 64 65 62 75 67 28 26 66 6f 72 6d 61  ore.debug(&forma
2ac0: 74 21 28 22 53 6f 72 72 79 2c 20 75 6e 6b 6e 6f  t!("Sorry, unkno
2ad0: 77 6e 20 65 72 72 6f 72 3a 20 7b 3a 23 3f 7d 5c  wn error: {:#?}\
2ae0: 6e 22 2c 20 65 72 72 29 29 3f 3b 0a 09 09 09 09  n", err))?;.....
2af0: 09 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 09  .......},.......
2b00: 09 09 09 09 7d 3b 0a 09 09 09 09 09 09 09 09 09  ....};..........
2b10: 7d 3b 0a 09 09 09 09 09 09 09 09 7d 3b 0a 09 09  };.........};...
2b20: 09 09 09 09 09 7d 2c 0a 0a 2f 2f 20 61 64 64 63  .....},..// addc
2b30: 68 61 6e 0a 0a 09 09 09 09 09 09 09 22 2f 61 64  han........."/ad
2b40: 64 63 68 61 6e 22 20 3d 3e 20 7b 0a 09 09 09 09  dchan" => {.....
2b50: 09 09 09 09 6c 65 74 20 63 68 61 6e 6e 65 6c 20  ....let channel 
2b60: 3d 20 77 6f 72 64 73 2e 6e 65 78 74 28 29 2e 75  = words.next().u
2b70: 6e 77 72 61 70 28 29 3b 0a 09 09 09 09 09 09 09  nwrap();........
2b80: 09 69 66 20 21 20 72 65 5f 75 73 65 72 6e 61 6d  .if ! re_usernam
2b90: 65 2e 69 73 5f 6d 61 74 63 68 28 26 63 68 61 6e  e.is_match(&chan
2ba0: 6e 65 6c 29 20 7b 0a 09 09 09 09 09 09 09 09 09  nel) {..........
2bb0: 72 65 70 6c 79 2e 70 75 73 68 28 22 55 73 65 72  reply.push("User
2bc0: 6e 61 6d 65 73 20 73 68 6f 75 6c 64 20 62 65 20  names should be 
2bd0: 73 6f 6d 65 74 68 69 6e 67 20 6c 69 6b 65 20 5c  something like \
2be0: 22 40 5c 5c 5b 61 5c 5c 2d 7a 41 5c 5c 2d 5a 5d  "@\\[a\\-zA\\-Z]
2bf0: 5c 5c 5b 61 5c 5c 2d 7a 41 5c 5c 2d 5a 30 5c 5c  \\[a\\-zA\\-Z0\\
2c00: 2d 39 5c 5c 5f 5d 2b 5c 22 2c 20 61 72 65 6e 27  -9\\_]+\", aren'
2c10: 74 20 74 68 65 79 3f 22 2e 74 6f 5f 73 74 72 69  t they?".to_stri
2c20: 6e 67 28 29 29 3b 0a 09 09 09 09 09 09 09 09 7d  ng());.........}
2c30: 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 09 09 09   else {.........
2c40: 09 6c 65 74 20 63 68 61 6e 3a 20 4f 70 74 69 6f  .let chan: Optio
2c50: 6e 3c 69 36 34 3e 20 3d 20 6d 61 74 63 68 20 73  n<i64> = match s
2c60: 71 6c 78 3a 3a 71 75 65 72 79 28 22 73 65 6c 65  qlx::query("sele
2c70: 63 74 20 63 68 61 6e 6e 65 6c 5f 69 64 20 66 72  ct channel_id fr
2c80: 6f 6d 20 72 73 73 74 67 5f 63 68 61 6e 6e 65 6c  om rsstg_channel
2c90: 20 77 68 65 72 65 20 75 73 65 72 6e 61 6d 65 20   where username 
2ca0: 3d 20 24 31 22 29 0a 09 09 09 09 09 09 09 09 09  = $1")..........
2cb0: 09 2e 62 69 6e 64 28 63 68 61 6e 6e 65 6c 29 0a  ..bind(channel).
2cc0: 09 09 09 09 09 09 09 09 09 09 2e 66 65 74 63 68  ...........fetch
2cd0: 5f 6f 6e 65 28 26 63 6f 72 65 2e 70 6f 6f 6c 29  _one(&core.pool)
2ce0: 2e 61 77 61 69 74 20 7b 0a 09 09 09 09 09 09 09  .await {........
2cf0: 09 09 09 09 4f 6b 28 63 68 61 6e 29 20 3d 3e 20  ....Ok(chan) => 
2d00: 53 6f 6d 65 28 63 68 61 6e 2e 74 72 79 5f 67 65  Some(chan.try_ge
2d10: 74 28 22 63 68 61 6e 6e 65 6c 5f 69 64 22 29 3f  t("channel_id")?
2d20: 29 2c 0a 09 09 09 09 09 09 09 09 09 09 09 45 72  ),............Er
2d30: 72 28 73 71 6c 78 3a 3a 45 72 72 6f 72 3a 3a 52  r(sqlx::Error::R
2d40: 6f 77 4e 6f 74 46 6f 75 6e 64 29 20 3d 3e 20 4e  owNotFound) => N
2d50: 6f 6e 65 2c 0a 09 09 09 09 09 09 09 09 09 09 09  one,............
2d60: 45 72 72 28 65 72 72 29 20 3d 3e 20 7b 0a 09 09  Err(err) => {...
2d70: 09 09 09 09 09 09 09 09 09 09 72 65 70 6c 79 2e  ..........reply.
2d80: 70 75 73 68 28 22 53 6f 72 72 79 2c 20 75 6e 6b  push("Sorry, unk
2d90: 6e 6f 77 6e 20 65 72 72 6f 72 5c 5c 2e 22 2e 74  nown error\\.".t
2da0: 6f 5f 73 74 72 69 6e 67 28 29 29 3b 0a 09 09 09  o_string());....
2db0: 09 09 09 09 09 09 09 09 09 63 6f 72 65 2e 64 65  .........core.de
2dc0: 62 75 67 28 26 66 6f 72 6d 61 74 21 28 22 53 6f  bug(&format!("So
2dd0: 72 72 79 2c 20 75 6e 6b 6e 6f 77 6e 20 65 72 72  rry, unknown err
2de0: 6f 72 3a 20 7b 3a 23 3f 7d 5c 6e 22 2c 20 65 72  or: {:#?}\n", er
2df0: 72 29 29 3f 3b 0a 09 09 09 09 09 09 09 09 09 09  r))?;...........
2e00: 09 09 4e 6f 6e 65 0a 09 09 09 09 09 09 09 09 09  ..None..........
2e10: 09 09 7d 2c 0a 09 09 09 09 09 09 09 09 09 7d 3b  ..},..........};
2e20: 0a 09 09 09 09 09 09 09 09 09 6d 61 74 63 68 20  ..........match 
2e30: 63 68 61 6e 20 7b 0a 09 09 09 09 09 09 09 09 09  chan {..........
2e40: 09 53 6f 6d 65 28 63 68 61 6e 29 20 3d 3e 20 7b  .Some(chan) => {
2e50: 0a 09 09 09 09 09 09 09 09 09 09 09 6c 65 74 20  ............let 
2e60: 6e 65 77 5f 63 68 61 6e 20 3d 20 63 6f 72 65 2e  new_chan = core.
2e70: 74 67 2e 73 65 6e 64 28 74 65 6c 65 67 72 61 6d  tg.send(telegram
2e80: 5f 62 6f 74 3a 3a 47 65 74 43 68 61 74 3a 3a 6e  _bot::GetChat::n
2e90: 65 77 28 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a  ew(telegram_bot:
2ea0: 3a 74 79 70 65 73 3a 3a 43 68 61 74 49 64 3a 3a  :types::ChatId::
2eb0: 6e 65 77 28 63 68 61 6e 29 29 29 2e 61 77 61 69  new(chan))).awai
2ec0: 74 3f 3b 0a 09 09 09 09 09 09 09 09 09 09 09 69  t?;............i
2ed0: 66 20 69 36 34 3a 3a 66 72 6f 6d 28 6e 65 77 5f  f i64::from(new_
2ee0: 63 68 61 6e 2e 69 64 28 29 29 20 3d 3d 20 63 68  chan.id()) == ch
2ef0: 61 6e 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09  an {............
2f00: 09 72 65 70 6c 79 2e 70 75 73 68 28 22 49 20 61  .reply.push("I a
2f10: 6c 72 65 61 64 79 20 6b 6e 6f 77 20 74 68 61 74  lready know that
2f20: 20 63 68 61 6e 6e 65 6c 5c 5c 2e 22 2e 74 6f 5f   channel\\.".to_
2f30: 73 74 72 69 6e 67 28 29 29 3b 0a 09 09 09 09 09  string());......
2f40: 09 09 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09  ......} else {..
2f50: 09 09 09 09 09 09 09 09 09 09 09 72 65 70 6c 79  ...........reply
2f60: 2e 70 75 73 68 28 22 48 6d 6d 2c 20 63 68 61 6e  .push("Hmm, chan
2f70: 6e 65 6c 20 68 61 73 20 63 68 61 6e 67 65 64 e2  nel has changed
2f80: 80 a6 20 49 27 6c 6c 20 66 69 78 20 69 74 20 6c   I'll fix it l
2f90: 61 74 65 72 5c 5c 2e 22 2e 74 6f 5f 73 74 72 69  ater\\.".to_stri
2fa0: 6e 67 28 29 29 3b 0a 09 09 09 09 09 09 09 09 09  ng());..........
2fb0: 09 09 7d 3b 0a 09 09 09 09 09 09 09 09 09 09 7d  ..};...........}
2fc0: 2c 0a 09 09 09 09 09 09 09 09 09 09 4e 6f 6e 65  ,...........None
2fd0: 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09 09 09   => {...........
2fe0: 09 6d 61 74 63 68 20 63 6f 72 65 2e 74 67 2e 73  .match core.tg.s
2ff0: 65 6e 64 28 74 65 6c 65 67 72 61 6d 5f 62 6f 74  end(telegram_bot
3000: 3a 3a 47 65 74 43 68 61 74 41 64 6d 69 6e 69 73  ::GetChatAdminis
3010: 74 72 61 74 6f 72 73 3a 3a 6e 65 77 28 74 65 6c  trators::new(tel
3020: 65 67 72 61 6d 5f 62 6f 74 3a 3a 74 79 70 65 73  egram_bot::types
3030: 3a 3a 43 68 61 74 52 65 66 3a 3a 43 68 61 6e 6e  ::ChatRef::Chann
3040: 65 6c 55 73 65 72 6e 61 6d 65 28 63 68 61 6e 6e  elUsername(chann
3050: 65 6c 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 29  el.to_string()))
3060: 29 2e 61 77 61 69 74 20 7b 0a 09 09 09 09 09 09  ).await {.......
3070: 09 09 09 09 09 09 4f 6b 28 63 68 61 6e 5f 61 64  ......Ok(chan_ad
3080: 6d 29 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09  m) => {.........
3090: 09 09 09 09 09 6c 65 74 20 28 6d 75 74 20 6d 65  .....let (mut me
30a0: 2c 20 6d 75 74 20 75 73 65 72 29 20 3d 20 28 66  , mut user) = (f
30b0: 61 6c 73 65 2c 20 66 61 6c 73 65 29 3b 0a 09 09  alse, false);...
30c0: 09 09 09 09 09 09 09 09 09 09 09 66 6f 72 20 61  ...........for a
30d0: 64 6d 69 6e 20 69 6e 20 26 63 68 61 6e 5f 61 64  dmin in &chan_ad
30e0: 6d 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09  m {.............
30f0: 09 09 69 66 20 61 64 6d 69 6e 2e 75 73 65 72 2e  ..if admin.user.
3100: 69 64 20 3d 3d 20 63 6f 72 65 2e 6d 79 2e 69 64  id == core.my.id
3110: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09 09   {..............
3120: 09 09 6d 65 20 3d 20 74 72 75 65 3b 0a 09 09 09  ..me = true;....
3130: 09 09 09 09 09 09 09 09 09 09 09 7d 3b 0a 09 09  ...........};...
3140: 09 09 09 09 09 09 09 09 09 09 09 09 69 66 20 61  ............if a
3150: 64 6d 69 6e 2e 75 73 65 72 2e 69 64 20 3d 3d 20  dmin.user.id == 
3160: 6d 65 73 73 61 67 65 2e 66 72 6f 6d 2e 69 64 20  message.from.id 
3170: 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09 09 09  {...............
3180: 09 75 73 65 72 20 3d 20 74 72 75 65 3b 0a 09 09  .user = true;...
3190: 09 09 09 09 09 09 09 09 09 09 09 09 7d 3b 0a 09  ............};..
31a0: 09 09 09 09 09 09 09 09 09 09 09 09 7d 3b 0a 09  ............};..
31b0: 09 09 09 09 09 09 09 09 09 09 09 09 69 66 20 21  ............if !
31c0: 20 6d 65 20 20 20 7b 20 72 65 70 6c 79 2e 70 75   me   { reply.pu
31d0: 73 68 28 22 49 20 6e 65 65 64 20 74 6f 20 62 65  sh("I need to be
31e0: 20 61 64 6d 69 6e 20 6f 6e 20 74 68 61 74 20 63   admin on that c
31f0: 68 61 6e 6e 65 6c 5c 5c 2e 22 2e 74 6f 5f 73 74  hannel\\.".to_st
3200: 72 69 6e 67 28 29 29 3b 20 7d 3b 0a 09 09 09 09  ring()); };.....
3210: 09 09 09 09 09 09 09 09 09 69 66 20 21 20 75 73  .........if ! us
3220: 65 72 20 7b 20 72 65 70 6c 79 2e 70 75 73 68 28  er { reply.push(
3230: 22 59 6f 75 20 73 68 6f 75 6c 64 20 62 65 20 61  "You should be a
3240: 64 6d 69 6e 20 6f 6e 20 74 68 61 74 20 63 68 61  dmin on that cha
3250: 6e 6e 65 6c 5c 5c 2e 22 2e 74 6f 5f 73 74 72 69  nnel\\.".to_stri
3260: 6e 67 28 29 29 3b 20 7d 3b 0a 09 09 09 09 09 09  ng()); };.......
3270: 09 09 09 09 09 09 09 69 66 20 6d 65 20 26 26 20  .......if me && 
3280: 75 73 65 72 20 7b 0a 09 09 09 09 09 09 09 09 09  user {..........
3290: 09 09 09 09 09 6c 65 74 20 63 68 61 6e 5f 69 64  .....let chan_id
32a0: 20 3d 20 63 6f 72 65 2e 74 67 2e 73 65 6e 64 28   = core.tg.send(
32b0: 74 65 6c 65 67 72 61 6d 5f 62 6f 74 3a 3a 47 65  telegram_bot::Ge
32c0: 74 43 68 61 74 3a 3a 6e 65 77 28 74 65 6c 65 67  tChat::new(teleg
32d0: 72 61 6d 5f 62 6f 74 3a 3a 74 79 70 65 73 3a 3a  ram_bot::types::
32e0: 43 68 61 74 52 65 66 3a 3a 43 68 61 6e 6e 65 6c  ChatRef::Channel
32f0: 55 73 65 72 6e 61 6d 65 28 63 68 61 6e 6e 65 6c  Username(channel
3300: 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29 29 29 2e  .to_string()))).
3310: 61 77 61 69 74 3f 3b 0a 09 09 09 09 09 09 09 09  await?;.........
3320: 09 09 09 09 09 09 73 71 6c 78 3a 3a 71 75 65 72  ......sqlx::quer
3330: 79 28 22 69 6e 73 65 72 74 20 69 6e 74 6f 20 72  y("insert into r
3340: 73 73 74 67 5f 63 68 61 6e 6e 65 6c 20 28 63 68  sstg_channel (ch
3350: 61 6e 6e 65 6c 5f 69 64 2c 20 75 73 65 72 6e 61  annel_id, userna
3360: 6d 65 29 20 76 61 6c 75 65 73 20 28 24 31 2c 20  me) values ($1, 
3370: 24 32 29 3b 22 29 0a 09 09 09 09 09 09 09 09 09  $2);")..........
3380: 09 09 09 09 09 09 2e 62 69 6e 64 28 69 36 34 3a  .......bind(i64:
3390: 3a 66 72 6f 6d 28 63 68 61 6e 5f 69 64 2e 69 64  :from(chan_id.id
33a0: 28 29 29 29 0a 09 09 09 09 09 09 09 09 09 09 09  ()))............
33b0: 09 09 09 09 2e 62 69 6e 64 28 63 68 61 6e 6e 65  .....bind(channe
33c0: 6c 29 0a 09 09 09 09 09 09 09 09 09 09 09 09 09  l)..............
33d0: 09 09 2e 65 78 65 63 75 74 65 28 26 63 6f 72 65  ...execute(&core
33e0: 2e 70 6f 6f 6c 29 2e 61 77 61 69 74 3f 3b 0a 09  .pool).await?;..
33f0: 09 09 09 09 09 09 09 09 09 09 09 09 09 72 65 70  .............rep
3400: 6c 79 2e 70 75 73 68 28 22 47 6f 6f 64 2c 20 49  ly.push("Good, I
3410: 20 6b 6e 6f 77 20 74 68 61 74 20 63 68 61 6e 6e   know that chann
3420: 65 6c 20 6e 6f 77 5c 5c 2e 5c 6e 22 2e 74 6f 5f  el now\\.\n".to_
3430: 73 74 72 69 6e 67 28 29 29 3b 0a 09 09 09 09 09  string());......
3440: 09 09 09 09 09 09 09 09 7d 3b 0a 09 09 09 09 09  ........};......
3450: 09 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09 09  .......},.......
3460: 09 09 09 09 09 09 45 72 72 28 5f 29 20 3d 3e 20  ......Err(_) => 
3470: 7b 0a 09 09 09 09 09 09 09 09 09 09 09 09 09 72  {..............r
3480: 65 70 6c 79 2e 70 75 73 68 28 22 53 6f 72 72 79  eply.push("Sorry
3490: 2c 20 49 20 68 61 76 65 20 6e 6f 20 61 63 63 65  , I have no acce
34a0: 73 73 20 74 6f 20 74 68 61 74 20 63 68 61 74 5c  ss to that chat\
34b0: 5c 2e 22 2e 74 6f 5f 73 74 72 69 6e 67 28 29 29  \.".to_string())
34c0: 3b 0a 09 09 09 09 09 09 09 09 09 09 09 09 7d 2c  ;.............},
34d0: 0a 09 09 09 09 09 09 09 09 09 09 09 7d 3b 0a 09  ............};..
34e0: 09 09 09 09 09 09 09 09 09 7d 2c 0a 09 09 09 09  .........},.....
34f0: 09 09 09 09 09 7d 3b 0a 09 09 09 09 09 09 09 09  .....};.........
3500: 7d 3b 0a 09 09 09 09 09 09 09 7d 2c 0a 0a 2f 2f  };........},..//
3510: 20 63 68 65 63 6b 0a 0a 09 09 09 09 09 09 09 22   check........."
3520: 2f 63 68 65 63 6b 22 20 3d 3e 20 7b 0a 09 09 09  /check" => {....
3530: 09 09 09 09 09 26 63 6f 72 65 2e 63 68 65 63 6b  .....&core.check
3540: 28 26 77 6f 72 64 73 2e 6e 65 78 74 28 29 2e 75  (&words.next().u
3550: 6e 77 72 61 70 28 29 2e 70 61 72 73 65 3a 3a 3c  nwrap().parse::<
3560: 69 33 32 3e 28 29 3f 2c 20 4e 6f 6e 65 29 2e 61  i32>()?, None).a
3570: 77 61 69 74 3f 3b 0a 09 09 09 09 09 09 09 7d 2c  wait?;........},
3580: 0a 0a 2f 2f 20 63 6c 65 61 72 0a 0a 09 09 09 09  ..// clear......
3590: 09 09 09 22 2f 63 6c 65 61 6e 22 20 3d 3e 20 7b  ..."/clean" => {
35a0: 0a 09 09 09 09 09 09 09 09 69 66 20 63 6f 72 65  .........if core
35b0: 2e 6f 77 6e 65 72 20 21 3d 20 69 36 34 3a 3a 66  .owner != i64::f
35c0: 72 6f 6d 28 6d 65 73 73 61 67 65 2e 66 72 6f 6d  rom(message.from
35d0: 2e 69 64 29 20 7b 0a 09 09 09 09 09 09 09 09 09  .id) {..........
35e0: 72 65 70 6c 79 2e 70 75 73 68 28 22 52 65 73 65  reply.push("Rese
35f0: 72 76 65 64 20 66 6f 72 20 74 65 73 74 69 6e 67  rved for testing
3600: 5c 5c 2e 22 2e 74 6f 5f 73 74 72 69 6e 67 28 29  \\.".to_string()
3610: 29 3b 0a 09 09 09 09 09 09 09 09 7d 20 65 6c 73  );.........} els
3620: 65 20 7b 0a 09 09 09 09 09 09 09 09 09 6c 65 74  e {..........let
3630: 20 73 6f 75 72 63 65 5f 69 64 20 3d 20 77 6f 72   source_id = wor
3640: 64 73 2e 6e 65 78 74 28 29 2e 75 6e 77 72 61 70  ds.next().unwrap
3650: 28 29 2e 70 61 72 73 65 3a 3a 3c 69 33 32 3e 28  ().parse::<i32>(
3660: 29 2e 75 6e 77 72 61 70 5f 6f 72 28 30 29 3b 0a  ).unwrap_or(0);.
3670: 09 09 09 09 09 09 09 09 09 26 63 6f 72 65 2e 63  .........&core.c
3680: 6c 65 61 6e 28 73 6f 75 72 63 65 5f 69 64 29 2e  lean(source_id).
3690: 61 77 61 69 74 3f 3b 0a 09 09 09 09 09 09 09 09  await?;.........
36a0: 7d 0a 09 09 09 09 09 09 09 7d 2c 0a 0a 2f 2f 20  }........},..// 
36b0: 65 6e 61 62 6c 65 0a 0a 09 09 09 09 09 09 09 22  enable........."
36c0: 2f 65 6e 61 62 6c 65 22 20 3d 3e 20 7b 0a 09 09  /enable" => {...
36d0: 09 09 09 09 09 09 6d 61 74 63 68 20 63 6f 72 65  ......match core
36e0: 2e 65 6e 61 62 6c 65 28 26 77 6f 72 64 73 2e 6e  .enable(&words.n
36f0: 65 78 74 28 29 2e 75 6e 77 72 61 70 28 29 2e 70  ext().unwrap().p
3700: 61 72 73 65 3a 3a 3c 69 33 32 3e 28 29 3f 29 2e  arse::<i32>()?).
3710: 61 77 61 69 74 20 7b 0a 09 09 09 09 09 09 09 09  await {.........
3720: 09 4f 6b 28 5f 29 20 3d 3e 20 7b 0a 09 09 09 09  .Ok(_) => {.....
3730: 09 09 09 09 09 09 72 65 70 6c 79 2e 70 75 73 68  ......reply.push
3740: 28 22 43 68 61 6e 6e 65 6c 20 65 6e 61 62 6c 65  ("Channel enable
3750: 64 5c 5c 2e 22 2e 74 6f 5f 73 74 72 69 6e 67 28  d\\.".to_string(
3760: 29 29 3b 0a 09 09 09 09 09 09 09 09 09 7d 0a 09  ));..........}..
3770: 09 09 09 09 09 09 09 09 45 72 72 28 65 72 72 29  ........Err(err)
3780: 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 09 09 09   => {...........
3790: 63 6f 72 65 2e 64 65 62 75 67 28 26 65 72 72 2e  core.debug(&err.
37a0: 74 6f 5f 73 74 72 69 6e 67 28 29 29 3f 3b 0a 09  to_string())?;..
37b0: 09 09 09 09 09 09 09 09 7d 2c 0a 09 09 09 09 09  ........},......
37c0: 09 09 09 7d 3b 0a 09 09 09 09 09 09 09 7d 2c 0a  ...};........},.
37d0: 0a 2f 2f 20 64 69 73 61 62 6c 65 0a 0a 09 09 09  .// disable.....
37e0: 09 09 09 09 22 2f 64 69 73 61 62 6c 65 22 20 3d  ...."/disable" =
37f0: 3e 20 7b 0a 09 09 09 09 09 09 09 09 6d 61 74 63  > {.........matc
3800: 68 20 63 6f 72 65 2e 64 69 73 61 62 6c 65 28 26  h core.disable(&
3810: 77 6f 72 64 73 2e 6e 65 78 74 28 29 2e 75 6e 77  words.next().unw
3820: 72 61 70 28 29 2e 70 61 72 73 65 3a 3a 3c 69 33  rap().parse::<i3
3830: 32 3e 28 29 3f 29 2e 61 77 61 69 74 20 7b 0a 09  2>()?).await {..
3840: 09 09 09 09 09 09 09 09 4f 6b 28 5f 29 20 3d 3e  ........Ok(_) =>
3850: 20 7b 0a 09 09 09 09 09 09 09 09 09 09 72 65 70   {...........rep
3860: 6c 79 2e 70 75 73 68 28 22 43 68 61 6e 6e 65 6c  ly.push("Channel
3870: 20 64 69 73 61 62 6c 65 64 5c 5c 2e 22 2e 74 6f   disabled\\.".to
3880: 5f 73 74 72 69 6e 67 28 29 29 3b 0a 09 09 09 09  _string());.....
3890: 09 09 09 09 09 7d 0a 09 09 09 09 09 09 09 09 09  .....}..........
38a0: 45 72 72 28 65 72 72 29 20 3d 3e 20 7b 0a 09 09  Err(err) => {...
38b0: 09 09 09 09 09 09 09 09 63 6f 72 65 2e 64 65 62  ........core.deb
38c0: 75 67 28 26 65 72 72 2e 74 6f 5f 73 74 72 69 6e  ug(&err.to_strin
38d0: 67 28 29 29 3f 3b 0a 09 09 09 09 09 09 09 09 09  g())?;..........
38e0: 7d 2c 0a 09 09 09 09 09 09 09 09 7d 3b 0a 09 09  },.........};...
38f0: 09 09 09 09 09 7d 2c 0a 0a 09 09 09 09 09 09 09  .....},.........
3900: 5f 20 3d 3e 20 7b 0a 09 09 09 09 09 09 09 7d 2c  _ => {........},
3910: 0a 09 09 09 09 09 09 7d 3b 0a 09 09 09 09 09 7d  .......};......}
3920: 2c 0a 09 09 09 09 09 5f 20 3d 3e 20 7b 0a 09 09  ,......_ => {...
3930: 09 09 09 7d 2c 0a 09 09 09 09 7d 3b 0a 09 09 09  ...},.....};....
3940: 09 69 66 20 72 65 70 6c 79 2e 6c 65 6e 28 29 20  .if reply.len() 
3950: 3e 20 30 20 7b 0a 09 09 09 09 09 6d 61 74 63 68  > 0 {......match
3960: 20 63 6f 72 65 2e 74 67 2e 73 65 6e 64 28 6d 65   core.tg.send(me
3970: 73 73 61 67 65 2e 74 65 78 74 5f 72 65 70 6c 79  ssage.text_reply
3980: 28 72 65 70 6c 79 2e 6a 6f 69 6e 28 22 5c 6e 22  (reply.join("\n"
3990: 29 29 2e 70 61 72 73 65 5f 6d 6f 64 65 28 74 79  )).parse_mode(ty
39a0: 70 65 73 3a 3a 50 61 72 73 65 4d 6f 64 65 3a 3a  pes::ParseMode::
39b0: 4d 61 72 6b 64 6f 77 6e 56 32 29 29 2e 61 77 61  MarkdownV2)).awa
39c0: 69 74 20 7b 0a 09 09 09 09 09 09 4f 6b 28 5f 29  it {.......Ok(_)
39d0: 20 3d 3e 20 7b 7d 2c 0a 09 09 09 09 09 09 45 72   => {},.......Er
39e0: 72 28 65 72 72 29 20 3d 3e 20 7b 0a 09 09 09 09  r(err) => {.....
39f0: 09 09 09 64 62 67 21 28 72 65 70 6c 79 2e 6a 6f  ...dbg!(reply.jo
3a00: 69 6e 28 22 5c 6e 22 29 29 3b 0a 09 09 09 09 09  in("\n"));......
3a10: 09 09 70 72 69 6e 74 6c 6e 21 28 22 7b 7d 22 2c  ..println!("{}",
3a20: 20 65 72 72 29 3b 0a 09 09 09 09 09 09 7d 2c 0a   err);.......},.
3a30: 09 09 09 09 09 7d 0a 09 09 09 09 7d 0a 09 09 09  .....}.....}....
3a40: 7d 2c 0a 09 09 09 5f 20 3d 3e 20 7b 7d 2c 0a 09  },...._ => {},..
3a50: 09 7d 3b 0a 09 7d 0a 0a 09 4f 6b 28 28 29 29 0a  .};..}...Ok(()).
3a60: 7d 0a                                            }.