use goish::prelude::*;
fn main() {
let lines = slice!([]string{
"GET https://example.com/index.html 200",
"POST https://api.example.com/v1/login?next=/home 204",
"GET https://static.cdn.example.com/a/b/c.png 304",
"GET https://example.com/page?x=1&y=2 200 ",
"GET https://alt.example.com/path 500",
});
let compact = regexp::MustCompile(r"\s+");
let normalized: slice<string> = lines.iter()
.map(|l| compact.ReplaceAllString(strings::TrimSpace(l), " "))
.collect();
let parts_re = regexp::MustCompile(r"^(\w+)\s+(\S+)\s+(\d+)$");
#[derive(Clone)]
struct Req { method: string, host: string, path: string, status: int }
let mut reqs: slice<Req> = slice::new();
for l in &normalized {
let caps = parts_re.FindStringSubmatch(l);
if caps.is_empty() { continue; }
let (u, err) = url::Parse(&caps[2]);
if err != nil { continue; }
reqs.push(Req {
method: caps[1].clone(),
host: u.Hostname(),
path: u.Path.clone(),
status: {
let (n, _) = strconv::Atoi(&caps[3]);
n
},
});
}
let mut by_host = make!(map[string]int);
for r in &reqs {
*by_host.entry(r.host.clone()).or_insert(0) += 1;
}
fmt::Printf!("%-32s %s\n", "host", "count");
fmt::Println!(strings::Repeat("-", 40));
let mut entries: slice<(string, int)> = by_host.iter()
.map(|(k, v)| (k.clone(), *v)).collect();
sort::Slice(&mut entries, |a, b| a.0 < b.0);
for (h, c) in &entries {
fmt::Printf!("%-32s %d\n", h, c);
}
let mut summary = json::Value::Object(Vec::new());
summary.Set("total", json::Value::Number(reqs.len() as f64));
let hosts_arr: slice<json::Value> = entries.iter()
.map(|(h, c)| {
let mut obj = json::Value::Object(Vec::new());
obj.Set("host", json::Value::String(h.clone()));
obj.Set("count", json::Value::Number(*c as f64));
obj
}).collect();
summary.Set("hosts", json::Array(hosts_arr));
let (out, _) = json::MarshalIndent(&summary, "", " ");
fmt::Println!();
fmt::Println!("json:");
fmt::Println!(String::from_utf8(out.clone()).unwrap());
let joined = strings::Join(&normalized, "\n");
let digest = crypto::sha256::Sum256(joined.as_bytes());
let hex_hash: string = digest.iter().map(|b| format!("{:02x}", b)).collect::<String>().into();
fmt::Printf!("\nsha256 of input: %s\n", hex_hash);
let mut w = csv::NewWriter();
w.Write(&["method", "host", "path", "status"]);
for r in &reqs {
w.Write(&[r.method.clone(), r.host.clone(), r.path.clone(), strconv::Itoa(r.status)]);
}
let csv_out = w.Flush();
fmt::Println!();
fmt::Println!("csv:");
fmt::Println!(csv_out);
let resource = path::Join(&["/api", "v1", "requests.json"]);
fmt::Printf!("\nwould POST to: %s\n", resource);
defer!{ fmt::Println!("done."); }
}