mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Implement new lib-c sources API
This commit is contained in:
@@ -27,6 +27,69 @@ enum vpkc_update_check_t
|
||||
typedef int8_t vpkc_update_check_t;
|
||||
#endif // __cplusplus
|
||||
|
||||
/**
|
||||
* Opaque type for a Velopack UpdateSource. Must be freed with `vpkc_free_update_source`.
|
||||
*/
|
||||
typedef void vpkc_update_source_t;
|
||||
|
||||
/**
|
||||
* User delegate for to fetch a release feed. This function should return the raw JSON string of the release.json feed.
|
||||
*/
|
||||
typedef const char *(*vpkc_release_feed_delegate_t)(void *p_user_data, const char *psz_releases_name);
|
||||
|
||||
/**
|
||||
* An individual Velopack asset, could refer to an asset on-disk or in a remote package feed.
|
||||
*/
|
||||
typedef struct vpkc_asset_t {
|
||||
/**
|
||||
* The name or Id of the package containing this release.
|
||||
*/
|
||||
char *PackageId;
|
||||
/**
|
||||
* The version of this release.
|
||||
*/
|
||||
char *Version;
|
||||
/**
|
||||
* The type of asset (eg. "Full" or "Delta").
|
||||
*/
|
||||
char *Type;
|
||||
/**
|
||||
* The filename of the update package containing this release.
|
||||
*/
|
||||
char *FileName;
|
||||
/**
|
||||
* The SHA1 checksum of the update package containing this release.
|
||||
*/
|
||||
char *SHA1;
|
||||
/**
|
||||
* The SHA256 checksum of the update package containing this release.
|
||||
*/
|
||||
char *SHA256;
|
||||
/**
|
||||
* The size in bytes of the update package containing this release.
|
||||
*/
|
||||
uint64_t Size;
|
||||
/**
|
||||
* The release notes in markdown format, as passed to Velopack when packaging the release. This may be an empty string.
|
||||
*/
|
||||
char *NotesMarkdown;
|
||||
/**
|
||||
* The release notes in HTML format, transformed from Markdown when packaging the release. This may be an empty string.
|
||||
*/
|
||||
char *NotesHtml;
|
||||
} vpkc_asset_t;
|
||||
|
||||
/**
|
||||
* User delegate for downloading an asset file. This function is expected to download the provided asset
|
||||
* to the provided local file path. Througout, you can use the progress callback to write progress reports.
|
||||
* The function should return true if the download was successful, false otherwise.
|
||||
* Progress
|
||||
*/
|
||||
typedef bool (*vpkc_download_asset_delegate_t)(void *p_user_data,
|
||||
const struct vpkc_asset_t *p_asset,
|
||||
const char *psz_local_path,
|
||||
size_t progress_callback_id);
|
||||
|
||||
/**
|
||||
* Options to customise the behaviour of UpdateManager.
|
||||
*/
|
||||
@@ -85,48 +148,6 @@ typedef struct vpkc_locator_config_t {
|
||||
*/
|
||||
typedef void vpkc_update_manager_t;
|
||||
|
||||
/**
|
||||
* An individual Velopack asset, could refer to an asset on-disk or in a remote package feed.
|
||||
*/
|
||||
typedef struct vpkc_asset_t {
|
||||
/**
|
||||
* The name or Id of the package containing this release.
|
||||
*/
|
||||
char *PackageId;
|
||||
/**
|
||||
* The version of this release.
|
||||
*/
|
||||
char *Version;
|
||||
/**
|
||||
* The type of asset (eg. "Full" or "Delta").
|
||||
*/
|
||||
char *Type;
|
||||
/**
|
||||
* The filename of the update package containing this release.
|
||||
*/
|
||||
char *FileName;
|
||||
/**
|
||||
* The SHA1 checksum of the update package containing this release.
|
||||
*/
|
||||
char *SHA1;
|
||||
/**
|
||||
* The SHA256 checksum of the update package containing this release.
|
||||
*/
|
||||
char *SHA256;
|
||||
/**
|
||||
* The size in bytes of the update package containing this release.
|
||||
*/
|
||||
uint64_t Size;
|
||||
/**
|
||||
* The release notes in markdown format, as passed to Velopack when packaging the release. This may be an empty string.
|
||||
*/
|
||||
char *NotesMarkdown;
|
||||
/**
|
||||
* The release notes in HTML format, transformed from Markdown when packaging the release. This may be an empty string.
|
||||
*/
|
||||
char *NotesHtml;
|
||||
} vpkc_asset_t;
|
||||
|
||||
/**
|
||||
* Holds information about the current version and pending updates, such as how many there are, and access to release notes.
|
||||
*/
|
||||
@@ -164,6 +185,38 @@ typedef void (*vpkc_log_callback_t)(void *p_user_data,
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
/**
|
||||
* Create a new FileSource update source for a given file path.
|
||||
*/
|
||||
vpkc_update_source_t *vpkc_new_source_file(const char *psz_file_path);
|
||||
|
||||
/**
|
||||
* Create a new HttpSource update source for a given HTTP URL.
|
||||
*/
|
||||
vpkc_update_source_t *vpkc_new_source_http_url(const char *psz_http_url);
|
||||
|
||||
/**
|
||||
* Create a new _CUSTOM_ update source with user-provided callbacks to fetch release feeds and download assets.
|
||||
* You can report download progress using `vpkc_source_report_progress`. Note that the callbacks must be valid
|
||||
* for the lifetime of any UpdateManager's that use this source. You should call `vpkc_free_source` to free the source,
|
||||
* but note that if the source is still in use by an UpdateManager, it will not be freed until the UpdateManager is freed.
|
||||
* Therefore to avoid possible issues, it is recommended to create this type of source once for the lifetime of your application.
|
||||
*/
|
||||
vpkc_update_source_t *vpkc_new_source_custom_callback(vpkc_release_feed_delegate_t cb_release_feed,
|
||||
vpkc_download_asset_delegate_t cb_download_entry,
|
||||
void *p_user_data);
|
||||
|
||||
/**
|
||||
* Sends a progress update to the callback with the specified ID. This is used by custom
|
||||
* update sources created with `vpkc_new_source_custom_callback` to report download progress.
|
||||
*/
|
||||
void vpkc_source_report_progress(size_t progress_callback_id, int16_t progress);
|
||||
|
||||
/**
|
||||
* Frees a vpkc_update_source_t instance.
|
||||
*/
|
||||
void vpkc_free_source(vpkc_update_source_t *p_source);
|
||||
|
||||
/**
|
||||
* Create a new UpdateManager instance.
|
||||
* @param urlOrPath Location of the update server or path to the local update directory.
|
||||
@@ -176,28 +229,15 @@ bool vpkc_new_update_manager(const char *psz_url_or_path,
|
||||
vpkc_update_manager_t **p_manager);
|
||||
|
||||
/**
|
||||
* Create a new UpdateManager instance.
|
||||
* Create a new UpdateManager instance with a custom UpdateSource.
|
||||
* @param urlOrPath Location of the update server or path to the local update directory.
|
||||
* @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);
|
||||
bool vpkc_new_update_manager_with_source(vpkc_update_source_t *p_source,
|
||||
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.
|
||||
|
||||
77
src/lib-cpp/src/csource.rs
Normal file
77
src/lib-cpp/src/csource.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use crate::types::*;
|
||||
use lazy_static::lazy_static;
|
||||
use libc::{c_void, size_t};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::CString,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
mpsc::Sender,
|
||||
RwLock,
|
||||
},
|
||||
};
|
||||
use velopack::{bundle::Manifest, sources::UpdateSource, Error, VelopackAsset, VelopackAssetFeed};
|
||||
|
||||
lazy_static! {
|
||||
static ref PROGRESS_CALLBACKS: RwLock<HashMap<size_t, Sender<i16>>> = RwLock::new(HashMap::new());
|
||||
static ref PROGRESS_ID: AtomicUsize = AtomicUsize::new(0);
|
||||
}
|
||||
|
||||
pub fn report_csource_progress(callback_id: size_t, progress: i16) {
|
||||
let progress_callbacks = PROGRESS_CALLBACKS.read().unwrap();
|
||||
if let Some(sender) = progress_callbacks.get(&callback_id) {
|
||||
let _ = sender.send(progress);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CCallbackUpdateSource {
|
||||
pub p_user_data: *mut c_void,
|
||||
pub cb_get_release_feed: vpkc_release_feed_delegate_t,
|
||||
pub cb_download_release_entry: vpkc_download_asset_delegate_t,
|
||||
}
|
||||
|
||||
unsafe impl Send for CCallbackUpdateSource {}
|
||||
unsafe impl Sync for CCallbackUpdateSource {}
|
||||
|
||||
impl UpdateSource for CCallbackUpdateSource {
|
||||
fn get_release_feed(&self, channel: &str, _: &Manifest) -> Result<VelopackAssetFeed, Error> {
|
||||
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)(self.p_user_data, releases_name_cstr.as_ptr());
|
||||
let json = c_to_string_opt(json_cstr_ptr)
|
||||
.ok_or(Error::Generic("User vpkc_release_feed_delegate_t returned a null pointer instead of an asset feed".to_string()))?;
|
||||
let feed: VelopackAssetFeed = serde_json::from_str(&json)?;
|
||||
Ok(feed)
|
||||
}
|
||||
|
||||
fn download_release_entry(&self, asset: &VelopackAsset, local_file: &str, progress_sender: Option<Sender<i16>>) -> Result<(), Error> {
|
||||
let local_file_cstr = CString::new(local_file).unwrap();
|
||||
let asset_ptr: *mut vpkc_asset_t = std::ptr::null_mut();
|
||||
unsafe { allocate_velopackasset(asset.clone(), asset_ptr) };
|
||||
|
||||
let progress_callback_id = PROGRESS_ID.fetch_add(1, Ordering::SeqCst);
|
||||
if let Some(progress_sender) = &progress_sender {
|
||||
let _ = progress_sender.send(0);
|
||||
PROGRESS_CALLBACKS.write().unwrap().insert(progress_callback_id, progress_sender.clone());
|
||||
}
|
||||
|
||||
let success = (self.cb_download_release_entry)(self.p_user_data, asset_ptr, local_file_cstr.as_ptr(), progress_callback_id);
|
||||
|
||||
unsafe { free_velopackasset(asset_ptr) };
|
||||
|
||||
if let Some(sender) = PROGRESS_CALLBACKS.write().unwrap().remove(&progress_callback_id) {
|
||||
let _ = sender.send(100);
|
||||
}
|
||||
|
||||
if !success {
|
||||
return Err(Error::Generic("User vpkc_download_asset_delegate_t returned false to indicate download failed".to_owned()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clone_boxed(&self) -> Box<dyn UpdateSource> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,76 @@
|
||||
|
||||
mod statics;
|
||||
use statics::*;
|
||||
|
||||
mod types;
|
||||
use types::*;
|
||||
mod csource;
|
||||
use csource::*;
|
||||
mod raw;
|
||||
use raw::*;
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use libc::{c_char, c_void, size_t};
|
||||
use std::{sync::mpsc::Sender, ffi::{CStr, CString}};
|
||||
use velopack::{bundle, sources, Error as VelopackError, UpdateCheck, UpdateManager, VelopackApp, VelopackAsset, VelopackAssetFeed};
|
||||
use std::{ffi::CString, ptr};
|
||||
use velopack::{sources, Error as VelopackError, UpdateCheck, UpdateManager, VelopackApp};
|
||||
|
||||
/// Create a new FileSource update source for a given file path.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn vpkc_new_source_file(psz_file_path: *const c_char) -> *mut vpkc_update_source_t {
|
||||
if let Some(update_path) = c_to_string_opt(psz_file_path) {
|
||||
UpdateSourceRawPtr::new(Box::new(sources::FileSource::new(update_path)))
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new HttpSource update source for a given HTTP URL.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn vpkc_new_source_http_url(psz_http_url: *const c_char) -> *mut vpkc_update_source_t {
|
||||
if let Some(update_url) = c_to_string_opt(psz_http_url) {
|
||||
UpdateSourceRawPtr::new(Box::new(sources::FileSource::new(update_url)))
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new _CUSTOM_ update source with user-provided callbacks to fetch release feeds and download assets.
|
||||
/// You can report download progress using `vpkc_source_report_progress`. Note that the callbacks must be valid
|
||||
/// for the lifetime of any UpdateManager's that use this source. You should call `vpkc_free_source` to free the source,
|
||||
/// but note that if the source is still in use by an UpdateManager, it will not be freed until the UpdateManager is freed.
|
||||
/// Therefore to avoid possible issues, it is recommended to create this type of source once for the lifetime of your application.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn vpkc_new_source_custom_callback(
|
||||
cb_release_feed: vpkc_release_feed_delegate_t,
|
||||
cb_download_entry: vpkc_download_asset_delegate_t,
|
||||
p_user_data: *mut c_void,
|
||||
) -> *mut vpkc_update_source_t {
|
||||
let cb_release_feed = cb_release_feed.to_option();
|
||||
let cb_download_entry = cb_download_entry.to_option();
|
||||
if cb_release_feed.is_none() || cb_download_entry.is_none() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
let source = CCallbackUpdateSource {
|
||||
p_user_data,
|
||||
cb_get_release_feed: cb_release_feed.unwrap(),
|
||||
cb_download_release_entry: cb_download_entry.unwrap(),
|
||||
};
|
||||
|
||||
UpdateSourceRawPtr::new(Box::new(source))
|
||||
}
|
||||
|
||||
/// Sends a progress update to the callback with the specified ID. This is used by custom
|
||||
/// update sources created with `vpkc_new_source_custom_callback` to report download progress.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn vpkc_source_report_progress(progress_callback_id: size_t, progress: i16) {
|
||||
report_csource_progress(progress_callback_id, progress);
|
||||
}
|
||||
|
||||
/// Frees a vpkc_update_source_t instance.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn vpkc_free_source(p_source: *mut vpkc_update_source_t) {
|
||||
UpdateSourceRawPtr::free(p_source);
|
||||
}
|
||||
|
||||
/// Create a new UpdateManager instance.
|
||||
/// @param urlOrPath Location of the update server or path to the local update directory.
|
||||
@@ -35,90 +97,22 @@ 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.
|
||||
/// Create a new UpdateManager instance with a custom UpdateSource.
|
||||
/// @param urlOrPath Location of the update server or path to the local update directory.
|
||||
/// @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,
|
||||
pub extern "C" fn vpkc_new_update_manager_with_source(
|
||||
p_source: *mut vpkc_update_source_t,
|
||||
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 source = UpdateSourceRawPtr::get_source_clone(p_source).ok_or(anyhow!("pSource must not be null"))?;
|
||||
let options = c_to_updateoptions_opt(p_options);
|
||||
let locator = c_to_velopacklocatorconfig_opt(p_locator);
|
||||
let manager = UpdateManager::new(source, options, locator)?;
|
||||
let manager = UpdateManager::new_boxed(source, options, locator)?;
|
||||
unsafe { *p_manager = UpdateManagerRawPtr::new(manager) };
|
||||
Ok(())
|
||||
})
|
||||
|
||||
104
src/lib-cpp/src/raw.rs
Normal file
104
src/lib-cpp/src/raw.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use crate::types::*;
|
||||
use velopack::{sources::UpdateSource, UpdateManager};
|
||||
|
||||
pub trait CallbackExt: Sized {
|
||||
fn to_option(self) -> Option<Self>;
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_progress_callback_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_log_callback_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_hook_callback_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_release_feed_delegate_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_download_asset_delegate_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RawPtrExt<'a, T>: Sized {
|
||||
fn to_opaque_ref(self) -> Option<&'a T>;
|
||||
}
|
||||
|
||||
impl<'a> RawPtrExt<'a, UpdateManager> for *mut vpkc_update_manager_t {
|
||||
fn to_opaque_ref(self) -> Option<&'a UpdateManager> {
|
||||
if self.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let opaque = unsafe { &*(self as *mut UpdateManager) };
|
||||
Some(opaque)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UpdateManagerRawPtr;
|
||||
|
||||
impl UpdateManagerRawPtr {
|
||||
pub fn new(obj: UpdateManager) -> *mut vpkc_update_manager_t {
|
||||
log::debug!("vpkc_update_manager_t allocated");
|
||||
let boxed = Box::new(obj);
|
||||
Box::into_raw(boxed) as *mut vpkc_update_manager_t
|
||||
}
|
||||
|
||||
pub fn free(p_manager: *mut vpkc_update_manager_t) {
|
||||
if p_manager.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the raw pointer back into a Box to deallocate it properly
|
||||
log::debug!("vpkc_update_manager_t freed");
|
||||
let _ = unsafe { Box::from_raw(p_manager as *mut UpdateManager) };
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UpdateSourceContainer {
|
||||
source: Box<dyn UpdateSource>,
|
||||
}
|
||||
|
||||
pub struct UpdateSourceRawPtr;
|
||||
|
||||
impl UpdateSourceRawPtr {
|
||||
pub fn new(source: Box<dyn UpdateSource>) -> *mut vpkc_update_source_t {
|
||||
log::debug!("vpkc_update_source_t allocated");
|
||||
let boxed = Box::new(UpdateSourceContainer { source });
|
||||
Box::into_raw(boxed) as *mut vpkc_update_source_t
|
||||
}
|
||||
|
||||
pub fn free(p_source: *mut vpkc_update_source_t) {
|
||||
if p_source.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the raw pointer back into a Box to deallocate it properly
|
||||
log::debug!("vpkc_update_source_t freed");
|
||||
let _ = unsafe { Box::from_raw(p_source as *mut UpdateSourceContainer) };
|
||||
}
|
||||
|
||||
pub fn get_source_clone(p_source: *mut vpkc_update_source_t) -> Option<Box<dyn UpdateSource>> {
|
||||
if p_source.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let opaque = unsafe { &*(p_source as *mut UpdateSourceContainer) };
|
||||
Some(opaque.source.clone())
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,45 @@
|
||||
use libc::{c_char, c_void, size_t};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::path::PathBuf;
|
||||
use velopack::{locator::VelopackLocatorConfig, UpdateInfo, UpdateManager, UpdateOptions, VelopackAsset};
|
||||
use velopack::{locator::VelopackLocatorConfig, UpdateInfo, UpdateOptions, VelopackAsset};
|
||||
|
||||
/// The result of a call to check for updates. This can indicate that an update is available, or that an error occurred.
|
||||
#[repr(i8)]
|
||||
pub enum vpkc_update_check_t {
|
||||
UPDATE_ERROR = -1,
|
||||
UPDATE_AVAILABLE = 0,
|
||||
NO_UPDATE_AVAILABLE = 1,
|
||||
REMOTE_IS_EMPTY = 2,
|
||||
}
|
||||
|
||||
/// Opaque type for the Velopack UpdateManager. Must be freed with `vpkc_free_update_manager`.
|
||||
pub type vpkc_update_manager_t = c_void;
|
||||
|
||||
/// Opaque type for a Velopack UpdateSource. Must be freed with `vpkc_free_update_source`.
|
||||
pub type vpkc_update_source_t = c_void;
|
||||
|
||||
/// Progress callback function.
|
||||
pub type vpkc_progress_callback_t = extern "C" fn(p_user_data: *mut c_void, progress: size_t);
|
||||
|
||||
/// Log callback function.
|
||||
pub type vpkc_log_callback_t = extern "C" fn(p_user_data: *mut c_void, psz_level: *const c_char, psz_message: *const c_char);
|
||||
|
||||
/// VelopackApp startup hook callback function.
|
||||
pub type vpkc_hook_callback_t = extern "C" fn(p_user_data: *mut c_void, psz_app_version: *const c_char);
|
||||
|
||||
/// User delegate for to fetch a release feed. This function should return the raw JSON string of the release.json feed.
|
||||
pub type vpkc_release_feed_delegate_t = extern "C" fn(p_user_data: *mut c_void, psz_releases_name: *const c_char) -> *const c_char;
|
||||
|
||||
/// User delegate for downloading an asset file. This function is expected to download the provided asset
|
||||
/// to the provided local file path. Througout, you can use the progress callback to write progress reports.
|
||||
/// The function should return true if the download was successful, false otherwise.
|
||||
/// Progress
|
||||
pub type vpkc_download_asset_delegate_t = extern "C" fn(
|
||||
p_user_data: *mut c_void,
|
||||
p_asset: *const vpkc_asset_t,
|
||||
psz_local_path: *const c_char,
|
||||
progress_callback_id: size_t,
|
||||
) -> bool;
|
||||
|
||||
pub fn c_to_string_opt(psz: *const c_char) -> Option<String> {
|
||||
if psz.is_null() {
|
||||
@@ -86,84 +124,6 @@ pub fn return_cstr(psz: *mut c_char, c: size_t, s: &str) -> size_t {
|
||||
return s.len();
|
||||
}
|
||||
|
||||
/// The result of a call to check for updates. This can indicate that an update is available, or that an error occurred.
|
||||
#[repr(i8)]
|
||||
pub enum vpkc_update_check_t {
|
||||
UPDATE_ERROR = -1,
|
||||
UPDATE_AVAILABLE = 0,
|
||||
NO_UPDATE_AVAILABLE = 1,
|
||||
REMOTE_IS_EMPTY = 2,
|
||||
}
|
||||
|
||||
/// Opaque type for the Velopack UpdateManager. Must be freed with `vpkc_free_update_manager`.
|
||||
pub type vpkc_update_manager_t = c_void;
|
||||
|
||||
/// Progress callback function.
|
||||
pub type vpkc_progress_callback_t = extern "C" fn(p_user_data: *mut c_void, progress: size_t);
|
||||
|
||||
/// Log callback function.
|
||||
pub type vpkc_log_callback_t = extern "C" fn(p_user_data: *mut c_void, psz_level: *const c_char, psz_message: *const c_char);
|
||||
|
||||
/// VelopackApp startup hook callback function.
|
||||
pub type vpkc_hook_callback_t = extern "C" fn(p_user_data: *mut c_void, psz_app_version: *const c_char);
|
||||
|
||||
pub trait CallbackExt: Sized {
|
||||
fn to_option(self) -> Option<Self>;
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_progress_callback_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_log_callback_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CallbackExt for vpkc_hook_callback_t {
|
||||
fn to_option(self) -> Option<Self> {
|
||||
unsafe { std::mem::transmute::<Self, Option<Self>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UpdateManagerExt<'a>: Sized {
|
||||
fn to_opaque_ref(self) -> Option<&'a UpdateManager>;
|
||||
}
|
||||
|
||||
impl<'a> UpdateManagerExt<'a> for *mut vpkc_update_manager_t {
|
||||
fn to_opaque_ref(self) -> Option<&'a UpdateManager> {
|
||||
if self.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let opaque = unsafe { &*(self as *mut UpdateManager) };
|
||||
Some(opaque)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UpdateManagerRawPtr;
|
||||
|
||||
impl UpdateManagerRawPtr {
|
||||
pub fn new(obj: UpdateManager) -> *mut vpkc_update_manager_t {
|
||||
log::debug!("vpkc_update_manager_t allocated");
|
||||
let boxed = Box::new(obj);
|
||||
Box::into_raw(boxed) as *mut vpkc_update_manager_t
|
||||
}
|
||||
|
||||
pub fn free(p_manager: *mut vpkc_update_manager_t) {
|
||||
if p_manager.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the raw pointer back into a Box to deallocate it properly
|
||||
log::debug!("vpkc_update_manager_t freed");
|
||||
let _ = unsafe { Box::from_raw(p_manager as *mut UpdateManager) };
|
||||
}
|
||||
}
|
||||
|
||||
// !! AUTO-GENERATED-START RUST_TYPES
|
||||
#[rustfmt::skip]
|
||||
#[repr(C)]
|
||||
|
||||
@@ -141,6 +141,23 @@ impl UpdateManager {
|
||||
source: T,
|
||||
options: Option<UpdateOptions>,
|
||||
locator: Option<VelopackLocatorConfig>,
|
||||
) -> Result<UpdateManager, Error> {
|
||||
UpdateManager::new_boxed(source.clone_boxed(), options, locator)
|
||||
}
|
||||
|
||||
/// Create a new UpdateManager instance using the specified UpdateSource.
|
||||
/// This will return an error if the application is not yet installed.
|
||||
/// ## Example:
|
||||
/// ```rust
|
||||
/// use velopack::*;
|
||||
///
|
||||
/// let source = sources::HttpSource::new("https://the.place/you-host/updates");
|
||||
/// let um = UpdateManager::new_boxed(Box::new(source), None, None);
|
||||
/// ```
|
||||
pub fn new_boxed(
|
||||
source: Box<dyn UpdateSource>,
|
||||
options: Option<UpdateOptions>,
|
||||
locator: Option<VelopackLocatorConfig>,
|
||||
) -> Result<UpdateManager, Error> {
|
||||
let locator = if let Some(config) = locator {
|
||||
warn!("Using explicit locator configuration, ignoring auto-locate.");
|
||||
@@ -151,7 +168,7 @@ impl UpdateManager {
|
||||
};
|
||||
Ok(UpdateManager {
|
||||
options: options.unwrap_or_default(),
|
||||
source: source.clone_boxed(),
|
||||
source,
|
||||
locator,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user