mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
add more rust/node functions
This commit is contained in:
84
Cargo.lock
generated
84
Cargo.lock
generated
@@ -269,6 +269,15 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blocking"
|
name = "blocking"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
@@ -474,6 +483,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
@@ -489,6 +507,16 @@ version = "0.8.20"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cvt"
|
name = "cvt"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -545,6 +573,16 @@ version = "0.1.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
@@ -807,6 +845,16 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -1677,12 +1725,34 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1_smol"
|
name = "sha1_smol"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
|
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -1963,6 +2033,12 @@ dependencies = [
|
|||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.15"
|
version = "0.3.15"
|
||||||
@@ -2044,6 +2120,8 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha1",
|
||||||
|
"sha2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"ts-rs",
|
"ts-rs",
|
||||||
"ureq",
|
"ureq",
|
||||||
@@ -2114,6 +2192,12 @@ dependencies = [
|
|||||||
"velopack",
|
"velopack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "versions"
|
name = "versions"
|
||||||
version = "5.0.1"
|
version = "5.0.1"
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ file-rotate = "0.7"
|
|||||||
simple-stopwatch = "0.1"
|
simple-stopwatch = "0.1"
|
||||||
enum-flags = "0.3"
|
enum-flags = "0.3"
|
||||||
remove_dir_all = { git = "https://github.com/caesay/remove_dir_all.git", features = ["log"] }
|
remove_dir_all = { git = "https://github.com/caesay/remove_dir_all.git", features = ["log"] }
|
||||||
|
sha1 = "0.10"
|
||||||
|
sha2 = "0.10"
|
||||||
sha1_smol = "1.0"
|
sha1_smol = "1.0"
|
||||||
time = "0.3"
|
time = "0.3"
|
||||||
os_info = "3.8"
|
os_info = "3.8"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { app, BrowserWindow, ipcMain } from 'electron';
|
import { app, BrowserWindow } from 'electron';
|
||||||
import { VelopackApp } from "velopack";
|
import { VelopackApp } from "velopack";
|
||||||
import { initializeUpdates } from "./update"
|
import { initializeUpdates } from "./update"
|
||||||
// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
|
// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
|
||||||
@@ -13,7 +13,7 @@ VelopackApp.build()
|
|||||||
.setLogger((lvl, msg) => console.log(`Velopack [${lvl}] ${msg}`))
|
.setLogger((lvl, msg) => console.log(`Velopack [${lvl}] ${msg}`))
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
// configure IPC listener for update messages
|
// Configure IPC listener for Velopack update messages
|
||||||
initializeUpdates();
|
initializeUpdates();
|
||||||
|
|
||||||
const createWindow = (): void => {
|
const createWindow = (): void => {
|
||||||
@@ -48,11 +48,6 @@ app.on('window-all-closed', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Respond to quit messages from the render
|
|
||||||
ipcMain.on("exit-request", () => {
|
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
// On OS X it's common to re-create a window in the app when the
|
// On OS X it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ strum.workspace = true
|
|||||||
derivative.workspace = true
|
derivative.workspace = true
|
||||||
glob.workspace = true
|
glob.workspace = true
|
||||||
remove_dir_all.workspace = true
|
remove_dir_all.workspace = true
|
||||||
sha1_smol.workspace = true
|
|
||||||
time.workspace = true
|
time.workspace = true
|
||||||
os_info.workspace = true
|
os_info.workspace = true
|
||||||
bitflags.workspace = true
|
bitflags.workspace = true
|
||||||
@@ -111,6 +110,7 @@ filelocksmith.workspace = true
|
|||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
ntest.workspace = true
|
ntest.workspace = true
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
|
sha1_smol.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
semver.workspace = true
|
semver.workspace = true
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::shared::{self, OperationWait};
|
use crate::shared::{self, OperationWait};
|
||||||
use velopack::{locator::VelopackLocator, constants};
|
use velopack::{locator, locator::VelopackLocator, constants};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ pub fn apply<'a>(
|
|||||||
shared::operation_wait(wait);
|
shared::operation_wait(wait);
|
||||||
|
|
||||||
let packages_dir = locator.get_packages_dir();
|
let packages_dir = locator.get_packages_dir();
|
||||||
let package = package.cloned().or_else(|| shared::find_latest_full_package(&packages_dir).map(|x| x.0));
|
let package = package.cloned().or_else(|| locator::find_latest_full_package(&packages_dir).map(|x| x.0));
|
||||||
|
|
||||||
match package {
|
match package {
|
||||||
Some(package) => {
|
Some(package) => {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use std::{
|
|||||||
process::Command as Process,
|
process::Command as Process,
|
||||||
};
|
};
|
||||||
use velopack::{bundle::Manifest, constants};
|
use velopack::{bundle::Manifest, constants};
|
||||||
use velopack::locator::{auto_locate_app_manifest, create_config_from_root_dir, LocationContext, VelopackLocator};
|
use velopack::locator::{self, LocationContext, VelopackLocator};
|
||||||
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
|
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
|
||||||
|
|
||||||
enum LocatorResult
|
enum LocatorResult
|
||||||
@@ -62,7 +62,7 @@ impl LocatorResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn legacy_locator() -> Result<LocatorResult> {
|
fn legacy_locator() -> Result<LocatorResult> {
|
||||||
let locator = auto_locate_app_manifest(LocationContext::IAmUpdateExe);
|
let locator = locator::auto_locate_app_manifest(LocationContext::IAmUpdateExe);
|
||||||
match locator {
|
match locator {
|
||||||
Ok(locator) => Ok(LocatorResult::Normal(locator)),
|
Ok(locator) => Ok(LocatorResult::Normal(locator)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -70,7 +70,7 @@ fn legacy_locator() -> Result<LocatorResult> {
|
|||||||
let my_exe = std::env::current_exe()?;
|
let my_exe = std::env::current_exe()?;
|
||||||
let parent_dir = my_exe.parent().expect("Unable to determine parent directory");
|
let parent_dir = my_exe.parent().expect("Unable to determine parent directory");
|
||||||
let packages_dir = parent_dir.join("packages");
|
let packages_dir = parent_dir.join("packages");
|
||||||
if let Some((path, manifest)) = shared::find_latest_full_package(&packages_dir) {
|
if let Some((path, manifest)) = locator::find_latest_full_package(&packages_dir) {
|
||||||
info!("Found full package to read: {}", path.to_string_lossy());
|
info!("Found full package to read: {}", path.to_string_lossy());
|
||||||
Ok(LocatorResult::Legacy(parent_dir.to_path_buf(), manifest))
|
Ok(LocatorResult::Legacy(parent_dir.to_path_buf(), manifest))
|
||||||
} else {
|
} else {
|
||||||
@@ -148,9 +148,9 @@ fn try_legacy_migration(root_dir: &PathBuf, manifest: &Manifest) -> Result<Velop
|
|||||||
std::env::set_current_dir(&root_dir)?;
|
std::env::set_current_dir(&root_dir)?;
|
||||||
|
|
||||||
let _mutex = shared::retry_io(|| crate::windows::create_global_mutex(&manifest.id))?;
|
let _mutex = shared::retry_io(|| crate::windows::create_global_mutex(&manifest.id))?;
|
||||||
let path_config = create_config_from_root_dir(root_dir);
|
let path_config = locator::create_config_from_root_dir(root_dir);
|
||||||
|
|
||||||
let package = shared::find_latest_full_package(&path_config.PackagesDir).ok_or_else(|| anyhow!("Unable to find latest full package."))?;
|
let package = locator::find_latest_full_package(&path_config.PackagesDir).ok_or_else(|| anyhow!("Unable to find latest full package."))?;
|
||||||
|
|
||||||
warn!("This application is installed in a folder prefixed with 'app-'. Attempting to migrate...");
|
warn!("This application is installed in a folder prefixed with 'app-'. Attempting to migrate...");
|
||||||
let _ = shared::force_stop_package(&root_dir);
|
let _ = shared::force_stop_package(&root_dir);
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ use anyhow::{anyhow, Result};
|
|||||||
use rand::distributions::{Alphanumeric, DistString};
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{path::Path, thread, time::Duration};
|
use std::{path::Path, thread, time::Duration};
|
||||||
use std::path::PathBuf;
|
|
||||||
use velopack::bundle::{load_bundle_from_file, Manifest};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum OperationWait {
|
pub enum OperationWait {
|
||||||
@@ -26,30 +24,6 @@ pub fn operation_wait(wait: OperationWait) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_latest_full_package(packages_dir: &PathBuf) -> Option<(PathBuf, Manifest)> {
|
|
||||||
let packages_dir = packages_dir.to_string_lossy();
|
|
||||||
|
|
||||||
info!("Attempting to auto-detect package in: {}", packages_dir);
|
|
||||||
let mut package: Option<(PathBuf, Manifest)> = None;
|
|
||||||
|
|
||||||
if let Ok(paths) = glob::glob(format!("{}/*.nupkg", packages_dir).as_str()) {
|
|
||||||
for path in paths {
|
|
||||||
if let Ok(path) = path {
|
|
||||||
trace!("Checking package: '{}'", path.to_string_lossy());
|
|
||||||
if let Ok(mut bun) = load_bundle_from_file(&path) {
|
|
||||||
if let Ok(mani) = bun.read_manifest() {
|
|
||||||
if package.is_none() || mani.version > package.clone().unwrap().1.version {
|
|
||||||
info!("Found {}: '{}'", mani.version, path.to_string_lossy());
|
|
||||||
package = Some((path, mani));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
package
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retry_io<F, T, E>(op: F) -> Result<T, E>
|
pub fn retry_io<F, T, E>(op: F) -> Result<T, E>
|
||||||
where
|
where
|
||||||
F: Fn() -> Result<T, E>,
|
F: Fn() -> Result<T, E>,
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ declare module "./load" {
|
|||||||
|
|
||||||
function js_get_current_version(um: UpdateManagerOpaque): string;
|
function js_get_current_version(um: UpdateManagerOpaque): string;
|
||||||
|
|
||||||
// function js_get_app_id(um: UpdateManagerOpaque): string;
|
function js_get_app_id(um: UpdateManagerOpaque): string;
|
||||||
// function js_is_portable(um: UpdateManagerOpaque): boolean;
|
|
||||||
// function js_is_installed(um: UpdateManagerOpaque): boolean;
|
function js_is_portable(um: UpdateManagerOpaque): boolean;
|
||||||
// function js_is_update_pending_restart(um: UpdateManagerOpaque): boolean;
|
|
||||||
|
function js_update_pending_restart(um: UpdateManagerOpaque): UpdateInfo | null;
|
||||||
|
|
||||||
function js_check_for_updates_async(
|
function js_check_for_updates_async(
|
||||||
um: UpdateManagerOpaque,
|
um: UpdateManagerOpaque,
|
||||||
@@ -146,14 +147,6 @@ export class VelopackApp {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a custom logger callback to receive log messages from Velopack. The default behavior is to log to console.log.
|
|
||||||
*/
|
|
||||||
setLogger(callback: (loglevel: LogLevel, msg: string) => void): VelopackApp {
|
|
||||||
addon.js_set_logger_callback(callback);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the Velopack startup logic. This should be the first thing to run in your app.
|
* Runs the Velopack startup logic. This should be the first thing to run in your app.
|
||||||
* In some circumstances it may terminate/restart the process to perform tasks.
|
* In some circumstances it may terminate/restart the process to perform tasks.
|
||||||
@@ -194,21 +187,28 @@ export class UpdateManager {
|
|||||||
return addon.js_get_current_version(this.opaque);
|
return addon.js_get_current_version(this.opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAppId(): string {
|
/**
|
||||||
// return addon.js_get_app_id.call(this.opaque);
|
* Returns the currently installed app id.
|
||||||
// }
|
*/
|
||||||
|
getAppId(): string {
|
||||||
|
return addon.js_get_app_id.call(this.opaque);
|
||||||
|
}
|
||||||
|
|
||||||
// isInstalled(): boolean {
|
/**
|
||||||
// return addon.js_is_installed.call(this.opaque);
|
* Returns whether the app is in portable mode. On Windows this can be true or false.
|
||||||
// }
|
* On MacOS and Linux this will always be true.
|
||||||
|
*/
|
||||||
|
isPortable(): boolean {
|
||||||
|
return addon.js_is_portable.call(this.opaque);
|
||||||
|
}
|
||||||
|
|
||||||
// isPortable(): boolean {
|
/**
|
||||||
// return addon.js_is_portable.call(this.opaque);
|
* Returns an UpdateInfo object if there is an update downloaded which still needs to be applied.
|
||||||
// }
|
* You can pass the UpdateInfo object to waitExitThenApplyUpdate to apply the update.
|
||||||
|
*/
|
||||||
// isUpdatePendingRestart(): boolean {
|
getUpdatePendingRestart(): UpdateInfo | null {
|
||||||
// return addon.js_is_update_pending_restart.call(this.opaque);
|
return addon.js_update_pending_restart.call(this.opaque);
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for updates, returning None if there are none available. If there are updates available, this method will return an
|
* Checks for updates, returning None if there are none available. If there are updates available, this method will return an
|
||||||
@@ -271,3 +271,10 @@ export class UpdateManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a custom logger callback to receive log messages from Velopack. The default behavior is to log to console.log.
|
||||||
|
*/
|
||||||
|
export function setVelopackLogger(callback: (loglevel: LogLevel, msg: string) => void) {
|
||||||
|
addon.js_set_logger_callback(callback);
|
||||||
|
}
|
||||||
@@ -68,10 +68,41 @@ fn js_new_update_manager(mut cx: FunctionContext) -> JsResult<BoxedUpdateManager
|
|||||||
fn js_get_current_version(mut cx: FunctionContext) -> JsResult<JsString> {
|
fn js_get_current_version(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||||
let mgr_boxed = cx.argument::<BoxedUpdateManager>(0)?;
|
let mgr_boxed = cx.argument::<BoxedUpdateManager>(0)?;
|
||||||
let mgr_ref = &mgr_boxed.borrow().manager;
|
let mgr_ref = &mgr_boxed.borrow().manager;
|
||||||
let version = mgr_ref.current_version().or_else(|e| cx.throw_error(e.to_string()))?;
|
let version = mgr_ref.get_current_version();
|
||||||
Ok(cx.string(version))
|
Ok(cx.string(version))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn js_get_app_id(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||||
|
let mgr_boxed = cx.argument::<BoxedUpdateManager>(0)?;
|
||||||
|
let mgr_ref = &mgr_boxed.borrow().manager;
|
||||||
|
let id = mgr_ref.get_app_id();
|
||||||
|
Ok(cx.string(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn js_is_portable(mut cx: FunctionContext) -> JsResult<JsBoolean> {
|
||||||
|
let mgr_boxed = cx.argument::<BoxedUpdateManager>(0)?;
|
||||||
|
let mgr_ref = &mgr_boxed.borrow().manager;
|
||||||
|
let is_portable = mgr_ref.get_is_portable();
|
||||||
|
Ok(cx.boolean(is_portable))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn js_update_pending_restart(mut cx: FunctionContext) -> JsResult<JsValue> {
|
||||||
|
let mgr_boxed = cx.argument::<BoxedUpdateManager>(0)?;
|
||||||
|
let mgr_ref = &mgr_boxed.borrow().manager;
|
||||||
|
let pending_restart = mgr_ref.get_update_pending_restart();
|
||||||
|
|
||||||
|
if let Some(asset) = pending_restart {
|
||||||
|
let json = serde_json::to_string(&asset);
|
||||||
|
match json {
|
||||||
|
Ok(json) => Ok(cx.string(json).upcast()),
|
||||||
|
Err(e) => cx.throw_error(e.to_string()),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let nil = cx.null().upcast();
|
||||||
|
Ok(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn js_check_for_updates_async(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
fn js_check_for_updates_async(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
let mgr_boxed = cx.argument::<BoxedUpdateManager>(0)?;
|
let mgr_boxed = cx.argument::<BoxedUpdateManager>(0)?;
|
||||||
let mgr_ref = &mgr_boxed.borrow().manager;
|
let mgr_ref = &mgr_boxed.borrow().manager;
|
||||||
@@ -254,10 +285,9 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
|||||||
|
|
||||||
cx.export_function("js_new_update_manager", js_new_update_manager)?;
|
cx.export_function("js_new_update_manager", js_new_update_manager)?;
|
||||||
cx.export_function("js_get_current_version", js_get_current_version)?;
|
cx.export_function("js_get_current_version", js_get_current_version)?;
|
||||||
// cx.export_function("js_get_app_id", js_get_app_id)?;
|
cx.export_function("js_get_app_id", js_get_app_id)?;
|
||||||
// cx.export_function("js_is_portable", js_is_portable)?;
|
cx.export_function("js_is_portable", js_is_portable)?;
|
||||||
// cx.export_function("js_is_installed", js_is_installed)?;
|
cx.export_function("js_update_pending_restart", js_update_pending_restart)?;
|
||||||
// cx.export_function("js_is_update_pending_restart", js_is_update_pending_restart)?;
|
|
||||||
cx.export_function("js_check_for_updates_async", js_check_for_updates_async)?;
|
cx.export_function("js_check_for_updates_async", js_check_for_updates_async)?;
|
||||||
cx.export_function("js_download_update_async", js_download_update_async)?;
|
cx.export_function("js_download_update_async", js_download_update_async)?;
|
||||||
cx.export_function("js_wait_exit_then_apply_update", js_wait_exit_then_apply_update)?;
|
cx.export_function("js_wait_exit_then_apply_update", js_wait_exit_then_apply_update)?;
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ normpath.workspace = true
|
|||||||
bitflags.workspace = true
|
bitflags.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
native-tls.workspace = true
|
native-tls.workspace = true
|
||||||
|
sha1.workspace = true
|
||||||
|
sha2.workspace = true
|
||||||
|
|
||||||
# typescript
|
# typescript
|
||||||
ts-rs = { workspace = true, optional = true }
|
ts-rs = { workspace = true, optional = true }
|
||||||
|
|||||||
@@ -355,6 +355,8 @@ pub struct Manifest {
|
|||||||
pub channel: String,
|
pub channel: String,
|
||||||
pub shortcut_locations: String,
|
pub shortcut_locations: String,
|
||||||
pub shortcut_amuid: String,
|
pub shortcut_amuid: String,
|
||||||
|
pub release_notes: String,
|
||||||
|
pub release_notes_html: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse manifest object from an XML string.
|
/// Parse manifest object from an XML string.
|
||||||
@@ -399,6 +401,10 @@ pub fn read_manifest_from_string(xml: &str) -> Result<Manifest, Error> {
|
|||||||
obj.shortcut_locations = text;
|
obj.shortcut_locations = text;
|
||||||
} else if el_name == "shortcutAmuid" {
|
} else if el_name == "shortcutAmuid" {
|
||||||
obj.shortcut_amuid = text;
|
obj.shortcut_amuid = text;
|
||||||
|
} else if el_name == "releaseNotes" {
|
||||||
|
obj.release_notes = text;
|
||||||
|
} else if el_name == "releaseNotesHtml" {
|
||||||
|
obj.release_notes_html = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(XmlEvent::EndElement { .. }) => {
|
Ok(XmlEvent::EndElement { .. }) => {
|
||||||
|
|||||||
@@ -482,3 +482,27 @@ fn read_current_manifest(nuspec_path: &PathBuf) -> Result<Manifest, Error> {
|
|||||||
Err(Error::MissingNuspec)
|
Err(Error::MissingNuspec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the path and manifest of the latest full package in the given directory.
|
||||||
|
pub fn find_latest_full_package(packages_dir: &PathBuf) -> Option<(PathBuf, Manifest)> {
|
||||||
|
let packages_dir = packages_dir.to_string_lossy();
|
||||||
|
|
||||||
|
info!("Attempting to auto-detect package in: {}", packages_dir);
|
||||||
|
let mut package: Option<(PathBuf, Manifest)> = None;
|
||||||
|
|
||||||
|
if let Ok(paths) = glob::glob(format!("{}/*.nupkg", packages_dir).as_str()) {
|
||||||
|
for path in paths {
|
||||||
|
if let Ok(path) = path {
|
||||||
|
trace!("Checking package: '{}'", path.to_string_lossy());
|
||||||
|
if let Ok(mut bun) = bundle::load_bundle_from_file(&path) {
|
||||||
|
if let Ok(mani) = bun.read_manifest() {
|
||||||
|
if package.is_none() || mani.version > package.clone().unwrap().1.version {
|
||||||
|
info!("Found {}: '{}'", mani.version, path.to_string_lossy());
|
||||||
|
package = Some((path, mani));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
package
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ use semver::Version;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
locator::{self, VelopackLocatorConfig},
|
locator::{self, VelopackLocatorConfig, LocationContext, VelopackLocator},
|
||||||
sources::UpdateSource,
|
sources::UpdateSource,
|
||||||
Error,
|
Error,
|
||||||
|
util,
|
||||||
};
|
};
|
||||||
use crate::locator::{auto_locate_app_manifest, LocationContext, VelopackLocator};
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
@@ -140,7 +140,7 @@ impl UpdateManager {
|
|||||||
let manifest = config.load_manifest()?;
|
let manifest = config.load_manifest()?;
|
||||||
VelopackLocator::new(config.clone(), manifest)
|
VelopackLocator::new(config.clone(), manifest)
|
||||||
} else {
|
} else {
|
||||||
auto_locate_app_manifest(LocationContext::FromCurrentExe)?
|
locator::auto_locate_app_manifest(LocationContext::FromCurrentExe)?
|
||||||
};
|
};
|
||||||
Ok(UpdateManager {
|
Ok(UpdateManager {
|
||||||
options: options.unwrap_or_default(),
|
options: options.unwrap_or_default(),
|
||||||
@@ -160,8 +160,42 @@ impl UpdateManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The currently installed app version.
|
/// The currently installed app version.
|
||||||
pub fn current_version(&self) -> Result<String, Error> {
|
pub fn get_current_version(&self) -> String {
|
||||||
Ok(self.locator.get_manifest_version_full_string())
|
self.locator.get_manifest_version_full_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The currently installed app id.
|
||||||
|
pub fn get_app_id(&self) -> String {
|
||||||
|
self.locator.get_manifest_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the app is in portable mode. This can be true or false on Windows.
|
||||||
|
/// On Linux and MacOS, this will always return true.
|
||||||
|
pub fn get_is_portable(&self) -> bool {
|
||||||
|
self.locator.get_is_portable()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns None if there is no local package waiting to be applied. Returns a VelopackAsset
|
||||||
|
/// if there is an update downloaded which has not yet been applied. In that case, the
|
||||||
|
/// VelopackAsset can be applied by calling apply_updates_and_restart or wait_exit_then_apply_updates.
|
||||||
|
pub fn get_update_pending_restart(&self) -> Option<VelopackAsset> {
|
||||||
|
let packages_dir = self.locator.get_packages_dir();
|
||||||
|
if let Some((path, manifest)) = locator::find_latest_full_package(&packages_dir) {
|
||||||
|
if manifest.version > self.locator.get_manifest_version() {
|
||||||
|
return Some(VelopackAsset {
|
||||||
|
PackageId: manifest.id,
|
||||||
|
Version: manifest.version.to_string(),
|
||||||
|
Type: "Full".to_string(),
|
||||||
|
FileName: path.file_name().unwrap().to_string_lossy().to_string(),
|
||||||
|
SHA1: util::calculate_file_sha1(&path).unwrap_or_default(),
|
||||||
|
SHA256: util::calculate_file_sha256(&path).unwrap_or_default(),
|
||||||
|
Size: path.metadata().map(|m| m.len()).unwrap_or(0),
|
||||||
|
NotesMarkdown: manifest.release_notes,
|
||||||
|
NotesHtml: manifest.release_notes_html,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a list of available remote releases from the package source.
|
/// Get a list of available remote releases from the package source.
|
||||||
@@ -252,7 +286,7 @@ impl UpdateManager {
|
|||||||
pub fn download_updates(&self, update: &UpdateInfo, progress: Option<Sender<i16>>) -> Result<(), Error> {
|
pub fn download_updates(&self, update: &UpdateInfo, progress: Option<Sender<i16>>) -> Result<(), Error> {
|
||||||
let name = &update.TargetFullRelease.FileName;
|
let name = &update.TargetFullRelease.FileName;
|
||||||
let packages_dir = &self.locator.get_packages_dir();
|
let packages_dir = &self.locator.get_packages_dir();
|
||||||
|
|
||||||
fs::create_dir_all(packages_dir)?;
|
fs::create_dir_all(packages_dir)?;
|
||||||
let target_file = packages_dir.join(name);
|
let target_file = packages_dir.join(name);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
use crate::Error;
|
||||||
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
|
use sha2::Digest;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::Path;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use rand::distributions::{Alphanumeric, DistString};
|
|
||||||
|
|
||||||
pub fn retry_io<F, T, E>(op: F) -> Result<T, E>
|
pub fn retry_io<F, T, E>(op: F) -> Result<T, E>
|
||||||
where
|
where
|
||||||
@@ -36,4 +40,20 @@ where
|
|||||||
|
|
||||||
pub fn random_string(len: usize) -> String {
|
pub fn random_string(len: usize) -> String {
|
||||||
Alphanumeric.sample_string(&mut rand::thread_rng(), len)
|
Alphanumeric.sample_string(&mut rand::thread_rng(), len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate_file_sha256<P: AsRef<Path>>(file: P) -> Result<String, Error> {
|
||||||
|
let mut file = File::open(file)?;
|
||||||
|
let mut sha256 = sha2::Sha256::new();
|
||||||
|
std::io::copy(&mut file, &mut sha256)?;
|
||||||
|
let hash = sha256.finalize();
|
||||||
|
Ok(format!("{:x}", hash))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate_file_sha1<P: AsRef<Path>>(file: P) -> Result<String, Error> {
|
||||||
|
let mut file = File::open(file)?;
|
||||||
|
let mut sha1o = sha1::Sha1::new();
|
||||||
|
std::io::copy(&mut file, &mut sha1o)?;
|
||||||
|
let hash = sha1o.finalize();
|
||||||
|
Ok(format!("{:x}", hash))
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user