diff options
| -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 | 
