213 lines
5.5 KiB
Go
213 lines
5.5 KiB
Go
package ccxt
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
func (this *Exchange) Fetch(url interface{}, method interface{}, headers interface{}, body interface{}) chan interface{} {
|
|
ch := make(chan interface{})
|
|
go func() {
|
|
defer close(ch)
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
ch <- "panic:" + ToString(r)
|
|
}
|
|
}()
|
|
|
|
if this.FetchResponse != nil {
|
|
ch <- this.FetchResponse
|
|
return
|
|
}
|
|
this.UpdateProxySettings() // for now this needs to be here
|
|
|
|
// Convert url to string
|
|
urlStr, ok := url.(string)
|
|
if !ok {
|
|
panic("url must be a string")
|
|
}
|
|
|
|
// Convert method to string
|
|
methodStr, ok := method.(string)
|
|
if !ok {
|
|
panic("method must be a string")
|
|
}
|
|
|
|
// Convert headers to map[string]string
|
|
headersMap, ok := headers.(map[string]interface{})
|
|
if !ok {
|
|
panic("headers must be a map[string]interface{}")
|
|
}
|
|
|
|
if this.Verbose {
|
|
fmt.Println("Headers:", headersMap)
|
|
fmt.Println("\n\n")
|
|
fmt.Printf("Request: %s %s\n", methodStr, urlStr)
|
|
fmt.Println("\n\n")
|
|
fmt.Printf("Body: %v\n", body)
|
|
fmt.Println("\n\n")
|
|
}
|
|
|
|
headersStrMap := make(map[string]string)
|
|
for k, v := range headersMap {
|
|
headersStrMap[k] = fmt.Sprintf("%v", v)
|
|
}
|
|
|
|
|
|
// Marshal the body to JSON if not nil
|
|
// var requestBody []byte
|
|
// var err error
|
|
// if body != nil {
|
|
// requestBody, err = json.Marshal(body)
|
|
// if err != nil {
|
|
// panic(fmt.Sprintf("failed to marshal body: %v", err))
|
|
// }
|
|
// }
|
|
|
|
var req *http.Request
|
|
var err error
|
|
|
|
if body != nil {
|
|
switch v := body.(type) {
|
|
case string:
|
|
// If the body is a string, use URL encoding
|
|
// data := urlLib.Values{}
|
|
// parsedData, err := urlLib.ParseQuery(v)
|
|
// if err != nil {
|
|
// panic(fmt.Sprintf("error parsing query string: %w", v))
|
|
// }
|
|
// for key, values := range parsedData {
|
|
// for _, value := range values {
|
|
// data.Set(key, value)
|
|
// }
|
|
// }
|
|
req, err = http.NewRequest(methodStr, urlStr, strings.NewReader(v))
|
|
if err != nil {
|
|
panic(fmt.Sprintf("error creating request"))
|
|
}
|
|
default:
|
|
requestBody, err := json.Marshal(body)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("error marshalling JSON"))
|
|
}
|
|
req, err = http.NewRequest(methodStr, urlStr, bytes.NewBuffer(requestBody))
|
|
if err != nil {
|
|
panic(fmt.Sprintf("error creating request"))
|
|
}
|
|
}
|
|
} else {
|
|
req, err = http.NewRequest(methodStr, urlStr, nil)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("error creating request"))
|
|
}
|
|
}
|
|
// Create the HTTP request
|
|
// req, err := http.NewRequest(methodStr, urlStr, bytes.NewBuffer(requestBody))
|
|
// if err != nil {
|
|
// panic(fmt.Sprintf("failed to create request: %v", err))
|
|
// }
|
|
|
|
//set default headers
|
|
defaultHeaders := this.Headers.(map[string]interface{})
|
|
for key, value := range defaultHeaders {
|
|
req.Header.Set(key, value.(string))
|
|
}
|
|
|
|
// Set headers
|
|
for key, value := range headersStrMap {
|
|
req.Header.Set(key, value)
|
|
}
|
|
|
|
// strings.NewReader()
|
|
// Send the request
|
|
resp, err := this.httpClient.Do(req)
|
|
|
|
// Read the response body
|
|
// respBody, err := ioutil.ReadAll(resp.Body)
|
|
var respBody []byte
|
|
|
|
if resp == nil {
|
|
// when resp is nil: The request failed at the transport level (e.g., network issue, DNS lookup failure).
|
|
networkError := NetworkError(fmt.Sprintf("Network error: %v", err))
|
|
panic(networkError)
|
|
}
|
|
|
|
if err == nil {
|
|
defer resp.Body.Close()
|
|
if resp.Header.Get("Content-Encoding") == "gzip" {
|
|
gzipReader, err := gzip.NewReader(resp.Body)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Error creating gzip reader: %s", err))
|
|
}
|
|
defer gzipReader.Close()
|
|
|
|
decompressedData, err := io.ReadAll(gzipReader)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Error reading decompressed data: %s", err))
|
|
}
|
|
respBody = decompressedData
|
|
} else {
|
|
respBodyAux, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("failed to read response body: %v", err))
|
|
}
|
|
respBody = respBodyAux
|
|
}
|
|
}
|
|
|
|
// Unmarshal the response body
|
|
var result interface{}
|
|
err = json.Unmarshal(respBody, &result)
|
|
if err != nil {
|
|
// panic(fmt.Sprintf("failed to unmarshal response body: %v", err))
|
|
result = string(respBody)
|
|
}
|
|
|
|
// Log the response (for debugging purposes)
|
|
if this.Verbose {
|
|
fmt.Printf("Response: %s\n", respBody)
|
|
}
|
|
|
|
statusText := http.StatusText(resp.StatusCode)
|
|
handleErrorResult := <-this.callInternal("handleErrors", resp.StatusCode, statusText, urlStr, methodStr, headers, string(respBody), result, headersStrMap, body)
|
|
PanicOnError(handleErrorResult)
|
|
|
|
if handleErrorResult == nil {
|
|
this.HandleHttpStatusCode(resp.StatusCode, statusText, urlStr, methodStr, result)
|
|
}
|
|
|
|
// Check for HTTP errors
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
// add handle http status()
|
|
panic(fmt.Sprintf("HTTP request failed with status code %d: %s", resp.StatusCode, string(respBody)))
|
|
}
|
|
|
|
// only handling failure here
|
|
if err != nil {
|
|
panic(fmt.Sprintf("request failed: %v", err))
|
|
}
|
|
|
|
ch <- result
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func (this *Exchange) HandleHttpStatusCode(code interface{}, reason interface{}, url interface{}, method interface{}, body interface{}) {
|
|
|
|
codeString := ToString(code)
|
|
codeinHttpExceptions := SafeValue(this.HttpExceptions, codeString, nil)
|
|
|
|
if codeinHttpExceptions != nil {
|
|
errorMessage := this.Id + " " + ToString(method) + " " + ToString(url) + " " + ToString(code) + " " + ToString(reason) + " " + ToString(body)
|
|
functionError := codeinHttpExceptions.(func(...interface{}) error)
|
|
panic(functionError(errorMessage))
|
|
}
|
|
|
|
}
|