From 0fdc23f923c50936571f46ca97323a55eb8056fe Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Sun, 24 Nov 2019 10:24:08 -0600 Subject: [PATCH] Hopefully prevent race conditions --- microchat.go | 180 ++++++++++++++++++++++++------------------- static/microchat.css | 4 + static/microchat.js | 4 +- 3 files changed, 107 insertions(+), 81 deletions(-) diff --git a/microchat.go b/microchat.go index 01405f2..0578c81 100644 --- a/microchat.go +++ b/microchat.go @@ -1,105 +1,125 @@ package main import ( - "net/http" - "log" - "time" - "strconv" - "encoding/json" + "encoding/json" + "log" + "net/http" + "strconv" + "time" ) type Message struct { - When int64 - Who string - Text string + When int64 + Who string + Text string } type Forum struct { - Name string - Log []Message + Name string + Log []Message + SendQ chan Message + LogQ chan []Message } var foraByName map[string]*Forum +func (f *Forum) HandleSends() { + for m := range f.SendQ { + f.Log = append(f.Log, m) + } +} + +func (f *Forum) HandleReads() { + for { + f.LogQ <- f.Log + } +} + func newForum(name string) *Forum { - f := &Forum{ - Name: name, - } - foraByName[name] = f - return f + f := &Forum{ + Name: name, + SendQ: make(chan Message, 10), + LogQ: make(chan []Message, 10), + } + go f.HandleSends() + go f.HandleReads() + + foraByName[name] = f + return f } func sayHandler(w http.ResponseWriter, r *http.Request) { - message := Message{ - When: time.Now().Unix(), - Who: r.FormValue("who"), - Text: r.FormValue("text"), - } - log.Println(message) - forumName := r.FormValue("forum") - forum, ok := foraByName[forumName] - if !ok { - forum = newForum(forumName) - } - forum.Log = append(forum.Log, message) - - w.WriteHeader(http.StatusOK) + message := Message{ + When: time.Now().Unix(), + Who: r.FormValue("who"), + Text: r.FormValue("text"), + } + forumName := r.FormValue("forum") + f, ok := foraByName[forumName] + if !ok { + f = newForum(forumName) + } + f.SendQ <- message + + w.WriteHeader(http.StatusOK) } func readHandler(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - - forumName := r.FormValue("forum") - entriesStr := r.FormValue("entries") - - if entriesStr == "" { - entriesStr = "0" - } - entries, err := strconv.Atoi(entriesStr) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - if entries <= 0 { - entries = 20 - } else if entries > 500 { - entries = 500 - } - - forum, ok := foraByName[forumName] - if !ok { - http.NotFound(w, r) - return - } + r.ParseForm() - pos := len(forum.Log) - entries - if pos < 0 { - pos = 0 - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - - e := json.NewEncoder(w) - e.Encode(forum.Log[pos:]) + forumName := r.FormValue("forum") + entriesStr := r.FormValue("entries") + + if entriesStr == "" { + entriesStr = "0" + } + entries, err := strconv.Atoi(entriesStr) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if entries <= 0 { + entries = 20 + } else if entries > 500 { + entries = 500 + } + + f, ok := foraByName[forumName] + if !ok { + http.NotFound(w, r) + return + } + + log := <-f.LogQ + + pos := len(log) - entries + if pos < 0 { + pos = 0 + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + e := json.NewEncoder(w) + e.Encode(f.Log[pos:]) } func main() { - http.HandleFunc("/say", sayHandler) - http.HandleFunc("/read", readHandler) - http.Handle("/", http.FileServer(http.Dir("static/"))) - - foraByName = map[string]*Forum{} - f := newForum("") - f.Log = []Message{ - { - When: time.Now().Unix(), - Who: "(system)", - Text: "Welcome to μChat", - }, - } - - bind := ":8080" - log.Printf("Listening on %s", bind) - log.Fatal(http.ListenAndServe(bind, nil)) + http.HandleFunc("/say", sayHandler) + http.HandleFunc("/read", readHandler) + http.Handle("/", http.FileServer(http.Dir("static/"))) + + foraByName = map[string]*Forum{} + f := newForum("") + f.Log = []Message{ + { + When: time.Now().Unix(), + Who: "(system)", + Text: "Welcome to μChat", + }, + } + + bind := ":8080" + log.Printf("Listening on %s", bind) + log.Fatal(http.ListenAndServe(bind, nil)) } diff --git a/static/microchat.css b/static/microchat.css index dbd811e..06411ff 100644 --- a/static/microchat.css +++ b/static/microchat.css @@ -11,6 +11,10 @@ body { input[name="who"] { width: 6em; } +input[name="text"] { + min-width: 30em; + width: calc(90% - 6em); +} .when { color: #888; diff --git a/static/microchat.js b/static/microchat.js index e3c7609..d999af2 100644 --- a/static/microchat.js +++ b/static/microchat.js @@ -18,7 +18,6 @@ function μchatInit(initEvent) { let form = event.target let inp = form.elements.text let body = new FormData(form) - console.log(form, body) fetch("say", { method: "POST", body: body, @@ -86,6 +85,9 @@ function μchatInit(initEvent) { .then(updateLog) } }) + .catch(err => { + toast("Server error: " + err) + }) } for (let f of document.forms) {