diff options
author | terminaldweller <devi@terminaldweller.com> | 2024-02-29 00:34:46 +0000 |
---|---|---|
committer | terminaldweller <devi@terminaldweller.com> | 2024-02-29 00:34:46 +0000 |
commit | 7baae789e2be9bfc3671f66ff0ad6a7da684c993 (patch) | |
tree | c082fb963af6b91f60493bd03e0ba13757e2aeb3 | |
parent | fixes #5 (diff) | |
download | hived-7baae789e2be9bfc3671f66ff0ad6a7da684c993.tar.gz hived-7baae789e2be9bfc3671f66ff0ad6a7da684c993.zip |
added new ticker endpoint that periodically sends crypto prices over telegram
-rw-r--r-- | hived/alertHandlers.go | 188 | ||||
-rw-r--r-- | hived/hived.go | 243 | ||||
-rw-r--r-- | hived/hived_responses.go | 2 | ||||
-rw-r--r-- | hived/hived_test.go | 12 | ||||
-rw-r--r-- | hived/tickerHandlers.go | 171 | ||||
-rwxr-xr-x | test/endpoints.sh | 24 |
6 files changed, 483 insertions, 157 deletions
diff --git a/hived/alertHandlers.go b/hived/alertHandlers.go new file mode 100644 index 0000000..fd49835 --- /dev/null +++ b/hived/alertHandlers.go @@ -0,0 +1,188 @@ +package main + +import ( + "context" + "encoding/json" + "net/http" + "time" + + "github.com/rs/zerolog/log" +) + +func (alertHandler Handler) HandleAlertPost(writer http.ResponseWriter, request *http.Request) { + var bodyJSON addAlertJSONType + + writer.Header().Add("Content-Type", "application/json") + + err := json.NewDecoder(request.Body).Decode(&bodyJSON) + if err != nil { + log.Printf(err.Error()) + + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + "error": "not all parameters are valid.", + }) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + } + + if bodyJSON.Name == "" || bodyJSON.Expr == "" { + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + "error": "not all parameters are valid.", + }) + if err != nil { + log.Error().Err(errFailedUnmarshall) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + + return + } + + ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) + defer cancel() + + key := "alert:" + bodyJSON.Name + alertHandler.rdb.Set(ctx, bodyJSON.Name, bodyJSON.Expr, 0) + alertHandler.rdb.SAdd(ctx, "alertkeys", key) + + err = json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": true, + "error": "", + }) + + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } +} + +func (alertHandler Handler) HandleAlertDelete(writer http.ResponseWriter, request *http.Request) { + var identifier string + + writer.Header().Add("Content-Type", "application/json") + + params := request.URL.Query() + + for key, value := range params { + switch key { + case "key": + identifier = value[0] + default: + log.Error().Err(errUnknownParam) + } + } + + if identifier == "" { + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + "error": "Id parameter is not valid.", + }) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + + return + } + + ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) + defer cancel() + + alertHandler.rdb.Del(ctx, identifier) + setKey := "alert:" + identifier + alertHandler.rdb.SRem(ctx, "alertkeys", setKey) + log.Printf(setKey) + + err := json.NewEncoder(writer).Encode(struct { + IsSuccessful bool `json:"isSuccessful"` + Err string `json:"err"` + }{IsSuccessful: true, Err: ""}) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } +} + +func (alertHandler Handler) HandleAlertGet(writer http.ResponseWriter, request *http.Request) { + var identifier string + + writer.Header().Add("Content-Type", "application/json") + + params := request.URL.Query() + for key, value := range params { + switch key { + case "key": + identifier = value[0] + default: + log.Error().Err(errUnknownParam) + } + } + + if identifier == "" { + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + "error": "Id parameter is not valid.", + }) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + + return + } + + ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) + defer cancel() + + redisResult := alertHandler.rdb.Get(ctx, identifier) + + redisResultString, err := redisResult.Result() + if err != nil { + log.Err(err) + } + + var ErrorString string + if err == nil { + ErrorString = "" + } else { + ErrorString = err.Error() + } + + writer.Header().Add("Content-Type", "application/json") + + err = json.NewEncoder(writer).Encode(struct { + IsSuccessful bool `json:"isSuccessful"` + Error string `json:"error"` + Key string `json:"key"` + Expr string `json:"expr"` + }{IsSuccessful: true, Error: ErrorString, Key: identifier, Expr: redisResultString}) + + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } +} + +func alertHandler(writer http.ResponseWriter, request *http.Request) { + addSecureHeaders(&writer) + + handler := Handler{rdb: rdb} + + switch request.Method { + case http.MethodPost: + handler.HandleAlertPost(writer, request) + case http.MethodPut: + http.Error(writer, "Method is not supported.", http.StatusNotFound) + case http.MethodPatch: + http.Error(writer, "Method is not supported.", http.StatusNotFound) + case http.MethodDelete: + handler.HandleAlertDelete(writer, request) + case http.MethodGet: + handler.HandleAlertGet(writer, request) + default: + http.Error(writer, "Method is not supported.", http.StatusNotFound) + } +} diff --git a/hived/hived.go b/hived/hived.go index 580a1f8..d72d427 100644 --- a/hived/hived.go +++ b/hived/hived.go @@ -37,6 +37,7 @@ const ( redisContextTimeout = 2 pingTimeout = 5 alertCheckIntervalDefault = 600 + tickerCheckIntervalDefault = 600 redisCacheDurationMultiplier = 1_000_000 cacheDurationdefault = 300_000 telegramTimeout = 10 @@ -139,19 +140,24 @@ func getPrice(ctx context.Context, priceChan chan<- priceChanStruct, errChan chan<- errorChanStruct, ) { + fmt.Println("zcheckpoint 1: ", name) val, err := rdb.Get(ctx, name+"_price").Float64() + fmt.Println("zcheckpoint 2") if err != nil { + fmt.Println("zcheckpoint 3: ", name) source := chooseGetPriceSource() if source == CryptoCompareSource { getPriceFromCryptoCompare(ctx, name, unit, waitGroup, priceChan, errChan) } } else { + fmt.Println("zcheckpoint 4: ", name) priceChan <- priceChanStruct{name: name, price: val} errChan <- errorChanStruct{hasError: false, err: nil} waitGroup.Done() } + fmt.Println("zcheckpoint 5: ", name) } func getPriceFromCryptoCompareErrorHandler( @@ -175,12 +181,14 @@ func getPriceFromCryptoCompare( errChan chan<- errorChanStruct, ) { defer wg.Done() + fmt.Println("xcheckpoint 1") params := "fsym=" + url.QueryEscape(name) + "&" + "tsyms=" + url.QueryEscape(unit) path := cryptocomparePriceURL + params client := GetProxiedClient() + fmt.Println("xcheckpoint 2") req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil) if err != nil { @@ -188,6 +196,7 @@ func getPriceFromCryptoCompare( return } + fmt.Println("xcheckpoint 3") resp, err := client.Do(req) if err != nil { @@ -196,6 +205,7 @@ func getPriceFromCryptoCompare( return } defer resp.Body.Close() + fmt.Println("xcheckpoint 4") jsonBody := make(map[string]float64) @@ -204,12 +214,15 @@ func getPriceFromCryptoCompare( getPriceFromCryptoCompareErrorHandler(err, name, priceChan, errChan) } + fmt.Println("xcheckpoint 5") + // add a price cache err = rdb.Set(ctx, name+"_price", jsonBody[unit], time.Duration(*cacheDuration*redisCacheDurationMultiplier)).Err() if err != nil { log.Error().Err(err) } + fmt.Println("xcheckpoint 6") priceChan <- priceChanStruct{name: name, price: jsonBody[unit]} errChan <- errorChanStruct{hasError: false, err: nil} @@ -405,6 +418,14 @@ type alertsType struct { Alerts []alertType `json:"alerts"` } +type tickerType struct { + Name string `json:"name"` +} + +type tickersType struct { + Tickers []tickerType `json:"tickers"` +} + func getAlerts() alertsType { var alerts alertsType @@ -426,6 +447,24 @@ func getAlerts() alertsType { return alerts } +func getTickers() tickersType { + var tickers tickersType + + ctx := context.Background() + keys := rdb.SMembersMap(ctx, "tickerkeys") + tickers.Tickers = make([]tickerType, len(keys.Val())) + vals := keys.Val() + + tickerIndex := 0 + + for key := range vals { + tickers.Tickers[tickerIndex].Name = key[7:] + tickerIndex++ + } + + return tickers +} + // FIXME- there is a crash here func alertManagerWorker(alert alertType) { expression, err := govaluate.NewEvaluableExpression(alert.Expr) @@ -505,7 +544,6 @@ func alertManagerWorker(alert alertType) { if err == nil { log.Error().Err(err) } - sendToTg("telebot:8000", msgText, tokenInt) } @@ -523,184 +561,96 @@ func alertManager(alertsCheckInterval int64) { } } -type addAlertJSONType struct { - Name string `json:"name"` - Expr string `json:"expr"` -} - -func (alertHandler AlertHandler) HandleAlertPost(writer http.ResponseWriter, request *http.Request) { - var bodyJSON addAlertJSONType - - writer.Header().Add("Content-Type", "application/json") - - err := json.NewDecoder(request.Body).Decode(&bodyJSON) - if err != nil { - log.Printf(err.Error()) +func tickerManager(tickerCheckInterval int64) { + for { + tickers := getTickers() - err := json.NewEncoder(writer).Encode(map[string]interface{}{ - "isSuccessful": false, - "error": "not all parameters are valid.", - }) - if err != nil { - log.Error().Err(err) - http.Error(writer, "internal server error", http.StatusInternalServerError) - } - } + log.Info().Msg(fmt.Sprintf("%v", tickers)) - if bodyJSON.Name == "" || bodyJSON.Expr == "" { - err := json.NewEncoder(writer).Encode(map[string]interface{}{ - "isSuccessful": false, - "error": "not all parameters are valid.", - }) - if err != nil { - log.Error().Err(errFailedUnmarshall) - http.Error(writer, "internal server error", http.StatusInternalServerError) + for tickerIndex := range tickers.Tickers { + go tickerManagerWorker(tickers.Tickers[tickerIndex]) } - return - } - - ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) - defer cancel() - - key := "alert:" + bodyJSON.Name - alertHandler.rdb.Set(ctx, bodyJSON.Name, bodyJSON.Expr, 0) - alertHandler.rdb.SAdd(ctx, "alertkeys", key) - - err = json.NewEncoder(writer).Encode(map[string]interface{}{ - "isSuccessful": true, - "error": "", - }) - - if err != nil { - log.Error().Err(err) - http.Error(writer, "internal server error", http.StatusInternalServerError) + time.Sleep(time.Second * time.Duration(tickerCheckInterval)) } } -func (alertHandler AlertHandler) HandleAlertDelete(writer http.ResponseWriter, request *http.Request) { - var identifier string - - writer.Header().Add("Content-Type", "application/json") - - params := request.URL.Query() - - for key, value := range params { - switch key { - case "key": - identifier = value[0] - default: - log.Error().Err(errUnknownParam) - } - } +func tickerManagerWorker(ticker tickerType) { + var waitGroup sync.WaitGroup - if identifier == "" { - err := json.NewEncoder(writer).Encode(map[string]interface{}{ - "isSuccessful": false, - "error": "Id parameter is not valid.", - }) - if err != nil { - log.Error().Err(err) - http.Error(writer, "internal server error", http.StatusInternalServerError) - } + priceChan := make(chan priceChanStruct, 1) + errChan := make(chan errorChanStruct, 1) - return - } + defer close(errChan) + defer close(priceChan) + waitGroup.Add(1) - ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), getTimeout*time.Second) defer cancel() - alertHandler.rdb.Del(ctx, identifier) - setKey := "alert:" + identifier - alertHandler.rdb.SRem(ctx, "alertkeys", setKey) - log.Printf(setKey) - - err := json.NewEncoder(writer).Encode(struct { - IsSuccessful bool `json:"isSuccessful"` - Err string `json:"err"` - }{IsSuccessful: true, Err: ""}) - if err != nil { - log.Error().Err(err) - http.Error(writer, "internal server error", http.StatusInternalServerError) - } -} - -func (alertHandler AlertHandler) HandleAlertGet(writer http.ResponseWriter, request *http.Request) { - var identifier string + fmt.Println("checkpoint 1: ", ticker.Name) + go getPrice(ctx, ticker.Name, "USD", &waitGroup, priceChan, errChan) + fmt.Println("checkpoint 2") - writer.Header().Add("Content-Type", "application/json") + waitGroup.Wait() + fmt.Println("checkpoint 3") - params := request.URL.Query() - for key, value := range params { - switch key { - case "key": - identifier = value[0] - default: - log.Error().Err(errUnknownParam) + select { + case err := <-errChan: + if err.hasError { + log.Error().Err(err.err) } + default: + log.Error().Err(errBadLogic) } + fmt.Println("checkpoint 4") - if identifier == "" { - err := json.NewEncoder(writer).Encode(map[string]interface{}{ - "isSuccessful": false, - "error": "Id parameter is not valid.", - }) - if err != nil { - log.Error().Err(err) - http.Error(writer, "internal server error", http.StatusInternalServerError) - } - - return + var price priceChanStruct + select { + case priceCh := <-priceChan: + price = priceCh + default: + log.Error().Err(errBadLogic) } + fmt.Println("checkpoint 5") - ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) - defer cancel() - - redisResult := alertHandler.rdb.Get(ctx, identifier) + token := os.Getenv(telegramBotTokenEnvVar) + msgText := "ticker: " + ticker.Name + ":" + strconv.FormatFloat(price.price, 'f', -1, 64) + tokenInt, err := strconv.ParseInt(token[1:len(token)-1], 10, 64) - redisResultString, err := redisResult.Result() - if err != nil { - log.Err(err) - } + fmt.Println(msgText) - var ErrorString string if err == nil { - ErrorString = "" - } else { - ErrorString = err.Error() + log.Error().Err(err) } + sendToTg("telebot:8000", msgText, tokenInt) +} - writer.Header().Add("Content-Type", "application/json") - - err = json.NewEncoder(writer).Encode(struct { - IsSuccessful bool `json:"isSuccessful"` - Error string `json:"error"` - Key string `json:"key"` - Expr string `json:"expr"` - }{IsSuccessful: true, Error: ErrorString, Key: identifier, Expr: redisResultString}) +type addAlertJSONType struct { + Name string `json:"name"` + Expr string `json:"expr"` +} - if err != nil { - log.Error().Err(err) - http.Error(writer, "internal server error", http.StatusInternalServerError) - } +type tickerJSONType struct { + Name string `json:"name"` } -func alertHandler(writer http.ResponseWriter, request *http.Request) { +func tickerHandler(writer http.ResponseWriter, request *http.Request) { addSecureHeaders(&writer) - alertHandler := AlertHandler{rdb: rdb} + handler := Handler{rdb: rdb} switch request.Method { case http.MethodPost: - alertHandler.HandleAlertPost(writer, request) + handler.HandleTickerPost(writer, request) case http.MethodPut: - alertHandler.HandleAlertPost(writer, request) + handler.HandleTickerPost(writer, request) case http.MethodPatch: - alertHandler.HandleAlertPost(writer, request) + handler.HandleTickerPost(writer, request) case http.MethodDelete: - alertHandler.HandleAlertDelete(writer, request) + handler.HandleTickerDelete(writer, request) case http.MethodGet: - alertHandler.HandleAlertGet(writer, request) + handler.HandleTickerGet(writer, request) default: http.Error(writer, "Method is not supported.", http.StatusNotFound) } @@ -790,6 +740,7 @@ func startServer(gracefulWait time.Duration, flagPort string) { router.HandleFunc("/crypto/v1/price", PriceHandler) router.HandleFunc("/crypto/v1/pair", PairHandler) router.HandleFunc("/crypto/v1/alert", alertHandler) + router.HandleFunc("/crypto/v1/ticker", tickerHandler) router.HandleFunc("/crypto/v1/robots.txt", robotsHandler) go func() { @@ -841,6 +792,10 @@ func main() { "alertinterval", alertCheckIntervalDefault, "in seconds, the amount of time between alert checks") + tickerCheckInterval := flag.Int64( + "interval", + tickerCheckIntervalDefault, + "in seconds, the amount of time between alert checks") flag.DurationVar( &gracefulWait, "gracefulwait", @@ -860,5 +815,7 @@ func main() { go alertManager(*alertsCheckInterval) + go tickerManager(*tickerCheckInterval) + startServer(gracefulWait, *flagPort) } diff --git a/hived/hived_responses.go b/hived/hived_responses.go index 72a340c..1065340 100644 --- a/hived/hived_responses.go +++ b/hived/hived_responses.go @@ -2,7 +2,7 @@ package main import "github.com/go-redis/redis/v8" -type AlertHandler struct { +type Handler struct { rdb *redis.Client } diff --git a/hived/hived_test.go b/hived/hived_test.go index e9c45e4..22cd8dc 100644 --- a/hived/hived_test.go +++ b/hived/hived_test.go @@ -96,7 +96,7 @@ func TestAlertHandlerPhase1(t *testing.T) { req.Header.Set("Content-Type", "application/json") recorder := httptest.NewRecorder() - alertHandler := AlertHandler{rdb: rdb} + alertHandler := Handler{rdb: rdb} alertHandler.HandleAlertPost(recorder, req) errorHandler(recorder, t, err) @@ -128,7 +128,7 @@ func TestAlertHandlerPhase2(t *testing.T) { req, err := http.NewRequest(http.MethodGet, endpoint+"/alert?key=alertTest", nil) recorder := httptest.NewRecorder() - alertHandler := AlertHandler{rdb: rdb} + alertHandler := Handler{rdb: rdb} alertHandler.HandleAlertGet(recorder, req) errorHandler(recorder, t, err) @@ -170,7 +170,7 @@ func TestAlertHandlerPhase3(t *testing.T) { req.Header.Set("Content-Type", "application/json") recorder := httptest.NewRecorder() - alertHandler := AlertHandler{rdb: rdb} + alertHandler := Handler{rdb: rdb} alertHandler.HandleAlertGet(recorder, req) errorHandler(recorder, t, err) } @@ -185,7 +185,7 @@ func TestAlertHandlerPhase4(t *testing.T) { req, err := http.NewRequest(http.MethodGet, endpoint+"/alert?key=alertTest", nil) recorder := httptest.NewRecorder() - alertHandler := AlertHandler{rdb: rdb} + alertHandler := Handler{rdb: rdb} alertHandler.HandleAlertGet(recorder, req) errorHandler(recorder, t, err) @@ -217,7 +217,7 @@ func TestAlertHandlerPhase5(t *testing.T) { req, err := http.NewRequest(http.MethodDelete, endpoint+"/alert?key=alertTest", nil) recorder := httptest.NewRecorder() - alertHandler := AlertHandler{rdb: rdb} + alertHandler := Handler{rdb: rdb} alertHandler.HandleAlertGet(recorder, req) errorHandler(recorder, t, err) @@ -250,7 +250,7 @@ func TestAlertHandlerPhase6(t *testing.T) { req, err := http.NewRequest(http.MethodGet, endpoint+"/alert?key=alertTest", nil) recorder := httptest.NewRecorder() - alertHandler := AlertHandler{rdb: rdb} + alertHandler := Handler{rdb: rdb} alertHandler.HandleAlertGet(recorder, req) errorHandler(recorder, t, err) diff --git a/hived/tickerHandlers.go b/hived/tickerHandlers.go new file mode 100644 index 0000000..d857eaf --- /dev/null +++ b/hived/tickerHandlers.go @@ -0,0 +1,171 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/rs/zerolog/log" +) + +func (tickerHandler Handler) HandleTickerGet(writer http.ResponseWriter, request *http.Request) { + var identifier string + + writer.Header().Add("Content-Type", "application/json") + + params := request.URL.Query() + for key, value := range params { + switch key { + case "key": + identifier = value[0] + default: + log.Error().Err(errUnknownParam) + } + } + + if identifier == "" { + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + "error": "Id parameter is not valid.", + }) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + + return + } + + ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) + defer cancel() + + redisResult := tickerHandler.rdb.Get(ctx, identifier) + + redisResultString, err := redisResult.Result() + if err != nil { + log.Err(err) + } + + var ErrorString string + if err == nil { + ErrorString = "" + } else { + ErrorString = err.Error() + } + + writer.Header().Add("Content-Type", "application/json") + + err = json.NewEncoder(writer).Encode(struct { + IsSuccessful bool `json:"isSuccessful"` + Error string `json:"error"` + Key string `json:"key"` + Expr string `json:"expr"` + }{IsSuccessful: true, Error: ErrorString, Key: identifier, Expr: redisResultString}) + + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } +} + +func (tickerHandler Handler) HandleTickerDelete(writer http.ResponseWriter, request *http.Request) { + var identifier string + + writer.Header().Add("Content-Type", "application/json") + + params := request.URL.Query() + + for key, value := range params { + switch key { + case "key": + identifier = value[0] + default: + log.Error().Err(errUnknownParam) + } + } + + if identifier == "" { + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + "error": "Id parameter is not valid.", + }) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + + return + } + + ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) + defer cancel() + + tickerHandler.rdb.Del(ctx, identifier) + setKey := "alert:" + identifier + tickerHandler.rdb.SRem(ctx, "tickerkeys", setKey) + log.Printf(setKey) + + err := json.NewEncoder(writer).Encode(struct { + IsSuccessful bool `json:"isSuccessful"` + Err string `json:"err"` + }{IsSuccessful: true, Err: ""}) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } +} + +func (tickerHandler Handler) HandleTickerPost(writer http.ResponseWriter, request *http.Request) { + var bodyJSON tickerJSONType + + writer.Header().Add("Content-Type", "application/json") + + err := json.NewDecoder(request.Body).Decode(&bodyJSON) + if err != nil { + fmt.Println(err.Error()) + log.Printf(err.Error()) + + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + // "error": "not all parameters are valid.", + "error": "XXX", + }) + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + } + + fmt.Println(bodyJSON.Name) + if bodyJSON.Name == "" { + err := json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": false, + "error": "name is empty.", + }) + if err != nil { + log.Error().Err(errFailedUnmarshall) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } + + return + } + + ctx, cancel := context.WithTimeout(request.Context(), redisContextTimeout*time.Second) + defer cancel() + + key := "ticker:" + bodyJSON.Name + tickerHandler.rdb.Set(ctx, bodyJSON.Name, true, 0) + tickerHandler.rdb.SAdd(ctx, "tickerkeys", key) + + err = json.NewEncoder(writer).Encode(map[string]interface{}{ + "isSuccessful": true, + "error": "", + }) + + if err != nil { + log.Error().Err(err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + } +} diff --git a/test/endpoints.sh b/test/endpoints.sh index 7f9533b..2b73614 100755 --- a/test/endpoints.sh +++ b/test/endpoints.sh @@ -2,11 +2,21 @@ set -e set -x -# sleep 5 -curl -k -X GET "https://localhost:8008/crypto/v1/price?name=CAKE&unit=USD" -curl -k -X GET "https://localhost:8008/crypto/v1/pair?one=ETH&two=CAKE&multiplier=4.0" -curl -k -X POST -H "Content-Type: application/json" -d '{"name":"alert1", "expr":"ETH>CAKE"}' https://localhost:8008/crypto/v1/alert +curl -k -X GET "https://localhost:10008/crypto/v1/price?name=PEPE&unit=USD" +curl -k -X GET "https://localhost:10008/crypto/v1/pair?one=ETH&two=CAKE&multiplier=4.0" +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"alert1", "expr":"ETH>CAKE"}' https://localhost:10008/crypto/v1/alert -curl -k -X GET -H "Content-Type: application/json" "https://localhost:8008/crypto/v1/alert?key=alert1" -curl -k -X DELETE -H "Content-Type: application/json" "https://localhost:8008/crypto/v1/alert?key=alert1" -curl -k -X POST -H "Content-Type: application/json" -d '{"name":"alert1", "expr":"ETH>CAKE"}' https://localhost:8008/crypto/v1/alert +# alert +curl -k -X GET -H "Content-Type: application/json" "https://localhost:10008/crypto/v1/alert?key=alert1" +curl -k -X DELETE -H "Content-Type: application/json" "https://localhost:10008/crypto/v1/alert?key=alert1" +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"alert1", "expr":"ETH>CAKE"}' https://localhost:10008/crypto/v1/alert + +# ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"ETH"}' https://localhost:10008/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"BTC"}' https://localhost:10008/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"XMR"}' https://localhost:10008/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"STX"}' https://localhost:10008/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"LINK"}' https://localhost:10008/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"PEPE"}' https://localhost:10008/crypto/v1/ticker +curl -k -X GET -H "Content-Type: application/json" https://localhost:10008/crypto/v1/ticker?key=ETH +curl -k -X DELETE -H "Content-Type: application/json" https://localhost:10008/crypto/v1/ticker?key=ETH |