Add bridge code for app builder

This commit is contained in:
Caelan Sayler
2024-10-16 21:24:28 +01:00
committed by Caelan
parent d04412dcce
commit e3a7b4614a
5 changed files with 125 additions and 33 deletions

View File

@@ -15,7 +15,7 @@ rust-version.workspace = true
[lib] [lib]
path = "src/lib.rs" path = "src/lib.rs"
crate-type = ["cdylib", "staticlib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
cxx.workspace = true cxx.workspace = true

View File

@@ -15,6 +15,27 @@
#if defined(VELOPACK_LIBC_EXPORTS) && defined(_WIN32) #if defined(VELOPACK_LIBC_EXPORTS) && defined(_WIN32)
#define VPKC_EXPORT __declspec(dllexport) #define VPKC_EXPORT __declspec(dllexport)
#pragma comment(linker, "/EXPORT:vpkc_new_update_manager") #pragma comment(linker, "/EXPORT:vpkc_new_update_manager")
#pragma comment(linker, "/EXPORT:vpkc_get_current_version")
#pragma comment(linker, "/EXPORT:vpkc_get_app_id")
#pragma comment(linker, "/EXPORT:vpkc_is_portable")
#pragma comment(linker, "/EXPORT:vpkc_update_pending_restart")
#pragma comment(linker, "/EXPORT:vpkc_download_updates")
#pragma comment(linker, "/EXPORT:vpkc_wait_exit_then_apply_update")
#pragma comment(linker, "/EXPORT:vpkc_app_set_auto_apply_on_startup")
#pragma comment(linker, "/EXPORT:vpkc_app_set_args")
#pragma comment(linker, "/EXPORT:vpkc_app_set_locator")
#pragma comment(linker, "/EXPORT:vpkc_app_set_hook_after_install")
#pragma comment(linker, "/EXPORT:vpkc_app_set_hook_before_uninstall")
#pragma comment(linker, "/EXPORT:vpkc_app_set_hook_before_update")
#pragma comment(linker, "/EXPORT:vpkc_app_set_hook_after_update")
#pragma comment(linker, "/EXPORT:vpkc_app_set_hook_first_run")
#pragma comment(linker, "/EXPORT:vpkc_app_set_hook_restarted")
#pragma comment(linker, "/EXPORT:vpkc_app_run")
#pragma comment(linker, "/EXPORT:vpkc_get_last_error")
#pragma comment(linker, "/EXPORT:vpkc_set_log")
#pragma comment(linker, "/EXPORT:vpkc_free_update_manager")
#pragma comment(linker, "/EXPORT:vpkc_free_update_info")
#pragma comment(linker, "/EXPORT:vpkc_free_asset")
#elif defined(VELOPACK_LIBC_EXPORTS) && !defined(_WIN32) #elif defined(VELOPACK_LIBC_EXPORTS) && !defined(_WIN32)
#define VPKC_EXPORT __attribute__((visibility("default"))) __attribute__((used)) #define VPKC_EXPORT __attribute__((visibility("default"))) __attribute__((used))
#else #else
@@ -69,6 +90,7 @@ typedef struct {
bool IsDowngrade; bool IsDowngrade;
} vpkc_update_info_t; } vpkc_update_info_t;
// Update Manager
VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, const vpkc_options_t* pOptions, const vpkc_locator_t* locator, vpkc_update_manager_t* pManager); VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, const vpkc_options_t* pOptions, const vpkc_locator_t* locator, vpkc_update_manager_t* pManager);
VPKC_EXPORT size_t VPKC_CALL vpkc_get_current_version(vpkc_update_manager_t* pManager, char* pszVersion, size_t cVersion); VPKC_EXPORT size_t VPKC_CALL vpkc_get_current_version(vpkc_update_manager_t* pManager, char* pszVersion, size_t cVersion);
VPKC_EXPORT size_t VPKC_CALL vpkc_get_app_id(vpkc_update_manager_t* pManager, char* pszId, size_t cId); VPKC_EXPORT size_t VPKC_CALL vpkc_get_app_id(vpkc_update_manager_t* pManager, char* pszId, size_t cId);
@@ -78,6 +100,7 @@ VPKC_EXPORT vpkc_update_check_t VPKC_CALL vpkc_check_for_updates(vpkc_update_man
VPKC_EXPORT bool VPKC_CALL vpkc_download_updates(vpkc_update_manager_t* pManager, const vpkc_update_info_t* pUpdate, vpkc_progress_callback_t cbProgress); VPKC_EXPORT bool VPKC_CALL vpkc_download_updates(vpkc_update_manager_t* pManager, const vpkc_update_info_t* pUpdate, vpkc_progress_callback_t cbProgress);
VPKC_EXPORT bool VPKC_CALL vpkc_wait_exit_then_apply_update(vpkc_update_manager_t* pManager, vpkc_asset_t* pAsset, bool bSilent, bool bRestart, char** pRestartArgs, size_t cRestartArgs); VPKC_EXPORT bool VPKC_CALL vpkc_wait_exit_then_apply_update(vpkc_update_manager_t* pManager, vpkc_asset_t* pAsset, bool bSilent, bool bRestart, char** pRestartArgs, size_t cRestartArgs);
// VelopackApp
VPKC_EXPORT void VPKC_CALL vpkc_app_set_auto_apply_on_startup(bool bAutoApply); VPKC_EXPORT void VPKC_CALL vpkc_app_set_auto_apply_on_startup(bool bAutoApply);
VPKC_EXPORT void VPKC_CALL vpkc_app_set_args(char** pArgs, size_t cArgs); VPKC_EXPORT void VPKC_CALL vpkc_app_set_args(char** pArgs, size_t cArgs);
VPKC_EXPORT void VPKC_CALL vpkc_app_set_locator(vpkc_locator_t* pLocator); VPKC_EXPORT void VPKC_CALL vpkc_app_set_locator(vpkc_locator_t* pLocator);
@@ -89,6 +112,7 @@ VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_first_run(vpkc_hook_callback_t cbFi
VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_restarted(vpkc_hook_callback_t cbRestarted); VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_restarted(vpkc_hook_callback_t cbRestarted);
VPKC_EXPORT void VPKC_CALL vpkc_app_run(); VPKC_EXPORT void VPKC_CALL vpkc_app_run();
// Misc functions
VPKC_EXPORT size_t VPKC_CALL vpkc_get_last_error(char* pszError, size_t cError); VPKC_EXPORT size_t VPKC_CALL vpkc_get_last_error(char* pszError, size_t cError);
VPKC_EXPORT void VPKC_CALL vpkc_set_log(vpkc_log_callback_t cbLog); VPKC_EXPORT void VPKC_CALL vpkc_set_log(vpkc_log_callback_t cbLog);
VPKC_EXPORT void VPKC_CALL vpkc_free_update_manager(vpkc_update_manager_t* pManager); VPKC_EXPORT void VPKC_CALL vpkc_free_update_manager(vpkc_update_manager_t* pManager);
@@ -336,7 +360,8 @@ namespace Velopack {
strcpy_s(pRestartArgs[i], restartArgs[i].size() + 1, restartArgs[i].c_str()); strcpy_s(pRestartArgs[i], restartArgs[i].size() + 1, restartArgs[i].c_str());
} }
bool result = vpkc_wait_exit_then_apply_update(&m_pManager, &to_vpkc(asset), silent, restart, pRestartArgs, restartArgs.size()); vpkc_asset_t vpkc_asset = to_vpkc(asset);
bool result = vpkc_wait_exit_then_apply_update(&m_pManager, &vpkc_asset, silent, restart, pRestartArgs, restartArgs.size());
// Free all the memory // Free all the memory
for (size_t i = 0; i < restartArgs.size(); i++) { for (size_t i = 0; i < restartArgs.size(); i++) {

View File

@@ -1,7 +1,65 @@
#include "velopack_libc/include/Velopack.h" #include "velopack_libc/src/lib.rs.h"
#include "velopack_libc/src/bridge.hpp"
VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, const vpkc_options_t* pOptions, const vpkc_locator_t* locator, vpkc_update_manager_t* pManager) // Update Manager
{ VPKC_EXPORT bool VPKC_CALL vpkc_new_update_manager(const char* pszUrlOrString, const vpkc_options_t* pOptions, const vpkc_locator_t* locator, vpkc_update_manager_t* pManager);
return 0; VPKC_EXPORT size_t VPKC_CALL vpkc_get_current_version(vpkc_update_manager_t* pManager, char* pszVersion, size_t cVersion);
} VPKC_EXPORT size_t VPKC_CALL vpkc_get_app_id(vpkc_update_manager_t* pManager, char* pszId, size_t cId);
VPKC_EXPORT bool VPKC_CALL vpkc_is_portable(vpkc_update_manager_t* pManager);
VPKC_EXPORT bool VPKC_CALL vpkc_update_pending_restart(vpkc_update_manager_t* pManager, vpkc_asset_t* pAsset);
VPKC_EXPORT vpkc_update_check_t VPKC_CALL vpkc_check_for_updates(vpkc_update_manager_t* pManager, vpkc_update_info_t* pUpdate);
VPKC_EXPORT bool VPKC_CALL vpkc_download_updates(vpkc_update_manager_t* pManager, const vpkc_update_info_t* pUpdate, vpkc_progress_callback_t cbProgress);
VPKC_EXPORT bool VPKC_CALL vpkc_wait_exit_then_apply_update(vpkc_update_manager_t* pManager, vpkc_asset_t* pAsset, bool bSilent, bool bRestart, char** pRestartArgs, size_t cRestartArgs);
// VelopackApp
bool autoApply = true;
StringArrayOption args{};
LocatorConfigOption locator{};
HookCallbackManager hooks{};
VPKC_EXPORT void VPKC_CALL vpkc_app_set_auto_apply_on_startup(bool bAutoApply) {
autoApply = bAutoApply;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_args(char** pArgs, size_t cArgs) {
args.has_data = true;
args.data.clear();
for (size_t i = 0; i < cArgs; i++) {
args.data.push_back(pArgs[i]);
}
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_locator(vpkc_locator_t* pLocator) {
locator.has_data = true;
locator.data.RootAppDir = pLocator->RootAppDir;
locator.data.UpdateExePath = pLocator->UpdateExePath;
locator.data.PackagesDir = pLocator->PackagesDir;
locator.data.ManifestPath = pLocator->ManifestPath;
locator.data.CurrentBinaryDir = pLocator->CurrentBinaryDir;
locator.data.IsPortable = pLocator->IsPortable;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_after_install(vpkc_hook_callback_t cbAfterInstall) {
hooks.after_install = cbAfterInstall;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_before_uninstall(vpkc_hook_callback_t cbBeforeUninstall) {
hooks.before_uninstall = cbBeforeUninstall;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_before_update(vpkc_hook_callback_t cbBeforeUpdate) {
hooks.before_update = cbBeforeUpdate;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_after_update(vpkc_hook_callback_t cbAfterUpdate) {
hooks.after_update = cbAfterUpdate;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_first_run(vpkc_hook_callback_t cbFirstRun) {
hooks.first_run = cbFirstRun;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_set_hook_restarted(vpkc_hook_callback_t cbRestarted) {
hooks.restarted = cbRestarted;
}
VPKC_EXPORT void VPKC_CALL vpkc_app_run() {
bridge_appbuilder_run(hooks, args, locator, autoApply);
}
// Misc functions
VPKC_EXPORT size_t VPKC_CALL vpkc_get_last_error(char* pszError, size_t cError);
VPKC_EXPORT void VPKC_CALL vpkc_set_log(vpkc_log_callback_t cbLog);
VPKC_EXPORT void VPKC_CALL vpkc_free_update_manager(vpkc_update_manager_t* pManager);
VPKC_EXPORT void VPKC_CALL vpkc_free_update_info(vpkc_update_info_t* pManager);
VPKC_EXPORT void VPKC_CALL vpkc_free_asset(vpkc_asset_t* pManager);

View File

@@ -3,6 +3,13 @@
#include "velopack_libc/include/Velopack.h" #include "velopack_libc/include/Velopack.h"
struct HookCallbackManager { struct HookCallbackManager {
vpkc_hook_callback_t after_install = nullptr;
vpkc_hook_callback_t before_uninstall = nullptr;
vpkc_hook_callback_t before_update = nullptr;
vpkc_hook_callback_t after_update = nullptr;
vpkc_hook_callback_t first_run = nullptr;
vpkc_hook_callback_t restarted = nullptr;
void install_hook(::rust::String app_version) const {}; void install_hook(::rust::String app_version) const {};
void update_hook(::rust::String app_version) const {}; void update_hook(::rust::String app_version) const {};
void obsolete_hook(::rust::String app_version) const {}; void obsolete_hook(::rust::String app_version) const {};

View File

@@ -48,30 +48,30 @@ mod ffi {
pub has_data: bool, pub has_data: bool,
} }
pub struct LocatorConfigDto<'a> { pub struct LocatorConfigDto {
pub RootAppDir: &'a CxxString, pub RootAppDir: String,
pub UpdateExePath: &'a CxxString, pub UpdateExePath: String,
pub PackagesDir: &'a CxxString, pub PackagesDir: String,
pub ManifestPath: &'a CxxString, pub ManifestPath: String,
pub CurrentBinaryDir: &'a CxxString, pub CurrentBinaryDir: String,
pub IsPortable: bool, pub IsPortable: bool,
} }
pub struct LocatorConfigOption<'a> { pub struct LocatorConfigOption {
pub data: LocatorConfigDto<'a>, pub data: LocatorConfigDto,
pub has_data: bool, pub has_data: bool,
} }
pub struct UpdateOptionsDto<'a> { pub struct UpdateOptionsDto {
pub AllowVersionDowngrade: bool, pub AllowVersionDowngrade: bool,
pub ExplicitChannel: &'a CxxString, pub ExplicitChannel: String,
} }
pub struct StringArrayOption { pub struct StringArrayOption {
pub data: Vec<String>, pub data: Vec<String>,
pub has_data: bool, pub has_data: bool,
} }
// C++ types and signatures exposed to Rust. // C++ types and signatures exposed to Rust.
unsafe extern "C++" { unsafe extern "C++" {
include!("velopack_libc/include/Velopack.h"); include!("velopack_libc/include/Velopack.h");
@@ -100,7 +100,7 @@ mod ffi {
fn bridge_check_for_updates(manager: &UpdateManagerOpaque) -> Result<UpdateInfoOption>; fn bridge_check_for_updates(manager: &UpdateManagerOpaque) -> Result<UpdateInfoOption>;
fn bridge_download_update(manager: &UpdateManagerOpaque, to_download: UpdateInfoDto, progress: UniquePtr<DownloadCallbackManager>) -> Result<()>; fn bridge_download_update(manager: &UpdateManagerOpaque, to_download: UpdateInfoDto, progress: UniquePtr<DownloadCallbackManager>) -> Result<()>;
fn bridge_wait_exit_then_apply_update(manager: &UpdateManagerOpaque, to_download: AssetDto, silent: bool, restart: bool, restart_args: Vec<String>) -> Result<()>; fn bridge_wait_exit_then_apply_update(manager: &UpdateManagerOpaque, to_download: AssetDto, silent: bool, restart: bool, restart_args: Vec<String>) -> Result<()>;
fn bridge_appbuilder_run(cb: UniquePtr<HookCallbackManager>, custom_args: StringArrayOption, locator: LocatorConfigOption, auto_apply: bool); unsafe fn bridge_appbuilder_run(cb: &HookCallbackManager, custom_args: &StringArrayOption, locator: &LocatorConfigOption, auto_apply: bool);
fn bridge_set_logger_callback(cb: UniquePtr<LoggerCallbackManager>); fn bridge_set_logger_callback(cb: UniquePtr<LoggerCallbackManager>);
} }
} }
@@ -112,17 +112,17 @@ struct UpdateManagerOpaque {
fn to_locator_config(locator: &ffi::LocatorConfigDto) -> VelopackLocatorConfig { fn to_locator_config(locator: &ffi::LocatorConfigDto) -> VelopackLocatorConfig {
VelopackLocatorConfig { VelopackLocatorConfig {
RootAppDir: PathBuf::from(locator.RootAppDir.to_string_lossy().to_string()), RootAppDir: PathBuf::from(locator.RootAppDir.clone()),
UpdateExePath: PathBuf::from(locator.UpdateExePath.to_string_lossy().to_string()), UpdateExePath: PathBuf::from(locator.UpdateExePath.clone()),
PackagesDir: PathBuf::from(locator.PackagesDir.to_string_lossy().to_string()), PackagesDir: PathBuf::from(locator.PackagesDir.clone()),
ManifestPath: PathBuf::from(locator.ManifestPath.to_string_lossy().to_string()), ManifestPath: PathBuf::from(locator.ManifestPath.clone()),
CurrentBinaryDir: PathBuf::from(locator.CurrentBinaryDir.to_string_lossy().to_string()), CurrentBinaryDir: PathBuf::from(locator.CurrentBinaryDir.clone()),
IsPortable: locator.IsPortable, IsPortable: locator.IsPortable,
} }
} }
fn to_update_options(options: &ffi::UpdateOptionsDto) -> VelopackUpdateOptions { fn to_update_options(options: &ffi::UpdateOptionsDto) -> VelopackUpdateOptions {
let channel = options.ExplicitChannel.to_string_lossy().to_string(); let channel = options.ExplicitChannel.clone();
VelopackUpdateOptions { VelopackUpdateOptions {
AllowVersionDowngrade: options.AllowVersionDowngrade, AllowVersionDowngrade: options.AllowVersionDowngrade,
ExplicitChannel: if channel.is_empty() { None } else { Some(channel) }, ExplicitChannel: if channel.is_empty() { None } else { Some(channel) },
@@ -267,15 +267,16 @@ fn bridge_wait_exit_then_apply_update(manager: &UpdateManagerOpaque, to_download
Ok(()) Ok(())
} }
fn bridge_appbuilder_run(cb: cxx::UniquePtr<ffi::HookCallbackManager>, custom_args: ffi::StringArrayOption, locator: ffi::LocatorConfigOption, auto_apply: bool) { fn bridge_appbuilder_run(cb: &ffi::HookCallbackManager, custom_args: &ffi::StringArrayOption, locator: &ffi::LocatorConfigOption, auto_apply: bool) {
let mut app = VelopackApp::build() let mut app = VelopackApp::build()
.set_auto_apply_on_startup(auto_apply)
.on_first_run(|v| cb.firstrun_hook(v.to_string())) .on_first_run(|v| cb.firstrun_hook(v.to_string()))
.on_restarted(|v| cb.restarted_hook(v.to_string())) .on_restarted(|v| cb.restarted_hook(v.to_string()));
.set_auto_apply_on_startup(auto_apply);
#[cfg(windows)] #[cfg(windows)]
{ {
app = app.on_after_install_fast_callback(|v| cb.install_hook(v.to_string())) app = app
.on_after_install_fast_callback(|v| cb.install_hook(v.to_string()))
.on_after_update_fast_callback(|v| cb.update_hook(v.to_string())) .on_after_update_fast_callback(|v| cb.update_hook(v.to_string()))
.on_before_update_fast_callback(|v| cb.obsolete_hook(v.to_string())) .on_before_update_fast_callback(|v| cb.obsolete_hook(v.to_string()))
.on_before_uninstall_fast_callback(|v| cb.uninstall_hook(v.to_string())); .on_before_uninstall_fast_callback(|v| cb.uninstall_hook(v.to_string()));
@@ -286,13 +287,14 @@ fn bridge_appbuilder_run(cb: cxx::UniquePtr<ffi::HookCallbackManager>, custom_ar
} }
if custom_args.has_data { if custom_args.has_data {
app = app.set_args(custom_args.data); app = app.set_args(custom_args.data.clone());
} }
app.run(); app.run();
} }
struct LoggerImpl {} struct LoggerImpl {}
static LOGGER: LoggerImpl = LoggerImpl {}; static LOGGER: LoggerImpl = LoggerImpl {};
impl Log for LoggerImpl { impl Log for LoggerImpl {
@@ -314,7 +316,7 @@ impl Log for LoggerImpl {
Level::Debug => "debug", Level::Debug => "debug",
Level::Trace => "trace", Level::Trace => "trace",
}.to_string(); }.to_string();
if let Some(cb) = get_logger() { if let Some(cb) = get_logger() {
if let Some(cb) = unsafe { cb.as_mut() } { if let Some(cb) = unsafe { cb.as_mut() } {
cb.log(level, text); cb.log(level, text);
@@ -345,7 +347,7 @@ fn get_logger() -> Option<*mut ffi::LoggerCallbackManager> {
fn bridge_set_logger_callback(cb: cxx::UniquePtr<ffi::LoggerCallbackManager>) { fn bridge_set_logger_callback(cb: cxx::UniquePtr<ffi::LoggerCallbackManager>) {
let _ = log::set_logger(&LOGGER); let _ = log::set_logger(&LOGGER);
log::set_max_level(log::LevelFilter::Trace); log::set_max_level(log::LevelFilter::Trace);
let cb = cb.into_raw(); let cb = cb.into_raw();
store_logger(cb); store_logger(cb);
} }