Introducing .json and .png extensions as well as default avatars

This commit is contained in:
nea 2022-11-26 19:08:14 +01:00
parent 0ed508b4ae
commit 10f3ac6b18
Signed by: nea
GPG Key ID: AA563E93EB628D91
2 changed files with 56 additions and 11 deletions

3
README
View File

@ -8,7 +8,8 @@ Run:
Listens to localhost:<port>
Requests to localhost:<port>/avatar/<userid> instead reply with a png of the users avatar.
Requests to localhost:<port>/avatar/<userid>.png reply with a png of the users avatar.
Requests to localhost:<port>/avatar/<userid>.json reply with a json of the users data.
A publicly hosted version is available at https://dp.nea.moe/avatar/310702108997320705

View File

@ -7,7 +7,7 @@ use hyper::client::{Client, HttpConnector};
use hyper::service::{make_service_fn, service_fn};
use hyper_tls::HttpsConnector;
async fn get_avatar_url(client: &Client<HttpsConnector<HttpConnector>>, token: &str, user_id: u64) -> anyhow::Result<String> {
async fn get_user_data(client: &Client<HttpsConnector<HttpConnector>>, token: &str, user_id: u64) -> anyhow::Result<serde_json::Value> {
let request = Request::builder()
.method(Method::GET)
.uri(format!("https://discord.com/api/v10/users/{}", user_id))
@ -18,20 +18,29 @@ async fn get_avatar_url(client: &Client<HttpsConnector<HttpConnector>>, token: &
let body = hyper::body::to_bytes(x.body_mut()).await?;
let json_data = String::from_utf8(Vec::from(body))?;
let json: serde_json::Value = serde_json::from_str(&json_data)?;
let avatar = json["avatar"].as_str().ok_or(anyhow::anyhow!("Missing avatar"))?;
Ok(json)
}
async fn get_avatar_url(client: &Client<HttpsConnector<HttpConnector>>, token: &str, user_id: u64) -> anyhow::Result<String> {
let json = get_user_data(client, token, user_id).await?;
let id = json["id"].as_str().ok_or(anyhow::anyhow!("Missing avatar"))?;
let avatar_url = format!("https://cdn.discordapp.com/avatars/{}/{}.png", id, avatar);
println!("Served request for {}: {}#{}", id, json["username"], json["discriminator"]);
let discrim = json["discriminator"].as_str().ok_or(anyhow::anyhow!("Missing discriminator"))?;
println!("Served request for {}: {}#{}", id, json["username"], discrim);
let avatar_url = match json["avatar"].as_str() {
None => default_avatar_url(discrim)?,
Some(avatar_hash) => format!("https://cdn.discordapp.com/avatars/{}/{}.png", id, avatar_hash)
};
Ok(avatar_url)
}
fn make_err(err: u16, text: &str) -> anyhow::Result<Response<Body>> {
return Ok(Response::builder()
.status(err)
.body(format!("{} {}", err, text).into())?);
}
async fn resp(arc: Arc<Ctx>, req: Request<Body>) -> anyhow::Result<Response<Body>> {
fn make_err(err: u16, text: &str) -> anyhow::Result<Response<Body>> {
return Ok(Response::builder()
.status(err)
.body(format!("{} {}", err, text).into())?);
}
let x = req.uri().path();
if x == "/" {
return Ok(Response::builder()
@ -43,7 +52,41 @@ async fn resp(arc: Arc<Ctx>, req: Request<Body>) -> anyhow::Result<Response<Body
None => return make_err(404, "Not found"),
Some(request) => request,
};
let num_id = match request.parse::<u64>() {
if let Some(userid) = request.strip_suffix(".png") {
return respond_with_image(arc, userid).await;
}
if let Some(userid) = request.strip_suffix(".json") {
return respond_with_json(arc, userid).await;
}
return make_err(404, "Invalid format");
}
fn default_avatar_url(discrim: &str) -> anyhow::Result<String> {
let d = discrim.parse::<u16>()?;
let bare = d % 5;
Ok(format!("https://cdn.discordapp.com/embed/avatars/{}.png", bare))
}
struct ResponseUserFormat {
username: String,
discriminator: String,
avatar: String,
banner: Option<String>,
}
async fn respond_with_json(arc: Arc<Ctx>, userid: &str) -> anyhow::Result<Response<Body>> {
let num_id = match userid.parse::<u64>() {
Err(_) => return make_err(404, "Not found"),
Ok(num) => num,
};
Ok(Response::builder()
.status(200)
.header("content-type", "application/json")
.body(serde_json::to_string("{\"todo\": true}")?.into())?)
}
async fn respond_with_image(arc: Arc<Ctx>, userid: &str) -> anyhow::Result<Response<Body>> {
let num_id = match userid.parse::<u64>() {
Err(_) => return make_err(404, "Not found"),
Ok(num) => num,
};
@ -61,6 +104,7 @@ async fn resp(arc: Arc<Ctx>, req: Request<Body>) -> anyhow::Result<Response<Body
.body(resp.into_body())?)
}
struct Ctx {
client: Client<HttpsConnector<HttpConnector>>,
token: String,