1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use crate::deserializers::question::Question;
use crate::errors::AppResult;
use crate::graphql::problemset_question_list::Query as QuestionDbQuery;
use crate::graphql::GQLLeetcodeQuery;
use crate::{config::Config, db_ops::ModelUtils};
use sea_orm::DatabaseConnection;

pub async fn update_database_questions(
    client: &reqwest::Client,
    database_client: &DatabaseConnection,
) -> AppResult<()> {
    let query = QuestionDbQuery::default();
    let query_response = query.post(client).await?;
    let total_questions = query_response.get_total_questions();

    let chunk_size = 100;
    let n_chunks = total_questions / chunk_size;
    for i in kdam::tqdm!(0..n_chunks) {
        let skip = i * chunk_size;
        let take = chunk_size;
        let client_copy = client.clone();
        let db_client_copy = database_client.clone();
        let resp = QuestionDbQuery::new(take, skip).post(&client_copy).await?;
        let questions = resp.get_questions();
        Question::multi_insert(&db_client_copy, questions).await?;
    }

    if total_questions % chunk_size != 0 {
        let skip = n_chunks * chunk_size;
        let take = total_questions - skip;
        let client_copy = client.clone();
        let db_client_copy = database_client.clone();
        let resp = QuestionDbQuery::new(take, skip).post(&client_copy).await?;
        Question::multi_insert(&db_client_copy, resp.get_questions()).await?;
    }
    Ok(())
}

use crate::migrations::{Migrator, MigratorTrait};

pub async fn do_migrations(database_client: &DatabaseConnection) -> AppResult<()> {
    Ok(Migrator::up(database_client, None).await?)
}

use reqwest::header::{HeaderMap, HeaderValue};

pub async fn get_reqwest_client(config: &Config) -> AppResult<reqwest::Client> {
    let csrf = config.leetcode.csrftoken.as_str();
    let sess = config.leetcode.leetcode_session.as_str();
    let mut headers = HeaderMap::new();
    let header_k_v = [
        (
            "Cookie",
            format!("LEETCODE_SESSION={sess}; csrftoken={csrf}"),
        ),
        ("Content-Type", "application/json".to_string()),
        ("x-csrftoken", csrf.to_string()),
        ("Origin", "https://leetcode.com".to_string()),
        ("Referer", "https://leetcode.com".to_string()),
        ("Connection", "keep-alive".to_string()),
    ];

    for (key, value) in header_k_v {
        headers.append(key, HeaderValue::from_str(value.as_str())?);
    }

    let client = reqwest::ClientBuilder::new()
        .default_headers(headers)
        .build()?;
    Ok(client)
}

use crate::config::Db;

pub async fn get_config() -> AppResult<Option<Config>> {
    let config_path = Config::get_base_config()?;
    let config: Config;

    if !config_path.exists() {
        config = Config::default();
        config.write_config(Config::get_base_config()?).await?;
        println!("\nConfig is created at config_path {}.\n\nKindly set LEETCODE_SESSION and csrftoken in the config file. These can be obained from leetcode cookies in the browser.", config_path.display());
        let db_data_path = Db::get_base_sqlite_data_path()?;
        if !db_data_path.exists() {
            Db::touch_default_db().await?;
            println!("\nDatabase resides in {}", db_data_path.display());
        }
        Ok(None)
    } else {
        println!("Config file found @ {}", &config_path.display());
        config = Config::read_config(config_path).await?;
        Ok(Some(config))
    }
}

use crate::app_ui::channel::{ChannelRequestReceiver, ChannelResponseSender};

pub async fn tasks_executor(
    mut rx_request: ChannelRequestReceiver,
    tx_response: ChannelResponseSender,
    client: &reqwest::Client,
    conn: &DatabaseConnection,
) -> AppResult<()> {
    while let Some(task) = rx_request.recv().await {
        let response = task.execute(client, conn).await;
        tx_response.send(response)?;
    }
    Ok(())
}