314 lines
14 KiB
Rust
314 lines
14 KiB
Rust
// file: crates/ksp-app-raw-transaction-ingest-desk/src/dto_route.rs
|
|
// version: 4
|
|
|
|
//! Safe route-identity, Config-composability and lifecycle DTOs for Raw Transaction Ingest Desk.
|
|
|
|
use ts_rs::TS; // rust-rules: trait-import
|
|
|
|
/// Stable logical V1 route identifiers owned by Raw Transaction Ingest Desk.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteId.ts")]
|
|
pub(crate) enum RawIngestRouteId {
|
|
/// Yellowstone Subscribe plus same-network HTTP hydration.
|
|
YellowstoneHydrated,
|
|
/// Standard Solana logs subscription plus same-network HTTP hydration.
|
|
StandardLogsHydrated,
|
|
/// Standard Solana block subscription with direct RAW projection.
|
|
StandardBlockDirect,
|
|
/// Helius transaction subscription plus same-network HTTP hydration.
|
|
HeliusTransactionHydrated,
|
|
/// HTTP block polling and direct block material projection.
|
|
HttpBlockPolling,
|
|
}
|
|
|
|
impl crate::RawIngestRouteId {
|
|
/// Returns all V1 route identifiers in stable UI order.
|
|
#[must_use]
|
|
pub(crate) fn all() -> std::vec::Vec<Self> {
|
|
return vec![
|
|
Self::YellowstoneHydrated,
|
|
Self::StandardLogsHydrated,
|
|
Self::StandardBlockDirect,
|
|
Self::HeliusTransactionHydrated,
|
|
Self::HttpBlockPolling,
|
|
];
|
|
}
|
|
|
|
/// Returns the application-owned route family used by safe UI projections.
|
|
#[must_use]
|
|
pub(crate) const fn family(self) -> crate::RawIngestRouteFamily {
|
|
return match self {
|
|
Self::YellowstoneHydrated => crate::RawIngestRouteFamily::Yellowstone,
|
|
Self::StandardLogsHydrated => crate::RawIngestRouteFamily::StandardLogs,
|
|
Self::StandardBlockDirect => crate::RawIngestRouteFamily::StandardBlock,
|
|
Self::HeliusTransactionHydrated => crate::RawIngestRouteFamily::HeliusTransaction,
|
|
Self::HttpBlockPolling => crate::RawIngestRouteFamily::HttpBlockPolling,
|
|
};
|
|
}
|
|
|
|
/// Returns the stable operator-facing route label without exposing physical endpoint metadata.
|
|
#[must_use]
|
|
pub(crate) const fn label(self) -> &'static str {
|
|
return match self {
|
|
Self::YellowstoneHydrated => "Yellowstone + HTTP hydration",
|
|
Self::StandardLogsHydrated => "Standard Logs + HTTP hydration",
|
|
Self::StandardBlockDirect => "Standard Block direct",
|
|
Self::HeliusTransactionHydrated => "Helius Transaction + HTTP hydration",
|
|
Self::HttpBlockPolling => "HTTP Block Polling",
|
|
};
|
|
}
|
|
|
|
/// Returns the stable kebab-case route identifier used by safe logs and IPC.
|
|
#[must_use]
|
|
pub(crate) const fn as_str(self) -> &'static str {
|
|
return match self {
|
|
Self::YellowstoneHydrated => "yellowstone-hydrated",
|
|
Self::StandardLogsHydrated => "standard-logs-hydrated",
|
|
Self::StandardBlockDirect => "standard-block-direct",
|
|
Self::HeliusTransactionHydrated => "helius-transaction-hydrated",
|
|
Self::HttpBlockPolling => "http-block-polling",
|
|
};
|
|
}
|
|
}
|
|
|
|
/// Start-time commitments accepted by Raw Transaction Ingest Desk.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestCommitment.ts")]
|
|
pub(crate) enum RawIngestCommitment {
|
|
/// Confirmed commitment.
|
|
Confirmed,
|
|
/// Finalized commitment.
|
|
Finalized,
|
|
}
|
|
|
|
impl crate::RawIngestCommitment {
|
|
/// Returns the stable wire label.
|
|
#[must_use]
|
|
pub(crate) const fn as_str(self) -> &'static str {
|
|
return match self {
|
|
Self::Confirmed => "confirmed",
|
|
Self::Finalized => "finalized",
|
|
};
|
|
}
|
|
|
|
/// Maps the application-owned bounded commitment into the Transport contract.
|
|
#[must_use]
|
|
pub(crate) const fn into_transport(self) -> ksp_onchain_transport_lib::SolanaCommitment {
|
|
return match self {
|
|
Self::Confirmed => ksp_onchain_transport_lib::SolanaCommitment::Confirmed,
|
|
Self::Finalized => ksp_onchain_transport_lib::SolanaCommitment::Finalized,
|
|
};
|
|
}
|
|
}
|
|
|
|
/// Safe request used to revalidate and reconstruct one future route Start without accepting physical resources from the frontend.
|
|
#[derive(Clone, Debug, serde::Deserialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteStartRequestDto.ts")]
|
|
pub(crate) struct RawIngestRouteStartRequestDto {
|
|
/// Confirmed/finalized commitment selected for the future Worker.
|
|
pub(crate) commitment: crate::RawIngestCommitment,
|
|
/// Inventory generation observed by the caller.
|
|
pub(crate) inventory_generation: u32,
|
|
/// Safe logical network-profile identifier selected from the current inventory.
|
|
pub(crate) profile_id: String,
|
|
/// Stable logical route identifier.
|
|
pub(crate) route_id: crate::RawIngestRouteId,
|
|
}
|
|
|
|
/// Safe acknowledgement that exact Start-time Transport resources were reconstructed and validated without Worker launch.
|
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteStartValidationDto.ts")]
|
|
pub(crate) struct RawIngestRouteStartValidationDto {
|
|
/// Commitment validated by the exact Worker source constructor.
|
|
pub(crate) commitment: crate::RawIngestCommitment,
|
|
/// Inventory generation validated against backend state.
|
|
pub(crate) inventory_generation: u32,
|
|
/// Logical network re-proven from Store and Transport Config.
|
|
pub(crate) network: String,
|
|
/// Safe logical network-profile identifier.
|
|
pub(crate) profile_id: String,
|
|
/// Exact logical route whose Transport resources were reconstructed.
|
|
pub(crate) route_id: crate::RawIngestRouteId,
|
|
}
|
|
|
|
/// Stable application-owned route families used only for safe presentation and orchestration.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteFamily.ts")]
|
|
pub(crate) enum RawIngestRouteFamily {
|
|
/// Yellowstone gRPC subscription route.
|
|
Yellowstone,
|
|
/// Standard Solana logs WebSocket route.
|
|
StandardLogs,
|
|
/// Standard Solana block WebSocket route.
|
|
StandardBlock,
|
|
/// Helius transaction WebSocket route.
|
|
HeliusTransaction,
|
|
/// HTTP block polling route.
|
|
HttpBlockPolling,
|
|
}
|
|
|
|
/// Safe reasons explaining why one logical route cannot currently be composed from Config.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteUnavailableReason.ts")]
|
|
pub(crate) enum RawIngestRouteUnavailableReason {
|
|
/// The selected composite or one of its typed Config components could not be resolved safely.
|
|
ProfileUnresolved,
|
|
/// Transport and Store do not prove one identical logical network.
|
|
NetworkMismatch,
|
|
/// No HTTP role can satisfy `getTransaction` for same-network hydration.
|
|
MissingHttpGetTransaction,
|
|
/// No HTTP role can satisfy the complete block-polling method set.
|
|
MissingHttpBlockScan,
|
|
/// No enabled standard WebSocket endpoint explicitly declares `Logs`.
|
|
MissingWsLogsCapability,
|
|
/// No enabled standard WebSocket endpoint explicitly declares `Block`.
|
|
MissingWsBlockCapability,
|
|
/// No enabled Helius WebSocket endpoint explicitly declares `HeliusTransaction`.
|
|
MissingHeliusTransactionCapability,
|
|
/// No enabled same-network Yellowstone gRPC endpoint is configured.
|
|
MissingYellowstoneGrpc,
|
|
/// A required Config secret is not resolved for the selected composite profile.
|
|
MissingRequiredSecret,
|
|
}
|
|
|
|
/// Stable Raw Transaction Ingest Desk route lifecycle states.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, TS)]
|
|
#[serde(rename_all = "snake_case")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteState.ts")]
|
|
pub(crate) enum RawIngestRouteState {
|
|
/// Required Config composition is incomplete or incoherent.
|
|
Unavailable,
|
|
/// Config proves composability but no runtime Worker is active.
|
|
Configured,
|
|
/// Runtime resources are being revalidated and assembled.
|
|
Starting,
|
|
/// One Worker instance is active for the logical route.
|
|
Running,
|
|
/// Stop has been requested and bounded termination is pending.
|
|
Stopping,
|
|
/// The route Worker terminated normally and its handle was removed.
|
|
Stopped,
|
|
/// Start or runtime failed with a safe projected code.
|
|
Faulted,
|
|
}
|
|
|
|
impl crate::RawIngestRouteState {
|
|
/// Returns all lifecycle states in stable presentation order.
|
|
#[must_use]
|
|
pub(crate) fn all() -> std::vec::Vec<Self> {
|
|
return vec![Self::Unavailable, Self::Configured, Self::Starting, Self::Running, Self::Stopping, Self::Stopped, Self::Faulted];
|
|
}
|
|
}
|
|
|
|
/// Static route/state foundation retained as the bounded vocabulary behind the live Config inventory.
|
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteFoundationDto.ts")]
|
|
pub(crate) struct RawIngestRouteFoundationDto {
|
|
/// Five stable V1 logical route identifiers; this is not a composability claim.
|
|
pub(crate) route_ids: std::vec::Vec<crate::RawIngestRouteId>,
|
|
/// Stable lifecycle state vocabulary reserved for runtime projections.
|
|
pub(crate) states: std::vec::Vec<crate::RawIngestRouteState>,
|
|
}
|
|
|
|
impl crate::RawIngestRouteFoundationDto {
|
|
/// Builds the bounded route/state vocabulary without resolving endpoints, secrets or Worker resources.
|
|
#[must_use]
|
|
pub(crate) fn scaffold() -> Self {
|
|
return Self { route_ids: crate::RawIngestRouteId::all(), states: crate::RawIngestRouteState::all() };
|
|
}
|
|
}
|
|
|
|
/// Safe Config-only composability projection for one logical route.
|
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteDto.ts")]
|
|
pub(crate) struct RawIngestRouteDto {
|
|
/// Stable route family used for presentation and bounded orchestration.
|
|
pub(crate) family: crate::RawIngestRouteFamily,
|
|
/// Stable operator-facing label with no physical resource identity.
|
|
pub(crate) label: String,
|
|
/// Logical network proven by Config when available.
|
|
pub(crate) network: std::option::Option<String>,
|
|
/// Safe reason explaining an unavailable route.
|
|
pub(crate) reason: std::option::Option<crate::RawIngestRouteUnavailableReason>,
|
|
/// Stable logical V1 route identifier.
|
|
pub(crate) route_id: crate::RawIngestRouteId,
|
|
/// Whether all Config requirements for the route are currently composable.
|
|
pub(crate) selectable: bool,
|
|
/// Config-level lifecycle projection; `Configured` is not a runtime health claim.
|
|
pub(crate) state: crate::RawIngestRouteState,
|
|
}
|
|
|
|
impl crate::RawIngestRouteDto {
|
|
/// Builds one route that is composable from Config without claiming runtime operability.
|
|
#[must_use]
|
|
pub(crate) fn configured(route_id: crate::RawIngestRouteId, network: &str) -> Self {
|
|
return Self {
|
|
family: route_id.family(),
|
|
label: route_id.label().to_owned(),
|
|
network: std::option::Option::Some(network.to_owned()),
|
|
reason: std::option::Option::None,
|
|
route_id,
|
|
selectable: true,
|
|
state: crate::RawIngestRouteState::Configured,
|
|
};
|
|
}
|
|
|
|
/// Builds one route that is not composable from the current Config profile.
|
|
#[must_use]
|
|
pub(crate) fn unavailable(
|
|
route_id: crate::RawIngestRouteId,
|
|
network: std::option::Option<&str>,
|
|
reason: crate::RawIngestRouteUnavailableReason,
|
|
) -> Self {
|
|
return Self {
|
|
family: route_id.family(),
|
|
label: route_id.label().to_owned(),
|
|
network: network.map(str::to_owned),
|
|
reason: std::option::Option::Some(reason),
|
|
route_id,
|
|
selectable: false,
|
|
state: crate::RawIngestRouteState::Unavailable,
|
|
};
|
|
}
|
|
}
|
|
|
|
/// Safe route inventory for one logical Raw Transaction Ingest Desk composite profile.
|
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestProfileInventoryDto.ts")]
|
|
pub(crate) struct RawIngestProfileInventoryDto {
|
|
/// Whether this profile is the composite's autonomous default.
|
|
pub(crate) is_default: bool,
|
|
/// Logical network proven from the resolved Config profile when available.
|
|
pub(crate) network: std::option::Option<String>,
|
|
/// Stable composite profile identifier.
|
|
pub(crate) profile_id: String,
|
|
/// Logical routes applicable to this network profile in stable V1 presentation order; provider-specific routes may be absent when their Config source is not declared.
|
|
pub(crate) routes: std::vec::Vec<crate::RawIngestRouteDto>,
|
|
}
|
|
|
|
/// Deterministic Config-only route inventory returned to the frontend.
|
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_raw_transaction_ingest_desk/dto_route/RawIngestRouteInventoryDto.ts")]
|
|
pub(crate) struct RawIngestRouteInventoryDto {
|
|
/// Composite default profile identifier.
|
|
pub(crate) default_profile: String,
|
|
/// Monotonic application-owned generation incremented after each successful inventory rebuild.
|
|
pub(crate) generation: u32,
|
|
/// Safe inventories for every validated composite profile in source order.
|
|
pub(crate) profiles: std::vec::Vec<crate::RawIngestProfileInventoryDto>,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "../unit_tests/dto_route.rs"]
|
|
mod tests;
|