Lots more plumbing

Focusing mostly on getting main in shape and figuring out how to make
the connections flow. The main is pretty much there, going to be a bit
more when I take a shot at federation.
This commit is contained in:
2026-05-16 13:31:23 -07:00
parent 1bd9555287
commit 42bcebb50c
8 changed files with 920 additions and 52 deletions
+118 -13
View File
@@ -1,16 +1,29 @@
mod client;
mod config;
mod connection;
mod state;
use diesel::{Connection,PgConnection};
use diesel_async::pooled_connection::AsyncDieselConnectionManager;
use diesel_async::pooled_connection::deadpool::Pool;
use diesel_async::{AsyncConnection,AsyncPgConnection};
use quinn::rustls::pki_types::{PrivateKeyDer,CertificateDer,pem::PemObject};
use std::net::{IpAddr,SocketAddr};
use std::str::FromStr;
use quinn::Endpoint;
use tracing::{error,instrument};
use std::io;
use std::fs;
use std::net::{IpAddr,SocketAddr};
use std::process::ExitCode;
use std::str::FromStr;
use std::sync::Arc;
use serde::{Deserialize,Serialize};
use tracing::{error,instrument,warn,debug};
use tokio::sync::{RwLock,broadcast,mpsc};
use crate::config::Config;
use crate::state::State;
#[derive(Hash,Eq,PartialEq,Clone,Serialize,Deserialize)]
pub struct Coordinate(Vec<i64>);
#[tokio::main]
#[instrument]
@@ -22,12 +35,19 @@ async fn main() -> ExitCode {
error!("Problem while reading config file");
error!("{:?}",e);
return ExitCode::FAILURE;
}
};
// Set up database connection
let db_connection = PgConnection::establish(&config.database.url);
let db_config = AsyncDieselConnectionManager::<diesel_async::AsyncPgConnection>::new(config.database.url.clone());
let db_pool = match Pool::builder(db_config).build() {
Ok(val) => val,
Err(e) => {
error!("Error while creating database connection pool");
error!("{:?}",e);
return ExitCode::FAILURE;
}
};
// Read certificate file
@@ -66,14 +86,99 @@ async fn main() -> ExitCode {
}
};
// Load or create new state
let state = match State::load_from_file(&config.statefile) {
Ok(state) => state,
// Create file if it does not exist
Err(e) => {
match e.kind() {
io::ErrorKind::NotFound => {
match fs::File::create(&config.statefile) {
// If the statefile is writable then create an empty state
// and use that
Ok(_) => State::new(),
Err(e) => {
error!("Could not open or create statefile. Check your config.");
error!("{:?}",e);
return ExitCode::FAILURE;
// Start iterating over incoming connections.
while let Some(conn) = endpoint.accept().await {
let connection = conn.await;
}
}
// Save connection somewhere, start transferring, receiving data, see DataTransfer tutorial.
},
_ => {
error!("Could not open or create statefile. Check your config.");
error!("{:?}",e);
return ExitCode::FAILURE;
}
}
},
};
let statehandle = Arc::new(RwLock::new(state));
// Global connections
let (close_send,close_recv) = broadcast::channel(1);
let (message_send,message_recv) = broadcast::channel(128);
let (message_ack_send,message_ack_recv) = mpsc::channel(128);
match ctrlc_async::set_async_handler(
async move { match close_send.send(()) {
Ok(_val) => (),
Err(e) => {
error!("Shutdown handler is broken. Cannot gracefully exit.");
error!("{:?}",e);
}
}
}
) {
Ok(()) => (),
Err(e) => {
error!("Could not set up signal handler");
error!("{:?}",e);
return ExitCode::FAILURE;
}
};
let mut join_handles = Vec::new();
// Create client listener
let statehandle_cloned = statehandle.clone();
join_handles.push(tokio::spawn(async move {
connection::client_handler(
statehandle_cloned,
(message_send.clone(),message_recv.resubscribe()),
message_ack_send,
db_pool,
endpoint,
close_recv.resubscribe()
).await;
} ));
// Wait for child threads to exit
for handle in join_handles {
match handle.await {
Ok(()) => (),
Err(e) => {
warn!("Problem while cleaning up threads");
warn!("{:?}",e);
}
}
}
//Save state
match statehandle.write().await.write_to_file(&config.statefile) {
Ok(()) => debug!("Successfully wrote state to {:?}",config.statefile),
Err(e) => {
error!("Problem while writing to statefile");
error!("{:?}",e);
}
}
// Should never reach this
// How should I gracefully shutdown? Can I trap ctrlc
ExitCode::SUCCESS