oboeruhttp.go (3296B)
1 package main 2 3 import ( 4 "bufio" 5 "context" 6 "flag" 7 "fmt" 8 "net/http" 9 "os" 10 "strings" 11 ) 12 13 var ctx context.Context 14 var cancel context.CancelFunc 15 16 var front, back string 17 var cardlock = false 18 19 var html_midf, html_midb, html_quit string 20 const html_head = "<!DOCTYPE html><html><head><meta charset='utf-8' />" + 21 "<link rel='stylesheet' type='text/css' href='/_/style.css'>" + 22 "<title>oboeru</title></head><body><div>" 23 const html_foot = "</div></body></html>" 24 25 func usage() { 26 fmt.Fprintf(os.Stderr, "usage: %s [-p port] [-FPQS label]\n", os.Args[0]) 27 flag.PrintDefaults() 28 } 29 30 func create_req_map() map[string]string { 31 return map[string]string { 32 "/fail": "fail", 33 "/pass": "pass", 34 "/quit": "quit", 35 "/show": "show", 36 } 37 } 38 39 func format_page(head string, body string, mid string, foot string) string { 40 return strings.Join([]string{head, body, mid, foot}, "") 41 } 42 43 func get_next_card() []string { 44 stdin := bufio.NewScanner(os.Stdin) 45 stdin.Scan() 46 return strings.Split(stdin.Text(), "\t") 47 } 48 49 func show_card(w http.ResponseWriter, card string, mid string) { 50 html := format_page(html_head, card, mid, html_foot) 51 w.Header().Set("Content-Type", "text/html; charset=utf-8") 52 fmt.Fprint(w, html) 53 } 54 55 func quit(w http.ResponseWriter) { 56 show_card(w, html_quit, "") 57 fmt.Fprintln(os.Stdout, "quit") 58 cancel() /* send signal to shutdown srv */ 59 } 60 61 func response(w http.ResponseWriter, r *http.Request) { 62 req_map := create_req_map() 63 64 /* won't err since all invalid reqs have been rerouted to "/" */ 65 str, _ := req_map[r.RequestURI] 66 67 switch str { 68 case "show": 69 show_card(w, back, html_midb) 70 case "quit": 71 quit(w) 72 case "fail": 73 fallthrough 74 case "pass": 75 cardlock = false 76 fmt.Fprintln(os.Stdout, str) 77 http.Redirect(w, r, "/", http.StatusSeeOther) 78 } 79 } 80 81 func serve(w http.ResponseWriter, r *http.Request) { 82 if cardlock == false { 83 card := get_next_card() 84 if len(card) != 2 { 85 quit(w) 86 } 87 88 cardlock = true 89 front = card[0] 90 back = card[1] 91 } 92 93 show_card(w, front, html_midf) 94 } 95 96 func main() { 97 var ( 98 port = flag.Uint("p", 6969, "port number") 99 fail = flag.String("F", "fail", "fail label") 100 pass = flag.String("P", "pass", "pass label") 101 show = flag.String("S", "show", "show label") 102 quit = flag.String("Q", "quit", "quit label") 103 bye = flag.String("q", "Goodbye!", "text to display before quitting") 104 ) 105 106 flag.Usage = usage 107 flag.Parse() 108 109 html_midf = strings.Join([]string{"<div class='link'><a href='/quit'>", 110 *quit, "</a> · <a href='/show'>", *show, 111 "</a></div>"}, "") 112 html_midb = strings.Join([]string{"<div class='link'><a href='/fail'>", 113 *fail, "</a> · <a href='/quit'>", *quit, 114 "</a> · <a href='/pass'>", *pass, "</a></div>"}, "") 115 html_quit = *bye 116 117 ctx, cancel = context.WithCancel(context.Background()) 118 119 wd, _ := os.Getwd() 120 fs := http.FileServer(http.Dir(wd)) 121 122 http.HandleFunc("/", serve) 123 124 /* pretend requested files are in wd/_/ so that they can 125 * be accessed on the fly */ 126 http.Handle("/_/", http.StripPrefix("/_/", fs)) 127 128 /* map allowed reqs to the handler fn response() */ 129 for k, _ := range create_req_map() { 130 http.HandleFunc(k, response) 131 } 132 133 server := fmt.Sprintf(":%d", *port) 134 srv := &http.Server{Addr: server} 135 go func() { 136 srv.ListenAndServe() 137 }() 138 <- ctx.Done() /* wait for signal to shutdown */ 139 140 srv.Shutdown(ctx) 141 }