Skip to content

Commit 0166fa6

Browse files
committed
?eval and ?play commands
1 parent 00f8d18 commit 0166fa6

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

src/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod ban;
1212
mod commands;
1313
mod crates;
1414
mod db;
15+
mod playground;
1516
mod schema;
1617
mod state_machine;
1718
mod tags;
@@ -30,6 +31,7 @@ use std::collections::HashMap;
3031
struct Config {
3132
tags: bool,
3233
crates: bool,
34+
eval: bool,
3335
discord_token: String,
3436
mod_id: String,
3537
talk_id: String,
@@ -108,6 +110,16 @@ fn app() -> Result<()> {
108110
cmds.help("?docs", "Lookup documentation", crates::doc_help);
109111
}
110112

113+
if config.eval {
114+
// rust playground
115+
cmds.add("?play ```\ncode```", playground::run);
116+
cmds.add("?play code...", playground::help);
117+
118+
cmds.add("?eval `code`", playground::eval);
119+
cmds.add("?eval ```\ncode```", playground::eval);
120+
cmds.add("?eval code...", playground::eval_help);
121+
}
122+
111123
// Slow mode.
112124
// 0 seconds disables slowmode
113125
cmds.add_protected("?slowmode {channel} {seconds}", api::slow_mode, api::is_mod);

src/playground.rs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//! run rust code on the rust-lang playground
2+
3+
use crate::{
4+
api,
5+
commands::{Args, Result},
6+
};
7+
8+
use reqwest::header;
9+
use serde::{Deserialize, Serialize};
10+
use std::collections::HashMap;
11+
12+
#[derive(Debug, Serialize)]
13+
struct PlaygroundCode {
14+
channel: Channel,
15+
edition: Edition,
16+
code: String,
17+
#[serde(rename = "crateType")]
18+
crate_type: CrateType,
19+
mode: Mode,
20+
tests: bool,
21+
}
22+
23+
impl PlaygroundCode {
24+
fn new(code: String) -> Self {
25+
PlaygroundCode {
26+
channel: Channel::Nightly,
27+
edition: Edition::E2018,
28+
code,
29+
crate_type: CrateType::Binary,
30+
mode: Mode::Debug,
31+
tests: false,
32+
}
33+
}
34+
}
35+
36+
#[derive(Debug, Serialize)]
37+
#[serde(rename_all = "snake_case")]
38+
enum Channel {
39+
Stable,
40+
Beta,
41+
Nightly,
42+
}
43+
44+
#[derive(Debug, Serialize)]
45+
enum Edition {
46+
#[serde(rename = "2015")]
47+
E2015,
48+
#[serde(rename = "2018")]
49+
E2018,
50+
}
51+
52+
#[derive(Debug, Serialize)]
53+
enum CrateType {
54+
#[serde(rename = "bin")]
55+
Binary,
56+
#[serde(rename = "lib")]
57+
Library,
58+
}
59+
60+
#[derive(Debug, Serialize)]
61+
#[serde(rename_all = "snake_case")]
62+
enum Mode {
63+
Debug,
64+
Release,
65+
}
66+
67+
#[derive(Debug, Deserialize)]
68+
struct PlayResult {
69+
success: bool,
70+
stdout: String,
71+
stderr: String,
72+
}
73+
74+
fn run_code(args: &Args, code: &str) -> Result<String> {
75+
info!("sending request to playground.");
76+
let request = PlaygroundCode::new(code.to_string());
77+
78+
let resp = args
79+
.http
80+
.post("https://play.rust-lang.org/execute")
81+
.json(&request)
82+
.send()?;
83+
84+
let result: PlayResult = resp.json()?;
85+
86+
let result = if result.success {
87+
result.stdout
88+
} else {
89+
result.stderr
90+
};
91+
92+
Ok(if result.len() > 1994 {
93+
format!(
94+
"Output too large. Playground link: {}",
95+
get_playground_link(args, code)?
96+
)
97+
} else {
98+
format!("```{}```", result)
99+
})
100+
}
101+
102+
fn get_playground_link(args: &Args, code: &str) -> Result<String> {
103+
let mut payload = HashMap::new();
104+
payload.insert("code", code);
105+
106+
let resp = args
107+
.http
108+
.get("https://play.rust-lang.org/meta/gist/")
109+
.header(header::REFERER, "https://discord.gg/rust-lang")
110+
.json(&payload)
111+
.send()?;
112+
113+
let resp = resp.text()?;
114+
debug!("{:?}", resp);
115+
116+
Ok(resp)
117+
}
118+
119+
pub fn run(args: Args) -> Result<()> {
120+
let code = args
121+
.params
122+
.get("code")
123+
.ok_or("Unable to retrieve param: query")?;
124+
125+
let result = run_code(&args, code)?;
126+
api::send_reply(&args, &result)?;
127+
Ok(())
128+
}
129+
130+
pub fn help(args: Args) -> Result<()> {
131+
let message = "Missing code block. Please use the following markdown:
132+
\\`\\`\\`rust
133+
code here
134+
\\`\\`\\`
135+
";
136+
137+
api::send_reply(&args, message)?;
138+
Ok(())
139+
}
140+
141+
pub fn eval(args: Args) -> Result<()> {
142+
let code = args
143+
.params
144+
.get("code")
145+
.ok_or("Unable to retrieve param: query")?;
146+
147+
let code = format!(
148+
"fn main(){{
149+
println!(\"{{:?}}\",{{
150+
{}
151+
}});
152+
}}",
153+
code
154+
);
155+
156+
let result = run_code(&args, &code)?;
157+
api::send_reply(&args, &result)?;
158+
Ok(())
159+
}
160+
161+
pub fn eval_help(args: Args) -> Result<()> {
162+
let message = "Missing code block. Please use the following markdown:
163+
\\`code here\\`
164+
or
165+
\\`\\`\\`rust
166+
code here
167+
\\`\\`\\`
168+
";
169+
170+
api::send_reply(&args, message)?;
171+
Ok(())
172+
}

0 commit comments

Comments
 (0)