dao-governance-framework/semantic-scholar-client/src/main.rs

110 lines
2.6 KiB
Rust

// During development, allowing dead code
#![allow(dead_code)]
use async_recursion::async_recursion;
use clap::Parser;
use std::fmt::Write;
use std::error::Error;
// use std::time::Duration;
// use std::thread::sleep;
use serde::Deserialize;
type DataResult<T> = Result<T, Box<dyn Error>>;
const BASE_URL: &str = "https://api.semanticscholar.org/graph/v1";
const MAX_DEPTH: u32 = 3;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// URL to query
#[clap(short, long, value_parser)]
paper_id: String,
}
struct Author {
name: String
}
struct Paper {
authors: Vec<Author>
}
/**
* Occurs within Citation struct
*/
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct CitingPaper {
paper_id: String,
title: String,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Citation {
citing_paper: CitingPaper
}
/**
* Generic struct to wrap the common API response pattern {data: [...]}
*/
#[derive(Deserialize, Debug)]
struct ApiListResponse<T> {
data: Vec<T>
}
// TODO: Cache results in a (separate but local) database such as Redis
// TODO: Store results in a (separate but local) database such as Postgres
#[async_recursion]
async fn get_citations(paper_id: String, depth: u32) -> DataResult<Vec<Citation>> {
// Bound recursion to some depth
if depth > MAX_DEPTH {
return Ok(vec![]);
}
// Naieve approach to possible rate-limiting
// sleep(Duration::new(1, 0));
// Build the URL
let mut url = String::new();
write!(&mut url, "{}/paper/{}/citations", BASE_URL, paper_id)?;
let resp = reqwest::get(url)
.await?
.text()
.await?;
// .json::<serde_json::Value>().await?;
let resp_deserialized_attempt = serde_json::from_str::<ApiListResponse<Citation>>(resp.as_str());
if let Err(err) = resp_deserialized_attempt {
println!("depth {} paper {} error {}", depth, paper_id, err);
return Ok(vec![]);
}
let resp_deserialized: ApiListResponse<Citation> = resp_deserialized_attempt.unwrap();
for Citation{citing_paper: CitingPaper{paper_id: cited_id, title}} in resp_deserialized.data {
println!("depth {} paper {} cites {} title {}", depth, paper_id, cited_id, title);
get_citations(cited_id, depth + 1).await?;
}
Ok(vec![])
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let Args{ paper_id } = Args::parse();
// let mut authors: Vec<Author> = Vec::new();
// let citations =
get_citations(paper_id, 0).await?;
Ok(())
}