Sentry tracking and more cleanup

This commit is contained in:
Evan Pratten 2021-09-29 22:20:04 -04:00
parent 0c8f679de9
commit e3d1d00786
10 changed files with 98 additions and 34 deletions

View File

@ -20,6 +20,7 @@ puffin = "0.9"
puffin_http = "0.6" puffin_http = "0.6"
dirty-fsm = "^0.2.1" dirty-fsm = "^0.2.1"
num-traits = "0.2" num-traits = "0.2"
sentry = "0.23"
[dev-dependencies] [dev-dependencies]
puffin_viewer = "0.6" puffin_viewer = "0.6"

View File

@ -9,5 +9,6 @@
"Developer" "Developer"
] ]
} }
] ],
"sentry_dsn": "https://d5d94e75f08841388287fa0c23606ac7@o398481.ingest.sentry.io/5985679"
} }

View File

@ -1,3 +1,3 @@
{ {
"app_id": 889531982978117633 "app_id": 889531982978117633
} }

37
game/src/discord_rpc.rs Normal file
View File

@ -0,0 +1,37 @@
use std::time::Duration;
use discord_sdk::activity::ActivityBuilder;
use tracing::{error, log::info};
use crate::utilities::discord::{rpc::DiscordError, DiscordConfig, DiscordRpcClient};
/// How long to wait before we give up on connecting to Discord.
const DISCORD_CONNECT_TIMEOUT_SECONDS: u64 = 5;
/// Try to connect to a local discord client for RPC, or return an error.
pub async fn try_connect_to_local_discord(
config: &DiscordConfig,
) -> Result<DiscordRpcClient, DiscordError> {
info!("Trying to locate and connect to a local Discord process for RPC. Will wait up to {} seconds before timing out", DISCORD_CONNECT_TIMEOUT_SECONDS);
// Connect while wrapped in a tokio timeout
let rpc_client = tokio::time::timeout(
Duration::from_secs(DISCORD_CONNECT_TIMEOUT_SECONDS),
DiscordRpcClient::new(config.app_id, discord_sdk::Subscriptions::ACTIVITY),
)
.await??;
info!("Successfully connected to Discord");
Ok(rpc_client)
}
/// If the discord client object exists, set rich presence, otherwise, do nothing.
pub async fn maybe_set_discord_presence(
client: &Option<DiscordRpcClient>,
activity: ActivityBuilder,
) -> Result<(), DiscordError> {
if let Some(rpc) = client {
rpc.set_rich_presence(activity).await?;
}
Ok(())
}

View File

@ -64,20 +64,19 @@
nonstandard_style, nonstandard_style,
rust_2018_idioms rust_2018_idioms
)] )]
#![feature(custom_inner_attributes)]
#![clippy::msrv = "1.57.0"]
use std::cell::RefCell; use std::cell::RefCell;
use discord_sdk::activity::ActivityBuilder; use discord_sdk::activity::ActivityBuilder;
use raylib::prelude::*; use raylib::prelude::*;
use tracing::{error, info}; use tracing::{error, info};
use utilities::{ use utilities::discord::DiscordConfig;
datastore::StaticGameData,
discord::{DiscordConfig, DiscordRpcClient},
game_config::GameConfig,
};
use crate::{ use crate::{
context::GameContext, context::GameContext,
discord_rpc::{maybe_set_discord_presence, try_connect_to_local_discord},
scenes::build_screen_state_machine, scenes::build_screen_state_machine,
utilities::shaders::{ utilities::shaders::{
shader::ShaderWrapper, shader::ShaderWrapper,
@ -91,45 +90,46 @@ extern crate thiserror;
extern crate serde; extern crate serde;
mod context; mod context;
mod discord_rpc;
mod scenes; mod scenes;
mod utilities; mod utilities;
pub use utilities::{datastore::StaticGameData, game_config::GameConfig};
/// The game entrypoint /// The game entrypoint
pub async fn game_begin() -> Result<(), Box<dyn std::error::Error>> { pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::error::Error>> {
// Load the general config for the game
let game_config = GameConfig::load(
StaticGameData::get("configs/application.json").expect("Failed to load application.json"),
)?;
// Set up profiling // Set up profiling
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
let _puffin_server = let _puffin_server =
puffin_http::Server::new(&format!("0.0.0.0:{}", puffin_http::DEFAULT_PORT))?; puffin_http::Server::new(&format!("0.0.0.0:{}", puffin_http::DEFAULT_PORT)).unwrap();
puffin::set_scopes_on(true); puffin::set_scopes_on(true);
// Attempt to connect to a locally running Discord instance for rich presence access // Attempt to connect to a locally running Discord instance for rich presence access
let discord_config = DiscordConfig::load( let discord_config = DiscordConfig::load(
StaticGameData::get("configs/discord.json").expect("Failed to load discord.json"), StaticGameData::get("configs/discord.json").expect("Failed to load discord.json"),
)?; )
let discord_rpc = .unwrap();
match DiscordRpcClient::new(discord_config.app_id, discord_sdk::Subscriptions::ACTIVITY) let discord_rpc = match try_connect_to_local_discord(&discord_config).await {
.await Ok(client) => Some(client),
{ Err(err) => match err {
Ok(client) => Some(client), utilities::discord::rpc::DiscordError::ConnectionTimeoutError(time) => {
Err(err) => { error!(
error!("Could not connect to or find a locally running Discord instance."); "Could not find or connect to a local Discord instance after {} seconds",
error!("Discord connection error: {:?}", err); time
);
None None
} }
}; _ => panic!("Failed to connect to Discord: {}", err),
},
if let Some(rpc) = discord_rpc { };
rpc.set_rich_presence(ActivityBuilder::default().details("Testing...")) maybe_set_discord_presence(
.await?; &discord_rpc,
} ActivityBuilder::default().details("Testing..."),
)
.await
.unwrap();
// Get the main state machine // Get the main state machine
let mut game_state_machine = build_screen_state_machine()?; let mut game_state_machine = build_screen_state_machine().unwrap();
let context; let context;
let raylib_thread; let raylib_thread;
@ -171,7 +171,9 @@ pub async fn game_begin() -> Result<(), Box<dyn std::error::Error>> {
puffin::GlobalProfiler::lock().new_frame(); puffin::GlobalProfiler::lock().new_frame();
// Update the GPU texture that we draw to. This handles screen resizing and some other stuff // Update the GPU texture that we draw to. This handles screen resizing and some other stuff
dynamic_texture.update(&mut context.renderer.borrow_mut(), &raylib_thread)?; dynamic_texture
.update(&mut context.renderer.borrow_mut(), &raylib_thread)
.unwrap();
// Switch into draw mode the unsafe way (using unsafe code here to avoid borrow checker hell) // Switch into draw mode the unsafe way (using unsafe code here to avoid borrow checker hell)
#[allow(unsafe_code)] #[allow(unsafe_code)]

View File

@ -2,3 +2,5 @@ pub mod rpc;
pub use rpc::DiscordRpcClient; pub use rpc::DiscordRpcClient;
pub mod config; pub mod config;
pub use config::DiscordConfig; pub use config::DiscordConfig;

View File

@ -7,6 +7,7 @@ use discord_sdk::{
Discord, DiscordApp, Subscriptions, Discord, DiscordApp, Subscriptions,
}; };
use tracing::info; use tracing::info;
use tokio::time::error::Elapsed;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum DiscordError { pub enum DiscordError {
@ -16,6 +17,8 @@ pub enum DiscordError {
AwaitConnectionError(#[from] tokio::sync::watch::error::RecvError), AwaitConnectionError(#[from] tokio::sync::watch::error::RecvError),
#[error("Could not connect")] #[error("Could not connect")]
ConnectionError, ConnectionError,
#[error(transparent)]
ConnectionTimeoutError(#[from] Elapsed)
} }
/// The client wrapper for Discord RPC /// The client wrapper for Discord RPC

View File

@ -15,6 +15,7 @@ pub struct Author {
pub struct GameConfig { pub struct GameConfig {
pub name: String, pub name: String,
pub authors: Vec<Author>, pub authors: Vec<Author>,
pub sentry_dsn: String
} }
impl GameConfig { impl GameConfig {

View File

@ -9,4 +9,5 @@ edition = "2018"
[dependencies] [dependencies]
game = { version = "0.1", path = "../game"} game = { version = "0.1", path = "../game"}
tracing-subscriber = "0.2" tracing-subscriber = "0.2"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
sentry = "0.23"

View File

@ -1,10 +1,26 @@
use game::game_begin; use game::{GameConfig, StaticGameData, game_begin};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
// Enable logging // Enable logging
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
// Load the general config for the game
// This happens here so we can properly track sentry events
let game_config = GameConfig::load(
StaticGameData::get("configs/application.json").expect("Failed to load application.json"),
).unwrap();
// Connect to sentry
let _sentry_guard = sentry::init((
game_config.sentry_dsn.clone(),
sentry::ClientOptions {
release: sentry::release_name!(),
attach_stacktrace: true,
..Default::default()
},
));
// Start the game // Start the game
game_begin().await.unwrap(); game_begin(&game_config).await.unwrap();
} }