Skip to content

Commit

Permalink
Adding custom error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
esiebert committed Jul 14, 2024
1 parent 429f06d commit 76d62d3
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 33 deletions.
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ async-stream = "0.3.5"
tonic-types = "0.11.0"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
anyhow = "1.0.86"
thiserror = "1.0.62"

[build-dependencies]
tonic-build = "0.11"
75 changes: 49 additions & 26 deletions src/api/grpc.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use tonic::service::interceptor::InterceptedService;
use tonic_reflection::server::{ServerReflection, ServerReflectionServer};

use crate::cycling_tracker::CyclingTrackerServer;
use crate::cycling_tracker::SessionAuthServer;
use crate::service::CyclingTrackerService;
use crate::service::SessionAuthService;
use anyhow::Result;
use thiserror::Error;
use tonic::service::interceptor::InterceptedService;
use tonic::{
metadata::MetadataValue,
transport::{server::Router, Identity, Server, ServerTlsConfig},
Request, Status,
};
use tonic_reflection::server::{ServerReflection, ServerReflectionServer};

use crate::service::CyclingTrackerService;
use crate::service::SessionAuthService;

use tracing::info;
use tracing::{info, instrument};

#[derive(Debug)]
pub struct GRPC {
addr: String,
// Wrap router with Option, because we will have to swap its content
Expand All @@ -26,8 +27,9 @@ impl GRPC {
Builder::new()
}

pub async fn run(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let addr = self.addr.parse().unwrap();
#[instrument(name = "gRPC::run", skip(self), err)]
pub async fn run(&mut self) -> Result<()> {
let addr: std::net::SocketAddr = self.addr.parse().unwrap();
info!("CyclingTracker listening on: {}", addr);

// Router doesn't implement clone, so we create an auxiliary variable,
Expand All @@ -43,16 +45,6 @@ impl GRPC {
}
}

fn config_tls() -> Result<ServerTlsConfig, Box<dyn std::error::Error>> {
let data_dir =
std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data/tls"]);
let cert = std::fs::read_to_string(data_dir.join("server.pem"))
.map_err(|err| format!("Error reading public key file: {}", err))?;
let key = std::fs::read_to_string(data_dir.join("server.key"))
.map_err(|err| format!("Error reading private key file: {}", err))?;
Ok(ServerTlsConfig::new().identity(Identity::from_pem(cert, key)))
}

fn check_session_token(req: Request<()>) -> Result<Request<()>, Status> {
let token: MetadataValue<_> = "Bearer session-token".parse().unwrap();

Expand All @@ -64,7 +56,7 @@ fn check_session_token(req: Request<()>) -> Result<Request<()>, Status> {

pub struct Builder {
server: Server,
addr: Option<String>,
addr: Option<std::net::SocketAddr>,
router: Option<Router>,
}

Expand All @@ -77,14 +69,37 @@ impl Builder {
}
}

pub fn with_addr(mut self, addr: String) -> Self {
self.addr = Some(addr);
self
pub fn with_addr(mut self, addr: String) -> Result<Self, GRPCBuildError> {
let socket_addr = addr.parse().map_err(|err| {
GRPCBuildError::InvalidAddr(format!("Can't parse address: {}", err))
})?;
self.addr = Some(socket_addr);

Ok(self)
}

pub fn with_tls(mut self) -> Self {
self.server = self.server.tls_config(config_tls().unwrap()).unwrap();
self
pub fn with_tls(mut self) -> Result<Self, GRPCBuildError> {
use std::fs::read_to_string;
use std::path::PathBuf;

let data_dir =
PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data/tls"]);

let cert = read_to_string(data_dir.join("server.pem")).map_err(|err| {
GRPCBuildError::TLSSetupError(format!("Error reading public key: {}", err))
})?;

let key = read_to_string(data_dir.join("server.key")).map_err(|err| {
GRPCBuildError::TLSSetupError(format!("Error reading private key: {}", err))
})?;

let config_tls = ServerTlsConfig::new().identity(Identity::from_pem(cert, key));

self.server = self.server.tls_config(config_tls).map_err(|err| {
GRPCBuildError::TLSSetupError(format!("Error configuring TLS: {}", err))
})?;

Ok(self)
}

pub fn add_auth_service(
Expand Down Expand Up @@ -146,6 +161,14 @@ impl Builder {
}
}

#[derive(Debug, Error)]
pub enum GRPCBuildError {
#[error("Unable to setup TLS: {0}")]
TLSSetupError(String),
#[error("Invalid socket address: {0}")]
InvalidAddr(String),
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
4 changes: 2 additions & 2 deletions src/api/sqlite.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Result;
use tokio::sync::mpsc::{channel, Receiver, Sender};

pub struct SQLite {
receiver: Receiver<Message>,
handler: Sender<Message>,
Expand All @@ -19,7 +19,7 @@ impl SQLite {
}
}

pub async fn run(mut self) -> Result<(), Box<dyn std::error::Error>> {
pub async fn run(mut self) -> Result<()> {
while let Some(i) = self.receiver.recv().await {
println!("Saving log to database = {:?}", i);
}
Expand Down
10 changes: 6 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
pub mod api;
pub mod service;
use anyhow::Result;
use api::{grpc::Builder, SQLite, GRPC};
use service::{CyclingTrackerService, SessionAuthService};
use tonic_reflection::server::Builder as ReflectionServerBuilder;

use api::{grpc::Builder, SQLite, GRPC};

type GRPCResult<T> = Result<tonic::Response<T>, tonic::Status>;

pub const FILE_DESCRIPTOR_SET: &[u8] = include_bytes!("fds/cyclingtracker.bin");
Expand Down Expand Up @@ -33,11 +33,13 @@ impl App {
let refl = ReflectionServerBuilder::configure()
.register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET)
.build()
.unwrap();
.expect("Failed to setup reflection service");

let grpc = Builder::new()
.with_addr(grpc_host_url)
.expect("Failed to set address")
.with_tls()
.expect("Failed when setting up TLS")
.add_auth_service(auth)
.add_reflection_service(refl)
.add_ct_service(cts, false)
Expand All @@ -50,7 +52,7 @@ impl App {
}

/// Run all actors.
pub async fn run(mut self) -> Result<(), Box<dyn std::error::Error>> {
pub async fn run(mut self) -> Result<()> {
tokio::select! {
e = self.grpc.run() => {
e
Expand Down
7 changes: 6 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ use tracing_subscriber;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt().with_max_level(Level::INFO).init();
let format = tracing_subscriber::fmt::format().with_target(false);

tracing_subscriber::fmt()
.event_format(format)
.with_max_level(Level::INFO)
.init();

info!("Starting gRPC server");

Expand Down

0 comments on commit 76d62d3

Please sign in to comment.