167 lines
5.4 KiB
Rust
167 lines
5.4 KiB
Rust
/*
|
|
* mCaptcha - A proof of work based DoS protection system
|
|
* Copyright © 2023 Aravinth Manivannan <realravinth@batsense.net>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#![allow(clippy::uninlined_format_args)]
|
|
|
|
use std::io::Cursor;
|
|
use std::sync::Arc;
|
|
|
|
use openraft::storage::Adaptor;
|
|
use openraft::BasicNode;
|
|
use openraft::Config;
|
|
use openraft::Raft;
|
|
use tonic::transport::Server;
|
|
|
|
use crate::app::DcacheApp;
|
|
use crate::network::raft_network_impl::DcacheNetwork;
|
|
use crate::protobuf::dcache::dcache_service_client::DcacheServiceClient;
|
|
use crate::protobuf::dcache::dcache_service_server::DcacheServiceServer;
|
|
use crate::protobuf::dcache::Learner;
|
|
use crate::store::DcacheRequest;
|
|
use crate::store::DcacheResponse;
|
|
use crate::store::DcacheStore;
|
|
|
|
pub mod app;
|
|
mod mcaptcha;
|
|
pub mod network;
|
|
mod pool;
|
|
mod protobuf;
|
|
pub mod store;
|
|
|
|
pub type DcacheNodeId = u64;
|
|
|
|
openraft::declare_raft_types!(
|
|
/// Declare the type configuration for example K/V store.
|
|
pub DcacheTypeConfig: D = DcacheRequest, R = DcacheResponse, NodeId = DcacheNodeId, Node = BasicNode,
|
|
Entry = openraft::Entry<DcacheTypeConfig>, SnapshotData = Cursor<Vec<u8>>
|
|
);
|
|
|
|
pub type LogStore = Adaptor<DcacheTypeConfig, Arc<DcacheStore>>;
|
|
pub type StateMachineStore = Adaptor<DcacheTypeConfig, Arc<DcacheStore>>;
|
|
pub type DcacheRaft = Raft<DcacheTypeConfig, Arc<DcacheNetwork>, LogStore, StateMachineStore>;
|
|
|
|
pub mod typ {
|
|
use openraft::BasicNode;
|
|
|
|
use crate::DcacheNodeId;
|
|
use crate::DcacheTypeConfig;
|
|
|
|
pub type RaftError<E = openraft::error::Infallible> =
|
|
openraft::error::RaftError<DcacheNodeId, E>;
|
|
pub type RPCError<E = openraft::error::Infallible> =
|
|
openraft::error::RPCError<DcacheNodeId, BasicNode, RaftError<E>>;
|
|
|
|
pub type ClientWriteError = openraft::error::ClientWriteError<DcacheNodeId, BasicNode>;
|
|
pub type CheckIsLeaderError = openraft::error::CheckIsLeaderError<DcacheNodeId, BasicNode>;
|
|
pub type ForwardToLeader = openraft::error::ForwardToLeader<DcacheNodeId, BasicNode>;
|
|
pub type InitializeError = openraft::error::InitializeError<DcacheNodeId, BasicNode>;
|
|
|
|
pub type ClientWriteResponse = openraft::raft::ClientWriteResponse<DcacheTypeConfig>;
|
|
}
|
|
|
|
pub async fn start_example_raft_node(
|
|
node_id: DcacheNodeId,
|
|
http_addr: String,
|
|
introducer_addr: String,
|
|
introducer_id: DcacheNodeId,
|
|
) -> std::io::Result<()> {
|
|
// Create a configuration for the raft instance.
|
|
let config = Config {
|
|
heartbeat_interval: 500,
|
|
election_timeout_min: 1500,
|
|
election_timeout_max: 3000,
|
|
..Default::default()
|
|
};
|
|
|
|
let salt = "foobar12".into();
|
|
#[cfg(release)]
|
|
todo!("set salt");
|
|
|
|
let config = Arc::new(config.validate().unwrap());
|
|
|
|
// Create a instance of where the Raft data will be stored.
|
|
let store = Arc::new(DcacheStore::new(salt));
|
|
|
|
let (log_store, state_machine) = Adaptor::new(store.clone());
|
|
|
|
// Create the network layer that will connect and communicate the raft instances and
|
|
// will be used in conjunction with the store created above.
|
|
|
|
let (manager_tx, manager_rx) = tokio::sync::mpsc::channel(1000);
|
|
// let health = Arc::new(crate::network::raft_network_impl::HealthLedger::new(manager_tx));
|
|
// let network = Arc::new(DcacheNetwork::new(health));
|
|
let network = Arc::new(DcacheNetwork::new(manager_tx));
|
|
|
|
// Create a local raft instance.
|
|
let raft = Raft::new(
|
|
node_id,
|
|
config.clone(),
|
|
network.clone(),
|
|
log_store,
|
|
state_machine,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
raft.enable_heartbeat(true);
|
|
raft.enable_elect(true);
|
|
|
|
// raft.enable_tick(true);
|
|
|
|
// Create an application that will store all the instances created above, this will
|
|
// be later used on the actix-web services.
|
|
let app = DcacheApp {
|
|
id: node_id,
|
|
addr: http_addr.clone(),
|
|
raft,
|
|
store,
|
|
config,
|
|
network,
|
|
};
|
|
let app = Arc::new(app);
|
|
let dcache_service = protobuf::MyDcacheImpl::new(app.clone());
|
|
|
|
if introducer_addr == http_addr {
|
|
app.init().await.unwrap();
|
|
}
|
|
|
|
let app_copy = app.clone();
|
|
|
|
let svc = DcacheServiceServer::new(dcache_service);
|
|
|
|
let x = Server::builder()
|
|
.add_service(svc)
|
|
.serve(http_addr.clone().parse().unwrap());
|
|
let server_fut = tokio::spawn(x);
|
|
|
|
tokio::time::sleep(std::time::Duration::new(3, 0)).await;
|
|
|
|
let url = format!("http://{}", introducer_addr);
|
|
let mut client = DcacheServiceClient::connect(url).await.unwrap();
|
|
client
|
|
.add_learner(Learner {
|
|
id: node_id,
|
|
addr: http_addr,
|
|
})
|
|
.await
|
|
.unwrap();
|
|
|
|
let health_metrics_handle =
|
|
crate::network::management::HealthMetrics::spawn(app_copy, 5, manager_rx).await;
|
|
server_fut.await?.unwrap();
|
|
health_metrics_handle.abort();
|
|
Ok(())
|
|
}
|