package main import ( "encoding/json" "fmt" "net/http" "net/url" "os" "os/exec" "bytes" // "log" "time" "strings" ) type BotMessage struct { User struct { ID int `json:"id"` Name string `json:"name"` } `json:"user"` Room struct { ID int `json:"id"` Name string `json:"name"` } `json:"room"` Message struct { ID int `json:"id"` Body struct { HTML string `json:"html"` Plain string `json:"plain"` } `json:"body"` } `json:"message"` } func main() { http.HandleFunc("/", commandHandler) port := os.Getenv("PORT") if port == "" { port = "8096" } panic(http.ListenAndServe(":"+port, nil)) } func SplitFirstWord(input string) (firstWord string, restOfString string) { words := strings.Fields(input) if len(words) == 0 { return "", "" } firstWord = words[0] restOfString = strings.Join(words[1:], " ") return strings.ToLower(firstWord), restOfString } func commandHandler(w http.ResponseWriter, r *http.Request) { var msg BotMessage err := json.NewDecoder(r.Body).Decode(&msg) if err != nil { errorResponse(w, http.StatusBadRequest, "invalid request body") return } command, arguments := SplitFirstWord(msg.Message.Body.Plain) switch command { case "ping": fmt.Println("ping command received") fmt.Fprintln(w, "Pong!") case "trace": fmt.Println("trace command received") var j = traceHandler(w, r, arguments, msg.User.Name) fmt.Fprintln(w, j) case "math": fmt.Fprintln(w, runMath(arguments)) case "hi": fmt.Fprintln(w, "Hello " + msg.User.Name + "! How are you doing today?") default: fmt.Fprintln(w, "Command is: " + command + " arguments are: " + arguments + ". Not sure what to do...") } return } func runMath(s string)(string){ cmd := exec.Command("qalc", s) // cmd.Stdin = strings.NewReader("and old falcon") var out bytes.Buffer cmd.Stdout = &out err := cmd.Run() if err != nil { // log.Warn(err) fmt.Println(err) } return out.String() // fmt.Printf("translated phrase: %q\n", out.String()) } func traceHandler(w http.ResponseWriter, r *http.Request, urlstring string, username string)(string) { var msg BotMessage err := json.NewDecoder(r.Body).Decode(&msg) uri, err := url.Parse(urlstring) if err != nil || (uri.Scheme != "http" && uri.Scheme != "https") { return "That doesn't look like a valid URL for to me to call" } response, err := timeRequest(username, uri) if err != nil { // fmt.Fprintf(w, "Failed to time the request (%s)", err) // return return "Failed to time the request " //+ err } // fmt.Fprintln(w, response) return response } func timeRequest(username string, uri *url.URL) (string, error) { trace, err := TraceRequest(uri) if err != nil { return "", err } result := fmt.Sprintf("Hi %s! I've checked %s for you, and here's what I found:

\n", username, uri) result += formatDuration("DNS lookup", trace.DNSStart, trace.DNSDone) result += formatDuration("Connect", trace.ConnectStart, trace.ConnectDone) result += formatDuration("TLS negotiation", trace.TLSStart, trace.TLSDone) result += formatDuration("Sending headers", trace.ConnectionReady(), trace.WroteHeaders) result += formatDuration("Time to first byte", trace.WroteHeaders, trace.FirstByte) result += formatDuration("Time to last byte", trace.WroteHeaders, trace.AllDone) return result, nil } func errorResponse(w http.ResponseWriter, status int, msg string) { w.WriteHeader(status) fmt.Fprintf(w, "Error: %s", msg) } func formatDuration(label string, start, end time.Time) string { dur := end.Sub(start).String() if start.IsZero() || end.IsZero() { dur = "n/a" } return fmt.Sprintf("%s: %s
\n", label, dur) }