#pragma once /// @file bex_engine.h /// @brief Pure C ABI for the Bex WASM Plugin Engine (v4). /// /// This header defines the boundary between the Rust engine and any C/C++ consumer. /// Rust implements these functions via `extern "C"`. C++ consumes them directly. /// No bridge crate, no code generation — just link against libbex_runtime. /// /// Architecture: /// - All async operations return a request_id immediately. /// - When the operation completes, Rust invokes the BexResultCallback from a /// background Tokio thread. /// - C++ must copy/parse the payload before the callback returns (payload is /// owned by Rust and freed after the callback returns). /// - Sync operations (install, uninstall, list, secrets) block until done. /// /// Thread safety: /// - bex_engine_new / bex_engine_free are NOT thread-safe. /// - All bex_submit_* functions are thread-safe (internally synchronized). /// - The callback is invoked from a Rust/Tokio background thread — the /// callback implementation must be thread-safe. #include #include #include #ifdef __cplusplus extern "C" { #endif // ── Opaque Engine Handle ─────────────────────────────────────────────── /// Opaque handle to the Rust BexEngine runtime. typedef struct BexEngine BexEngine; // ── Callback Signature ───────────────────────────────────────────────── /// Universal async result callback. /// /// Rust calls this from a background Tokio thread when an async task finishes. /// /// @param user_data The opaque pointer passed to the submit function. /// @param request_id The ID returned by the submit function. /// @param success true if the operation succeeded, false on error. /// @param payload Pointer to the result payload bytes (JSON string). /// Owned by Rust — C++ must copy before returning. /// @param payload_len Number of bytes in payload. typedef void (*BexResultCallback)( void* user_data, uint64_t request_id, bool success, const uint8_t* payload, size_t payload_len ); // ── Plugin Info (returned by list/info sync calls) ───────────────────── /// Information about a single installed plugin. /// Returned by bex_engine_list_plugins and bex_engine_plugin_info. typedef struct BexPluginInfo { char* id; ///< Plugin identifier (e.g., "com.gogoanime") char* name; ///< Human-readable plugin name char* version; ///< Plugin version string uint32_t capabilities; ///< Capability bitmask bool enabled; ///< Whether the plugin is currently enabled char* description; ///< Plugin description (may be empty) char* author; ///< Plugin author (may be empty) char* homepage; ///< Plugin homepage URL (may be empty) } BexPluginInfo; /// Array of BexPluginInfo structs returned by bex_engine_list_plugins. typedef struct BexPluginInfoList { BexPluginInfo* items; ///< Array of plugin info structs size_t count; ///< Number of items in the array } BexPluginInfoList; // ── Lifecycle ────────────────────────────────────────────────────────── /// Create a new BexEngine instance. /// /// @param data_dir Path to the data directory (created if not exists). /// @return Opaque engine handle, or NULL on failure. BexEngine* bex_engine_new(const char* data_dir); /// Free a BexEngine instance and release all resources. /// /// This will wait for in-flight requests to complete (up to 10 seconds), /// then shut down the Tokio runtime and release all memory. /// /// @param engine The engine handle (may be NULL, in which case this is a no-op). void bex_engine_free(BexEngine* engine); // ── Plugin Management (synchronous) ──────────────────────────────────── /// Install a plugin from a .bex package file. /// /// @param engine The engine handle. /// @param path Filesystem path to the .bex package. /// @return 0 on success, non-zero on error. int bex_engine_install(BexEngine* engine, const char* path); /// Uninstall a plugin by its ID. /// /// @param engine The engine handle. /// @param id The plugin identifier. /// @return 0 on success, non-zero on error. int bex_engine_uninstall(BexEngine* engine, const char* id); /// List all installed plugins. /// /// Returns a BexPluginInfoList. The caller must free it with /// bex_plugin_info_list_free when done. /// /// @param engine The engine handle. /// @return List of installed plugins (empty list if none, never NULL). BexPluginInfoList bex_engine_list_plugins(BexEngine* engine); /// Get detailed info for a single plugin. /// /// @param engine The engine handle. /// @param id The plugin identifier. /// @param out Pointer to a BexPluginInfo struct to fill. /// @return 0 on success, non-zero if plugin not found. int bex_engine_plugin_info(BexEngine* engine, const char* id, BexPluginInfo* out); /// Enable a plugin. int bex_engine_enable(BexEngine* engine, const char* id); /// Disable a plugin. int bex_engine_disable(BexEngine* engine, const char* id); /// Free a BexPluginInfoList returned by bex_engine_list_plugins. void bex_plugin_info_list_free(BexPluginInfoList list); /// Free the strings inside a BexPluginInfo struct. void bex_plugin_info_free(BexPluginInfo info); // ── API Key / Secret Management (synchronous) ───────────────────────── /// Set an API key/secret for a plugin. /// /// @param engine The engine handle. /// @param plugin_id The plugin identifier. /// @param key The key name (e.g., "api_key"). /// @param value The key value. /// @return 0 on success, non-zero on error. int bex_engine_secret_set(BexEngine* engine, const char* plugin_id, const char* key, const char* value); /// Get an API key/secret value for a plugin. /// /// @param engine The engine handle. /// @param plugin_id The plugin identifier. /// @param key The key name. /// @param out_buf Buffer to write the value into. /// @param out_buf_len Size of out_buf. On success, the actual length (excluding NUL) is written back. /// @return 0 on success, non-zero if not found or error. int bex_engine_secret_get(BexEngine* engine, const char* plugin_id, const char* key, char* out_buf, size_t* out_buf_len); /// Delete an API key/secret for a plugin. /// /// @return 0 if deleted, 1 if key not found, negative on error. int bex_engine_secret_delete(BexEngine* engine, const char* plugin_id, const char* key); /// List all secret key names for a plugin. /// /// Returns a comma-separated string of key names. Caller must free with bex_string_free(). /// Returns NULL on error. char* bex_engine_secret_keys(BexEngine* engine, const char* plugin_id); /// Free a string returned by the engine (e.g., from bex_engine_secret_keys). void bex_string_free(char* s); // ── Async Operations ────────────────────────────────────────────────── /// Submit a search request. /// /// @param engine The engine handle. /// @param plugin_id The plugin to use. /// @param query The search query. /// @param callback Called when the result is ready. /// @param user_data Opaque pointer passed to the callback. /// @return Request ID (non-zero). Returns 0 if engine is NULL or invalid. uint64_t bex_submit_search(BexEngine* engine, const char* plugin_id, const char* query, BexResultCallback callback, void* user_data); /// Submit a home page request. uint64_t bex_submit_home(BexEngine* engine, const char* plugin_id, BexResultCallback callback, void* user_data); /// Submit a get_info request. /// /// The media_id is opaque to the engine — the plugin knows how to interpret it. uint64_t bex_submit_info(BexEngine* engine, const char* plugin_id, const char* media_id, BexResultCallback callback, void* user_data); /// Submit a get_servers request. /// /// The id is self-describing — the plugin knows how to parse its own IDs. /// Example: "one-piece$ep=1$sub=1$dub=0" uint64_t bex_submit_servers(BexEngine* engine, const char* plugin_id, const char* id, BexResultCallback callback, void* user_data); /// Submit a resolve_stream request. /// /// @param server_json JSON string representing a server entry (from get_servers result). uint64_t bex_submit_stream(BexEngine* engine, const char* plugin_id, const char* server_json, BexResultCallback callback, void* user_data); // ── Cancellation ────────────────────────────────────────────────────── /// Cancel a pending async request. /// /// @return true if the request was found and cancelled, false otherwise. bool bex_cancel_request(BexEngine* engine, uint64_t request_id); // ── Engine Stats (synchronous) ──────────────────────────────────────── /// Get engine statistics as a JSON string. /// Caller must free the returned string with bex_string_free(). char* bex_engine_stats(BexEngine* engine); // ── Last Error ──────────────────────────────────────────────────────── /// Get the last error message from a failed sync operation. /// Returns NULL if no error. Caller must free with bex_string_free(). char* bex_engine_last_error(BexEngine* engine); #ifdef __cplusplus } #endif