Skip to content

Commit

Permalink
chore: create and use sha256 file
Browse files Browse the repository at this point in the history
  • Loading branch information
anatawa12 committed Jan 25, 2023
1 parent 89d404b commit 68442ad
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 19 deletions.
66 changes: 66 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ reqwest = { version = "0.11.14", features = ["blocking", "serde_json", "json", "
semver = { version = "1.0.16", features = ["serde"] }
serde = { version = "1.0.152", features = ["derive", "rc"] }
serde_json = { version = "1.0.91", features = ["preserve_order"] }
sha2 = "0.10.6"
tokio = { version = "1.24.2", features = ["rt", "macros", "fs"] }
uuid = { version = "1.2.2", features = ["v4"] }
120 changes: 101 additions & 19 deletions src/vpm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,38 @@
//!
//! This module might be a separated crate.

use crate::version::{Version, VersionRange};
use crate::vpm::structs::manifest::{VpmDependency, VpmLockedDependency};
use crate::vpm::structs::package::PackageJson;
use crate::vpm::structs::remote_repo::PackageVersions;
use crate::vpm::structs::repository::LocalCachedRepository;
use crate::vpm::structs::setting::UserRepoSetting;
use futures::future::{join_all, try_join_all};
use futures::prelude::*;
use indexmap::IndexMap;
use itertools::Itertools as _;
use reqwest::{Client, IntoUrl, Url};
use serde_json::{from_value, to_value, Map, Value};
use std::collections::HashSet;
use std::ffi::OsStr;
use std::future::ready;
use std::io::SeekFrom;
use std::path::{Path, PathBuf};
use std::{env, fmt, io};

use futures::future::{join_all, try_join_all};
use futures::prelude::*;
use indexmap::IndexMap;
use itertools::Itertools as _;
use reqwest::{Client, IntoUrl, Url};
use serde_json::{from_value, to_value, Map, Value};
use tokio::fs::{create_dir_all, read_dir, remove_dir_all, remove_file, File, OpenOptions};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeekExt, AsyncWriteExt};

use repo_holder::RepoHolder;
use utils::*;
use vpm_manifest::VpmManifest;

use crate::version::{Version, VersionRange};
use crate::vpm::structs::manifest::{VpmDependency, VpmLockedDependency};
use crate::vpm::structs::package::PackageJson;
use crate::vpm::structs::remote_repo::PackageVersions;
use crate::vpm::structs::repository::LocalCachedRepository;
use crate::vpm::structs::setting::UserRepoSetting;
use sha2::{Digest, Sha256};

mod repo_holder;
pub mod structs;
mod utils;

use repo_holder::RepoHolder;

type JsonMap = Map<String, Value>;

/// This struct holds global state (will be saved on %LOCALAPPDATA% of VPM.
Expand Down Expand Up @@ -258,17 +262,84 @@ impl Environment {
package: &PackageJson,
target_packages_folder: &Path,
) -> io::Result<()> {
let zip_file_name = format!("vrc-get-{}-{}.zip", &package.name, &package.version);
let zip_path = {
let mut building = self.global_dir.clone();
building.push("Repos");
building.push(&package.name);
create_dir_all(&building).await?;
building.push(&format!("{}-{}.zip", &package.name, &package.version));
building.push(&zip_file_name);
building
};
let sha_path = zip_path.with_extension("zip.sha256");
let dest_folder = target_packages_folder.join(&package.name);

let zip_file = if let Some(cache_file) = try_open_file(&zip_path).await? {
fn parse_hex(hex: [u8; 256 / 4]) -> Option<[u8; 256 / 8]> {
let mut result = [0u8; 256 / 8];
for i in 0..(256 / 8) {
let upper = match hex[i * 2 + 0] {
c @ b'0'..=b'9' => c - b'0',
c @ b'a'..=b'f' => c - b'a' + 10,
c @ b'A'..=b'F' => c - b'A' + 10,
_ => return None,
};
let lower = match hex[i * 2 + 1] {
c @ b'0'..=b'9' => c - b'0',
c @ b'a'..=b'f' => c - b'a' + 10,
c @ b'A'..=b'F' => c - b'A' + 10,
_ => return None,
};
result[i] = upper << 4 | lower;
}
Some(result)
}

fn to_hex(data: &[u8]) -> String {
static HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
let mut result = vec![0u8; data.len() * 2];
for i in 0..data.len() {
result[i * 2 + 0] = HEX_CHARS[((data[i] >> 4) & 0xf) as usize];
result[i * 2 + 1] = HEX_CHARS[((data[i] >> 0) & 0xf) as usize];
}
unsafe { String::from_utf8_unchecked(result) }
}

async fn try_cache(zip_path: &Path, sha_path: &Path) -> Option<File> {
let mut cache_file = try_open_file(&zip_path).await.ok()??;
let mut sha_file = try_open_file(&sha_path).await.ok()??;

let mut buf = [0u8; 256 / 4];
sha_file.read_exact(&mut buf).await.ok()?;

let hex = parse_hex(buf)?;

let mut sha256 = Sha256::default();
let mut buffer = [0u8; 1024 * 4];

// process sha256
loop {
match cache_file.read(&mut buffer).await {
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(_) => return None,
Ok(0) => break,
Ok(size) => sha256.update(&buffer[0..size]),
}
}

drop(buffer);

let hash = sha256.finalize();
let hash = &hash[..];
if hash != &hex[..] {
return None;
}

cache_file.seek(SeekFrom::Start(0)).await.ok()?;

Some(cache_file)
}

let zip_file = if let Some(cache_file) = try_cache(&zip_path, &sha_path).await {
cache_file
} else {
// file not found: err
Expand All @@ -294,6 +365,17 @@ impl Environment {
cache_file.write_all(&got_data).await?;
cache_file.flush().await?;
cache_file.seek(SeekFrom::Start(0)).await?;

// write sha file
let mut sha_file = File::create(&sha_path).await?;
let mut sha256 = Sha256::default();
sha256.update(&got_data);
let hash_hex = to_hex(&sha256.finalize()[..]);
let sha_file_content = format!("{} {}\n", hash_hex, zip_file_name);
sha_file.write_all(sha_file_content.as_bytes()).await?;
sha_file.flush().await?;
drop(sha_file);

cache_file
};

Expand Down Expand Up @@ -518,7 +600,7 @@ impl From<serde_json::Error> for AddRepositoryErr {

async fn update_from_remote(client: &Client, path: &Path, repo: &mut LocalCachedRepository) {
let Some(remote_url) = repo.creation_info.as_ref().and_then(|x| x.url.as_ref()) else {
return
return;
};

match download_remote_repository(&client, remote_url).await {
Expand Down Expand Up @@ -569,12 +651,12 @@ pub(crate) async fn download_remote_repository(
.err_mapped()
}

use vpm_manifest::VpmManifest;
mod vpm_manifest {
use super::*;
use serde::Serialize;
use serde_json::json;

use super::*;

#[derive(Debug)]
pub(super) struct VpmManifest {
json: JsonMap,
Expand Down

0 comments on commit 68442ad

Please sign in to comment.