func isMsgValid(msg string, topic *Topic) bool { if msg == "" { return false } // prevent duplicate posts within the topic if topic != nil { sha1 := u.Sha1OfBytes([]byte(msg)) for _, p := range topic.Posts { if bytes.Compare(p.MessageSha1[:], sha1) == 0 { return false } } } return true }
func (store *Store) Put(d []byte) (id string, err error) { store.Lock() defer store.Unlock() idBytes := u.Sha1OfBytes(d) id = fmt.Sprintf("%x", idBytes) if _, ok := store.sha1HexToBlobNo[id]; ok { return id, nil } blob := blob{ size: len(d), offset: store.currSegmentSize, nSegment: store.currSegmentNo, } copy(blob.sha1[:], idBytes) if _, err = store.currSegmentFile.Write(d); err != nil { return "", err } if err = store.currSegmentFile.Sync(); err != nil { return "", err } store.currSegmentSize += blob.size if store.currSegmentSize >= store.maxSegmentSize { // filled current segment => create a new one err = store.currSegmentFile.Close() if err != nil { return "", err } store.currSegmentNo += 1 store.currSegmentSize = 0 path := segmentFilePath(store.basePath, store.currSegmentNo) store.currSegmentFile, err = os.Create(path) if err != nil { return "", err } } if err = writeBlobRec(store.idxCsvWriter, &blob); err != nil { return "", err } store.appendBlob(blob) return id, nil }
func (store *Store) addNewPost(msg, user, ipAddr string, topic *Topic, newTopic bool) error { msgBytes := []byte(msg) sha1 := u.Sha1OfBytes(msgBytes) p := &Post{ Id: len(topic.Posts) + 1, CreatedOn: time.Now(), UserNameInternal: remSep(user), IpAddrInternal: remSep(ipAddrToInternal(ipAddr)), IsDeleted: false, Topic: topic, } copy(p.MessageSha1[:], sha1) if err := store.writeMessageAsSha1(msgBytes, p.MessageSha1); err != nil { return err } topicStr := "" if newTopic { topicStr = fmt.Sprintf("T%d|%s\n", topic.Id, topic.Subject) } s1 := fmt.Sprintf("%d", p.CreatedOn.Unix()) s2 := base64.StdEncoding.EncodeToString(p.MessageSha1[:]) s2 = s2[:len(s2)-1] // remove unnecessary '=' from the end s3 := p.UserNameInternal sIp := p.IpAddrInternal postStr := fmt.Sprintf("P%d|%d|%s|%s|%s|%s\n", topic.Id, p.Id, s1, s2, sIp, s3) str := topicStr + postStr if err := store.appendString(str); err != nil { return err } topic.Posts = append(topic.Posts, *p) if newTopic { store.topics = append(store.topics, *topic) } store.posts = append(store.posts, &topic.Posts[len(topic.Posts)-1]) return nil }
func (s *StoreCrashes) SaveCrash(appName, appVer, ipAddr string, crashData []byte) error { s.Lock() defer s.Unlock() // TODO: white-list app names? app := s.FindOrCreateApp(appName) programVersionInterned := s.FindOrCreateVersion(appVer) ipAddrInterned := s.FindOrCreateIp(ipAddrToInternal(ipAddr)) cl := storeCrashingLine(crashData) crashingLine := s.FindOrCreateCrashingLine(cl) c := &Crash{ Id: len(s.crashes), App: app, CreatedOn: time.Now(), ProgramVersion: programVersionInterned, IpAddrInternal: ipAddrInterned, CrashingLine: crashingLine, } var buf bytes.Buffer buf.Write(getCrashPrefixData(c)) buf.Write(crashData) dstData := buf.Bytes() sha1 := u.Sha1OfBytes(dstData) copy(c.Sha1[:], sha1) if err := s.writeMessageAsSha1(crashData, sha1); err != nil { return err } crashLine := serCrash(c) if err := s.appendString(crashLine); err != nil { return err } s.appendCrash(c) return nil }
func testGet(t *testing.T, store *Store, rnd *rand.Rand, blobIds []string) { var d []byte var err error nBlobs := len(blobIds) for i := 0; i < nBlobs; i++ { // we don't test all blobs due to randomness but testing most of them // is good enough n := rnd.Intn(nBlobs) id := blobIds[n] d, err = store.Get(id) if err != nil { t.Fatalf("store.Get(%q) failed with %q, i: %d, sha1: %s", id, err, i, hex.EncodeToString([]byte(id))) } sha1Hex := fmt.Sprintf("%x", u.Sha1OfBytes(d)) if sha1Hex != id { t.Fatalf("store.Get() returned bad content, id is %s while sha1 is %s, should be same", id, sha1Hex) } } k := "non-existint" d, err = store.Get(k) if err == nil { t.Fatalf("store.Get(%q) returned nil err, expected an error", k) } }