github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/main/shared/ipfs.go (about) 1 package shared 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io" 9 "mime/multipart" 10 "net/http" 11 "time" 12 ) 13 14 const ( 15 baseUrl = "https://api.pinata.cloud" 16 ) 17 18 type IpfsClient struct { 19 BaseURL string 20 apiKey string 21 apiSecret string 22 HTTPClient *http.Client 23 } 24 25 type ipfsErrorResponse struct { 26 Code int `json:"code"` 27 Message string `json:"message"` 28 } 29 30 type ipfsSuccessResponse struct { 31 Code int `json:"code"` 32 Data interface{} `json:"data"` 33 } 34 35 type Pin struct { 36 IpfsHash string `json:"IpfsHash"` 37 PinSize int `json:"PinSize"` 38 Timestamp time.Time `json:"Timestamp"` 39 IsDuplicate bool `json:"isDuplicate"` 40 } 41 42 func NewIpfsClient(apiKey string, apiSecret string) *IpfsClient { 43 return &IpfsClient{ 44 BaseURL: baseUrl, 45 apiKey: apiKey, 46 apiSecret: apiSecret, 47 HTTPClient: &http.Client{ 48 Timeout: time.Second * 10, 49 }, 50 } 51 } 52 53 func (c *IpfsClient) sendRequest(req *http.Request, v interface{}) error { 54 req.Header.Set("pinata_api_key", c.apiKey) 55 req.Header.Set("pinata_secret_api_key", c.apiSecret) 56 57 res, err := c.HTTPClient.Do(req) 58 if err != nil { 59 return err 60 } 61 62 defer res.Body.Close() 63 64 if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest { 65 var errRes ipfsErrorResponse 66 if err = json.NewDecoder(res.Body).Decode(&errRes); err == nil { 67 return errors.New(errRes.Message) 68 } 69 return fmt.Errorf("unknown error, status code: %d", res.StatusCode) 70 } 71 72 fullResponse := ipfsSuccessResponse{ 73 Data: v, 74 } 75 76 if err = json.NewDecoder(res.Body).Decode(&fullResponse.Data); err != nil { 77 return err 78 } 79 80 return nil 81 } 82 83 func (c *IpfsClient) PinJson(data interface{}) (*Pin, error) { 84 url := c.BaseURL + "/pinning/pinJSONToIPFS" 85 json_data, err := json.Marshal(data) 86 87 if err != nil { 88 return nil, err 89 } 90 91 req, _ := http.NewRequest("POST", url, bytes.NewBuffer(json_data)) 92 req.Header.Set("Content-Type", "application/json; charset=UTF-8") 93 94 res := Pin{} 95 96 if err := c.sendRequest(req, &res); err != nil { 97 return nil, err 98 } 99 100 return &res, nil 101 } 102 103 func (c *IpfsClient) PinFile(file multipart.File, fileName string) (*Pin, error) { 104 url := c.BaseURL + "/pinning/pinFileToIPFS" 105 106 body := &bytes.Buffer{} 107 writer := multipart.NewWriter(body) 108 part, _ := writer.CreateFormFile("file", fileName) 109 io.Copy(part, file) 110 writer.Close() 111 112 req, _ := http.NewRequest("POST", url, body) 113 req.Header.Add("Content-Type", writer.FormDataContentType()) 114 115 res := Pin{} 116 117 if err := c.sendRequest(req, &res); err != nil { 118 return nil, err 119 } 120 121 return &res, nil 122 }