@cryptotaxi247 / kubo / commits / 02c7c329a

commands: Added File interface and implementations

Matt Bell committed Nov 16, 2014 at 00:04 UTC 02c7c329aa17f8cf7c1e5b79762554010a9cad07
1 file changed +156
commands/file.go new
+156
@@ -0,0 +1,156 @@
1 +package commands
2 +
3 +import (
4 + "errors"
5 + "io"
6 + "mime"
7 + "mime/multipart"
8 + "net/http"
9 +)
10 +
11 +const (
12 + multipartFormdataType = "multipart/form-data"
13 + multipartMixedType = "multipart/mixed"
14 +
15 + contentTypeHeader = "Content-Type"
16 +)
17 +
18 +var (
19 + ErrNotDirectory = errors.New("Couln't call NextFile(), this isn't a directory")
20 + ErrNotReader = errors.New("This file is a directory, can't use Reader functions")
21 +)
22 +
23 +type File interface {
24 + io.ReadCloser
25 + FileName() string
26 + IsDirectory() bool
27 + NextFile() (File, error)
28 +}
29 +
30 +type MultipartFile struct {
31 + File
32 +
33 + Part *multipart.Part
34 + Reader *multipart.Reader
35 + Mediatype string
36 +}
37 +
38 +func NewFileFromPart(part *multipart.Part) (File, error) {
39 + f := &MultipartFile{
40 + Part: part,
41 + }
42 +
43 + contentType := part.Header.Get(contentTypeHeader)
44 +
45 + var params map[string]string
46 + var err error
47 + f.Mediatype, params, err = mime.ParseMediaType(contentType)
48 + if err != nil {
49 + return nil, err
50 + }
51 +
52 + if f.IsDirectory() {
53 + boundary, found := params["boundary"]
54 + if !found {
55 + return nil, http.ErrMissingBoundary
56 + }
57 +
58 + f.Reader = multipart.NewReader(part, boundary)
59 + }
60 +
61 + return f, nil
62 +}
63 +
64 +func (f *MultipartFile) IsDirectory() bool {
65 + return f.Mediatype == multipartFormdataType || f.Mediatype == multipartMixedType
66 +}
67 +
68 +func (f *MultipartFile) NextFile() (File, error) {
69 + if !f.IsDirectory() {
70 + return nil, ErrNotDirectory
71 + }
72 +
73 + part, err := f.Reader.NextPart()
74 + if err != nil {
75 + return nil, err
76 + }
77 +
78 + return NewFileFromPart(part)
79 +}
80 +
81 +func (f *MultipartFile) FileName() string {
82 + return f.Part.FileName()
83 +}
84 +
85 +func (f *MultipartFile) Read(p []byte) (int, error) {
86 + if f.IsDirectory() {
87 + return 0, ErrNotReader
88 + }
89 + return f.Part.Read(p)
90 +}
91 +
92 +func (f *MultipartFile) Close() error {
93 + if f.IsDirectory() {
94 + return ErrNotReader
95 + }
96 + return f.Part.Close()
97 +}
98 +
99 +type SliceFile struct {
100 + Filename string
101 + Files []File
102 +}
103 +
104 +func (f *SliceFile) IsDirectory() bool {
105 + return true
106 +}
107 +
108 +func (f *SliceFile) NextFile() (File, error) {
109 + if len(f.Files) == 0 {
110 + return nil, io.EOF
111 + }
112 + file := f.Files[0]
113 + f.Files = f.Files[1:]
114 + return file, nil
115 +}
116 +
117 +func (f *SliceFile) FileName() string {
118 + return f.Filename
119 +}
120 +
121 +func (f *SliceFile) Read(p []byte) (int, error) {
122 + return 0, ErrNotReader
123 +}
124 +
125 +func (f *SliceFile) Close() error {
126 + return ErrNotReader
127 +}
128 +
129 +type ReaderFile struct {
130 + Filename string
131 + Reader io.Reader
132 +}
133 +
134 +func (f *ReaderFile) IsDirectory() bool {
135 + return false
136 +}
137 +
138 +func (f *ReaderFile) NextFile() (File, error) {
139 + return nil, ErrNotDirectory
140 +}
141 +
142 +func (f *ReaderFile) FileName() string {
143 + return f.Filename
144 +}
145 +
146 +func (f *ReaderFile) Read(p []byte) (int, error) {
147 + return f.Reader.Read(p)
148 +}
149 +
150 +func (f *ReaderFile) Close() error {
151 + closer, ok := f.Reader.(io.Closer)
152 + if !ok {
153 + return nil
154 + }
155 + return closer.Close()
156 +}