//! Internal Raft RPC service implementation //! //! This service handles Raft protocol messages between nodes in the cluster. //! It bridges the gRPC layer with the custom Raft implementation. use crate::internal_proto::{ raft_service_server::RaftService, AppendEntriesRequest as ProtoAppendEntriesRequest, AppendEntriesResponse as ProtoAppendEntriesResponse, InstallSnapshotRequest, InstallSnapshotResponse, VoteRequest as ProtoVoteRequest, VoteResponse as ProtoVoteResponse, }; use chainfire_raft::core::{ RaftCore, VoteRequest, AppendEntriesRequest, }; use chainfire_storage::{LogId, LogEntry as RaftLogEntry, EntryPayload}; use chainfire_types::command::RaftCommand; use std::sync::Arc; use tokio::sync::oneshot; use tonic::{Request, Response, Status, Streaming}; use tracing::{debug, info, trace, warn}; /// Internal Raft RPC service implementation /// /// This service handles Raft protocol messages between nodes. pub struct RaftServiceImpl { /// Reference to the Raft core raft: Arc, } impl RaftServiceImpl { /// Create a new Raft service with a RaftCore instance pub fn new(raft: Arc) -> Self { Self { raft } } } #[tonic::async_trait] impl RaftService for RaftServiceImpl { async fn vote( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); info!( term = req.term, candidate = req.candidate_id, "Vote request received" ); // Convert proto request to custom Raft request let vote_req = VoteRequest { term: req.term, candidate_id: req.candidate_id, last_log_index: req.last_log_index, last_log_term: req.last_log_term, }; // Forward to Raft core using oneshot channel let (resp_tx, resp_rx) = oneshot::channel(); self.raft.request_vote_rpc(vote_req, resp_tx).await; // Wait for response let resp = resp_rx.await.map_err(|e| { warn!(error = %e, "Vote request channel closed"); Status::internal("Vote request failed: channel closed") })?; trace!(term = resp.term, granted = resp.vote_granted, "Vote response"); Ok(Response::new(ProtoVoteResponse { term: resp.term, vote_granted: resp.vote_granted, last_log_index: 0, // Not used in custom impl last_log_term: 0, // Not used in custom impl })) } async fn append_entries( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); info!( term = req.term, leader = req.leader_id, entries = req.entries.len(), "AppendEntries request received" ); // Convert proto entries to custom Raft entries let entries: Vec> = req .entries .into_iter() .map(|e| { let payload = if e.data.is_empty() { EntryPayload::Blank } else { // Deserialize the command from the entry data match bincode::deserialize::(&e.data) { Ok(cmd) => EntryPayload::Normal(cmd), Err(_) => EntryPayload::Blank, } }; RaftLogEntry { log_id: LogId { term: e.term, index: e.index, }, payload, } }) .collect(); let append_req = AppendEntriesRequest { term: req.term, leader_id: req.leader_id, prev_log_index: req.prev_log_index, prev_log_term: req.prev_log_term, entries, leader_commit: req.leader_commit, }; // Forward to Raft core using oneshot channel let (resp_tx, resp_rx) = oneshot::channel(); self.raft.append_entries_rpc(append_req, resp_tx).await; // Wait for response let resp = resp_rx.await.map_err(|e| { warn!(error = %e, "AppendEntries request channel closed"); Status::internal("AppendEntries request failed: channel closed") })?; trace!(success = resp.success, "AppendEntries response"); Ok(Response::new(ProtoAppendEntriesResponse { term: resp.term, success: resp.success, conflict_index: resp.conflict_index.unwrap_or(0), conflict_term: resp.conflict_term.unwrap_or(0), })) } async fn install_snapshot( &self, request: Request>, ) -> Result, Status> { let mut stream = request.into_inner(); debug!("InstallSnapshot stream started"); // Collect all chunks (for compatibility) while let Some(chunk) = stream.message().await? { if chunk.done { break; } } // Custom Raft doesn't support snapshots yet warn!("InstallSnapshot not supported in custom Raft implementation"); Err(Status::unimplemented("Snapshots not supported in custom Raft implementation")) } }