forked from ungerik/go-start
/
blob.go
142 lines (124 loc) · 3.21 KB
/
blob.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package media
import (
"bytes"
"io"
"mime"
"net/http"
"path"
"github.com/ungerik/go-start/model"
"github.com/ungerik/go-start/view"
)
func BlobIterator() model.Iterator {
return Config.Backend.BlobIterator()
}
func NewBlob(filename string, data []byte) (*Blob, error) {
return NewBlobFromReader(filename, bytes.NewReader(data))
}
func NewBlobFromReader(filename string, reader io.Reader) (*Blob, error) {
contentType := mime.TypeByExtension(path.Ext(filename))
blob := &Blob{
Filename: model.String(filename),
ContentType: model.String(contentType),
}
blob.Init()
writer, err := blob.FileWriter()
if err != nil {
return nil, err
}
defer writer.Close()
size, err := io.Copy(writer, reader)
if err != nil {
return nil, err
}
blob.Size.Set(size)
err = blob.Save()
if err != nil {
return nil, err
}
return blob, nil
}
// NewBlobFromURL creates and saves a new Blob by downloading it from url.
func NewBlobFromURL(url string) (*Blob, error) {
response, err := http.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
return NewBlobFromReader(path.Base(url), response.Body)
}
// LoadBlob loads an existing image from Config.Backend.
func LoadBlob(id string) (*Blob, error) {
return Config.Backend.LoadBlob(id)
}
type Blob struct {
ID model.String `bson:",omitempty"`
Title model.String
Link model.Url
Filename model.String
ContentType model.String
Size model.Int
FileID model.String
}
func (self *Blob) Init() *Blob {
if self.Title == "" {
self.Title = self.Filename
}
return self
}
func (self *Blob) FileURL() view.URL {
return view.NewURLWithArgs(FileView, self.FileID.Get(), self.Filename.Get())
}
func (self *Blob) FileLink(class string) *view.Link {
return &view.Link{
Model: &view.URLLink{
Url: self.FileURL(),
Title: self.Title.Get(),
Content: view.HTML(self.Filename.Get()),
},
Class: class,
}
}
func (self *Blob) Save() error {
return Config.Backend.SaveBlob(self)
}
func (self *Blob) Delete() error {
err := self.deleteFileIfExists()
if err != nil {
return err
}
return Config.Backend.DeleteBlob(self)
}
func (self *Blob) CountRefs() (int, error) {
return Config.Backend.CountBlobRefs(self.ID.Get())
}
func (self *Blob) RemoveAllRefs() (count int, err error) {
return Config.Backend.RemoveAllBlobRefs(self.ID.Get())
}
// FileWriter deletes the current blob-file and returns a writer
// for a new file. The ID of the new file is set at Blob,
// but Blob is not saved. You have to call Save() after FileWriter().
func (self *Blob) FileWriter() (writer io.WriteCloser, err error) {
err = self.deleteFileIfExists()
if err != nil {
return nil, err
}
writer, id, err := Config.Backend.FileWriter(self.Filename.Get(), self.ContentType.Get())
if err == nil {
self.FileID.Set(id)
}
return writer, err
}
// FileReader returns a reader for the blob-file if it exists.
func (self *Blob) FileReader() (reader io.ReadCloser, filename, contentType string, err error) {
return Config.Backend.FileReader(self.FileID.Get())
}
func (self *Blob) deleteFileIfExists() error {
if self.FileID.IsEmpty() {
return nil
}
err := Config.Backend.DeleteFile(self.FileID.Get())
if err == nil {
self.FileID.Set("")
}
return err
}