Skip to content

Commit

Permalink
Add basic support for cppinsights.io requests
Browse files Browse the repository at this point in the history
  • Loading branch information
Headline committed Nov 22, 2023
1 parent a1ed769 commit 9193576
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 3 deletions.
57 changes: 57 additions & 0 deletions src/apis/insights.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use reqwest::StatusCode;
use serde::*;

pub const POST_URL: &str = "https://cppinsights.io/api/v1/transform";

#[derive(Serialize)]
pub struct InsightsRequest {
pub code: String,
#[serde(rename = "insightsOptions")]
pub insights_options: Vec<String>,
}

#[derive(Deserialize)]
pub struct InsightsResponse {
#[serde(rename = "returncode")]
pub return_code: i32,
pub stderr: String,
pub stdout: String,
}
pub struct InsightsAPI {
client: reqwest::Client,
}

impl InsightsAPI {
pub fn new() -> Self {
InsightsAPI {
client: reqwest::Client::new(),
}
}

pub async fn get_insights(&self, req: InsightsRequest) -> Option<InsightsResponse> {
let req_result = self
.client
.post(POST_URL)
.header("Content-Type", "application/json")
.json(&req)
.send()
.await;
if let Err(e) = req_result {
warn!("Insights request failure: {}", e);
return None;
}
let req = req_result.unwrap();
if req.status() != StatusCode::OK {
warn!("Received non-ok status code.");
return None;
}

let resp = req.json::<InsightsResponse>().await;
if let Err(e) = resp {
warn!("Unable to get source insights: {}", e);
None
} else {
Some(resp.unwrap())
}
}
}
1 change: 1 addition & 0 deletions src/apis/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod dbl;
pub mod insights;
pub mod quick_link;
11 changes: 11 additions & 0 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use serenity::prelude::{TypeMap, TypeMapKey};
use crate::managers::stats::StatsManager;
use crate::utls::blocklist::Blocklist;

use crate::apis::insights::InsightsAPI;
use crate::apis::quick_link::LinkAPI;
use crate::managers::command::CommandManager;
use crate::managers::compilation::CompilationManager;
Expand Down Expand Up @@ -64,6 +65,12 @@ impl TypeMapKey for LinkAPICache {
type Value = Arc<RwLock<LinkAPI>>;
}

/// Contains the cpp insights api - used for ;insights
pub struct InsightsAPICache;
impl TypeMapKey for InsightsAPICache {
type Value = Arc<Mutex<InsightsAPI>>;
}

#[derive(Clone)]
pub struct MessageCacheEntry {
pub our_msg: Message,
Expand Down Expand Up @@ -189,6 +196,10 @@ pub async fn fill(
}
}

// Cpp insights
let insights = InsightsAPI::new();
data.insert::<InsightsAPICache>(Arc::new(Mutex::new(insights)));

// Stats tracking
let stats = StatsManager::new();
if stats.should_track() {
Expand Down
3 changes: 2 additions & 1 deletion src/commands/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,15 @@ pub async fn help(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
e.color(COLOR_OKAY);
e.title("Commands");
e.field("invite", "``` Grabs the bot's invite link ```", false);
e.field("compile", "``` Compiles a script ```", false);
e.field("compile", "``` Compiles and executes code ```", false);
e.field("compilers", "``` Displays the compilers for the specified language ```", false);
e.field("languages", "``` Displays all supported languages ```", false);
e.field("asm", "``` Outputs the assembly for the input code```", false);
e.field("botinfo", "``` Displays information about the bot ```", false);
e.field("cpp", format!("``` Executes c++ code using geordi-like syntax\n See {}help cpp for more info ```", prefix), false);
e.field("format", "``` Formats code using a code formatter (i.e. clang-format or rustfmt) ```", false);
e.field("formats", "``` Displays all formatting options & styles ```", false);
e.field("insights", "``` Sends a code block to cppinsights.io ```", false);
e
})
}).await?;
Expand Down
88 changes: 88 additions & 0 deletions src/commands/insights.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use serenity::framework::standard::{macros::command, Args, CommandError, CommandResult};
use serenity::model::prelude::*;
use serenity::prelude::*;

use crate::apis::insights::InsightsRequest;

use crate::cache::{ConfigCache, InsightsAPICache};
use crate::utls::constants::{COLOR_FAIL, COLOR_OKAY};
use crate::utls::parser::ParserResult;
use crate::utls::{discordhelpers, parser};

#[command]
pub async fn insights(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
let data_read = ctx.data.read().await;
let insights_lock = data_read.get::<InsightsAPICache>().unwrap();
let botinfo_lock = data_read.get::<ConfigCache>().unwrap();
let botinfo = botinfo_lock.read().await;

let loading_reaction = {
if let Some(loading_id) = botinfo.get("LOADING_EMOJI_ID") {
let loading_name = botinfo
.get("LOADING_EMOJI_NAME")
.expect("Unable to find loading emoji name")
.clone();
discordhelpers::build_reaction(loading_id.parse::<u64>()?, &loading_name)
} else {
ReactionType::Unicode(String::from("⏳"))
}
};

let mut parse_result = ParserResult::default();
if !parser::find_code_block(&mut parse_result, &msg.content, &msg.author).await? {
return Err(CommandError::from("Unable to find a codeblock to format!"));
}
let req = InsightsRequest {
code: parse_result.code,
insights_options: vec![String::from("cpp2c")], // hard coded version for now
};

if msg
.react(&ctx.http, loading_reaction.clone())
.await
.is_err()
{
return Err(CommandError::from(
"Unable to react to message, am I missing permissions to react or use external emoji?",
));
}

let resp = {
let insights = insights_lock.lock().await;
insights.get_insights(req).await
};

discordhelpers::delete_bot_reacts(ctx, msg, loading_reaction).await?;

if let Some(resp_obj) = resp {
let error = resp_obj.return_code != 0;
let sent = msg
.channel_id
.send_message(&ctx.http, |m| {
m.embed(|emb| {
emb.color(if error { COLOR_FAIL } else { COLOR_OKAY })
.title("cppinsights.io")
.description(format!(
"```cpp\n{}\n```",
if error {
resp_obj.stderr
} else {
resp_obj.stdout
}
))
})
})
.await;

if let Ok(sent_msg) = sent {
discordhelpers::send_completion_react(ctx, &sent_msg, !error).await?;
}
} else {
return Err(CommandError::from(
"Unable to retrieve insights at this time! Please try again later.",
));
}

debug!("Command executed");
Ok(())
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod cpp;
pub mod format;
pub mod formats;
pub mod help;
pub mod insights;
pub mod invite;
pub mod languages;
pub mod ping;
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ extern crate pretty_env_logger;
/** Command Registration **/
use crate::commands::{
asm::*, block::*, botinfo::*, compile::*, compilers::*, cpp::*, format::*, formats::*, help::*,
invite::*, languages::*, ping::*, unblock::*,
insights::*, invite::*, languages::*, ping::*, unblock::*,
};
use crate::utls::discordhelpers::embeds::panic_embed;
use crate::utls::discordhelpers::manual_dispatch;

#[group]
#[commands(
botinfo, compile, languages, compilers, ping, help, asm, block, unblock, invite, cpp, formats,
format
format, insights
)]
struct General;

Expand Down

0 comments on commit 9193576

Please sign in to comment.