mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Add installation_proxy cpp bindings
This commit is contained in:
60
cpp/include/idevice++/installation_proxy.hpp
Normal file
60
cpp/include/idevice++/installation_proxy.hpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
|
#include <idevice++/bindings.hpp>
|
||||||
|
#include <idevice++/ffi.hpp>
|
||||||
|
#include <idevice++/provider.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <sys/_types/_u_int64_t.h>
|
||||||
|
|
||||||
|
namespace IdeviceFFI {
|
||||||
|
|
||||||
|
using InstallationProxyPtr =
|
||||||
|
std::unique_ptr<InstallationProxyClientHandle,
|
||||||
|
FnDeleter<InstallationProxyClientHandle, installation_proxy_client_free>>;
|
||||||
|
|
||||||
|
class InstallationProxy {
|
||||||
|
public:
|
||||||
|
// Factory: connect via Provider
|
||||||
|
static Result<InstallationProxy, FfiError> connect(Provider& provider);
|
||||||
|
|
||||||
|
// Factory: wrap an existing Idevice socket (consumes it on success)
|
||||||
|
static Result<InstallationProxy, FfiError> from_socket(Idevice&& socket);
|
||||||
|
|
||||||
|
// Ops
|
||||||
|
Result<std::vector<plist_t>, FfiError>
|
||||||
|
get_apps(Option<std::string> application_type,
|
||||||
|
Option<std::vector<std::string>> bundle_identifiers);
|
||||||
|
Result<void, FfiError> install(std::string package_path, Option<plist_t> options);
|
||||||
|
Result<void, FfiError> install_with_callback(std::string package_path,
|
||||||
|
Option<plist_t> options,
|
||||||
|
std::function<void(u_int64_t)>& lambda);
|
||||||
|
Result<void, FfiError> upgrade(std::string package_path, Option<plist_t> options);
|
||||||
|
Result<void, FfiError> upgrade_with_callback(std::string package_path,
|
||||||
|
Option<plist_t> options,
|
||||||
|
std::function<void(u_int64_t)>& lambda);
|
||||||
|
Result<void, FfiError> uninstall(std::string package_path, Option<plist_t> options);
|
||||||
|
Result<void, FfiError> uninstall_with_callback(std::string package_path,
|
||||||
|
Option<plist_t> options,
|
||||||
|
std::function<void(u_int64_t)>& lambda);
|
||||||
|
Result<bool, FfiError> check_capabilities_match(std::vector<plist_t> capabilities,
|
||||||
|
Option<plist_t> options);
|
||||||
|
Result<std::vector<plist_t>, FfiError> browse(Option<plist_t> options);
|
||||||
|
|
||||||
|
// RAII / moves
|
||||||
|
~InstallationProxy() noexcept = default;
|
||||||
|
InstallationProxy(InstallationProxy&&) noexcept = default;
|
||||||
|
InstallationProxy& operator=(InstallationProxy&&) noexcept = default;
|
||||||
|
InstallationProxy(const InstallationProxy&) = delete;
|
||||||
|
InstallationProxy& operator=(const InstallationProxy&) = delete;
|
||||||
|
|
||||||
|
InstallationProxyClientHandle* raw() const noexcept { return handle_.get(); }
|
||||||
|
static InstallationProxy adopt(InstallationProxyClientHandle* h) noexcept {
|
||||||
|
return InstallationProxy(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit InstallationProxy(InstallationProxyClientHandle* h) noexcept : handle_(h) {}
|
||||||
|
InstallationProxyPtr handle_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace IdeviceFFI
|
||||||
240
cpp/src/installation_proxy.cpp
Normal file
240
cpp/src/installation_proxy.cpp
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <idevice++/bindings.hpp>
|
||||||
|
#include <idevice++/installation_proxy.hpp>
|
||||||
|
#include <sys/_types/_u_int64_t.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace IdeviceFFI {
|
||||||
|
|
||||||
|
// -------- Anonymous Namespace for Helpers --------
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
* @brief A C-style trampoline function to call back into a C++ std::function.
|
||||||
|
*
|
||||||
|
* This function is passed to the Rust FFI layer. It receives a void* context,
|
||||||
|
* which it casts back to the original std::function object to invoke it.
|
||||||
|
*/
|
||||||
|
extern "C" void progress_trampoline(u_int64_t progress, void* context) {
|
||||||
|
if (context) {
|
||||||
|
auto& callback_fn = *static_cast<std::function<void(u_int64_t)>*>(context);
|
||||||
|
callback_fn(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// -------- Factory Methods --------
|
||||||
|
|
||||||
|
Result<InstallationProxy, FfiError> InstallationProxy::connect(Provider& provider) {
|
||||||
|
InstallationProxyClientHandle* handle = nullptr;
|
||||||
|
FfiError e(::installation_proxy_connect(provider.raw(), &handle));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok(InstallationProxy::adopt(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<InstallationProxy, FfiError> InstallationProxy::from_socket(Idevice&& socket) {
|
||||||
|
InstallationProxyClientHandle* handle = nullptr;
|
||||||
|
// The Rust FFI function consumes the socket, so we must release it from the
|
||||||
|
// C++ RAII wrapper's control. An `Idevice::release()` method is assumed here.
|
||||||
|
FfiError e(::installation_proxy_new(socket.release(), &handle));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok(InstallationProxy::adopt(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Ops --------
|
||||||
|
|
||||||
|
Result<std::vector<plist_t>, FfiError>
|
||||||
|
InstallationProxy::get_apps(Option<std::string> application_type,
|
||||||
|
Option<std::vector<std::string>> bundle_identifiers) {
|
||||||
|
plist_t* apps_raw = nullptr;
|
||||||
|
size_t apps_len = 0;
|
||||||
|
|
||||||
|
const char* application_type_ptr = NULL;
|
||||||
|
if (application_type.is_some()) {
|
||||||
|
application_type_ptr = application_type.unwrap().c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> c_bundle_id;
|
||||||
|
size_t bundle_identifiers_len = 0;
|
||||||
|
if (bundle_identifiers.is_some()) {
|
||||||
|
c_bundle_id.reserve(bundle_identifiers.unwrap().size());
|
||||||
|
for (auto& a : bundle_identifiers.unwrap()) {
|
||||||
|
c_bundle_id.push_back(a.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(::installation_proxy_get_apps(
|
||||||
|
this->raw(),
|
||||||
|
application_type_ptr,
|
||||||
|
c_bundle_id.empty() ? nullptr : const_cast<const char* const*>(c_bundle_id.data()),
|
||||||
|
bundle_identifiers_len,
|
||||||
|
apps_raw,
|
||||||
|
&apps_len));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<plist_t> apps;
|
||||||
|
if (apps_raw) {
|
||||||
|
apps.assign(apps_raw, apps_raw + apps_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(std::move(apps));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> InstallationProxy::install(std::string package_path,
|
||||||
|
Option<plist_t> options) {
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(::installation_proxy_install(this->raw(), package_path.c_str(), &unwrapped_options));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> InstallationProxy::install_with_callback(
|
||||||
|
std::string package_path, Option<plist_t> options, std::function<void(u_int64_t)>& lambda
|
||||||
|
|
||||||
|
) {
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(::installation_proxy_install_with_callback(
|
||||||
|
this->raw(), package_path.c_str(), &unwrapped_options, progress_trampoline, &lambda));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> InstallationProxy::upgrade(std::string package_path,
|
||||||
|
Option<plist_t> options) {
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(::installation_proxy_upgrade(this->raw(), package_path.c_str(), &unwrapped_options));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> InstallationProxy::upgrade_with_callback(
|
||||||
|
std::string package_path, Option<plist_t> options, std::function<void(u_int64_t)>& lambda
|
||||||
|
|
||||||
|
) {
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(::installation_proxy_upgrade_with_callback(
|
||||||
|
this->raw(), package_path.c_str(), &unwrapped_options, progress_trampoline, &lambda));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> InstallationProxy::uninstall(std::string package_path,
|
||||||
|
Option<plist_t> options) {
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(
|
||||||
|
::installation_proxy_uninstall(this->raw(), package_path.c_str(), &unwrapped_options));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> InstallationProxy::uninstall_with_callback(
|
||||||
|
std::string package_path, Option<plist_t> options, std::function<void(u_int64_t)>& lambda
|
||||||
|
|
||||||
|
) {
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(::installation_proxy_uninstall_with_callback(
|
||||||
|
this->raw(), package_path.c_str(), &unwrapped_options, progress_trampoline, &lambda));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<bool, FfiError>
|
||||||
|
InstallationProxy::check_capabilities_match(std::vector<plist_t> capabilities,
|
||||||
|
Option<plist_t> options) {
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = false;
|
||||||
|
FfiError e(::installation_proxy_check_capabilities_match(
|
||||||
|
this->raw(),
|
||||||
|
capabilities.empty() ? nullptr : capabilities.data(),
|
||||||
|
capabilities.size(),
|
||||||
|
unwrapped_options,
|
||||||
|
&res));
|
||||||
|
return e ? Result<bool, FfiError>(Err(e)) : Result<bool, FfiError>(Ok(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::vector<plist_t>, FfiError> InstallationProxy::browse(Option<plist_t> options) {
|
||||||
|
plist_t* apps_raw = nullptr;
|
||||||
|
size_t apps_len = 0;
|
||||||
|
|
||||||
|
plist_t unwrapped_options;
|
||||||
|
if (options.is_some()) {
|
||||||
|
unwrapped_options = std::move(options).unwrap();
|
||||||
|
} else {
|
||||||
|
unwrapped_options = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FfiError e(::installation_proxy_browse(this->raw(), unwrapped_options, &apps_raw, &apps_len));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<plist_t> apps;
|
||||||
|
if (apps_raw) {
|
||||||
|
apps.assign(apps_raw, apps_raw + apps_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(std::move(apps));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace IdeviceFFI
|
||||||
@@ -25,7 +25,7 @@ pub struct InstallationProxyClientHandle(pub InstallationProxyClient);
|
|||||||
/// `provider` must be a valid pointer to a handle allocated by this library
|
/// `provider` must be a valid pointer to a handle allocated by this library
|
||||||
/// `client` must be a valid, non-null pointer to a location where the handle will be stored
|
/// `client` must be a valid, non-null pointer to a location where the handle will be stored
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn installation_proxy_connect_tcp(
|
pub unsafe extern "C" fn installation_proxy_connect(
|
||||||
provider: *mut IdeviceProviderHandle,
|
provider: *mut IdeviceProviderHandle,
|
||||||
client: *mut *mut InstallationProxyClientHandle,
|
client: *mut *mut InstallationProxyClientHandle,
|
||||||
) -> *mut IdeviceFfiError {
|
) -> *mut IdeviceFfiError {
|
||||||
|
|||||||
Reference in New Issue
Block a user