package pointer import ( "fmt" "html/template" "math/rand" "net/http" "strings" "appengine" "appengine/channel" "appengine/memcache" ) const key = "ids" func init() { http.HandleFunc("/", main) http.HandleFunc("/update", update) http.HandleFunc("/leave", leave) } func main(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) ids := getIDs(c) id := fmt.Sprintf("%d", rand.Int()) found := false for _, mid := range ids { if id == mid { found = true } } if !found { ids = append(ids, id) _ = memcache.Set(c, &memcache.Item{ Key: key, Value: []byte(strings.Join(ids, ",")), }) } tok, _ := channel.Create(c, id) tmpl.Execute(w, struct{ Token, ClientID string }{tok, id}) } func update(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) ids := getIDs(c) x := r.FormValue("x") y := r.FormValue("y") from := r.FormValue("id") msg := fmt.Sprintf("{\"x\":%s,\"y\":%s,\"id\":\"%s\"}", x, y, from) for _, id := range ids { if id != from { _ = channel.Send(c, id, msg) } } } func leave(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) ids := getIDs(c) i := -1 id := r.FormValue("id") for ni, mid := range ids { if id == mid { i = ni break } } if i != -1 { ids = append(ids[:i], ids[i+1:]...) _ = memcache.Set(c, &memcache.Item{ Key: key, Value: []byte(strings.Join(ids, ",")), }) } msg := fmt.Sprintf("{\"x\":-1,\"y\":-1,\"id\":\"%s\"}", id) for _, id := range ids { _ = channel.Send(c, id, msg) } } func getIDs(c appengine.Context) []string { var ids []string if i, err := memcache.Get(c, key); err == nil { ids = strings.Split(string(i.Value), ",") } return ids } var tmpl = template.Must(template.New("n").Parse(`
Welcome to Pointer Party!
Directions: Move your mouse pointer. See the mouse pointers of other users on this page.
Built using App Engine Channel API (src) `))