oboeru

a collection of simple, scriptable flashcard programs
git clone anongit@rnpnr.xyz:oboeru.git
Log | Files | Refs | Feed | README | LICENSE

Commit: 96cb82a6a478ff62ad2559ad12243be22e7f9b26
Parent: e786a1955194a065984aa34575491764893073bc
Author: Randy Palamar
Date:   Sun, 15 Aug 2021 16:57:38 -0600

import oboeruhttp

Diffstat:
MMakefile | 10++++++++--
Mconfig.mk | 3+++
Aoboeruhttp.go | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 152 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile @@ -4,7 +4,7 @@ include config.mk OBOERU_SRC = oboeru.c util.c OBOERU_OBJ = $(OBOERU_SRC:.c=.o) -default: oboeru +default: oboeru oboeruhttp config.h: cp config.def.h $@ @@ -17,13 +17,19 @@ $(OBOERU_OBJ): config.h oboeru: $(OBOERU_OBJ) $(CC) -o $@ $(OBOERU_OBJ) $(LDFLAGS) +oboeruhttp: + go build -ldflags "$(GOLDFLAGS)" $@.go + install: oboeru mkdir -p $(PREFIX)/bin cp oboeru $(PREFIX)/bin chmod 755 $(PREFIX)/bin/oboeru + cp oboeruhttp $(PREFIX)/bin + chmod 755 $(PREFIX)/bin/oboeruhttp uninstall: rm $(PREFIX)/bin/oboeru + rm $(PREFIX)/bin/oboeruhttp clean: - rm *.o oboeru + rm *.o oboeru oboeruhttp diff --git a/config.mk b/config.mk @@ -2,3 +2,6 @@ PREFIX = /usr/local CPPFLAGS = -D_BSD_SOURCE CFLAGS = -O2 -std=c99 -Wall -pedantic $(CPPFLAGS) $(INCS) +LDFLAGS = -s -static + +GOLDFLAGS = -s diff --git a/oboeruhttp.go b/oboeruhttp.go @@ -0,0 +1,141 @@ +package main + +import ( + "bufio" + "context" + "flag" + "fmt" + "net/http" + "os" + "strings" +) + +var ctx context.Context +var cancel context.CancelFunc + +var front, back string +var cardlock = false + +var html_midf, html_midb, html_quit string +const html_head = "<!DOCTYPE html><html><head><meta charset='utf-8' />" + + "<link rel='stylesheet' type='text/css' href='/_/style.css'>" + + "<title>oboeru</title></head><body><div>" +const html_foot = "</div></body></html>" + +func usage() { + fmt.Fprintf(os.Stderr, "usage: %s [-p port] [-FPQS label]\n", os.Args[0]) + flag.PrintDefaults() +} + +func create_req_map() map[string]string { + return map[string]string { + "/fail": "fail", + "/pass": "pass", + "/quit": "quit", + "/show": "show", + } +} + +func format_page(head string, body string, mid string, foot string) string { + return strings.Join([]string{head, body, mid, foot}, "") +} + +func get_next_card() []string { + stdin := bufio.NewScanner(os.Stdin) + stdin.Scan() + return strings.Split(stdin.Text(), "\t") +} + +func show_card(w http.ResponseWriter, card string, mid string) { + html := format_page(html_head, card, mid, html_foot) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprint(w, html) +} + +func quit(w http.ResponseWriter) { + show_card(w, html_quit, "") + fmt.Fprintln(os.Stdout, "quit") + cancel() /* send signal to shutdown srv */ +} + +func response(w http.ResponseWriter, r *http.Request) { + req_map := create_req_map() + + /* won't err since all invalid reqs have been rerouted to "/" */ + str, _ := req_map[r.RequestURI] + + switch str { + case "show": + show_card(w, back, html_midb) + case "quit": + quit(w) + case "fail": + fallthrough + case "pass": + cardlock = false + fmt.Fprintln(os.Stdout, str) + http.Redirect(w, r, "/", http.StatusSeeOther) + } +} + +func serve(w http.ResponseWriter, r *http.Request) { + var card []string + if cardlock == false { + card = get_next_card() + if len(card) != 2 { + quit(w) + } + + cardlock = true + front = card[0] + back = card[1] + } + + show_card(w, front, html_midf) +} + +func main() { + var ( + port = flag.Uint("p", 6969, "port number") + fail = flag.String("F", "fail", "fail label") + pass = flag.String("P", "pass", "pass label") + show = flag.String("S", "show", "show label") + quit = flag.String("Q", "quit", "quit label") + bye = flag.String("q", "Goodbye!", "text to display before quitting") + ) + + flag.Usage = usage + flag.Parse() + + html_midf = strings.Join([]string{"<a href='/quit'>", *quit, + "</a> · <a href='/show'>", *show, "</a>"}, "") + html_midb = strings.Join([]string{"<a href='/fail'>", *fail, + "</a> · <a href='/quit'>", *quit, + "</a> · <a href='/pass'>", *pass, "</a>"}, "") + html_quit = *bye + + ctx, cancel = context.WithCancel(context.Background()) + + wd, _ := os.Getwd() + fs := http.FileServer(http.Dir(wd)) + + http.HandleFunc("/", serve) + + /* pretend requested files are in wd/_/ so that they can + * be accessed on the fly */ + http.Handle("/_/", http.StripPrefix("/_/", fs)) + + /* map allowed reqs to the handler fn response() */ + for k, _ := range create_req_map() { + http.HandleFunc(k, response) + } + + server := fmt.Sprintf(":%d", *port) + srv := &http.Server{Addr: server} + go func() { + srv.ListenAndServe() + }() + <- ctx.Done() /* wait for signal to shutdown */ + + srv.Shutdown(ctx) +}