mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Add support for custom update sources in the C++ library
This commit is contained in:
committed by
Caelan
parent
8ac4f68467
commit
304eac3b71
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2123,6 +2123,7 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"serde_json",
|
||||||
"velopack",
|
"velopack",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ anyhow.workspace = true
|
|||||||
lazy_static.workspace = true
|
lazy_static.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
libc.workspace = true
|
libc.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cbindgen.workspace = true
|
cbindgen.workspace = true
|
||||||
@@ -175,6 +175,30 @@ bool vpkc_new_update_manager(const char *psz_url_or_path,
|
|||||||
struct vpkc_locator_config_t *p_locator,
|
struct vpkc_locator_config_t *p_locator,
|
||||||
vpkc_update_manager_t **p_manager);
|
vpkc_update_manager_t **p_manager);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new UpdateManager instance.
|
||||||
|
* @param options Optional extra configuration for update manager.
|
||||||
|
* @param locator Override the default locator configuration (usually used for testing / mocks).
|
||||||
|
* @param callback to override the default update source
|
||||||
|
* (AutoSource). Retrieve the list of available remote releases from
|
||||||
|
* the package source. These releases can subsequently be downloaded
|
||||||
|
* with cb_download_release_entry.
|
||||||
|
* @param callback to override the default update source
|
||||||
|
* (AutoSource). Download the specified VelopackAsset to the provided
|
||||||
|
* local file path.
|
||||||
|
* @param parameter to the callbacks to override the default update
|
||||||
|
* source (AutoSource). It's the user's responsibilty to ensure that
|
||||||
|
* it's safe to send and share it across threads
|
||||||
|
*/
|
||||||
|
bool vpkc_new_custom_update_manager(const char *(*cb_get_release_feed)(const char*, void*),
|
||||||
|
bool (*cb_download_release_entry)(const char*,
|
||||||
|
const char*,
|
||||||
|
void*),
|
||||||
|
void *p_user_data,
|
||||||
|
struct vpkc_update_options_t *p_options,
|
||||||
|
struct vpkc_locator_config_t *p_locator,
|
||||||
|
vpkc_update_manager_t **p_manager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the currently installed version of the app.
|
* Returns the currently installed version of the app.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "Velopack.h"
|
#include "Velopack.h"
|
||||||
|
|
||||||
@@ -333,12 +334,31 @@ public:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface override the default update source
|
||||||
|
* (AutoSource)
|
||||||
|
*/
|
||||||
|
class IUpdateSource {
|
||||||
|
public:
|
||||||
|
/** @param Retrieve the list of available remote releases from
|
||||||
|
* the package source. These releases can subsequently be downloaded
|
||||||
|
* with DownloadReleaseEntry().
|
||||||
|
*/
|
||||||
|
virtual const char* GetReleaseFeed(const char* releasesName) = 0;
|
||||||
|
|
||||||
|
/** @param Download the specified VelopackAsset to the provided local file path.
|
||||||
|
*/
|
||||||
|
virtual bool DownloadReleaseEntry(const char* assetFileName, const char* localFilePath) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides functionality for checking for updates, downloading updates, and applying updates to the current application.
|
* Provides functionality for checking for updates, downloading updates, and applying updates to the current application.
|
||||||
*/
|
*/
|
||||||
class UpdateManager {
|
class UpdateManager {
|
||||||
private:
|
private:
|
||||||
vpkc_update_manager_t* m_pManager = 0;
|
vpkc_update_manager_t* m_pManager = 0;
|
||||||
|
std::unique_ptr<IUpdateSource> m_pUpdateSource;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a new UpdateManager instance.
|
* Create a new UpdateManager instance.
|
||||||
@@ -366,6 +386,42 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new UpdateManager instance.
|
||||||
|
* @param pUpdateSource Custom update source implementation.
|
||||||
|
* @param options Optional extra configuration for update manager.
|
||||||
|
* @param locator Override the default locator configuration (usually used for testing / mocks).
|
||||||
|
*/
|
||||||
|
UpdateManager(std::unique_ptr<IUpdateSource> pUpdateSource, const UpdateOptions* options = nullptr, const VelopackLocatorConfig* locator = nullptr) {
|
||||||
|
vpkc_update_options_t* pOptions = nullptr;
|
||||||
|
if (options != nullptr) {
|
||||||
|
vpkc_update_options_t vpkc_options = to_c(*options);
|
||||||
|
pOptions = &vpkc_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
vpkc_locator_config_t* pLocator = nullptr;
|
||||||
|
if (locator != nullptr) {
|
||||||
|
vpkc_locator_config_t vpkc_locator = to_c(*locator);
|
||||||
|
pLocator = &vpkc_locator;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cbGetReleaseFeed = [](const char* releasesName, void* userData) {
|
||||||
|
IUpdateSource* source = reinterpret_cast<IUpdateSource*>(userData);
|
||||||
|
return source->GetReleaseFeed(releasesName);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto cbDownloadReleaseEntry = [](const char* assetFileName, const char* localFilePath, void* userData) {
|
||||||
|
IUpdateSource* source = reinterpret_cast<IUpdateSource*>(userData);
|
||||||
|
return source->DownloadReleaseEntry(assetFileName, localFilePath);
|
||||||
|
};
|
||||||
|
|
||||||
|
m_pUpdateSource.swap(pUpdateSource);
|
||||||
|
|
||||||
|
if (!vpkc_new_custom_update_manager(cbGetReleaseFeed, cbDownloadReleaseEntry, m_pUpdateSource.get(), pOptions, pLocator, &m_pManager)) {
|
||||||
|
throw_last_error();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor for UpdateManager.
|
* Destructor for UpdateManager.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ use types::*;
|
|||||||
|
|
||||||
use anyhow::{anyhow, bail};
|
use anyhow::{anyhow, bail};
|
||||||
use libc::{c_char, c_void, size_t};
|
use libc::{c_char, c_void, size_t};
|
||||||
use std::ffi::CString;
|
use std::{sync::mpsc::Sender, ffi::{CStr, CString}};
|
||||||
use velopack::{sources, Error as VelopackError, UpdateCheck, UpdateManager, VelopackApp};
|
use velopack::{bundle, sources, Error as VelopackError, UpdateCheck, UpdateManager, VelopackApp, VelopackAsset, VelopackAssetFeed};
|
||||||
|
|
||||||
/// Create a new UpdateManager instance.
|
/// Create a new UpdateManager instance.
|
||||||
/// @param urlOrPath Location of the update server or path to the local update directory.
|
/// @param urlOrPath Location of the update server or path to the local update directory.
|
||||||
@@ -35,6 +35,95 @@ pub extern "C" fn vpkc_new_update_manager(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// Retrieves available updates using a custom method. This is
|
||||||
|
/// intended to be used from C and C++ code when `AutoSource` is
|
||||||
|
/// inadequate.
|
||||||
|
struct CCallbackUpdateSource {
|
||||||
|
/// Opaque data that's passed to the callbacks
|
||||||
|
p_user_data: *mut c_void,
|
||||||
|
/// Callback function that returns the requrested asset feed JSON as a string
|
||||||
|
cb_get_release_feed: extern "C" fn(psz_releases_name: *const c_char, p_user_data: *mut c_void) -> *const c_char,
|
||||||
|
/// Callback function that downloads the requested asset file to a local path
|
||||||
|
cb_download_release_entry: extern "C" fn(psz_asset_file_name: *const c_char, psz_local_file: *const c_char, p_user_data: *mut c_void) -> bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for CCallbackUpdateSource {}
|
||||||
|
unsafe impl Sync for CCallbackUpdateSource {}
|
||||||
|
|
||||||
|
impl sources::UpdateSource for CCallbackUpdateSource {
|
||||||
|
fn get_release_feed(&self, channel: &str, _: &bundle::Manifest) -> Result<VelopackAssetFeed, VelopackError> {
|
||||||
|
let releases_name = format!("releases.{}.json", channel);
|
||||||
|
let releases_name_cstr = CString::new(releases_name).unwrap();
|
||||||
|
let json_cstr_ptr = (self.cb_get_release_feed)(releases_name_cstr.as_ptr(), self.p_user_data);
|
||||||
|
if json_cstr_ptr.is_null() {
|
||||||
|
Err(VelopackError::Generic("Failed to fetch releases JSON".to_owned()))
|
||||||
|
} else {
|
||||||
|
let json_cstr = unsafe { CStr::from_ptr(json_cstr_ptr) };
|
||||||
|
let feed: VelopackAssetFeed = serde_json::from_str(json_cstr.to_str().unwrap())?;
|
||||||
|
Ok(feed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn download_release_entry(&self, asset: &VelopackAsset, local_file: &str, progress_sender: Option<Sender<i16>>) -> Result<(), VelopackError> {
|
||||||
|
if let Some(progress_sender) = &progress_sender {
|
||||||
|
let _ = progress_sender.send(50);
|
||||||
|
}
|
||||||
|
let asset_file_name_cstr = CString::new(asset.FileName.as_str()).unwrap();
|
||||||
|
let local_file_cstr = CString::new(local_file).unwrap();
|
||||||
|
let success = (self.cb_download_release_entry)(asset_file_name_cstr.as_ptr(), local_file_cstr.as_ptr(), self.p_user_data);
|
||||||
|
if success {
|
||||||
|
if let Some(progress_sender) = &progress_sender {
|
||||||
|
let _ = progress_sender.send(100);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(VelopackError::Generic("Failed to download asset file".to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_boxed(&self) -> Box<dyn sources::UpdateSource> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Create a new UpdateManager instance.
|
||||||
|
/// @param options Optional extra configuration for update manager.
|
||||||
|
/// @param locator Override the default locator configuration (usually used for testing / mocks).
|
||||||
|
/// @param callback to override the default update source
|
||||||
|
/// (AutoSource). Retrieve the list of available remote releases from
|
||||||
|
/// the package source. These releases can subsequently be downloaded
|
||||||
|
/// with cb_download_release_entry.
|
||||||
|
/// @param callback to override the default update source
|
||||||
|
/// (AutoSource). Download the specified VelopackAsset to the provided
|
||||||
|
/// local file path.
|
||||||
|
/// @param parameter to the callbacks to override the default update
|
||||||
|
/// source (AutoSource). It's the user's responsibilty to ensure that
|
||||||
|
/// it's safe to send and share it across threads
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn vpkc_new_custom_update_manager(
|
||||||
|
cb_get_release_feed: extern "C" fn(*const c_char, *mut c_void) -> *const c_char,
|
||||||
|
cb_download_release_entry: extern "C" fn(*const c_char, *const c_char, *mut c_void) -> bool,
|
||||||
|
p_user_data: *mut c_void,
|
||||||
|
p_options: *mut vpkc_update_options_t,
|
||||||
|
p_locator: *mut vpkc_locator_config_t,
|
||||||
|
p_manager: *mut *mut vpkc_update_manager_t,
|
||||||
|
) -> bool {
|
||||||
|
wrap_error(|| {
|
||||||
|
let source = CCallbackUpdateSource {
|
||||||
|
p_user_data,
|
||||||
|
cb_get_release_feed,
|
||||||
|
cb_download_release_entry,
|
||||||
|
};
|
||||||
|
let options = c_to_updateoptions_opt(p_options);
|
||||||
|
let locator = c_to_velopacklocatorconfig_opt(p_locator);
|
||||||
|
let manager = UpdateManager::new(source, options, locator)?;
|
||||||
|
unsafe { *p_manager = UpdateManagerRawPtr::new(manager) };
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the currently installed version of the app.
|
/// Returns the currently installed version of the app.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn vpkc_get_current_version(p_manager: *mut vpkc_update_manager_t, psz_version: *mut c_char, c_version: size_t) -> size_t {
|
pub extern "C" fn vpkc_get_current_version(p_manager: *mut vpkc_update_manager_t, psz_version: *mut c_char, c_version: size_t) -> size_t {
|
||||||
|
|||||||
Reference in New Issue
Block a user