getter.go 2.19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package feeds

import (
	"context"
	"encoding/binary"
	"fmt"
	"time"

	"github.com/ethersphere/bee/pkg/soc"
	"github.com/ethersphere/bee/pkg/storage"
	"github.com/ethersphere/bee/pkg/swarm"
)

// Lookup is the interface for time based feed lookup
type Lookup interface {
20
	At(ctx context.Context, at, after int64) (chunk swarm.Chunk, currentIndex, nextIndex Index, err error)
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
}

// Getter encapsulates a chunk Getter getter and a feed and provides
//  non-concurrent lookup methods
type Getter struct {
	getter storage.Getter
	*Feed
}

// NewGetter constructs a feed Getter
func NewGetter(getter storage.Getter, feed *Feed) *Getter {
	return &Getter{getter, feed}
}

// Latest looks up the latest update of the feed
// after is a unix time hint of the latest known update
func Latest(ctx context.Context, l Lookup, after int64) (swarm.Chunk, error) {
38 39
	c, _, _, err := l.At(ctx, time.Now().Unix(), after)
	return c, err
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
}

// Get creates an update of the underlying feed at the given epoch
// and looks it up in the chunk Getter based on its address
func (f *Getter) Get(ctx context.Context, i Index) (swarm.Chunk, error) {
	addr, err := f.Feed.Update(i).Address()
	if err != nil {
		return nil, err
	}
	return f.getter.Get(ctx, storage.ModeGetRequest, addr)
}

// FromChunk parses out the timestamp and the payload
func FromChunk(ch swarm.Chunk) (uint64, []byte, error) {
	s, err := soc.FromChunk(ch)
	if err != nil {
		return 0, nil, err
	}
58
	cac := s.WrappedChunk()
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
	if len(cac.Data()) < 16 {
		return 0, nil, fmt.Errorf("feed update payload too short")
	}
	payload := cac.Data()[16:]
	at := binary.BigEndian.Uint64(cac.Data()[8:16])
	return at, payload, nil
}

// UpdatedAt extracts the time of feed other than update
func UpdatedAt(ch swarm.Chunk) (uint64, error) {
	d := ch.Data()
	if len(d) < 113 {
		return 0, fmt.Errorf("too short: %d", len(d))
	}
	// a soc chunk with time information in the wrapped content addressed chunk
	// 0-32    index,
	// 65-97   signature,
	// 98-105  span of wrapped chunk
	// 105-113 timestamp
	return binary.BigEndian.Uint64(d[105:113]), nil
}