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

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

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

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

37
game/src/discord_rpc.rs Normal 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(())
}

@ -64,20 +64,19 @@
nonstandard_style,
rust_2018_idioms
)]
#![feature(custom_inner_attributes)]
#![clippy::msrv = "1.57.0"]
use std::cell::RefCell;
use discord_sdk::activity::ActivityBuilder;
use raylib::prelude::*;
use tracing::{error, info};
use utilities::{
datastore::StaticGameData,
discord::{DiscordConfig, DiscordRpcClient},
game_config::GameConfig,
};
use utilities::discord::DiscordConfig;
use crate::{
context::GameContext,
discord_rpc::{maybe_set_discord_presence, try_connect_to_local_discord},
scenes::build_screen_state_machine,
utilities::shaders::{
shader::ShaderWrapper,
@ -91,45 +90,46 @@ extern crate thiserror;
extern crate serde;
mod context;
mod discord_rpc;
mod scenes;
mod utilities;
pub use utilities::{datastore::StaticGameData, game_config::GameConfig};
/// The game entrypoint
pub async fn game_begin() -> 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"),
)?;
pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::error::Error>> {
// Set up profiling
#[cfg(debug_assertions)]
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);
// Attempt to connect to a locally running Discord instance for rich presence access
let discord_config = DiscordConfig::load(
StaticGameData::get("configs/discord.json").expect("Failed to load discord.json"),
)?;
let discord_rpc =
match DiscordRpcClient::new(discord_config.app_id, discord_sdk::Subscriptions::ACTIVITY)
.await
{
Ok(client) => Some(client),
Err(err) => {
error!("Could not connect to or find a locally running Discord instance.");
error!("Discord connection error: {:?}", err);
)
.unwrap();
let discord_rpc = match try_connect_to_local_discord(&discord_config).await {
Ok(client) => Some(client),
Err(err) => match err {
utilities::discord::rpc::DiscordError::ConnectionTimeoutError(time) => {
error!(
"Could not find or connect to a local Discord instance after {} seconds",
time
);
None
}
};
if let Some(rpc) = discord_rpc {
rpc.set_rich_presence(ActivityBuilder::default().details("Testing..."))
.await?;
}
_ => panic!("Failed to connect to Discord: {}", err),
},
};
maybe_set_discord_presence(
&discord_rpc,
ActivityBuilder::default().details("Testing..."),
)
.await
.unwrap();
// 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 raylib_thread;
@ -171,7 +171,9 @@ pub async fn game_begin() -> Result<(), Box<dyn std::error::Error>> {
puffin::GlobalProfiler::lock().new_frame();
// 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)
#[allow(unsafe_code)]

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

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

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

@ -9,4 +9,5 @@ edition = "2018"
[dependencies]
game = { version = "0.1", path = "../game"}
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"

@ -1,10 +1,26 @@
use game::game_begin;
use game::{GameConfig, StaticGameData, game_begin};
#[tokio::main]
async fn main() {
// Enable logging
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
game_begin().await.unwrap();
game_begin(&game_config).await.unwrap();
}