lssa/lez/indexer/ffi/src/api/lifecycle.rs

139 lines
4.6 KiB
Rust
Raw Normal View History

2026-04-02 15:49:42 +03:00
use std::{ffi::c_char, path::PathBuf};
2026-04-22 17:39:27 +03:00
use crate::{
IndexerServiceFFI, Runtime,
2026-04-22 17:39:27 +03:00
api::{
PointerResult,
client::{UrlProtocol, addr_to_url},
},
2026-05-05 15:45:24 +03:00
client::{IndexerClient, IndexerClientTrait as _},
2026-04-22 17:39:27 +03:00
errors::OperationStatus,
};
2026-04-02 15:49:42 +03:00
pub type InitializedIndexerServiceFFIResult = PointerResult<IndexerServiceFFI, OperationStatus>;
/// Creates and starts an indexer based on the provided
/// configuration file path.
///
/// # Arguments
///
/// - `config_path`: A pointer to a string representing the path to the configuration file.
/// - `port`: Number representing a port, on which indexers RPC will start.
///
/// # Returns
///
/// An `InitializedIndexerServiceFFIResult` containing either a pointer to the
/// initialized `IndexerServiceFFI` or an error code.
///
/// # Safety
/// The caller must ensure that:
/// - `runtime` is a valid pointer to a `tokio::runtime::Runtime` instance.
/// - `config_path` is a valid pointer to a null-terminated C string.
2026-04-02 15:49:42 +03:00
#[unsafe(no_mangle)]
pub unsafe extern "C" fn start_indexer(
runtime: *const Runtime,
2026-04-02 15:49:42 +03:00
config_path: *const c_char,
port: u16,
) -> InitializedIndexerServiceFFIResult {
// SAFETY: The caller must ensure the validness of the `runtime` and `config_path` pointers.
unsafe { setup_indexer(runtime, config_path, port) }.map_or_else(
2026-04-02 15:49:42 +03:00
InitializedIndexerServiceFFIResult::from_error,
InitializedIndexerServiceFFIResult::from_value,
)
}
/// Creates a new [`tokio::runtime::Runtime`].
#[unsafe(no_mangle)]
pub extern "C" fn new_runtime() -> PointerResult<Runtime, OperationStatus> {
Runtime::new().map_or_else(
|_e| PointerResult::from_error(OperationStatus::InitializationError),
PointerResult::from_value,
)
}
2026-04-02 15:49:42 +03:00
/// Initializes and starts an indexer based on the provided
/// configuration file path.
///
/// # Arguments
///
/// - `config_path`: A pointer to a string representing the path to the configuration file.
/// - `port`: Number representing a port, on which indexers RPC will start.
///
/// # Returns
///
/// A `Result` containing either the initialized `IndexerServiceFFI` or an
/// error code.
///
/// # Safety
/// The caller must ensure that:
/// - `runtime` is a valid pointer to a `tokio::runtime::Runtime` instance.
/// - `config_path` is a valid pointer to a null-terminated C string.
unsafe fn setup_indexer(
runtime: *const Runtime,
2026-04-02 15:49:42 +03:00
config_path: *const c_char,
port: u16,
) -> Result<IndexerServiceFFI, OperationStatus> {
let user_config_path = PathBuf::from(
unsafe { std::ffi::CStr::from_ptr(config_path) }
.to_str()
.map_err(|e| {
log::error!("Could not convert the config path to string: {e}");
OperationStatus::InitializationError
})?,
);
let config = indexer_service::IndexerConfig::from_path(&user_config_path).map_err(|e| {
log::error!("Failed to read config: {e}");
OperationStatus::InitializationError
})?;
// SAFETY: The caller must ensure that `runtime` is a valid pointer to a
// `tokio::runtime::Runtime` instance.
let runtime = unsafe { &*runtime };
2026-04-02 15:49:42 +03:00
let indexer_handle = runtime
2026-04-02 15:49:42 +03:00
.block_on(indexer_service::run_server(config, port))
.map_err(|e| {
log::error!("Could not start indexer service: {e}");
OperationStatus::InitializationError
})?;
2026-04-22 17:39:27 +03:00
let indexer_url = addr_to_url(UrlProtocol::Ws, indexer_handle.addr())?;
let indexer_client = runtime
.block_on(IndexerClient::new(&indexer_url))
.map_err(|e| {
log::error!("Could not start indexer client: {e}");
OperationStatus::InitializationError
})?;
2026-04-22 17:39:27 +03:00
Ok(IndexerServiceFFI::new(indexer_handle, indexer_client))
2026-04-02 15:49:42 +03:00
}
/// Stops and frees the resources associated with the given indexer service.
///
/// # Arguments
///
/// - `indexer`: A pointer to the `IndexerServiceFFI` instance to be stopped.
///
/// # Returns
///
/// An `OperationStatus` indicating success or failure.
///
/// # Safety
///
/// The caller must ensure that:
/// - `indexer` is a valid pointer to a `IndexerServiceFFI` instance
/// - The `IndexerServiceFFI` instance was created by this library
/// - The pointer will not be used after this function returns
#[unsafe(no_mangle)]
pub unsafe extern "C" fn stop_indexer(indexer: *mut IndexerServiceFFI) -> OperationStatus {
if indexer.is_null() {
log::error!("Attempted to stop a null indexer pointer. This is a bug. Aborting.");
return OperationStatus::NullPointer;
}
let indexer = unsafe { Box::from_raw(indexer) };
drop(indexer);
OperationStatus::Ok
}