/
upload_to_ipfs.go
180 lines (154 loc) · 4.81 KB
/
upload_to_ipfs.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package utils
import (
"bytes"
"encoding/json"
"fmt"
"github.com/Crossbell-Box/OperatorSync/app/worker/config"
"github.com/Crossbell-Box/OperatorSync/app/worker/global"
"image"
_ "image/gif" // Add GIF support
_ "image/jpeg" // Add JPEG support
_ "image/png" // Add PNG support
"log"
"mime/multipart"
"net/http"
"net/url"
"path"
"strconv"
"strings"
"time"
)
type response struct {
Status string `json:"status"`
CID string `json:"cid"`
URL string `json:"url"`
Web2URL string `json:"web2url"`
FileSize uint `json:"fileSize"`
Error string `json:"error"`
}
func UploadURLToIPFS(targetUrl string, withProxy bool) (string, string, uint, string, string, error) {
// Get filename
global.Logger.Debug("Uploading file ", targetUrl, " to IPFS...")
if targetUrl == "" {
return "", "", 0, "", "", fmt.Errorf("empty uri")
}
reqUrl, err := url.Parse(targetUrl)
if err != nil {
return "", "", 0, "", "", err
}
filename := path.Base(reqUrl.Path)
// Retrieve data
body, err := HttpRequest(targetUrl, withProxy)
if err != nil {
global.Logger.Error("Failed to retrieve data from: ", targetUrl)
return "", "", 0, "", "", err
}
bodyBytes := body[:]
// Detect content-type
contentType := http.DetectContentType(bodyBytes)
// Upload to IPFS
global.Logger.Debug("File download successfully, uploading...")
ipfsUri, fileSize, err := UploadBytesToIPFS(bodyBytes, filename)
if err != nil {
global.Logger.Errorf("Failed to upload data to IPFS with error: %s", err.Error())
return "", "", 0, "", "", err
}
// Attach additional props
additionalProps := make(map[string]string)
if strings.Contains(contentType, "image/") {
// Is image
imgConfig, format, err := image.DecodeConfig(bytes.NewReader(bodyBytes))
if err != nil {
// Unable to handle this
global.Logger.Errorf("Failed to decode image with error: %s", err.Error())
} else {
additionalProps["format"] = format
additionalProps["width"] = strconv.Itoa(imgConfig.Width)
additionalProps["height"] = strconv.Itoa(imgConfig.Height)
}
}
additionalPropsBytes, err := json.Marshal(&additionalProps)
if err != nil {
global.Logger.Errorf("Failed to parse additional props with error: %s", err.Error())
additionalPropsBytes = nil
}
// Return response
return filename, ipfsUri, fileSize, contentType, string(additionalPropsBytes), nil
}
func UploadBytesToIPFS(data []byte, filename string) (string, uint, error) {
// Prepare
bodyBuffer := &bytes.Buffer{}
bodyWriter := multipart.NewWriter(bodyBuffer)
fileWriter, err := bodyWriter.CreateFormFile("file", filename)
if err != nil {
return "", 0, err
}
fileSize, err := fileWriter.Write(data)
if err != nil {
global.Logger.Error("Failed to copy buffer data")
}
// Upload to proxy
var resp response
formContentType := bodyWriter.FormDataContentType()
_ = bodyWriter.Close() // Ignore error
ipfsReq, err := http.NewRequest("POST", fmt.Sprintf("%s/upload", config.Config.IPFSEndpoint), bodyBuffer)
if err != nil {
global.Logger.Error("Failed to initialize request: ", err.Error())
return "", 0, err
}
ipfsReq.Header.Set("Content-Type", formContentType)
ipfsRes, err := (&http.Client{}).Do(ipfsReq)
if err != nil {
global.Logger.Error("Failed to do request: ", err.Error())
return "", 0, err
}
err = json.NewDecoder(ipfsRes.Body).Decode(&resp)
if err != nil {
log.Println("Error decoding JSON:", err)
return "", 0, err
}
// Return URL
if resp.Status == "ok" {
global.Logger.Debug("File (Size: ", fileSize, ") upload succeeded: ", resp.URL)
return resp.URL, uint(fileSize), nil
} else {
return "", 0, fmt.Errorf(resp.Error)
}
}
func UploadVideoToIPFS(videoUrl string) (string, uint, error) {
for {
// Prepare request
ipfsReq, err := http.NewRequest("POST", fmt.Sprintf("%s/video", config.Config.IPFSEndpoint), nil)
if err != nil {
global.Logger.Error("Failed to initialize request: ", err.Error())
return "", 0, err
}
// Add query
q := ipfsReq.URL.Query()
q.Add("url", videoUrl)
ipfsReq.URL.RawQuery = q.Encode()
// Do request
global.Logger.Debugf("Checking upload status for %s", videoUrl)
var resp response
ipfsRes, err := (&http.Client{}).Do(ipfsReq)
if err != nil {
global.Logger.Error("Failed to do request: ", err.Error())
return "", 0, err
}
err = json.NewDecoder(ipfsRes.Body).Decode(&resp)
if err != nil {
log.Println("Error decoding JSON:", err)
return "", 0, err
}
if resp.Status == "ok" {
global.Logger.Debugf("Video %s uploaded successfully!", videoUrl)
return resp.URL, resp.FileSize, nil
} else if resp.Status == "error" {
global.Logger.Errorf("Failed to upload video %s with IPFS Upload Relay error: %s", videoUrl, err.Error())
return "", 0, fmt.Errorf(resp.Error)
}
// else: pending
global.Logger.Debugf("Video %s upload status: %s", videoUrl, resp.Status)
time.Sleep(10 * time.Second)
}
}