You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
2.7 KiB

  1. package operation
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "sort"
  9. "github.com/chrislusf/seaweedfs/go/util"
  10. )
  11. var ErrOutOfRange = errors.New("Out of Range")
  12. type ChunkInfo struct {
  13. Fid string `json:"fid,omitempty"`
  14. Offset uint64 `json:"offset,omitempty"`
  15. Size uint32 `json:"size,omitempty"`
  16. }
  17. type ChunkList []*ChunkInfo
  18. type ChunkedFile struct {
  19. Name string `json:"name,omitempty"`
  20. Mime string `json:"mime,omitempty"`
  21. Size uint64 `json:"size,omitempty"`
  22. Chunks ChunkList `json:"chunks,omitempty"`
  23. master string `json:"-"`
  24. }
  25. func (s ChunkList) Len() int { return len(s) }
  26. func (s ChunkList) Less(i, j int) bool { return s[i].Offset < s[j].Offset }
  27. func (s ChunkList) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  28. func NewChunkedNeedle(buffer []byte, master string) (*ChunkedFile, error) {
  29. c := ChunkedFile{}
  30. if e := json.Unmarshal(buffer, c); e != nil {
  31. return nil, e
  32. }
  33. sort.Sort(c.Chunks)
  34. c.master = master
  35. return &c, nil
  36. }
  37. func (c *ChunkedFile) Marshal() ([]byte, error) {
  38. return json.Marshal(c)
  39. }
  40. func copyChunk(fileUrl string, w io.Writer, startOffset, size int64) (written int64, e error) {
  41. req, err := http.NewRequest("GET", fileUrl, nil)
  42. if err != nil {
  43. return written, err
  44. }
  45. if startOffset > 0 {
  46. req.Header.Set("Range", fmt.Sprintf("bytes=%d-", startOffset))
  47. }
  48. resp, err := util.Do(req)
  49. if err != nil {
  50. return written, err
  51. }
  52. defer resp.Close()
  53. if startOffset > 0 && resp.StatusCode != 206 {
  54. return written, fmt.Errorf("Cannot Read Needle Position: %d [%s]", startOffset, fileUrl)
  55. }
  56. if size > 0 {
  57. return io.CopyN(w, resp, size)
  58. } else {
  59. return io.Copy(w, resp)
  60. }
  61. }
  62. func (c *ChunkedFile) WriteBuffer(w io.Writer, offset, size int64) (written int64, e error) {
  63. if offset >= c.Size || offset+size > c.Size {
  64. return written, ErrOutOfRange
  65. }
  66. chunkIndex := -1
  67. chunkStartOffset := 0
  68. for i, ci := range c.Chunks {
  69. if offset >= ci.Offset && offset < ci.Offset+ci.Size {
  70. chunkIndex = i
  71. chunkStartOffset = offset - ci.Offset
  72. break
  73. }
  74. }
  75. if chunkIndex < 0 {
  76. return written, ErrOutOfRange
  77. }
  78. for ; chunkIndex < c.Chunks.Len(); chunkIndex++ {
  79. ci := c.Chunks[chunkIndex]
  80. fileUrl, lookupError := LookupFileId(c.master, ci.Fid)
  81. if lookupError != nil {
  82. return written, lookupError
  83. }
  84. rsize := 0
  85. if size > 0 {
  86. rsize = size - written
  87. }
  88. if n, e := copyChunk(fileUrl, w, chunkStartOffset, rsize); e != nil {
  89. return written, e
  90. } else {
  91. written += n
  92. }
  93. if size > 0 && written >= size {
  94. break
  95. }
  96. chunkStartOffset = 0
  97. }
  98. return written, nil
  99. }
  100. func (c *ChunkedFile) DeleteHelper() error {
  101. //TODO Delete all chunks
  102. return nil
  103. }
  104. func (c *ChunkedFile) StoredHelper() error {
  105. //TODO
  106. return nil
  107. }