Skip to content

Commit 38c2c5b

Browse files
authored
Brought Post Request and API key from .env changes back (#1097)
* Brought Post Request and API key from .env changes back * Fixed createJob ReadMe * Implemented new ReplaceValueWithDataFromENVFile() to get data from env file * Removed unused function to get env file path * Requested changes * Replaced gemini job with kraken job
1 parent 2a3009d commit 38c2c5b

File tree

13 files changed

+384
-256
lines changed

13 files changed

+384
-256
lines changed

README.md

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ $ ./razor createJob --url https://www.alphavantage.co/query\?function\=GLOBAL_QU
559559
OR
560560

561561
```
562-
$ ./razor createJob --address 0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c -n btc_gecko --power 2 -s 'table tbody tr td span[data-coin-id="1"][data-target="price.price"] span' -u https://www.coingecko.com/en --selectorType 0 --weight 100
562+
$ ./razor createJob --address 0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c -n btc_gecko --power 2 -s 'table tbody tr td span[data-coin-id="1"][data-target="price.price"] span' -u https://www.coingecko.com/en --selectorType 0 --weight 100
563563
```
564564

565565
### Create Collection
@@ -842,30 +842,39 @@ Shown below is an example of how your `assets.json` file should be -
842842
843843
``` json
844844
{
845-
"assets": {
846-
"collection": {
847-
"ethCollectionMean": {
848-
"power": 2,
849-
"official jobs": {
850-
"1": {
851-
"URL": "https://data.messari.io/api/v1/assets/eth/metrics",
852-
"selector": "[`data`][`market_data`][`price_usd`]",
853-
"power": 2,
854-
"weight": 2
855-
},
856-
},
857-
"custom jobs": [
858-
{
859-
"URL": "https://api.lunarcrush.com/v2?data=assets&symbol=ETH",
860-
"selector": "[`data`][`0`][`price`]",
861-
"power": 3,
862-
"weight": 2
863-
},
864-
]
865-
}
866-
}
867-
}
868-
}
845+
"assets": {
846+
"collection": {
847+
"ethCollectionMedian": {
848+
"power": 2,
849+
"official jobs": {
850+
"1": {
851+
"URL": {
852+
"type": "GET",
853+
"url": "https://data.messari.io/api/v1/assets/eth/metrics",
854+
"body": {},
855+
"content-type": ""
856+
},
857+
"selector": "[`data`][`market_data`][`price_usd`]",
858+
"power": 2,
859+
"weight": 2
860+
},
861+
},
862+
"custom jobs": [{
863+
"URL": {
864+
"type": "GET",
865+
"url": "https: //api.lunarcrush.com/v2?data=assets&symbol=ETH",
866+
"body": {},
867+
"content-type": ""
868+
},
869+
"name:" "eth_lunarCrush",
870+
"selector": "[`data`][`0`][`price`]",
871+
"power": 3,
872+
"weight": 2
873+
]
874+
}
875+
}
876+
}
877+
}
869878
```
870879

871880
Breaking down into components

core/constants.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,16 @@ var DefaultPathName = ".razor"
5151
//BlockNumberInterval is the interval in seconds after which blockNumber needs to be calculated again
5252
var BlockNumberInterval = 5
5353

54+
//APIKeyRegex will be used as a regular expression to be matched in job Urls
55+
var APIKeyRegex = `\$\{(.+?)\}`
56+
57+
// Following are the constants which defines retry attempts and retry delay if there is an error in processing request
58+
59+
var ProcessRequestRetryAttempts uint = 2
60+
var ProcessRequestRetryDelay = 2
61+
5462
//SwitchClientDuration is the time after which alternate client from secondary RPC will be switched back to client from primary RPC
5563
var SwitchClientDuration = 5 * EpochLength
64+
65+
// HexReturnType is the ReturnType for a job if that job returns a hex value
66+
var HexReturnType = "hex"

core/types/assets.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,16 @@ type AssignedAsset struct {
5151

5252
type CustomJob struct {
5353
URL string `json:"URL"`
54+
Name string `json:"name"`
5455
Selector string `json:"selector"`
5556
Power int8 `json:"power"`
5657
Weight uint8 `json:"weight"`
5758
}
59+
60+
type DataSourceURL struct {
61+
Type string `json:"type"`
62+
URL string `json:"url"`
63+
Body map[string]interface{} `json:"body"`
64+
Header map[string]string `json:"header"`
65+
ReturnType string `json:"returnType"`
66+
}

logger/logger.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ func InitializeLogger(fileName string, config types.Configurations) {
6060
MaxBackups: config.LogFileMaxBackups,
6161
MaxAge: config.LogFileMaxAge,
6262
}
63-
fmt.Println(config.LogFileMaxSize)
64-
fmt.Println(config.LogFileMaxBackups)
65-
fmt.Println(config.LogFileMaxAge)
6663

6764
out := os.Stderr
6865
mw := io.MultiWriter(out, lumberJackLogger)

path/mocks/path_interface.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

utils/api.go

Lines changed: 93 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,77 @@
11
package utils
22

33
import (
4+
"bytes"
5+
"encoding/json"
46
"errors"
7+
"io"
58
"net/http"
69
"razor/cache"
710
"razor/core"
11+
"regexp"
812
"time"
913

14+
"razor/core/types"
15+
1016
"github.com/PaesslerAG/jsonpath"
1117
"github.com/avast/retry-go"
1218
"github.com/gocolly/colly"
1319
)
1420

15-
func (*UtilsStruct) GetDataFromAPI(url string, localCache *cache.LocalCache) ([]byte, error) {
21+
func GetDataFromAPI(dataSourceURLStruct types.DataSourceURL, localCache *cache.LocalCache) ([]byte, error) {
1622
client := http.Client{
1723
Timeout: time.Duration(HTTPTimeout) * time.Second,
1824
}
19-
cachedData, err := localCache.Read(url)
20-
if err != nil {
21-
var body []byte
22-
err := retry.Do(
23-
func() error {
24-
response, err := client.Get(url)
25-
if err != nil {
26-
return err
27-
}
28-
defer response.Body.Close()
29-
if response.StatusCode != 200 {
30-
log.Errorf("API: %s responded with status code %d", url, response.StatusCode)
31-
return errors.New("unable to reach API")
32-
}
33-
body, err = IOInterface.ReadAll(response.Body)
34-
if err != nil {
35-
return err
36-
}
37-
return nil
38-
}, retry.Attempts(2), retry.Delay(time.Second*2))
39-
if err != nil {
40-
return nil, err
25+
cachedData, cachedErr := localCache.Read(dataSourceURLStruct.URL)
26+
if cachedErr != nil {
27+
var response []byte
28+
switch dataSourceURLStruct.Type {
29+
case "GET":
30+
err := retry.Do(
31+
func() error {
32+
responseBody, err := ProcessRequest(client, dataSourceURLStruct, nil)
33+
if err != nil {
34+
log.Error("Error in processing GET request: ", err)
35+
return err
36+
}
37+
response = responseBody
38+
return nil
39+
}, retry.Attempts(core.ProcessRequestRetryAttempts), retry.Delay(time.Second*time.Duration(core.ProcessRequestRetryDelay)))
40+
if err != nil {
41+
return nil, err
42+
}
43+
case "POST":
44+
postBody, err := json.Marshal(dataSourceURLStruct.Body)
45+
if err != nil {
46+
log.Errorf("Error in marshalling body of a POST request URL %s: %v", dataSourceURLStruct.URL, err)
47+
return nil, err
48+
}
49+
requestBody := bytes.NewBuffer(postBody)
50+
err = retry.Do(
51+
func() error {
52+
responseBody, err := ProcessRequest(client, dataSourceURLStruct, requestBody)
53+
if err != nil {
54+
log.Error("Error in processing POST request: ", err)
55+
return err
56+
}
57+
response = responseBody
58+
return nil
59+
}, retry.Attempts(core.ProcessRequestRetryAttempts), retry.Delay(time.Second*time.Duration(core.ProcessRequestRetryDelay)))
60+
if err != nil {
61+
return nil, err
62+
}
63+
default:
64+
return nil, errors.New("invalid request type")
4165
}
4266
//Storing the data into cache
43-
localCache.Update(body, url, time.Now().Add(time.Second*time.Duration(core.StateLength)).Unix())
44-
return body, nil
67+
localCache.Update(response, dataSourceURLStruct.URL, time.Now().Add(time.Second*time.Duration(core.StateLength)).Unix())
68+
return response, nil
4569
}
46-
log.Debugf("Getting Data for URL %s from local cache...", url)
70+
log.Debugf("Getting Data for URL %s from local cache...", dataSourceURLStruct.URL)
4771
return cachedData, nil
4872
}
4973

50-
func (*UtilsStruct) GetDataFromJSON(jsonObject map[string]interface{}, selector string) (interface{}, error) {
74+
func GetDataFromJSON(jsonObject map[string]interface{}, selector string) (interface{}, error) {
5175
if selector[0] == '[' {
5276
selector = "$" + selector
5377
} else {
@@ -56,15 +80,55 @@ func (*UtilsStruct) GetDataFromJSON(jsonObject map[string]interface{}, selector
5680
return jsonpath.Get(selector, jsonObject)
5781
}
5882

59-
func (*UtilsStruct) GetDataFromXHTML(url string, selector string) (string, error) {
83+
func GetDataFromXHTML(dataSourceURLStruct types.DataSourceURL, selector string) (string, error) {
6084
c := colly.NewCollector()
6185
var priceData string
6286
c.OnXML(selector, func(e *colly.XMLElement) {
6387
priceData = e.Text
6488
})
65-
err := c.Visit(url)
89+
err := c.Visit(dataSourceURLStruct.URL)
6690
if err != nil {
6791
return "", err
6892
}
6993
return priceData, nil
7094
}
95+
96+
func AddHeaderToRequest(request *http.Request, headerMap map[string]string) (*http.Request, error) {
97+
for key, value := range headerMap {
98+
re := regexp.MustCompile(core.APIKeyRegex)
99+
isAPIKeyRequired := re.MatchString(value)
100+
if isAPIKeyRequired {
101+
value = ReplaceValueWithDataFromENVFile(re, value)
102+
}
103+
log.Debugf("Adding key: %s, value: %s pair to header", key, value)
104+
request.Header.Add(key, value)
105+
}
106+
return request, nil
107+
}
108+
109+
func ProcessRequest(client http.Client, dataSourceURLStruct types.DataSourceURL, requestBody io.Reader) ([]byte, error) {
110+
request, err := http.NewRequest(dataSourceURLStruct.Type, dataSourceURLStruct.URL, requestBody)
111+
if err != nil {
112+
return nil, err
113+
}
114+
requestWithHeader, err := AddHeaderToRequest(request, dataSourceURLStruct.Header)
115+
if err != nil {
116+
log.Errorf("Error in adding header to %s request: %v", dataSourceURLStruct.Type, err)
117+
return nil, err
118+
}
119+
response, err := client.Do(requestWithHeader)
120+
if err != nil {
121+
log.Errorf("Error sending %s request URL %s: %v", dataSourceURLStruct.Type, dataSourceURLStruct.URL, err)
122+
return nil, err
123+
}
124+
defer response.Body.Close()
125+
if response.StatusCode != 200 {
126+
log.Errorf("API: %s responded with status code %d", dataSourceURLStruct.URL, response.StatusCode)
127+
return nil, errors.New("unable to reach API")
128+
}
129+
responseBody, err := io.ReadAll(response.Body)
130+
if err != nil {
131+
return nil, err
132+
}
133+
return responseBody, nil
134+
}

0 commit comments

Comments
 (0)