getter.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package storage
  2. import (
  3. "bytes"
  4. "errors"
  5. "hash/crc64"
  6. "io"
  7. "os"
  8. "path/filepath"
  9. )
  10. // FileGetter is the interface for getting a stream of a file payload,
  11. // addressed by name/filename. Presumably, the names will be scoped to relative
  12. // file paths.
  13. type FileGetter interface {
  14. // Get returns a stream for the provided file path
  15. Get(filename string) (output io.ReadCloser, err error)
  16. }
  17. // FilePutter is the interface for storing a stream of a file payload,
  18. // addressed by name/filename.
  19. type FilePutter interface {
  20. // Put returns the size of the stream received, and the crc64 checksum for
  21. // the provided stream
  22. Put(filename string, input io.Reader) (size int64, checksum []byte, err error)
  23. }
  24. // FileGetPutter is the interface that groups both Getting and Putting file
  25. // payloads.
  26. type FileGetPutter interface {
  27. FileGetter
  28. FilePutter
  29. }
  30. // NewPathFileGetter returns a FileGetter that is for files relative to path
  31. // relpath.
  32. func NewPathFileGetter(relpath string) FileGetter {
  33. return &pathFileGetter{root: relpath}
  34. }
  35. type pathFileGetter struct {
  36. root string
  37. }
  38. func (pfg pathFileGetter) Get(filename string) (io.ReadCloser, error) {
  39. return os.Open(filepath.Join(pfg.root, filename))
  40. }
  41. type bufferFileGetPutter struct {
  42. files map[string][]byte
  43. }
  44. func (bfgp bufferFileGetPutter) Get(name string) (io.ReadCloser, error) {
  45. if _, ok := bfgp.files[name]; !ok {
  46. return nil, errors.New("no such file")
  47. }
  48. b := bytes.NewBuffer(bfgp.files[name])
  49. return &readCloserWrapper{b}, nil
  50. }
  51. func (bfgp *bufferFileGetPutter) Put(name string, r io.Reader) (int64, []byte, error) {
  52. crc := crc64.New(CRCTable)
  53. buf := bytes.NewBuffer(nil)
  54. cw := io.MultiWriter(crc, buf)
  55. i, err := io.Copy(cw, r)
  56. if err != nil {
  57. return 0, nil, err
  58. }
  59. bfgp.files[name] = buf.Bytes()
  60. return i, crc.Sum(nil), nil
  61. }
  62. type readCloserWrapper struct {
  63. io.Reader
  64. }
  65. func (w *readCloserWrapper) Close() error { return nil }
  66. // NewBufferFileGetPutter is a simple in-memory FileGetPutter
  67. //
  68. // Implication is this is memory intensive...
  69. // Probably best for testing or light weight cases.
  70. func NewBufferFileGetPutter() FileGetPutter {
  71. return &bufferFileGetPutter{
  72. files: map[string][]byte{},
  73. }
  74. }
  75. // NewDiscardFilePutter is a bit bucket FilePutter
  76. func NewDiscardFilePutter() FilePutter {
  77. return &bitBucketFilePutter{}
  78. }
  79. type bitBucketFilePutter struct {
  80. }
  81. func (bbfp *bitBucketFilePutter) Put(name string, r io.Reader) (int64, []byte, error) {
  82. c := crc64.New(CRCTable)
  83. i, err := io.Copy(c, r)
  84. return i, c.Sum(nil), err
  85. }
  86. // CRCTable is the default table used for crc64 sum calculations
  87. var CRCTable = crc64.MakeTable(crc64.ISO)