rustlog/src/app/mod.rs

142 lines
4.6 KiB
Rust
Raw Normal View History

2023-06-17 13:31:16 -04:00
pub mod cache;
use self::cache::UsersCache;
2024-03-03 01:35:20 -03:00
use crate::{config::Config, error::Error, Result};
use anyhow::Context;
2023-06-17 13:31:16 -04:00
use dashmap::DashSet;
use std::{collections::HashMap, sync::Arc};
use tracing::{debug, info};
2022-08-13 03:38:02 -04:00
use twitch_api2::{helix::users::GetUsersRequest, twitch_oauth2::AppAccessToken, HelixClient};
#[derive(Clone)]
2023-06-22 06:29:41 -04:00
pub struct App {
pub helix_client: HelixClient<'static, reqwest::Client>,
2022-08-13 03:38:02 -04:00
pub token: Arc<AppAccessToken>,
2023-06-17 13:31:16 -04:00
pub users: UsersCache,
2024-03-03 01:35:20 -03:00
// pub optout_codes: Arc<DashSet<String>>,
2023-05-26 13:55:58 -04:00
pub db: Arc<clickhouse::Client>,
pub config: Arc<Config>,
2022-08-13 03:38:02 -04:00
}
2023-06-22 06:29:41 -04:00
impl App {
2022-08-13 03:38:02 -04:00
pub async fn get_users(
&self,
ids: Vec<String>,
names: Vec<String>,
2022-09-02 16:43:47 -04:00
) -> Result<HashMap<String, String>> {
2022-08-13 03:38:02 -04:00
let mut users = HashMap::new();
let mut ids_to_request = Vec::new();
let mut names_to_request = Vec::new();
for id in ids {
match self.users.get_login(&id) {
Some(Some(login)) => {
users.insert(id, login);
}
Some(None) => (),
None => ids_to_request.push(id.into()),
2022-08-13 03:38:02 -04:00
}
}
for name in names {
match self.users.get_id(&name) {
Some(Some(id)) => {
users.insert(id, name);
}
Some(None) => (),
None => names_to_request.push(name.into()),
2022-08-13 03:38:02 -04:00
}
}
2023-01-28 17:06:28 -03:00
let mut new_users = Vec::with_capacity(ids_to_request.len() + names_to_request.len());
2022-08-13 03:38:02 -04:00
2023-01-28 17:06:28 -03:00
// There are no chunks if the vec is empty, so there is no empty request made
for chunk in ids_to_request.chunks(100) {
2023-05-26 13:55:58 -04:00
debug!("Requesting user info for ids {chunk:?}");
2023-01-28 17:06:28 -03:00
let request = GetUsersRequest::builder().id(chunk.to_vec()).build();
2022-08-13 03:38:02 -04:00
let response = self.helix_client.req_get(request, &*self.token).await?;
2023-01-28 17:06:28 -03:00
new_users.extend(response.data);
}
2022-08-13 03:38:02 -04:00
2023-01-28 17:06:28 -03:00
for chunk in names_to_request.chunks(100) {
debug!("Requesting user info for names {chunk:?}");
2022-08-13 03:38:02 -04:00
2023-01-28 17:06:28 -03:00
let request = GetUsersRequest::builder().login(chunk.to_vec()).build();
let response = self.helix_client.req_get(request, &*self.token).await?;
new_users.extend(response.data);
}
2022-08-13 03:38:02 -04:00
2023-01-28 17:06:28 -03:00
for user in new_users {
let id = user.id.into_string();
let login = user.login.into_string();
self.users.insert(id.clone(), login.clone());
users.insert(id, login);
2022-08-13 03:38:02 -04:00
}
// Banned users which were not returned by the api
for id in ids_to_request {
if !users.contains_key(id.as_str()) {
self.users.insert_optional(Some(id.into_string()), None);
}
}
for name in names_to_request {
if !users.values().any(|login| login == name.as_str()) {
self.users.insert_optional(None, Some(name.into_string()));
}
}
2022-08-13 03:38:02 -04:00
Ok(users)
}
2022-09-02 16:43:47 -04:00
pub async fn get_user_id_by_name(&self, name: &str) -> Result<String> {
match self.users.get_id(name) {
Some(Some(id)) => Ok(id),
Some(None) => Err(Error::NotFound),
None => {
let request = GetUsersRequest::builder().login(vec![name.into()]).build();
let response = self.helix_client.req_get(request, &*self.token).await?;
match response.data.into_iter().next() {
Some(user) => {
let user_id = user.id.into_string();
self.users.insert(user_id.clone(), user.login.into_string());
Ok(user_id)
}
None => {
self.users.insert_optional(None, Some(name.to_owned()));
Err(Error::NotFound)
}
}
}
}
2022-09-02 16:43:47 -04:00
}
2023-06-04 01:44:55 -04:00
2024-03-03 01:35:20 -03:00
// pub async fn optout_user(&self, user_id: &str) -> anyhow::Result<()> {
// delete_user_logs(&self.db, user_id)
// .await
// .context("Could not delete logs")?;
2024-03-03 01:35:20 -03:00
// self.config.opt_out.insert(user_id.to_owned(), true);
// self.config.save()?;
// info!("User {user_id} opted out");
2024-03-03 01:35:20 -03:00
// Ok(())
// }
2023-06-04 01:44:55 -04:00
pub fn check_opted_out(&self, channel_id: &str, user_id: Option<&str>) -> Result<()> {
if self.config.opt_out.contains_key(channel_id) {
return Err(Error::ChannelOptedOut);
2023-06-04 01:44:55 -04:00
}
if let Some(user_id) = user_id {
if self.config.opt_out.contains_key(user_id) {
return Err(Error::UserOptedOut);
2023-06-04 01:44:55 -04:00
}
}
Ok(())
}
2022-08-13 03:38:02 -04:00
}