github.com/leg100/ots@v0.0.7-0.20210919080622-034055ced4bd/blob.go (about) 1 package ots 2 3 import ( 4 "fmt" 5 6 "github.com/google/uuid" 7 ) 8 9 const ( 10 // ChunkMaxLimit is maximum permissible size of a chunk 11 ChunkMaxLimit = 65536 12 13 // ChunkStartMarker is the special byte that prefixes the first chunk 14 ChunkStartMarker = byte(2) 15 16 // ChunkEndMarker is the special byte that suffixes the last chunk 17 ChunkEndMarker = byte(3) 18 ) 19 20 // BlobStore implementations provide a persistent store from and to which binary 21 // objects can be fetched and uploaded. 22 type BlobStore interface { 23 // Get fetches a blob 24 Get(string) ([]byte, error) 25 26 // Get fetches a blob chunk 27 GetChunk(string, GetChunkOptions) ([]byte, error) 28 29 // Put uploads a blob 30 Put(string, []byte) error 31 32 // Put uploads a blob chunk 33 PutChunk(string, []byte, PutChunkOptions) error 34 } 35 36 type GetChunkOptions struct { 37 // The maximum number of bytes of logs to return to the client 38 Limit int `schema:"limit"` 39 40 // The start position in the logs from which to send to the client 41 Offset int `schema:"offset"` 42 } 43 44 type PutChunkOptions struct { 45 // End indicates this is the last and final chunk 46 End bool `schema:"end"` 47 } 48 49 // NewBlobID generates a unique blob ID 50 func NewBlobID() string { 51 return uuid.NewString() 52 } 53 54 // GetChunk retrieves a chunk of bytes from a byte slice. The first chunk in the 55 // slice is prefixed with a special byte. If complete is true then the last 56 // chunk in the slice is suffixed with a special byte. 57 func GetChunk(p []byte, opts GetChunkOptions, complete bool) ([]byte, error) { 58 if opts.Offset == 0 { 59 p = append([]byte{ChunkStartMarker}, p...) 60 } 61 62 if complete { 63 p = append(p, ChunkEndMarker) 64 } 65 66 if opts.Offset > len(p) { 67 return nil, fmt.Errorf("offset greater than size of binary object") 68 } 69 70 if opts.Limit > ChunkMaxLimit { 71 opts.Limit = ChunkMaxLimit 72 } 73 74 // Adjust limit if it extends beyond size of binary object 75 if (opts.Offset + opts.Limit) > len(p) { 76 opts.Limit = len(p) - opts.Offset 77 } 78 79 return p[opts.Offset:(opts.Offset + opts.Limit)], nil 80 }