Sentry tracking and more cleanup
This commit is contained in:
parent
0c8f679de9
commit
e3d1d00786
@ -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"
|
||||||
|
@ -9,5 +9,6 @@
|
|||||||
"Developer"
|
"Developer"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"sentry_dsn": "https://d5d94e75f08841388287fa0c23606ac7@o398481.ingest.sentry.io/5985679"
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"app_id": 889531982978117633
|
"app_id": 889531982978117633
|
||||||
}
|
}
|
||||||
|
37
game/src/discord_rpc.rs
Normal file
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,
|
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)]
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user