diff --git a/libs/portable/generate.py b/libs/portable/generate.py index df02566a3..0116c2cd5 100755 --- a/libs/portable/generate.py +++ b/libs/portable/generate.py @@ -4,6 +4,7 @@ import os import optparse from hashlib import md5 import brotli +import datetime # 4GB maximum length_count = 4 @@ -22,7 +23,7 @@ def generate_md5_table(folder: str, level) -> dict: for f in files: md5_generator = md5() full_path = os.path.join(root, f) - print(f"processing {full_path}...") + print(f"Processing {full_path}...") f = open(full_path, "rb") content = f.read() content_compressed = brotli.compress( @@ -34,7 +35,7 @@ def generate_md5_table(folder: str, level) -> dict: return res -def write_metadata(md5_table: dict, output_folder: str, exe: str): +def write_package_metadata(md5_table: dict, output_folder: str, exe: str): output_path = os.path.join(output_folder, "data.bin") with open(output_path, "wb") as f: f.write("rustdesk".encode(encoding=encoding)) @@ -55,8 +56,13 @@ def write_metadata(md5_table: dict, output_folder: str, exe: str): f.write("rustdesk".encode(encoding=encoding)) # executable f.write(exe.encode(encoding='utf-8')) - print(f"metadata had written to {output_path}") + print(f"Metadata has been written to {output_path}") +def write_app_metadata(output_folder: str): + output_path = os.path.join(output_folder, "app_metadata.toml") + with open(output_path, "w") as f: + f.write(f"timestamp = {int(datetime.datetime.now().timestamp() * 1000)}\n") + print(f"App metadata has been written to {output_path}") def build_portable(output_folder: str, target: str): os.chdir(output_folder) @@ -91,11 +97,12 @@ if __name__ == '__main__': options.executable = folder + '/' + options.executable exe: str = os.path.abspath(options.executable) if not exe.startswith(os.path.abspath(folder)): - print("the executable must locate in source folder") + print("The executable must locate in source folder") exit(-1) exe = '.' + exe[len(os.path.abspath(folder)):] - print("executable path: " + exe) - print("compression level: " + str(options.level)) + print("Executable path: " + exe) + print("Compression level: " + str(options.level)) md5_table = generate_md5_table(folder, options.level) - write_metadata(md5_table, output_folder, exe) + write_package_metadata(md5_table, output_folder, exe) + write_app_metadata(output_folder) build_portable(output_folder, options.target) diff --git a/libs/portable/src/main.rs b/libs/portable/src/main.rs index 6e3648c4e..1ffc8aa5d 100644 --- a/libs/portable/src/main.rs +++ b/libs/portable/src/main.rs @@ -9,9 +9,52 @@ use bin_reader::BinaryReader; pub mod bin_reader; +#[cfg(windows)] +const APP_METADATA: &[u8] = include_bytes!("../app_metadata.toml"); +#[cfg(not(windows))] +const APP_METADATA: &[u8] = &[]; +const APP_METADATA_CONFIG: &str = "meta.toml"; +const META_LINE_PREFIX_TIMESTAMP: &str = "timestamp = "; const APP_PREFIX: &str = "rustdesk"; const APPNAME_RUNTIME_ENV_KEY: &str = "RUSTDESK_APPNAME"; +fn is_timestamp_matches(dir: &PathBuf, ts: &mut u64) -> bool { + let Ok(app_metadata) = std::str::from_utf8(APP_METADATA) else { + return true; + }; + for line in app_metadata.lines() { + if line.starts_with(META_LINE_PREFIX_TIMESTAMP) { + if let Ok(stored_ts) = line.replace(META_LINE_PREFIX_TIMESTAMP, "").parse::() { + *ts = stored_ts; + break; + } + } + } + if *ts == 0 { + return true; + } + + if let Ok(content) = std::fs::read_to_string(dir.join(APP_METADATA_CONFIG)) { + for line in content.lines() { + if line.starts_with(META_LINE_PREFIX_TIMESTAMP) { + if let Ok(stored_ts) = line.replace(META_LINE_PREFIX_TIMESTAMP, "").parse::() { + return *ts == stored_ts; + } + } + } + } + false +} + +fn write_meta(dir: &PathBuf, ts: u64) { + let meta_file = dir.join(APP_METADATA_CONFIG); + if ts != 0 { + let content = format!("{}{}", META_LINE_PREFIX_TIMESTAMP, ts); + // Ignore is ok here + let _ = std::fs::write(meta_file, content); + } +} + fn setup(reader: BinaryReader, dir: Option, clear: bool) -> Option { let dir = if let Some(dir) = dir { dir @@ -24,12 +67,15 @@ fn setup(reader: BinaryReader, dir: Option, clear: bool) -> Option