rustlog/src/app/mod.rs

111 lines
3.4 KiB
Rust

pub mod cache;
use self::cache::UsersCache;
use crate::{config::Config, error::Error, Result};
use anyhow::Context;
use dashmap::DashSet;
use std::{collections::HashMap, sync::Arc};
use tracing::debug;
use twitch_api2::{helix::users::GetUsersRequest, twitch_oauth2::AppAccessToken, HelixClient};
#[derive(Clone)]
pub struct App {
pub helix_client: HelixClient<'static, reqwest::Client>,
pub token: Arc<AppAccessToken>,
pub users: UsersCache,
pub optout_codes: Arc<DashSet<String>>,
pub db: Arc<clickhouse::Client>,
pub config: Arc<Config>,
}
impl App {
pub async fn get_users(
&self,
ids: Vec<String>,
names: Vec<String>,
) -> Result<HashMap<String, String>> {
let mut users = HashMap::new();
let mut ids_to_request = Vec::new();
let mut names_to_request = Vec::new();
for id in ids {
if let Some(login) = self.users.get_login(&id) {
users.insert(id, login);
} else {
ids_to_request.push(id.into())
}
}
for name in names {
if let Some(id) = self.users.get_id(&name) {
users.insert(id, name);
} else {
names_to_request.push(name.into());
}
}
let mut new_users = Vec::with_capacity(ids_to_request.len() + names_to_request.len());
// There are no chunks if the vec is empty, so there is no empty request made
for chunk in ids_to_request.chunks(100) {
debug!("Requesting user info for ids {chunk:?}");
let request = GetUsersRequest::builder().id(chunk.to_vec()).build();
let response = self.helix_client.req_get(request, &*self.token).await?;
new_users.extend(response.data);
}
for chunk in names_to_request.chunks(100) {
debug!("Requesting user info for names {chunk:?}");
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);
}
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);
}
Ok(users)
}
pub async fn get_user_id_by_name(&self, name: &str) -> Result<String> {
if let Some(id) = self.users.get_id(name) {
Ok(id)
} else {
let request = GetUsersRequest::builder().login(vec![name.into()]).build();
let response = self.helix_client.req_get(request, &*self.token).await?;
let user = response
.data
.into_iter()
.next()
.context("Could not get user")?;
let user_id = user.id.into_string();
self.users.insert(user_id.clone(), user.login.into_string());
Ok(user_id)
}
}
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::OptedOut);
}
if let Some(user_id) = user_id {
if self.config.opt_out.contains_key(user_id) {
return Err(Error::OptedOut);
}
}
Ok(())
}
}