aboutsummaryrefslogtreecommitdiff
path: root/src-tauri/src/development/mod.rs
blob: cb2aeec9e28c58f8b7d6647d9130f6ee25d90027 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use crate::constants::NS_LAUNCHER_COMMITS_API_URL;
use crate::github::{
    pull_requests::{check_github_api, download_zip_into_memory, get_launcher_download_link},
    CommitInfo,
};
use crate::GameInstall;
use serde::{Deserialize, Serialize};
use std::io::Read;

#[tauri::command]
pub async fn install_git_main(game_install_path: &str) -> Result<String, String> {
    // Get list of commits
    let commits: Vec<CommitInfo> = serde_json::from_value(
        check_github_api(NS_LAUNCHER_COMMITS_API_URL)
            .await
            .expect("Failed request"),
    )
    .unwrap();

    // Get latest commit...
    let latest_commit_sha = commits[0].sha.clone();
    // ...and according artifact download URL
    let download_url = get_launcher_download_link(latest_commit_sha.clone()).await?;

    let archive = match download_zip_into_memory(download_url).await {
        Ok(archive) => archive,
        Err(err) => return Err(err.to_string()),
    };

    let extract_directory = format!(
        "{}/___flightcore-temp-download-dir/launcher-pr-{}",
        game_install_path, latest_commit_sha
    );
    match std::fs::create_dir_all(extract_directory.clone()) {
        Ok(_) => (),
        Err(err) => {
            return Err(format!(
                "Failed creating temporary download directory: {}",
                err
            ))
        }
    };

    let target_dir = std::path::PathBuf::from(extract_directory.clone()); // Doesn't need to exist
    match zip_extract::extract(std::io::Cursor::new(archive), &target_dir, true) {
        Ok(()) => (),
        Err(err) => {
            return Err(format!("Failed unzip: {}", err));
        }
    };

    // Copy only necessary files from temp dir
    // Copy:
    // - NorthstarLauncher.exe
    // - Northstar.dll
    let files_to_copy = vec!["NorthstarLauncher.exe", "Northstar.dll"];
    for file_name in files_to_copy {
        let source_file_path = format!("{}/{}", extract_directory, file_name);
        let destination_file_path = format!("{}/{}", game_install_path, file_name);
        match std::fs::copy(source_file_path, destination_file_path) {
            Ok(_result) => (),
            Err(err) => {
                return Err(format!(
                    "Failed to copy necessary file {} from temp dir: {}",
                    file_name, err
                ))
            }
        };
    }

    // delete extract directory
    match std::fs::remove_dir_all(&extract_directory) {
        Ok(()) => (),
        Err(err) => {
            return Err(format!(
                "Failed to delete temporary download directory: {}",
                err
            ))
        }
    }

    log::info!(
        "All done with installing launcher from {}",
        latest_commit_sha
    );
    Ok(latest_commit_sha)
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Checksum {
    path: String,
    checksum: String,
}

impl ToString for Checksum {
    fn to_string(&self) -> String {
        format!("{} {}", self.checksum, self.path)
    }
}

/// Computes the checksum of a given file
fn compute_checksum<P: AsRef<std::path::Path>>(
    path: P,
) -> Result<Checksum, Box<dyn std::error::Error>> {
    dbg!(path.as_ref().to_string_lossy().into_owned());
    let mut file = std::fs::File::open(&path)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;

    let checksum = crypto_hash::hex_digest(crypto_hash::Algorithm::SHA256, &buffer);
    Ok(Checksum {
        path: path.as_ref().to_string_lossy().into_owned(),
        checksum,
    })
}

fn convert_to_string(checksums: Vec<Checksum>) -> String {
    let mut result = String::new();

    for entry in checksums {
        result.push_str(&entry.to_string());
        result.push('\n');
    }
    result
}

#[tauri::command]
/// Calculates checksums over the passed game_install folder and returns results
pub async fn calculate_checksums_gameinstall(game_install: GameInstall) -> Result<String, String> {
    log::info!("Computing checksums");

    let path = game_install.game_path;
    let mut checksums = Vec::new();

    // Iterate over folder
    for entry in walkdir::WalkDir::new(path.clone()) {
        let entry = entry.unwrap();
        if !entry.file_type().is_file() {
            continue;
        }

        match compute_checksum(entry.path()) {
            Ok(mut checksum) => {
                checksum.path = checksum
                    .path
                    .strip_prefix(&path.clone())
                    .unwrap()
                    .to_string();
                checksums.push(checksum)
            }
            Err(err) => log::warn!("Failed to compute checksum for {:?}: {:?}", entry, err),
        }
    }

    for checksum in &checksums {
        println!("{:?}", checksum);
    }

    log::info!("Done calculating");
    let s = convert_to_string(checksums);
    Ok(s)
}