1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Add arc thumbnail support as part of #10

This commit is contained in:
NG (Graham)
2025-05-24 23:56:48 -04:00
parent 59612e6aa3
commit 2607903f7b
13 changed files with 310 additions and 20 deletions

View File

@@ -27,6 +27,7 @@ async fn main() -> std::io::Result<()> {
.service(robocraft::clan_avatar::get)
.service(robocraft::brawl_data::get)
.service(robocraft::campaign_data::get)
.service(robocraft::factory::arc::get)
})
.bind((cli_args.ip, cli_args.port))?
.run()

View File

@@ -1,8 +1,8 @@
use actix_web::{dev::ResourcePath, get, web::{Data, Path}, Responder};
use actix_web::{get, web::{Data, Path}, Responder};
#[get("/brawldata/Live/{name}")]
pub async fn get(cli: Data<crate::cli::CliArgs>, name: Path<String>) -> impl Responder {
let path = std::path::PathBuf::from(&cli.data_robocraft).join("brawldata").join(format!("{}.jpg", name.path()));
let path = std::path::PathBuf::from(&cli.data_robocraft).join("brawldata").join(format!("{}.jpg", *name));
log::debug!("RC asset at {} (exists? {})", path.display(), path.exists());
actix_files::NamedFile::open_async(path).await
}

View File

@@ -1,8 +1,8 @@
use actix_web::{dev::ResourcePath, get, web::{Data, Path}, Responder};
use actix_web::{get, web::{Data, Path}, Responder};
#[get("/campaigndata/Live/{name}")]
pub async fn get(cli: Data<crate::cli::CliArgs>, name: Path<String>) -> impl Responder {
let path = std::path::PathBuf::from(&cli.data_robocraft).join("campaigndata").join(format!("{}.jpg", name.path()));
let path = std::path::PathBuf::from(&cli.data_robocraft).join("campaigndata").join(format!("{}.jpg", *name));
log::debug!("RC asset at {} (exists? {})", path.display(), path.exists());
actix_files::NamedFile::open_async(path).await
}

View File

@@ -1,8 +1,8 @@
use actix_web::{dev::ResourcePath, get, web::{Data, Path}, Responder};
use actix_web::{get, web::{Data, Path}, Responder};
#[get("/clanavatar/Live/{name}")]
pub async fn get(cli: Data<crate::cli::CliArgs>, name: Path<String>) -> impl Responder {
let path = std::path::PathBuf::from(&cli.data_robocraft).join("clanavatar").join(format!("{}.jpg", name.path()));
let path = std::path::PathBuf::from(&cli.data_robocraft).join("clanavatar").join(format!("{}.jpg", *name));
log::debug!("RC asset at {} (exists? {})", path.display(), path.exists());
actix_files::NamedFile::open_async(path).await
}

View File

@@ -0,0 +1,82 @@
use std::io::Read;
use actix_web::{get, web::{Data, Path}, HttpResponse};
static ZIP_FILE: std::sync::Mutex<Option<zip::read::ZipArchive<std::io::BufReader<std::fs::File>>>> = std::sync::Mutex::new(None);
#[get("/roboshop/arc/Live/{id}")]
pub async fn get(cli: Data<crate::cli::CliArgs>, id: Path<u32>) -> HttpResponse {
let id: u32 = *id;
let zip_path = std::path::PathBuf::from(&cli.data_robocraft).join("rc_archive_thumbnails.zip");
try_find_file(zip_path, id).await
}
async fn try_find_file(zip_path: std::path::PathBuf, id: u32) -> HttpResponse {
let result = tokio::task::spawn_blocking(move || get_file_in_zip(zip_path, id)).await.unwrap();
match result {
Ok(bytes) => {
log::debug!("Found id {} in factory arc", id);
actix_web::HttpResponseBuilder::new(actix_web::http::StatusCode::OK)
.append_header(("Content-Type", "image/jpeg"))
.body(bytes)
},
Err(e) => {
log::debug!("Failed to find id {} in factory arc: {}", id, e);
match e {
zip::result::ZipError::Io(e) => {
actix_web::HttpResponseBuilder::new(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("zip io error: {}", e.to_string()))
},
zip::result::ZipError::InvalidArchive(e) => {
actix_web::HttpResponseBuilder::new(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("invalid zip file: {}", e.to_string()))
},
zip::result::ZipError::UnsupportedArchive(e) => {
actix_web::HttpResponseBuilder::new(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("unsupported zip file: {}", e.to_string()))
},
zip::result::ZipError::FileNotFound => {
actix_web::HttpResponseBuilder::new(actix_web::http::StatusCode::NOT_FOUND)
.body(format!("file not found in zip archive"))
},
zip::result::ZipError::InvalidPassword => {
actix_web::HttpResponseBuilder::new(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("invalid zip password"))
},
_ => actix_web::HttpResponseBuilder::new(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("unknown zip error")),
}
}
}
}
fn get_file_in_zip(zip_path: std::path::PathBuf, id: u32) -> zip::result::ZipResult<Vec<u8>> {
let prefix = format!("rc_archive_thumbnails/{} - ", id);
let mut lock = ZIP_FILE.lock().unwrap();
if let Some(archive) = lock.as_mut() {
Ok(read_file_with_prefix(&prefix, archive)?)
} else {
// this is usually very slow, but thankfully should only run the first time this endpoint is hit
let file = std::fs::File::open(zip_path)?;
let buf = std::io::BufReader::new(file);
let mut archive = zip::read::ZipArchive::new(buf)?;
let bytes = read_file_with_prefix(&prefix, &mut archive)?;
*lock = Some(archive);
Ok(bytes)
}
}
fn read_file_with_prefix(prefix: &str, archive: &mut zip::read::ZipArchive<std::io::BufReader<std::fs::File>>) -> zip::result::ZipResult<Vec<u8>> {
let index = if let Some((index, _)) = archive.file_names().enumerate().find(|(_, name)| name.starts_with(prefix)) {
index
} else {
return Err(zip::result::ZipError::FileNotFound);
};
let mut buf = Vec::new();
let mut file = archive.by_index(index)?;
file.read_to_end(&mut buf)?;
Ok(buf)
}

View File

@@ -0,0 +1 @@
pub mod arc;

View File

@@ -3,3 +3,4 @@ pub mod user_avatar;
pub mod clan_avatar;
pub mod brawl_data;
pub mod campaign_data;
pub mod factory;

View File

@@ -1,8 +1,8 @@
use actix_web::{dev::ResourcePath, get, web::{Data, Path}, Responder};
use actix_web::{get, web::{Data, Path}, Responder};
#[get("/customavatar/Live/{name}")]
pub async fn get(cli: Data<crate::cli::CliArgs>, name: Path<String>) -> impl Responder {
let path = std::path::PathBuf::from(&cli.data_robocraft).join("customavatars").join(format!("{}.jpg", name.path()));
let path = std::path::PathBuf::from(&cli.data_robocraft).join("customavatars").join(format!("{}.jpg", *name));
log::debug!("RC asset at {} (exists? {})", path.display(), path.exists());
actix_files::NamedFile::open_async(path).await
}