sentry and other misc stuff

This commit is contained in:
Skye 2024-06-14 14:57:42 +09:00
parent 3d381e017f
commit eafc9e355c
6 changed files with 893 additions and 38 deletions

3
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"rust-analyzer.check.command": "check"
}

895
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -7,10 +7,9 @@ license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = { version = "1.0.71", features = ["backtrace"] }
async-trait = "0.1.68"
axum = "0.6.18" axum = "0.6.18"
env_logger = "0.10.0" env_logger = "0.10.0"
eyre = "0.6.12"
idna = "0.4.0" idna = "0.4.0"
log = "0.4.19" log = "0.4.19"
parking_lot = "0.12.1" parking_lot = "0.12.1"
@ -18,6 +17,7 @@ quinn = "0.10.1"
rand = "0.8.5" rand = "0.8.5"
rustls = "0.21.9" rustls = "0.21.9"
rustls-pemfile = "1.0.2" rustls-pemfile = "1.0.2"
sentry = { version = "0.34.0", default-features = false, features = ["backtrace", "contexts", "panic", "debug-images", "reqwest", "rustls"] }
serde = { version = "1.0.164", features = ["derive"] } serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0.97" serde_json = "1.0.97"
thiserror = "1.0.40" thiserror = "1.0.40"

View file

@ -113,6 +113,12 @@
example = "/path/to/key.pem"; example = "/path/to/key.pem";
description = lib.mdDoc "Path to TLS key to use for quiclime connections."; description = lib.mdDoc "Path to TLS key to use for quiclime connections.";
}; };
sentryDsn = mkOption {
type = types.str;
example = "https://key@sentry.io/42";
description = lib.mdDoc "Sentry DSN to use for error reports.";
};
}; };
}; };
@ -137,6 +143,7 @@
QUICLIME_BIND_ADDR_WEB = cfg.controlAddr; QUICLIME_BIND_ADDR_WEB = cfg.controlAddr;
QUICLIME_CERT_PATH = cfg.cert; QUICLIME_CERT_PATH = cfg.cert;
QUICLIME_KEY_PATH = cfg.key; QUICLIME_KEY_PATH = cfg.key;
SENTRY_DSN = cfg.sentryDsn;
}; };
}; };

View file

@ -4,7 +4,7 @@
use std::{convert::Infallible, net::SocketAddr, sync::Arc, time::Duration}; use std::{convert::Infallible, net::SocketAddr, sync::Arc, time::Duration};
use anyhow::{anyhow, Context}; use eyre::{anyhow, Context, self as anyhow};
use axum::{ use axum::{
http::StatusCode, http::StatusCode,
routing::{get, post}, routing::{get, post},
@ -85,6 +85,7 @@ async fn create_server_config() -> anyhow::Result<ServerConfig> {
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
let _guard = sentry::init(std::env::var("SENTRY_DSN").ok());
env_logger::init(); env_logger::init();
// JUSTIFICATION: this lives until the end of the entire program // JUSTIFICATION: this lives until the end of the entire program
let endpoint = Box::leak(Box::new(Endpoint::server( let endpoint = Box::leak(Box::new(Endpoint::server(
@ -103,6 +104,7 @@ async fn main() -> anyhow::Result<()> {
listen_control(endpoint, routing_table), listen_control(endpoint, routing_table),
listen_minecraft(routing_table) listen_minecraft(routing_table)
)?; )?;
drop(_guard);
Ok(()) Ok(())
} }
@ -182,6 +184,7 @@ async fn try_handle_quic(
async fn handle_quic(connection: Connecting, routing_table: &RoutingTable) { async fn handle_quic(connection: Connecting, routing_table: &RoutingTable) {
if let Err(e) = try_handle_quic(connection, routing_table).await { if let Err(e) = try_handle_quic(connection, routing_table).await {
sentry::capture_error::<dyn std::error::Error>(e.as_ref());
error!("Error handling QUIClime connection: {}", e); error!("Error handling QUIClime connection: {}", e);
}; };
info!("Finished handling QUIClime connection"); info!("Finished handling QUIClime connection");
@ -225,6 +228,9 @@ async fn listen_control(
.route( .route(
"/stop", "/stop",
post(|| async { post(|| async {
endpoint.reject_new_connections();
routing_table.broadcast("e4mc relay server stopping!");
tokio::time::sleep(Duration::from_secs(1)).await;
endpoint.close(0u32.into(), b"e4mc closing"); endpoint.close(0u32.into(), b"e4mc closing");
}), }),
); );
@ -259,11 +265,8 @@ async fn try_handle_minecraft(
return politely_disconnect(connection, handshake).await; return politely_disconnect(connection, handshake).await;
}; };
handshake.send(&mut send_host).await?; handshake.send(&mut send_host).await?;
let (mut recv_client, mut send_client) = connection.split(); let mut conn_host = tokio::io::join(&mut recv_host, &mut send_host);
tokio::select! { _ = tokio::io::copy_bidirectional(&mut connection, &mut conn_host);
_ = tokio::io::copy(&mut recv_client, &mut send_host) => (),
_ = tokio::io::copy(&mut recv_host, &mut send_client) => ()
}
_ = connection.shutdown().await; _ = connection.shutdown().await;
_ = send_host.finish().await; _ = send_host.finish().await;
_ = recv_host.stop(0u32.into()); _ = recv_host.stop(0u32.into());
@ -323,7 +326,8 @@ async fn politely_disconnect(
async fn handle_minecraft(connection: TcpStream, routing_table: &'static RoutingTable) { async fn handle_minecraft(connection: TcpStream, routing_table: &'static RoutingTable) {
if let Err(e) = try_handle_minecraft(connection, routing_table).await { if let Err(e) = try_handle_minecraft(connection, routing_table).await {
error!("Error handling Minecraft connection: {}", e.backtrace()); sentry::capture_error::<dyn std::error::Error>(e.as_ref());
error!("Error handling Minecraft connection: {:#}", e);
}; };
} }
@ -340,6 +344,7 @@ async fn listen_minecraft(routing_table: &'static RoutingTable) -> anyhow::Resul
tokio::spawn(handle_minecraft(connection, routing_table)); tokio::spawn(handle_minecraft(connection, routing_table));
} }
Err(e) => { Err(e) => {
sentry::capture_error(&e);
error!("Error accepting minecraft connection: {}", e); error!("Error accepting minecraft connection: {}", e);
} }
} }

View file

@ -4,9 +4,9 @@ use std::io::Read;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use async_trait::async_trait;
use log::error; use log::error;
use thiserror::Error; use thiserror::Error;
use eyre as anyhow;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ReadError { pub enum ReadError {
@ -119,7 +119,6 @@ async fn read_varint(mut reader: impl AsyncReadExt + Unpin) -> Result<i32, ReadE
impl<T: Read> ReadExt for T {} impl<T: Read> ReadExt for T {}
#[async_trait]
pub trait WriteExt: AsyncWriteExt + Unpin { pub trait WriteExt: AsyncWriteExt + Unpin {
async fn write_varint(&mut self, mut val: i32) -> std::io::Result<()> { async fn write_varint(&mut self, mut val: i32) -> std::io::Result<()> {
for _ in 0..5 { for _ in 0..5 {