// A helper function to produce information about inbox items func fillInboxItem(s *store, perma_blobref string, lastSeq int64, entry map[string]interface{}) (err os.Error) { followers := []string{} authors := []string{} latestauthors := []string{} data, err := s.GetPermaNode(perma_blobref) if err != nil { log.Printf("ERR: Failed reading permanode") return err } perma := grapher.NewPermaNode(nil) perma.FromMap(perma_blobref, data) updates := perma.Updates() for _, user := range perma.Followers() { if seq, ok := updates[user]; ok { if seq > lastSeq { latestauthors = append(latestauthors, userShortName(user)) } else if seq >= 0 { authors = append(authors, userShortName(user)) } else { followers = append(followers, userShortName(user)) } } else { followers = append(followers, userShortName(user)) } } entry["followers"] = followers entry["authors"] = authors entry["latestauthors"] = latestauthors entry["digest"] = "Untitled Page" // TODO entry["latestseq"] = perma.SequenceNumber() - 1 return nil }
func handleDelayedNotify(w http.ResponseWriter, r *http.Request) { log.Printf("Task started") c := appengine.NewContext(r) // Read the form data perma_blobref := r.FormValue("perma") // Allow for further notification tasks to be enqueued memcache.Delete(c, "notify-"+perma_blobref) // Find out about the users of this permanode s := newStore(c) data, err := s.GetPermaNode(perma_blobref) if err != nil { http.Error(w, "Err: Failed reading permanode", http.StatusInternalServerError) return } perma := grapher.NewPermaNode(nil) perma.FromMap(perma_blobref, data) message := fmt.Sprintf(`{"type":"notification", "perma":"%v", "lastseq":%v}`, perma_blobref, perma.SequenceNumber()-1) // For all users find all channels on which they are listening for _, user := range perma.Users() { // Do we know this user? userid, err := isLocalUser(c, user) if err != nil { // TODO: In the case of federation this is not really an error? log.Printf("Err: Unknown user %v", user) continue } // Mark that there is an unread file err = addUnread(c, userid, perma_blobref) if err != nil { log.Printf("Err writing unread: %v", err) } // Notify browser instances where this user is logged in var channels []channelStruct query := datastore.NewQuery("channel").Filter("UserEmail =", user) for it := query.Run(c); ; { var data channelStruct _, e := it.Next(&data) if e == datastore.Done { break } if e != nil { log.Printf("Err: in query: %v", e) break } channels = append(channels, data) } for _, ch := range channels { log.Printf("Sending to %v", ch.UserID+"/"+ch.SessionID) err := channel.Send(c, ch.UserID+"/"+ch.SessionID, message) if err != nil { log.Printf("Failed sending to channel %v", ch.UserID+"/"+ch.SessionID) } } } }
func handleListUnread(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) userid, _, err := getSession(c, r) if err != nil { sendError(w, r, "No session cookie") return } s := newStore(c) inbox, err := s.ListInbox(userid, true) if err != nil { sendError(w, r, err.String()) return } // Read the bloom filter parent := datastore.NewKey("user", userid, 0, nil) key := datastore.NewKey("unread", "unread", 0, parent) filter := NewBloomFilter(sha256.New()) var b UnreadStruct err = datastore.Get(c, key, &b) if err == datastore.ErrNoSuchEntity { log.Printf("No filter found") // Do nothing } else if err != nil { sendError(w, r, "Failed reading unread-bloom-filter") return } else { filter.Load(b.BloomFilter) } // Read the updates for all items in the inbox unread := map[string]interface{}{} for _, entry := range inbox { perma_blobref := entry["perma"].(string) lastSeq := entry["seq"].(int64) log.Printf("Testing %v for unread", perma_blobref) if !filter.Has([]byte(perma_blobref)) { log.Printf(" not in filter") continue } data, err := s.GetPermaNode(perma_blobref) if err != nil { log.Printf("ERR: Failed reading permanode") continue } perma := grapher.NewPermaNode(nil) perma.FromMap(perma_blobref, data) updates := perma.Updates() var authors int64 = 0 for _, user := range perma.Users() { if seq, ok := updates[user]; ok { if seq > lastSeq { authors++ } } } if authors > 0 { unread[perma_blobref] = lastSeq } } j := map[string]interface{}{"ok": true, "unread": unread} msg, err := json.Marshal(j) if err != nil { panic("Cannot serialize") } fmt.Fprint(w, string(msg)) }
func handleOpen(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) userid, sessionid, err := getSession(c, r) if err != nil { sendError(w, r, "No session cookie") return } // Read the request body jreq, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, "Error reading request body", http.StatusInternalServerError) return } r.Body.Close() // Parse request var req openCloseRequest err = json.Unmarshal(jreq, &req) if err != nil { sendError(w, r, "Malformed JSON") return } // Load the channel infos var ch channelStruct if err = datastore.Get(c, datastore.NewKey("channel", userid+"/"+sessionid, 0, nil), &ch); err != nil { sendError(w, r, "Unknown channel: "+userid+"/"+sessionid) return } // Check if len(ch.OpenPermas) >= 10 { sendError(w, r, "Too many open channels") return } is_open := false for _, p := range ch.OpenPermas { if p == req.Perma { is_open = true break } } var perma grapher.PermaNode if !is_open { // Update channel infos ch.OpenPermas = append(ch.OpenPermas, req.Perma) _, err = datastore.Put(c, datastore.NewKey("channel", userid+"/"+sessionid, 0, nil), &ch) if err != nil { sendError(w, r, "Internal server error") return } // Repeat all blobs from this document. s := newStore(c) g := grapher.NewGrapher(userid, schema, s, s, nil) s.SetGrapher(g) ch := newChannelAPI(c, s, userid, sessionid, true, g) perma, err = g.Repeat(req.Perma, req.From) if err != nil { sendError(w, r, "Failed opening") return } fmt.Fprintf(w, `{"ok":true, "blobs":[%v]}`, strings.Join(ch.messageBuffer, ",")) } else { fmt.Fprint(w, `{"ok":true, "blobs":[]}`) } if req.MarkAsRead { if perma == nil { s := newStore(c) data, err := s.GetPermaNode(req.Perma) if err != nil { log.Printf("Err: Failed reading permanode") return } perma = grapher.NewPermaNode(nil) perma.FromMap(req.Perma, data) } markAsRead(c, userid, perma.BlobRef(), perma.SequenceNumber()-1) } }