GoでCometチャットサーバを書いてみた
最近流行りのGoでCometなチャットサーバを書いてみたよ!
いちおう動いてるっぽいけど正しいかは知らないよ!
package main import ( "flag"; "http"; "log"; "container/list"; "strconv"; "bytes"; "json"; "time"; ) type post struct { id uint64; name string; comment string; at *time.Time; } type chatData struct { lastId uint64; posts list.List; waits list.List; } type request interface { execute(data *chatData); } type addRequest struct { name string; comment string; } type getRequest struct { id uint64; resCh chan []post; } func (req addRequest) execute(data *chatData) { data.lastId++; p := post{data.lastId, req.name, req.comment, time.LocalTime()}; data.posts.PushBack(p); if data.posts.Len() > 100 { data.posts.Remove(data.posts.Front()); } for ch := range data.waits.Iter() { res := make([]post, 1); res[0] = p; ch.(chan []post) <- res; } data.waits.Init(); } func (req getRequest) execute(data *chatData) { if req.id == data.lastId { data.waits.PushBack(req.resCh); }else{ i := 0; e := data.posts.Front(); for ; e != nil; i,e = i+1,e.Next() { if e.Value.(post).id > req.id { break; } } res := make([]post, data.posts.Len()-i); for i = 0; e != nil; i,e = i+1,e.Next() { res[i] = e.Value.(post); } req.resCh <- res; } } var requestCh = make(chan request) var addr = flag.String("addr", ":8080", "http service address") func backend() { var data chatData; for { req := <- requestCh; req.execute(&data); } } func add(c *http.Conn, req *http.Request) { requestCh <- addRequest{req.FormValue("name"), req.FormValue("c")}; c.WriteHeader(http.StatusOK); } func get(c *http.Conn, req *http.Request){ id,err := strconv.Atoui64(req.FormValue("id")); if err != nil { c.WriteHeader(http.StatusBadRequest); }else{ q := getRequest{id, make(chan []post)}; requestCh <- q; res := <- q.resCh; c.SetHeader("Content-Type", "application/json; charset=utf-8"); var buf bytes.Buffer; buf.WriteString("{\"post\":["); last := len(res)-1; for i,val := range res { buf.WriteString("{\"id\":" + strconv.Uitoa64(val.id) + ",\"name\":" + json.Quote(val.name) + ",\"c\":" + json.Quote(val.comment) + ",\"at\":"+ json.Quote(val.at.String()) + "}"); if(i != last){ buf.WriteString(","); } } buf.WriteString("]}"); c.Write(buf.Bytes()); } } func main() { flag.Parse(); http.Handle("/", http.FileServer("www", "")); http.Handle("/add", http.HandlerFunc(add)); http.Handle("/get", http.HandlerFunc(get)); go backend(); err := http.ListenAndServe(*addr, nil); if err != nil { log.Exit("ListenAndServe:", err); } }