-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathattachment.go
162 lines (140 loc) · 3.76 KB
/
attachment.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package llm
import (
"encoding/base64"
"encoding/json"
"io"
"mime"
"net/http"
"os"
"path/filepath"
)
///////////////////////////////////////////////////////////////////////////////
// TYPES
type AttachmentMeta struct {
Id string `json:"id,omitempty"`
Filename string `json:"filename,omitempty"`
ExpiresAt uint64 `json:"expires_at,omitempty"`
Caption string `json:"transcript,omitempty"`
Data []byte `json:"data"`
}
// Attachment for messages
type Attachment struct {
meta AttachmentMeta
}
const (
defaultMimetype = "application/octet-stream"
)
////////////////////////////////////////////////////////////////////////////////
// LIFECYCLE
// NewAttachment creates a new, empty attachment
func NewAttachment() *Attachment {
return new(Attachment)
}
// ReadAttachment returns an attachment from a reader object.
// It is the responsibility of the caller to close the reader.
func ReadAttachment(r io.Reader) (*Attachment, error) {
var filename string
data, err := io.ReadAll(r)
if err != nil {
return nil, err
}
if f, ok := r.(*os.File); ok {
filename = f.Name()
}
return &Attachment{
meta: AttachmentMeta{
Filename: filename,
Data: data,
},
}, nil
}
////////////////////////////////////////////////////////////////////////////////
// STRINGIFY
// Convert JSON into an attachment
func (a *Attachment) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &a.meta)
}
// Convert an attachment into JSON
func (a *Attachment) MarshalJSON() ([]byte, error) {
// Create a JSON representation
var j struct {
Id string `json:"id,omitempty"`
Filename string `json:"filename,omitempty"`
Type string `json:"type"`
Bytes uint64 `json:"bytes"`
Caption string `json:"transcript,omitempty"`
}
j.Id = a.meta.Id
j.Filename = a.meta.Filename
j.Type = a.Type()
j.Bytes = uint64(len(a.meta.Data))
j.Caption = a.meta.Caption
return json.Marshal(j)
}
// Stringify an attachment
func (a *Attachment) String() string {
data, err := json.MarshalIndent(a.meta, "", " ")
if err != nil {
return err.Error()
}
return string(data)
}
////////////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
// Return the filename of an attachment
func (a *Attachment) Filename() string {
return a.meta.Filename
}
// Return the raw attachment data
func (a *Attachment) Data() []byte {
return a.meta.Data
}
// Return the caption for the attachment
func (a *Attachment) Caption() string {
return a.meta.Caption
}
// Return the mime media type for the attachment, based
// on the data and/or filename extension. Returns an empty string if
// there is no data or filename
func (a *Attachment) Type() string {
// If there's no data or filename, return empty
if len(a.meta.Data) == 0 && a.meta.Filename == "" {
return ""
}
// Mimetype based on content
mimetype := defaultMimetype
if len(a.meta.Data) > 0 {
mimetype = http.DetectContentType(a.meta.Data)
if mimetype != defaultMimetype {
return mimetype
}
}
// Mimetype based on filename
if a.meta.Filename != "" {
// Detect mimetype from extension
mimetype = mime.TypeByExtension(filepath.Ext(a.meta.Filename))
}
// Return the default mimetype
return mimetype
}
func (a *Attachment) Url() string {
return "data:" + a.Type() + ";base64," + base64.StdEncoding.EncodeToString(a.meta.Data)
}
// Streaming includes the ability to append data
func (a *Attachment) Append(other *Attachment) {
if other.meta.Id != "" {
a.meta.Id = other.meta.Id
}
if other.meta.Filename != "" {
a.meta.Filename = other.meta.Filename
}
if other.meta.ExpiresAt != 0 {
a.meta.ExpiresAt = other.meta.ExpiresAt
}
if other.meta.Caption != "" {
a.meta.Caption += other.meta.Caption
}
if len(other.meta.Data) > 0 {
a.meta.Data = append(a.meta.Data, other.meta.Data...)
}
}