Skip to main content

shared/
heavy.rs

1use crate::extensions::distr::{ExtensionDistrFile, MetadataToml};
2use std::path::Path;
3use tokio::io::AsyncWriteExt;
4
5pub static EXTENSION_DIR: &str = "/app/extensions";
6pub static EXTENSION_ROOT_DIR: &str = "/app/repo";
7pub static EXTENSION_LOG: &str = "/tmp/extension_build.log";
8pub static EXTENSION_BUILD_LOCK: &str = "/tmp/extension_build.lock";
9pub static EXTENSION_REBUILD_TRIGGER: &str = "/tmp/rebuild_trigger";
10
11pub async fn is_locked() -> bool {
12    tokio::fs::metadata(EXTENSION_BUILD_LOCK).await.is_ok()
13}
14
15pub async fn trigger_rebuild() -> Result<(), std::io::Error> {
16    let mut file = tokio::fs::File::create(EXTENSION_REBUILD_TRIGGER).await?;
17    file.write_all(b"rebuild").await?;
18
19    Ok(())
20}
21
22pub async fn get_build_logs() -> Box<dyn tokio::io::AsyncRead + Unpin + Send> {
23    match tokio::fs::File::open(EXTENSION_LOG).await {
24        Ok(file) => Box::new(file) as Box<dyn tokio::io::AsyncRead + Unpin + Send>,
25        Err(_) => Box::new(tokio::io::empty()),
26    }
27}
28
29pub async fn write_extension(
30    data: &mut (dyn tokio::io::AsyncRead + Unpin + Send),
31) -> Result<ExtensionDistrFile, anyhow::Error> {
32    let tmp_dir = tempfile::tempdir()?;
33    let tmp_path = tmp_dir.path().join("extension.c7s.zip");
34
35    let mut tmp_file = tokio::fs::File::create_new(&tmp_path).await?;
36    tokio::io::copy(data, &mut tmp_file).await?;
37    let tmp_file = tmp_file.into_std().await;
38
39    let distr =
40        tokio::task::spawn_blocking(move || ExtensionDistrFile::parse_from_reader(tmp_file))
41            .await??;
42
43    let identifier = distr.metadata_toml.get_package_identifier();
44    if !MetadataToml::is_valid_package_identifier(&identifier) {
45        return Err(anyhow::anyhow!("invalid package identifier `{identifier}`"));
46    }
47
48    tokio::fs::copy(
49        tmp_path,
50        Path::new(EXTENSION_DIR).join(format!("{}.c7s.zip", identifier)),
51    )
52    .await?;
53
54    Ok(distr)
55}
56
57pub async fn remove_extension(package_name: &str) -> Result<(), std::io::Error> {
58    let identifier = MetadataToml::convert_package_name_to_identifier(package_name);
59    if !MetadataToml::is_valid_package_identifier(&identifier) {
60        return Err(std::io::Error::new(
61            std::io::ErrorKind::InvalidInput,
62            format!("invalid package identifier `{identifier}`"),
63        ));
64    }
65
66    let path = Path::new(EXTENSION_DIR).join(format!("{}.c7s.zip", identifier));
67
68    tokio::fs::remove_file(path).await?;
69
70    Ok(())
71}
72
73pub async fn list_extensions() -> Result<Vec<ExtensionDistrFile>, anyhow::Error> {
74    let mut entries = tokio::fs::read_dir(EXTENSION_DIR).await?;
75    let mut extensions = Vec::new();
76
77    while let Some(entry) = entries.next_entry().await? {
78        if entry.file_type().await?.is_file() {
79            let path = entry.path();
80            if path.extension().and_then(|s| s.to_str()) == Some("zip") {
81                let file = tokio::fs::File::open(path).await?;
82                let file = file.into_std().await;
83                let distr = match tokio::task::spawn_blocking(move || {
84                    ExtensionDistrFile::parse_from_reader(file)
85                })
86                .await
87                {
88                    Ok(Ok(d)) => d,
89                    _ => continue,
90                };
91
92                extensions.push(distr);
93            }
94        }
95    }
96
97    Ok(extensions)
98}