github.com/janelia-flyem/dvid@v1.0.0/datatype/imagetile/keys.go (about) 1 /* 2 This file supports imagetile-specific keys. 3 */ 4 5 package imagetile 6 7 import ( 8 "bytes" 9 "fmt" 10 "net/http" 11 "strconv" 12 13 "github.com/janelia-flyem/dvid/datastore" 14 "github.com/janelia-flyem/dvid/dvid" 15 "github.com/janelia-flyem/dvid/storage" 16 ) 17 18 // TODO -- Introduce imagetile key type to allow for expansion in future. Since we currently 19 // have datasets using old keys, hold off on upgrade until a breaking change is introduced for all keys. 20 21 const ( 22 // keyUnknown should never be used and is a check for corrupt or incorrectly set keys 23 keyUnknown storage.TKeyClass = iota 24 25 // reserved type-specific key for metadata 26 keyProperties = datastore.PropertyTKeyClass 27 28 // key = legacy tile. Must be 3. 29 keyLegacyTile = 3 30 ) 31 32 func describeTKeyClass(tkc storage.TKeyClass) string { 33 switch tkc { 34 case keyLegacyTile: 35 return "imagetile tile key" 36 default: 37 return "unknown imagetile key class" 38 } 39 } 40 41 // DescribeTKeyClass returns a string explanation of what a particular TKeyClass 42 // is used for. Implements the datastore.TKeyClassDescriber interface. 43 func (d *Data) DescribeTKeyClass(tkc storage.TKeyClass) string { 44 return describeTKeyClass(tkc) 45 } 46 47 // NewTKey returns an imagetile-specific key component based on the components of a tile request. 48 func NewTKey(tile dvid.ChunkPoint3d, plane dvid.DataShape, scale Scaling) (tk storage.TKey, err error) { 49 // NOTE: For legacy reasons, first two bytes must be 3 and then 2. The current storage.TKey 50 // formatting has a TKeyClass for first byte and then 1 for second, but this second byte is only 51 // used for min/max key generation, so using 2 is ok as well. 52 var buf bytes.Buffer 53 buf.Write(plane.Bytes()) 54 55 buf.WriteByte(byte(scale)) 56 buf.WriteByte(byte(3)) 57 idx := dvid.IndexZYX(tile) 58 buf.Write(idx.Bytes()) 59 return buf.Bytes(), nil 60 } 61 62 // NewTKeyByTileReq returns an imagetile-specific key component based on a tile request. 63 func NewTKeyByTileReq(req TileReq) (storage.TKey, error) { 64 return NewTKey(req.tile, req.plane, req.scale) 65 } 66 67 // DecodeTKey returns the components of a tile request based on an imagetile-specific key component. 68 func DecodeTKey(tk storage.TKey) (tile dvid.ChunkPoint3d, plane dvid.DataShape, scale Scaling, err error) { 69 if len(tk) != 21 { 70 err = fmt.Errorf("expected 21 bytes for imagetile type-specific key, got %d bytes instead", len(tk)) 71 return 72 } 73 plane, err = dvid.BytesToDataShape(tk[0:dvid.DataShapeBytes]) 74 if err != nil { 75 return 76 } 77 scale = Scaling(tk[dvid.DataShapeBytes]) 78 var idx dvid.IndexZYX 79 if err = idx.IndexFromBytes(tk[dvid.DataShapeBytes+2:]); err != nil { 80 return 81 } 82 tile = dvid.ChunkPoint3d(idx) 83 return 84 } 85 86 type TileReq struct { 87 tile dvid.ChunkPoint3d 88 plane dvid.DataShape 89 scale Scaling 90 } 91 92 func (d *Data) ParseTileReq(r *http.Request, parts []string) (TileReq, error) { 93 if len(parts) < 7 { 94 return TileReq{}, fmt.Errorf("'tile' request must be following by plane, scale level, and tile coordinate") 95 } 96 shapeStr, scalingStr, coordStr := parts[4], parts[5], parts[6] 97 98 // Construct the index for this tile 99 planeStr := dvid.DataShapeString(shapeStr) 100 plane, err := planeStr.DataShape() 101 if err != nil { 102 err = fmt.Errorf("Illegal tile plane: %s (%v)", planeStr, err) 103 return TileReq{}, err 104 } 105 scale, err := strconv.ParseUint(scalingStr, 10, 8) 106 if err != nil { 107 err = fmt.Errorf("Illegal tile scale: %s (%v)", scalingStr, err) 108 return TileReq{}, err 109 } 110 tileCoord, err := dvid.StringToChunkPoint3d(coordStr, "_") 111 if err != nil { 112 err = fmt.Errorf("Illegal tile coordinate: %s (%v)", coordStr, err) 113 return TileReq{}, err 114 } 115 return TileReq{tileCoord, plane, Scaling(scale)}, nil 116 } 117 118 func NewTileReq(tile dvid.ChunkPoint3d, plane dvid.DataShape, scale Scaling) TileReq { 119 return TileReq{tile, plane, scale} 120 }