microchat/microchat.go

126 lines
2.0 KiB
Go

package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"time"
)
type Message struct {
When int64
Who string
Text string
}
type Forum struct {
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,
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"),
}
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
}
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))
}