File size: 10,285 Bytes
3374e90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#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 <stdint.h>
#include <stdbool.h>
#include <stddef.h>

#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