1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
package torchwood
import (
"context"
"encoding/binary"
"fmt"
"strings"
"golang.org/x/mod/sumdb/tlog"
)
const TileHeight = 8
const TileWidth = 1 << TileHeight
// TilePath returns a tile coordinate path describing t, according to
// c2sp.org/tlog-tiles.
//
// For the go.dev/design/25530-sumdb scheme, use [tlog.Tile.Path]. For the
// c2sp.org/static-ct-api scheme, use [filippo.io/sunlight/TilePath].
//
// If t.Height is not TileHeight, TilePath panics.
func TilePath(t tlog.Tile) string {
if t.H != TileHeight {
panic(fmt.Sprintf("unexpected tile height %d", t.H))
}
if t.L == -1 {
return "tile/entries/" + strings.TrimPrefix(t.Path(), "tile/8/data/")
}
return "tile/" + strings.TrimPrefix(t.Path(), "tile/8/")
}
// ParseTilePath parses a tile coordinate path according to c2sp.org/tlog-tiles.
//
// For the go.dev/design/25530-sumdb scheme, use [tlog.ParseTilePath]. For the
// c2sp.org/static-ct-api scheme, use [filippo.io/sunlight/ParseTilePath].
func ParseTilePath(path string) (tlog.Tile, error) {
if rest, ok := strings.CutPrefix(path, "tile/entries/"); ok {
t, err := tlog.ParseTilePath("tile/8/data/" + rest)
if err != nil {
return tlog.Tile{}, fmt.Errorf("malformed tile path %q", path)
}
return t, nil
}
if rest, ok := strings.CutPrefix(path, "tile/"); ok {
t, err := tlog.ParseTilePath("tile/8/" + rest)
if err != nil {
return tlog.Tile{}, fmt.Errorf("malformed tile path %q", path)
}
return t, nil
}
return tlog.Tile{}, fmt.Errorf("malformed tile path %q", path)
}
// ReadTileEntry reads the next entry from the entry bundle according to
// c2sp.org/tlog-tiles, and returns the remaining data in the tile.
func ReadTileEntry(tile []byte) (entry, rest []byte, err error) {
if len(tile) < 2 {
return nil, nil, fmt.Errorf("tile too short")
}
l := binary.BigEndian.Uint16(tile)
tile = tile[2:]
if len(tile) < int(l) {
return nil, nil, fmt.Errorf("tile too short for entry length %d", l)
}
return tile[:l], tile[l:], nil
}
// AppendTileEntry appends the given entry to the entry bundle, according to
// c2sp.org/tlog-tiles.
func AppendTileEntry(tile []byte, entry []byte) ([]byte, error) {
if len(entry) > 0xFFFF {
return nil, fmt.Errorf("entry too long: %d bytes", len(entry))
}
tile = binary.BigEndian.AppendUint16(tile, uint16(len(entry)))
tile = append(tile, entry...)
return tile, nil
}
// TileReader is an interface equivalent to [tlog.TileReader], but with a
// context parameter for cancellation, a fixed [TileHeight], and a method to
// fetch arbitrary additional endpoints, if available.
type TileReader interface {
// ReadTiles returns the data for each requested tile.
// See [tlog.TileReader.ReadTiles] for details.
ReadTiles(ctx context.Context, tiles []tlog.Tile) (data [][]byte, err error)
// SaveTiles informs the TileReader that the tile data has been confirmed.
// See [tlog.TileReader.SaveTiles] for details.
SaveTiles(tiles []tlog.Tile, data [][]byte)
// ReadEndpoint fetches an arbitrary endpoint at the given path, such as
// "checkpoint", if supported.
ReadEndpoint(ctx context.Context, path string) (data []byte, err error)
}
// TileReaderWithContext is an obsolete name for [TileReader].
//
// Deprecated: use [TileReader] instead.
//
//go:fix inline
type TileReaderWithContext = TileReader
// TileHashReaderWithContext returns a HashReader that satisfies requests by
// loading tiles of the given tree.
//
// It is equivalent to [tlog.TileHashReader], but passes the ctx argument to the
// [TileReader] methods.
func TileHashReaderWithContext(ctx context.Context, tree tlog.Tree, tr TileReader) tlog.HashReader {
return tlog.HashReaderFunc(func(i []int64) ([]tlog.Hash, error) {
return tlog.TileHashReader(tree, tileReaderAndContext{tr: tr, ctx: ctx}).ReadHashes(i)
})
}
type tileReaderAndContext struct {
tr TileReader
ctx context.Context
}
func (tr tileReaderAndContext) Height() int { return TileHeight }
func (tr tileReaderAndContext) ReadTiles(tiles []tlog.Tile) (data [][]byte, err error) {
return tr.tr.ReadTiles(tr.ctx, tiles)
}
func (tr tileReaderAndContext) SaveTiles(tiles []tlog.Tile, data [][]byte) {
tr.tr.SaveTiles(tiles, data)
}
|