Last active
July 23, 2017 13:21
-
-
Save lifthrasiir/ffa5fa82c4400cfb7da25ef29a9b6057 to your computer and use it in GitHub Desktop.
Cog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
target | |
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "cog" | |
version = "0.1.0" | |
authors = ["Kang Seonghoon <public+git@mearie.org>"] | |
[[bin]] | |
name = "cog" | |
path = "main.rs" | |
[dependencies] | |
irc = "0.11" | |
hyper = "0.9" | |
serde = "1.0" | |
serde_json = "1.0" | |
regex = "0.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate irc; | |
extern crate hyper; | |
extern crate serde; | |
extern crate serde_json; | |
extern crate regex; | |
use std::io; | |
use std::ascii::AsciiExt; | |
use std::default::Default; | |
use std::collections::BTreeMap; | |
use std::thread; | |
use irc::client::prelude::*; | |
use regex::Regex; | |
use serde_json::Value; | |
fn playpen(code: &str, opts: &str) -> Result<String, String> { | |
let mut channel = None; | |
let mut mode = None; | |
for opt in opts.split(',') { | |
let opt = opt.trim().to_owned(); | |
match &opt[..] { | |
"stable" | "beta" | "nightly" => { channel = Some(opt); } | |
"debug" | "release" => { mode = Some(opt); } | |
_ => {} | |
} | |
} | |
let channel = channel.unwrap_or_else(|| "stable".to_owned()); | |
let mode = mode.unwrap_or_else(|| "debug".to_owned()); | |
let mut map = BTreeMap::new(); | |
map.insert("channel", Value::String(channel)); | |
map.insert("mode", Value::String(mode)); | |
map.insert("code", Value::String(code.to_string())); | |
map.insert("crateType", Value::String("bin".to_string())); | |
map.insert("tests", Value::Bool(false)); | |
let json = serde_json::to_string(&map).unwrap(); | |
let client = hyper::client::Client::new(); | |
let req = client.post("https://play.rust-lang.org/execute"); | |
let req = req.header(hyper::header::ContentType::json()); | |
let req = req.body(&json); | |
match req.send() { | |
Ok(resp) => { | |
let map: BTreeMap<String, Value> = match serde_json::from_reader(resp) { | |
Ok(map) => map, | |
Err(e) => return Err(format!("playpen 응답 파싱 오류: {}", e)), | |
}; | |
if let Some(&Value::String(ref e)) = map.get("error") { | |
Ok(format!("playpen 오류: {}", e)) | |
} else if let Some(&Value::Bool(true)) = map.get("success") { | |
Ok(map.get("stdout").and_then(|v| v.as_str()).unwrap_or("").to_string()) | |
} else { | |
Err(map.get("stderr").and_then(|v| v.as_str()).unwrap_or("").to_string()) | |
} | |
} | |
Err(e) => { | |
Err(format!("playpen 접속 오류: {}", e)) | |
} | |
} | |
} | |
fn truncate(s: &str, maxlines: usize, maxbytesperline: usize) -> Vec<&str> { | |
let mut lines = Vec::new(); | |
for mut line in s.lines() { | |
while line.len() > maxbytesperline { | |
let mut i = maxbytesperline; | |
while !line.is_char_boundary(i) { i -= 1; } | |
lines.push(&line[..i]); | |
if lines.len() >= maxlines { break; } | |
line = &line[i..]; | |
} | |
lines.push(line); | |
if lines.len() >= maxlines { break; } | |
} | |
lines | |
} | |
fn main_() -> io::Result<()> { | |
let config = Config { | |
nickname: Some(format!("cog")), | |
server: Some(format!("bassoon.irc.ozinger.org")), | |
channels: Some(vec![format!("#rust")]), | |
.. Default::default() | |
}; | |
let server = try!(IrcServer::from_config(config)); | |
try!(server.identify()); | |
let code_pattern = Regex::new(r"(?x) | |
^ (?: | |
(?: \( \s* | |
(?P<opts> [a-z0-9]+\s* (?: , \s*[a-z0-9]+\s* )* ) | |
\s* \) )? | |
[:,] | |
\s* (?P<code>.*) \s* | |
)? $").unwrap(); | |
for message in server.iter() { | |
let message = try!(message); | |
print!("{}", message); | |
match message.command { | |
Command::PRIVMSG(ref target, ref msg) => { | |
let current_nick = server.current_nickname(); | |
if !msg.starts_with(current_nick) { continue; } | |
let target = if target.starts_with("#") { | |
target.to_owned() // reply to the channel | |
} else if let Some(nick) = message.source_nickname() { | |
nick.to_owned() // reply to the private message | |
} else { | |
continue; // otherwise do not reply | |
}; | |
let m = if let Some(m) = code_pattern.captures(&msg[current_nick.len()..]) { | |
m | |
} else { | |
continue; | |
}; | |
let opts = m.name("opts").unwrap_or("").to_ascii_lowercase(); | |
let code = m.name("code").unwrap_or(""); | |
if code.is_empty() { | |
let _ = server.send_notice(&target, &format!( | |
"cog란 무엇입니까? 그것은 \"{nick}:\"나 \"{nick},\"로 부르면 \ | |
Rust 코드를 실행해 주는 훌륭한 봇인 것입니다.", nick = current_nick)); | |
let _ = server.send_notice(&target, &format!( | |
"\"{nick}(nightly):\"나 \"{nick}(o3),\"같은 것도 됩니다. 코드를 봅시다: \ | |
https://gist.github.com/lifthrasiir/ffa5fa82c4400cfb7da25ef29a9b6057", | |
nick = current_nick)); | |
continue; | |
} | |
let code = if !code.contains("fn main") { | |
// the code should be at its own line, otherwise comments won't work | |
format!("fn main() {{\n\ | |
let result = {{\n\ | |
{}\n\ | |
}};\n\ | |
println!(\"{{:?}}\", result);\n\ | |
}}", code) | |
} else { | |
code.to_owned() | |
}; | |
let server = server.clone(); | |
thread::spawn(move || { | |
match playpen(&code, &opts) { | |
Ok(result) => { | |
for line in truncate(&result, 3, 400) { | |
let _ = server.send_notice(&target, line); | |
} | |
} | |
Err(error) => { | |
for line in truncate(&error, 3, 400 - 4) { | |
let _ = server.send_notice(&target, &format!("*** {}", line)); | |
} | |
} | |
} | |
}); | |
}, | |
_ => (), | |
} | |
} | |
Ok(()) | |
} | |
fn main() { | |
main_().unwrap(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment