github.com/diadata-org/diadata@v1.4.593/pkg/utils/downloadResource.go (about) 1 package utils 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/json" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "net/url" 12 "os" 13 "path/filepath" 14 "time" 15 ) 16 17 var openseaKey string 18 19 // DownloadResource is a simple utility that downloads a resource 20 // from @url and stores it into @filepath. 21 func DownloadResource(path, url string) (err error) { 22 23 fmt.Println("url: ", url) 24 resp, err := http.Get(url) //nolint:noctx,gosec 25 if err != nil { 26 return 27 } 28 29 defer func() { 30 cerr := resp.Body.Close() 31 if err == nil { 32 err = cerr 33 } 34 }() 35 36 // Create the file 37 out, err := os.Create(filepath.Clean(path)) 38 if err != nil { 39 return 40 } 41 defer func() { 42 cerr := out.Close() 43 if err == nil { 44 err = cerr 45 } 46 }() 47 48 // Write the body to file 49 _, err = io.Copy(out, resp.Body) 50 return 51 } 52 53 // GetRequest performs a get request on @url and returns the response body 54 // as a slice of byte data. 55 func GetRequest(url string) ([]byte, int, error) { 56 57 response, err := http.Get(url) //nolint:noctx,gosec 58 if err != nil { 59 log.Error("get request: ", err) 60 return []byte{}, 0, err 61 } 62 63 // Close response body after function 64 defer func() { 65 cerr := response.Body.Close() 66 if err == nil { 67 err = cerr 68 } 69 }() 70 71 // Check the status code for a 200 so we know we have received a 72 // proper response. 73 if response.StatusCode != 200 { 74 return []byte{}, response.StatusCode, fmt.Errorf("HTTP Response Error %d", response.StatusCode) 75 } 76 77 // Read the response body 78 XMLdata, err := ioutil.ReadAll(response.Body) 79 if err != nil { 80 log.Error(err) 81 return []byte{}, response.StatusCode, err 82 } 83 84 return XMLdata, response.StatusCode, err 85 } 86 87 // GetRequest performs a get request on @url and returns the response body 88 // as a slice of byte data. 89 func GetRequestWithStatus(url string) ([]byte, int, error) { 90 91 // Get url 92 response, err := http.Get(url) //nolint:noctx,gosec 93 94 // Check, whether the request was successful 95 if err != nil { 96 log.Error(err) 97 return []byte{}, response.StatusCode, err 98 } 99 100 // Close response body after function 101 defer func(Body io.ReadCloser) { 102 errClose := Body.Close() 103 if errClose != nil { 104 log.Error("error closing body ", errClose) 105 } 106 }(response.Body) 107 108 // Read the response body 109 XMLdata, err := ioutil.ReadAll(response.Body) 110 111 if err != nil { 112 log.Error(err) 113 return []byte{}, response.StatusCode, err 114 } 115 116 return XMLdata, response.StatusCode, err 117 } 118 119 // PostRequest performs a POST request on @url and returns the response body 120 // as a slice of byte data. 121 func PostRequest(url string, body io.Reader) ([]byte, error) { 122 123 // Get url 124 response, err := http.Post(url, "", body) //nolint:noctx,gosec 125 126 // Check, whether the request was successful 127 if err != nil { 128 log.Error(err) 129 return []byte{}, err 130 } 131 132 // Close response body after function 133 defer func() { 134 cerr := response.Body.Close() 135 if err == nil { 136 err = cerr 137 } 138 }() 139 140 // Check the status code for a 200 so we know we have received a 141 // proper response. 142 if response.StatusCode != 200 { 143 log.Error("HTTP Response Error: ", response.StatusCode) 144 return []byte{}, fmt.Errorf("HTTP Response Error %d", response.StatusCode) 145 } 146 147 // Read the response body 148 XMLdata, err := ioutil.ReadAll(response.Body) 149 150 if err != nil { 151 log.Error(err) 152 return []byte{}, err 153 } 154 155 return XMLdata, err 156 } 157 158 // HTTPRequest returns the request body and defers the closing compliant 159 // to linting. 160 func HTTPRequest(request *http.Request) (body []byte, statusCode int, err error) { 161 client := &http.Client{} 162 resp, err := client.Do(request) 163 if err != nil { 164 return 165 } 166 defer func() { 167 cerr := resp.Body.Close() 168 if err == nil { 169 err = cerr 170 } 171 }() 172 173 statusCode = resp.StatusCode 174 body, err = ioutil.ReadAll(resp.Body) 175 if err != nil { 176 return 177 } 178 return 179 } 180 181 // CloseHTTPResp is a wrapper for closing http response bodies 182 // while complying with the linter. 183 func CloseHTTPResp(resp *http.Response) { 184 err := resp.Body.Close() 185 if err != nil { 186 log.Error(err) 187 } 188 } 189 190 // GraphQLGet returns the body of the result of a graphQL GET query. 191 // @url is the base url of the graphQL API 192 // @query is a byte slice representing the graphQL query message 193 // @bearer contains the API key if present 194 func GraphQLGet(url string, query []byte, bearer string) ([]byte, int, error) { 195 196 // Form post request with graphQL query 197 req, err := http.NewRequest("POST", url, bytes.NewBuffer(query)) //nolint:noctx 198 if err != nil { 199 return []byte{}, 0, err 200 } 201 202 // Add authorization bearer to header 203 req.Header.Add("Authorization", bearer) 204 205 return HTTPRequest(req) 206 } 207 208 func getOpenseaApiKey() string { 209 if openseaKey != "" { 210 return openseaKey 211 } 212 if Getenv("USE_ENV", "false") == "true" { 213 openseaKey = Getenv("API_KEY_OPENSEA", "") 214 return openseaKey 215 } 216 217 var lines []string 218 var filename string 219 if Getenv("EXEC_MODE", "debug") == "production" { 220 filename = "/run/secrets/Opensea-API.key" 221 } else { 222 filename = "../../secrets/Opensea-API.key" 223 } 224 225 file, err := os.Open(filepath.Clean(filename)) 226 if err != nil { 227 log.Fatal(err) 228 } 229 defer func(file *os.File) { 230 errClose := file.Close() 231 if errClose != nil { 232 log.Error("failure closing opensea-api.key file ", errClose) 233 } 234 }(file) 235 236 scanner := bufio.NewScanner(file) 237 for scanner.Scan() { 238 lines = append(lines, scanner.Text()) 239 } 240 if err = scanner.Err(); err != nil { 241 log.Fatal(err) 242 } 243 if len(lines) != 1 { 244 log.Fatal("Secrets file for opensea API key should have exactly one line") 245 } 246 openseaKey = lines[0] 247 return openseaKey 248 } 249 250 // OpenseaGetRequest returns the data for a get request on @url with an Opensea API key. 251 func OpenseaGetRequest(OpenseaURL string) ([]byte, int, error) { 252 253 client := &http.Client{} 254 req, err := http.NewRequest("GET", OpenseaURL, nil) 255 if err != nil { 256 log.Print(err) 257 return []byte{}, 0, err 258 } 259 apiKey := getOpenseaApiKey() 260 q := url.Values{} 261 req.Header.Set("Accepts", "application/json") 262 req.Header.Add("X-API-KEY", apiKey) 263 req.URL.RawQuery = q.Encode() 264 265 resp, err := client.Do(req) 266 if err != nil { 267 fmt.Println("Error sending request to server") 268 os.Exit(1) 269 } 270 defer func(Body io.ReadCloser) { 271 errClose := Body.Close() 272 if errClose != nil { 273 fmt.Println("Error closing body ", errClose) 274 } 275 }(resp.Body) 276 respData, err := ioutil.ReadAll(resp.Body) 277 if err != nil { 278 log.Error("read response body: ", err) 279 return respData, resp.StatusCode, err 280 } 281 return respData, resp.StatusCode, nil 282 } 283 284 // GetCoinPrice Gets the price in USD of coin through our API. 285 // Looks it up on coingecko in case it doesn't find it there. 286 func GetCoinPrice(coin string) (float64, error) { 287 // TODO Add UNIV2DAIETH quotation 288 // log.Info("Get price for ", coin) 289 switch coin { 290 case "WETH": 291 coin = "ETH" 292 case "HBTC": 293 coin = "BTC" 294 } 295 296 type Quotation struct { 297 Symbol string `json:"Symbol"` 298 Name string `json:"Name"` 299 Price float64 `json:"Price"` 300 PriceYesterday *float64 `json:"PriceYesterday"` 301 VolumeYesterdayUSD *float64 `json:"VolumeYesterdayUSD"` 302 Source string `json:"Source"` 303 Time time.Time `json:"Time"` 304 ITIN string `json:"ITIN"` 305 } 306 /* 307 type QuotationGecko struct { 308 ID struct { 309 Price string `json:"vs_currencies"` 310 } `json:"ids"` 311 } 312 */ 313 type QuotationCrptcmp struct { 314 Price float64 `json:"USD"` 315 } 316 url := "https://api.diadata.org/v1/quotation/" + coin 317 data, _, err := GetRequest(url) 318 if err == nil { 319 Quot := Quotation{} 320 err = json.Unmarshal(data, &Quot) 321 if err != nil { 322 return 0, err 323 } 324 return Quot.Price, nil 325 } 326 // Try to get price from cryptocompare in case we don't have it in our API yet. 327 data, _, err = GetRequest("https://min-api.cryptocompare.com/data/price?fsym=" + coin + "&tsyms=USD") 328 if err != nil { 329 log.Error("Could not get price") 330 return 0, err 331 } 332 Quot := QuotationCrptcmp{} 333 err = json.Unmarshal(data, &Quot) 334 if err != nil { 335 return 0, err 336 } 337 price := Quot.Price 338 339 // // Retrieval through coingecko. Is down at the moment. 340 // data, err = GetRequest("https://api.coingecko.com/api/v3/simple/price?ids=" + coin + "&vs_currencies=USD") 341 // if err != nil { 342 // return 0, err 343 // } 344 // Quot := QuotationGecko{} 345 // err = json.Unmarshal(data, &Quot) 346 // price, err := strconv.ParseFloat(Quot.ID.Price, 64) 347 // if err != nil { 348 // return 0, err 349 // } 350 return price, nil 351 352 }