diff options
Diffstat (limited to '')
| -rw-r--r-- | .gitpod.Dockerfile | 10 | ||||
| -rw-r--r-- | README.md | 60 | ||||
| -rw-r--r-- | arbiter/.golangci.yml | 18 | ||||
| -rw-r--r-- | arbiter/Dockerfile | 18 | ||||
| -rw-r--r-- | arbiter/arbiter.go | 505 | ||||
| -rw-r--r-- | arbiter/go.mod | 17 | ||||
| -rw-r--r-- | arbiter/go.sum | 41 | ||||
| -rwxr-xr-x | arbiter/tests.sh | 4 | ||||
| -rw-r--r-- | docker-compose-test.yaml | 100 | ||||
| -rw-r--r-- | docker-compose.yaml | 119 | ||||
| -rw-r--r-- | hived/Dockerfile | 14 | ||||
| -rw-r--r-- | hived/alertHandlers.go | 8 | ||||
| -rwxr-xr-x | hived/docker-entrypoint.sh | 6 | ||||
| -rw-r--r-- | hived/go.mod | 100 | ||||
| -rw-r--r-- | hived/go.sum | 346 | ||||
| -rw-r--r-- | hived/hived.go | 591 | ||||
| -rw-r--r-- | hived/hived.toml | 7 | ||||
| -rw-r--r-- | nginx.conf | 35 | ||||
| -rw-r--r-- | telebot/.golangci.yml | 19 | ||||
| -rw-r--r-- | telebot/Dockerfile | 21 | ||||
| -rwxr-xr-x | telebot/docker-entrypoint.sh | 6 | ||||
| -rw-r--r-- | telebot/go.mod | 22 | ||||
| -rw-r--r-- | telebot/go.sum | 149 | ||||
| -rw-r--r-- | telebot/telebot.go | 167 | ||||
| -rwxr-xr-x | test/endpoints.sh | 35 | 
25 files changed, 973 insertions, 1445 deletions
diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile deleted file mode 100644 index 1810344..0000000 --- a/.gitpod.Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM alpine:3.13 as builder - -RUN apk update && apk upgrade -RUN apk add go git -COPY go.* /hived/ -RUN cd /hived && go mod download -COPY *.go /hived/ -RUN cd /hived && go build -COPY ./docker-entrypoint.sh /hived/ -# ENTRYPOINT ["/hived/docker-entrypoint.sh"] @@ -3,62 +3,4 @@  # hived -`hived` is small personal cryptocurrency server:<br/> - -- It sends notifications through telegram.<br/> - -Currently it has 5 endpoint:<br/> - -### /price - -Lets you ask for the price of the currency. You can determine the currency the value is returned in.<br/> - -### /pair - -Takes in a pair of currencies and a multiplier. Determines and returns the ratio.<br/> - -### /alert - -#### POST - -Takes in a name and a math expression containing the names of the currencies. Checks the expression periodically. Sends a message over telegram when the expression holds true.<br/> -The expression's result must be boolean. As an example:<br/> - -```Go -ETH*50>50000. -ETH*60/(DOGE*300000) < 4. -``` - -You can have as many parameters as you like. The requests for the crypto prices are all turned into individual goroutines so it's fast.<br/> -The expression evaluation is powered by [govaluate](https://github.com/Knetic/govaluate). So for a set of rules and what you can and cannot do please check the documentation over there.<br/> - -#### DELETE - -Deletes the key from the DB so you will no longer receive updates.<br/> - -#### PUT - -Updates the alert.<br/.> - -#### GET - -Fetch the alert with the given name.<br/> - -### /ex - -Gets the list of currencies that are available to be traded.<br/> - -You can check under `./test` for some examples of curl commands.<br/> - -### /health - -Returns the health status of the service.<br/> - -```sh -TELEGRAM_BOT_TOKEN="my-telegram-bot-api-key" -``` - -If you want to use docker-compose, it's as simple as running `docker-compose up`. You just need to provide the files. You can check the file names in the docker-compose file.<br/> -Both the server itself and the redis image are alpine-based so they're pretty small.<br/> - -## telebot +`hived` is a cryptocurrency api server:<br/> diff --git a/arbiter/.golangci.yml b/arbiter/.golangci.yml deleted file mode 100644 index 878e031..0000000 --- a/arbiter/.golangci.yml +++ /dev/null @@ -1,18 +0,0 @@ -run: -  concurrency: 16 -  timeout: 5m -  modules-download-mode: readonly -  allow-parallel-runners: true -  allow-serial-runners: true -  go: '1.22' -linters-settings: -  depguard: -    rules: -      srcs: -        listMode: "Strict" -        allow: -        - $gostd -        - github.com/go-redis/redis/v8 -        - github.com/gorilla/mux -        - github.com/rs/zerolog -        - github.com/rs/zerolog/log diff --git a/arbiter/Dockerfile b/arbiter/Dockerfile deleted file mode 100644 index a512798..0000000 --- a/arbiter/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM golang:1.22-alpine3.19 as builder -RUN apk update && apk upgrade -RUN apk add go git -COPY go.* /arbiter/ -RUN cd /arbiter && go mod download -COPY *.go /arbiter/ -RUN cd /arbiter && go build - -FROM alpine:3.19 as certbuilder -RUN apk add openssl -WORKDIR /certs -RUN openssl req -nodes -new -x509 -subj="/C=US/ST=Denial/L=springfield/O=Dis/CN=localhost" -keyout server.key -out server.cert - -# FROM gcr.io/distroless/static-debian10 -FROM alpine:3.19 -COPY --from=certbuilder /certs /certs -COPY --from=builder /arbiter/arbiter /arbiter/ -ENTRYPOINT ["/arbiter/arbiter"] diff --git a/arbiter/arbiter.go b/arbiter/arbiter.go deleted file mode 100644 index 6145a45..0000000 --- a/arbiter/arbiter.go +++ /dev/null @@ -1,505 +0,0 @@ -package main - -import ( -	"context" -	"crypto/tls" -	"encoding/json" -	"errors" -	"flag" -	"io" -	"net/http" -	"net/url" -	"os" -	"os/signal" -	"strconv" -	"sync" -	"time" - -	"github.com/go-redis/redis/v8" -	"github.com/gorilla/mux" -	"github.com/rs/zerolog" -	"github.com/rs/zerolog/log" -) - -var ( -	errBadLogic          = errors.New("we should not be here") -	errUnexpectedParam   = errors.New("got unexpected parameter") -	errUnknownDeployment = errors.New("unknown deployment kind") -) - -const ( -	serverDeploymentType    = "SERVER_DEPLOYMENT_TYPE" -	coingeckoAPIURLv3       = "https://api.coingecko.com/api/v3" -	coincapAPIURLv2         = "https://api.coincap.io/v2" -	getTimeout              = 5 -	httpClientTimeout       = 5 -	serverTLSReadTimeout    = 15 -	serverTLSWriteTimeout   = 15 -	defaultGracefulShutdown = 15 -) - -// https://docs.coincap.io/ -type CoinCapAssetGetResponseData struct { -	ID                string `json:"id"` -	Rank              string `json:"rank"` -	Symbol            string `json:"symbol"` -	Name              string `json:"name"` -	Supply            string `json:"supply"` -	MaxSupply         string `json:"maxSupply"` -	MarketCapUsd      string `json:"marketCapUsd"` -	VolumeUsd24Hr     string `json:"volumeUsd24Hr"` -	PriceUsd          string `json:"priceUsd"` -	ChangePercent24Hr string `json:"changePercent24Hr"` -	Vwap24Hr          string `json:"vwap24Hr"` -} - -type priceResponseData struct { -	Name         string  `json:"name"` -	Price        float64 `json:"price"` -	Unit         string  `json:"unit"` -	Err          string  `json:"err"` -	IsSuccessful bool    `json:"isSuccessful"` -} - -type CoinCapAssetGetResponse struct { -	Data      CoinCapAssetGetResponseData `json:"data"` -	TimeStamp int64                       `json:"timestamp"` -} - -type HTTPHandlerFunc func(http.ResponseWriter, *http.Request) - -type HTTPHandler struct { -	name     string -	function HTTPHandlerFunc -} - -type priceChanStruct struct { -	name  string -	price float64 -} - -type errorChanStruct struct { -	hasError bool -	err      error -} - -func GetProxiedClient() *http.Client { -	transport := &http.Transport{ -		DisableKeepAlives: true, -		Proxy:             http.ProxyFromEnvironment, -	} -	client := &http.Client{ -		Transport:     transport, -		Timeout:       httpClientTimeout * time.Second, -		CheckRedirect: nil, -		Jar:           nil, -	} - -	return client -} - -// OWASP: https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html -func addSecureHeaders(writer *http.ResponseWriter) { -	(*writer).Header().Set("Cache-Control", "no-store") -	(*writer).Header().Set("Content-Security-Policy", "default-src https;") -	(*writer).Header().Set("Strict-Transport-Security", "max-age=63072000;") -	(*writer).Header().Set("X-Content-Type-Options", "nosniff") -	(*writer).Header().Set("X-Frame-Options", "DENY") -	(*writer).Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS") -} - -func getPriceFromCoinGecko( -	ctx context.Context, -	name, unit string, -	wg *sync.WaitGroup, -	priceChan chan<- priceChanStruct, -	errChan chan<- errorChanStruct, -) { -	defer wg.Done() - -	priceFloat := 0. - -	params := "/simple/price?ids=" + url.QueryEscape(name) + "&" + -		"vs_currencies=" + url.QueryEscape(unit) -	path := coingeckoAPIURLv3 + params - -	client := GetProxiedClient() - -	req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err) - -		return -	} - -	resp, err := client.Do(req) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err).Send() - -		return -	} -	defer resp.Body.Close() - -	body, err := io.ReadAll(resp.Body) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err).Send() -	} - -	jsonBody := make(map[string]interface{}) - -	err = json.Unmarshal(body, &jsonBody) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err).Send() -	} - -	price, isOk := jsonBody[name].(map[string]interface{}) -	if !isOk { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err) - -		return -	} - -	log.Info().Msg(string(body)) - -	priceFloat, isOk = price[unit].(float64) -	if !isOk { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err) - -		return -	} - -	priceChan <- priceChanStruct{name: name, price: priceFloat} -	errChan <- errorChanStruct{hasError: false, err: nil} -} - -func getPriceFromCoinCap( -	ctx context.Context, -	name string, -	wg *sync.WaitGroup, -	priceChan chan<- priceChanStruct, -	errChan chan<- errorChanStruct, -) { -	defer wg.Done() - -	priceFloat := 0. - -	params := "/assets/" + url.QueryEscape(name) -	path := coincapAPIURLv2 + params - -	client := GetProxiedClient() - -	req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err) - -		return -	} - -	resp, err := client.Do(req) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err).Send() - -		return -	} -	defer resp.Body.Close() - -	body, err := io.ReadAll(resp.Body) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err) -	} - -	var coinCapAssetGetResponse CoinCapAssetGetResponse - -	err = json.Unmarshal(body, &coinCapAssetGetResponse) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err).Send() -	} - -	priceFloat, err = strconv.ParseFloat(coinCapAssetGetResponse.Data.PriceUsd, 64) -	if err != nil { -		priceChan <- priceChanStruct{name: name, price: priceFloat} -		errChan <- errorChanStruct{hasError: true, err: err} - -		log.Error().Err(err).Send() -	} - -	log.Info().Msg(string(body)) - -	priceChan <- priceChanStruct{name: name, price: priceFloat} -	errChan <- errorChanStruct{hasError: false, err: nil} -} - -func arbHandler(w http.ResponseWriter, r *http.Request) { -	w.Header().Add("Content-Type", "application/json") - -	if r.Method != http.MethodGet { -		http.Error(w, "Method is not supported.", http.StatusNotFound) -	} - -	addSecureHeaders(&w) - -	var name string - -	var unit string - -	params := r.URL.Query() -	for key, value := range params { -		switch key { -		case "name": -			name = value[0] -		case "unit": -			unit = value[0] -		default: -			log.Error().Err(errUnexpectedParam) -		} -	} - -	priceChan := make(chan priceChanStruct, 1) -	errChan := make(chan errorChanStruct, 1) - -	var waitGroup sync.WaitGroup - -	ctx, cancel := context.WithTimeout(context.Background(), getTimeout*time.Second) -	defer cancel() - -	waitGroup.Add(1) - -	//nolint:contextcheck -	getPriceFromCoinGecko(ctx, name, unit, &waitGroup, priceChan, errChan) -	waitGroup.Wait() - -	select { -	case err := <-errChan: -		if err.hasError { -			log.Error().Err(err.err) -		} -	default: -		log.Error().Err(errBadLogic).Send() -	} - -	var price priceChanStruct -	select { -	case priceCh := <-priceChan: -		price = priceCh -	default: -		log.Error().Err(errBadLogic) -	} - -	responseData := priceResponseData{ -		Name:         price.name, -		Price:        price.price, -		Unit:         "USD", -		Err:          "", -		IsSuccessful: true, -	} - -	jsonResp, err := json.Marshal(responseData) -	if err != nil { -		cancel() -		//nolint:gocritic -		log.Fatal().Err(err) -	} - -	_, err = w.Write(jsonResp) -	if err != nil { -		cancel() -		log.Fatal().Err(err) -	} -} - -func coincapHandler(w http.ResponseWriter, r *http.Request) { -	if r.Method != http.MethodGet { -		http.Error(w, "Method is not supported.", http.StatusNotFound) -	} - -	w.Header().Add("Content-Type", "application/json") - -	addSecureHeaders(&w) - -	var name string - -	params := r.URL.Query() -	for key, value := range params { -		switch key { -		case "name": -			name = value[0] -		default: -			log.Error().Err(errUnexpectedParam).Send() -		} -	} - -	priceChan := make(chan priceChanStruct, 1) -	errChan := make(chan errorChanStruct, 1) - -	var waitGroup sync.WaitGroup - -	waitGroup.Add(1) - -	ctx, cancel := context.WithTimeout(context.Background(), getTimeout*time.Second) -	defer cancel() - -	getPriceFromCoinCap(ctx, name, &waitGroup, priceChan, errChan) -	waitGroup.Wait() - -	select { -	case err := <-errChan: -		if err.hasError { -			log.Error().Err(err.err) -		} -	default: -		log.Error().Err(errBadLogic) -	} - -	var price priceChanStruct -	select { -	case priceCh := <-priceChan: -		price = priceCh -	default: -		log.Error().Err(errBadLogic) -	} - -	responseData := priceResponseData{ -		Name:         price.name, -		Price:        price.price, -		Unit:         "USD", -		Err:          "", -		IsSuccessful: true, -	} - -	jsonResp, err := json.Marshal(responseData) -	if err != nil { -		cancel() - -		log.Fatal().Err(err).Send() -	} - -	_, err = w.Write(jsonResp) -	if err != nil { -		cancel() -		log.Fatal().Err(err) -	} -} - -func setupLogging() { -	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix -} - -func startServer(gracefulWait time.Duration, -	handlers []HTTPHandler, -	serverDeploymentType string, port string, -) { -	route := mux.NewRouter() -	cfg := &tls.Config{ -		MinVersion: tls.VersionTLS13, -	} - -	srv := &http.Server{ -		Addr:         "0.0.0.0:" + port, -		WriteTimeout: time.Second * serverTLSWriteTimeout, -		ReadTimeout:  time.Second * serverTLSReadTimeout, -		Handler:      route, -		TLSConfig:    cfg, -	} - -	for i := range len(handlers) { -		route.HandleFunc(handlers[i].name, handlers[i].function) -	} - -	go func() { -		var certPath, keyPath string - -		switch os.Getenv(serverDeploymentType) { -		case "deployment": -			certPath = "/etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem" -			keyPath = "/etc/letsencrypt/live/api.terminaldweller.com/privkey.pem" -		case "test": -			certPath = "/certs/server.cert" -			keyPath = "/certs/server.key" -		default: -			log.Error().Err(errUnknownDeployment).Send() -		} - -		if err := srv.ListenAndServeTLS(certPath, keyPath); err != nil { -			log.Error().Err(err) -		} -	}() - -	c := make(chan os.Signal, 1) - -	signal.Notify(c, os.Interrupt) -	<-c - -	ctx, cancel := context.WithTimeout(context.Background(), gracefulWait) -	defer cancel() - -	if err := srv.Shutdown(ctx); err != nil { -		log.Error().Err(err) -	} - -	log.Info().Msg("gracefully shut down the server") -} - -func main() { -	var gracefulWait time.Duration - -	var rdb *redis.Client - -	flag.DurationVar( -		&gracefulWait, -		"gracefulwait", -		time.Second*defaultGracefulShutdown, -		"the duration to wait during the graceful shutdown", -	) - -	flagPort := flag.String("port", "8009", "determines the port the server will listen on") -	redisDB := flag.Int64("redisdb", 1, "determines the db number") -	redisAddress := flag.String("redisaddress", "redis:6379", "determines the address of the redis instance") -	redisPassword := flag.String("redispassword", "", "determines the password of the redis db") -	flag.Parse() - -	rdb = redis.NewClient(&redis.Options{ -		Addr:     *redisAddress, -		Password: *redisPassword, -		DB:       int(*redisDB), -	}) -	defer rdb.Close() - -	setupLogging() - -	handlerFuncs := []HTTPHandler{ -		{name: "/crypto/v1/arb/gecko", function: arbHandler}, -		{name: "/crypto/v1/arb/coincap", function: coincapHandler}, -	} - -	startServer(gracefulWait, handlerFuncs, serverDeploymentType, *flagPort) -} diff --git a/arbiter/go.mod b/arbiter/go.mod deleted file mode 100644 index a7a87c6..0000000 --- a/arbiter/go.mod +++ /dev/null @@ -1,17 +0,0 @@ -module arbiter - -go 1.22 - -require ( -	github.com/go-redis/redis/v8 v8.11.5 -	github.com/gorilla/mux v1.8.1 -	github.com/rs/zerolog v1.31.0 -) - -require ( -	github.com/cespare/xxhash/v2 v2.2.0 // indirect -	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect -	github.com/mattn/go-colorable v0.1.13 // indirect -	github.com/mattn/go-isatty v0.0.20 // indirect -	golang.org/x/sys v0.15.0 // indirect -) diff --git a/arbiter/go.sum b/arbiter/go.sum deleted file mode 100644 index 85a6437..0000000 --- a/arbiter/go.sum +++ /dev/null @@ -1,41 +0,0 @@ -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= -github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/arbiter/tests.sh b/arbiter/tests.sh deleted file mode 100755 index be923f3..0000000 --- a/arbiter/tests.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh - -curl -k -X GET "https://localhost:8009/crypto/v1/arb/gecko?name=ethereum&unit=usd" -curl -k -X GET "https://localhost:8009/crypto/v1/arb/coincap?name=ethereum" diff --git a/docker-compose-test.yaml b/docker-compose-test.yaml index 6b7367a..49ceab9 100644 --- a/docker-compose-test.yaml +++ b/docker-compose-test.yaml @@ -1,31 +1,4 @@  services: -  auth: -    image: auth -    build: -      context: ./auth -    deploy: -      resources: -        limits: -          memory: 256M -    logging: -      driver: "json-file" -      options: -        max-size: "100m" -    networks: -      - authnet -    restart: unless-stopped -    ports: -      - "127.0.0.1:8091:8090" -    depends_on: -      - nginx -    volumes: -      - pb-vault:/auth/pb_data -    cap_drop: -      - ALL -    environment: -      - SERVER_DEPLOYMENT_TYPE=deployment -    entrypoint: ["/auth/auth"] -    command: ["serve", "--http=0.0.0.0:8090"]    nginx:      image: nginx:stable      deploy: @@ -37,9 +10,9 @@ services:        options:          max-size: "100m"      ports: -      - "127.0.0.1:8090:443" +      - "127.0.0.1:10008:443"      networks: -      - authnet +      - apinet      restart: unless-stopped      cap_drop:        - ALL @@ -50,9 +23,11 @@ services:        - SETUID        - NET_BIND_SERVICE      volumes: -      - ./auth/nginx.conf:/etc/nginx/nginx.conf:ro +      - ./nginx.conf:/etc/nginx/nginx.conf:ro        - ./ss_certs/server.cert:/etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem:ro        - ./ss_certs/server.key:/etc/letsencrypt/live/api.terminaldweller.com/privkey.pem:ro +    depends_on: +      - hived    hived:      image: hived      build: @@ -70,66 +45,23 @@ services:      networks:        - apinet        - dbnet -      - telenet      ports: -      - "127.0.0.1:10008:8008" +      - "127.0.0.1:10009:8090" +    entrypoint: ["/hived/hived"] +    command: ["serve", "--http=0.0.0.0:8090"]      depends_on:        - keydb -      - telebot -    entrypoint: ["/hived/docker-entrypoint.sh"]      cap_drop:        - ALL      environment:        - SERVER_DEPLOYMENT_TYPE=test -      - HIVED_PRICE_SOURCE=cmc +      - HIVED_PRICE_SOURCE=cryptocompare        - CMC_API_KEY=        - POLYGON_API_KEY= -  telebot: -    image: telebot -    build: -      context: ./telebot -    deploy: -      resources: -        limits: -          memory: 256M -    logging: -      driver: "json-file" -      options: -        max-size: "100m" -    secrets: -      - tg_bot_token -    networks: -      - telenet -    ports: -      - "127.0.0.1:10009:8000" -    entrypoint: ["/telebot/docker-entrypoint.sh"] -    cap_drop: -      - ALL -    environment: -      - SERVER_DEPLOYMENT_TYPE=test -  arbiter: -    image: arbiter -    build: -      context: ./arbiter -    deploy: -      resources: -        limits: -          memory: 256M -    logging: -      driver: "json-file" -      options: -        max-size: "100m" -    networks: -      - apinet -      - dbnet -      - telenet -    ports: -      - "127.0.0.1:8009:8009" -    entrypoint: ["/arbiter/arbiter"] -    cap_drop: -      - ALL -    environment: -      - SERVER_DEPLOYMENT_TYPE=test +      - CRYPTOCOMPARE_API_KEY= +      - TELEGRAM_BOT_TOKEN= +    volumes: +      - ./hived/hived.toml:/hived/hived.toml    keydb:      image: eqalpha/keydb:alpine_x86_64_v6.3.4      deploy: @@ -146,12 +78,10 @@ services:        - "127.0.0.1:6380:6379"      environment:        - ALLOW_EMPTY_PASSWORD=yes -    # volumes: -    #   - keydb-data:/data/ +    volumes: +      - keydb-data:/data/  networks: -  authnet:    dbnet: -  telenet:    apinet:  secrets:    tg_bot_token: diff --git a/docker-compose.yaml b/docker-compose.yaml index 23e7d32..65d853a 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,80 +1,95 @@  services: +  nginx: +    image: nginx:stable +    deploy: +      resources: +        limits: +          memory: 128M +    logging: +      driver: "json-file" +      options: +        max-size: "100m" +    ports: +      - "127.0.0.1:10008:443" +    networks: +      - apinet +    restart: unless-stopped +    cap_drop: +      - ALL +    cap_add: +      - CHOWN +      - DAC_OVERRIDE +      - SETGID +      - SETUID +      - NET_BIND_SERVICE +    volumes: +      - ./nginx.conf:/etc/nginx/nginx.conf:ro +      - /etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem:/etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem:ro +      - /etc/letsencrypt/live/api.terminaldweller.com/privkey.pem:/etc/letsencrypt/live/api.terminaldweller.com/privkey.pem:ro +    depends_on: +      - hived    hived:      image: hived      build:        context: ./hived +    deploy: +      resources: +        limits: +          memory: 256M +    logging: +      driver: "json-file" +      options: +        max-size: "100m"      secrets:        - tg_bot_token      networks: -      - mainnet -      - telenet -    restart: unless-stopped +      - apinet +      - dbnet      ports: -      - "8007:8008" +      - "127.0.0.1:10009:8090" +    entrypoint: ["/hived/hived"] +    command: ["serve", "--http=0.0.0.0:8090"]      depends_on:        - keydb -      - telebot -    entrypoint: ["/hived/docker-entrypoint.sh"] -    volumes: -      - /etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem:/etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem -      - /etc/letsencrypt/live/api.terminaldweller.com/privkey.pem:/etc/letsencrypt/live/api.terminaldweller.com/privkey.pem      cap_drop:        - ALL      environment: -      - SERVER_DEPLOYMENT_TYPE=deployment +      - SERVER_DEPLOYMENT_TYPE=test +      - HIVED_PRICE_SOURCE=cryptocompare +      - CMC_API_KEY=        - POLYGON_API_KEY=        - CRYPTOCOMPARE_API_KEY= -      - HIVED_PRICE_SOURCE=  -  telebot: -    image: telebot -    build: -      context: ./telebot -    secrets: -      - tg_bot_token -    networks: -      - telenet -    restart: unless-stopped -    ports: -      - "127.0.0.1:9009:8000" -    entrypoint: ["/telebot/docker-entrypoint.sh"] -    cap_drop: -      - ALL -    environment: -      - SERVER_DEPLOYMENT_TYPE=deployment +      - TELEGRAM_BOT_TOKEN= +    volumes: +      - ./hived/hived.toml:/hived/hived.toml    keydb:      image: eqalpha/keydb:alpine_x86_64_v6.3.4 +    deploy: +      resources: +        limits: +          memory: 256M +    logging: +      driver: "json-file" +      options: +        max-size: "100m"      networks: -      - mainnet -    restart: unless-stopped +      - dbnet      ports: -      - "127.0.0.1:6379:6379" +      - "127.0.0.1:6380:6379"      environment:        - ALLOW_EMPTY_PASSWORD=yes      volumes: -      - redis-data:/data/ -  arbiter: -    image: arbiter -    build: -      context: ./arbiter -    networks: -      - mainnet -    ports: -      - "8009:8009" -    entrypoint: ["/arbiter/arbiter"] -    volumes: -      - /etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem:/etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem -      - /etc/letsencrypt/live/api.terminaldweller.com/privkey.pem:/etc/letsencrypt/live/api.terminaldweller.com/privkey.pem -    cap_drop: -      - ALL -    environment: -      - SERVER_DEPLOYMENT_TYPE=deployment +      - keydb-data:/data/  networks: -  mainnet: -    driver: bridge -  telenet: -    driver: bridge +  dbnet: +  apinet:  secrets:    tg_bot_token:      file: ./tgtoken +  polygon_api_key: +    file: ./polygon_api_key +  cmc_api_key: +    file: ./cmc_api_key  volumes: -  redis-data: +  keydb-data: +  p diff --git a/hived/Dockerfile b/hived/Dockerfile index 64e4789..a9c84ac 100644 --- a/hived/Dockerfile +++ b/hived/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22-alpine3.19 as builder +FROM golang:1.22-alpine3.20 as builder  RUN apk update && apk upgrade  RUN apk add go git  COPY go.* /hived/ @@ -6,14 +6,6 @@ RUN cd /hived && go mod download  COPY *.go /hived/  RUN cd /hived && go build -FROM alpine:3.19 as certbuilder -RUN apk add openssl -WORKDIR /certs -RUN openssl req -nodes -new -x509 -subj="/C=US/ST=Denial/L=springfield/O=Dis/CN=localhost" -keyout server.key -out server.cert - -# FROM gcr.io/distroless/static-debian10 -FROM alpine:3.19 -COPY --from=certbuilder /certs /certs +FROM alpine:3.20  COPY --from=builder /hived/hived /hived/ -COPY ./docker-entrypoint.sh /hived/ -ENTRYPOINT ["/hived/docker-entrypoint.sh"] +ENTRYPOINT ["/hived/hived"] diff --git a/hived/alertHandlers.go b/hived/alertHandlers.go index fd49835..6fb7614 100644 --- a/hived/alertHandlers.go +++ b/hived/alertHandlers.go @@ -6,6 +6,7 @@ import (  	"net/http"  	"time" +	"github.com/labstack/echo/v5"  	"github.com/rs/zerolog/log"  ) @@ -166,7 +167,10 @@ func (alertHandler Handler) HandleAlertGet(writer http.ResponseWriter, request *  	}  } -func alertHandler(writer http.ResponseWriter, request *http.Request) { +func (aw appWrapper) alertHandler(echoCtx echo.Context) error { +	writer := echoCtx.Response().Writer +	request := echoCtx.Request() +  	addSecureHeaders(&writer)  	handler := Handler{rdb: rdb} @@ -185,4 +189,6 @@ func alertHandler(writer http.ResponseWriter, request *http.Request) {  	default:  		http.Error(writer, "Method is not supported.", http.StatusNotFound)  	} + +	return nil  } diff --git a/hived/docker-entrypoint.sh b/hived/docker-entrypoint.sh deleted file mode 100755 index 0e41826..0000000 --- a/hived/docker-entrypoint.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -set -ex - -export "$(cat /run/secrets/tg_bot_token)" - -"/hived/hived" "$@" diff --git a/hived/go.mod b/hived/go.mod index dead3e3..d9b8a4e 100644 --- a/hived/go.mod +++ b/hived/go.mod @@ -3,33 +3,97 @@ module hived  go 1.22  require ( +	github.com/BurntSushi/toml v0.3.1  	github.com/Knetic/govaluate v3.0.0+incompatible  	github.com/go-redis/redis/v8 v8.11.5 -	github.com/gorilla/mux v1.8.1 -	github.com/polygon-io/client-go v1.16.4 +	github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible +	github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 +	github.com/pocketbase/pocketbase v0.22.13  	github.com/rs/zerolog v1.31.0  	github.com/terminaldweller/grpc v1.0.3 -	google.golang.org/grpc v1.59.0 -	google.golang.org/protobuf v1.31.0 +	google.golang.org/grpc v1.64.0 +	google.golang.org/protobuf v1.34.1  )  require ( +	github.com/AlecAivazis/survey/v2 v2.3.7 // indirect +	github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect +	github.com/aws/aws-sdk-go-v2 v1.27.0 // indirect +	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect +	github.com/aws/aws-sdk-go-v2/config v1.27.16 // indirect +	github.com/aws/aws-sdk-go-v2/credentials v1.17.16 // indirect +	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 // indirect +	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.21 // indirect +	github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect +	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect +	github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect +	github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 // indirect +	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect +	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9 // indirect +	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 // indirect +	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7 // indirect +	github.com/aws/aws-sdk-go-v2/service/s3 v1.54.3 // indirect +	github.com/aws/aws-sdk-go-v2/service/sso v1.20.9 // indirect +	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3 // indirect +	github.com/aws/aws-sdk-go-v2/service/sts v1.28.10 // indirect +	github.com/aws/smithy-go v1.20.2 // indirect  	github.com/cespare/xxhash/v2 v2.2.0 // indirect  	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect -	github.com/gabriel-vasile/mimetype v1.4.2 // indirect -	github.com/go-playground/form/v4 v4.2.1 // indirect -	github.com/go-playground/locales v0.14.1 // indirect -	github.com/go-playground/universal-translator v0.18.1 // indirect -	github.com/go-playground/validator/v10 v10.16.0 // indirect -	github.com/go-resty/resty/v2 v2.11.0 // indirect -	github.com/golang/protobuf v1.5.3 // indirect -	github.com/google/go-cmp v0.6.0 // indirect -	github.com/leodido/go-urn v1.2.4 // indirect +	github.com/disintegration/imaging v1.6.2 // indirect +	github.com/dlclark/regexp2 v1.10.0 // indirect +	github.com/domodwyer/mailyak/v3 v3.6.2 // indirect +	github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d // indirect +	github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c // indirect +	github.com/dustin/go-humanize v1.0.1 // indirect +	github.com/fatih/color v1.17.0 // indirect +	github.com/fsnotify/fsnotify v1.7.0 // indirect +	github.com/gabriel-vasile/mimetype v1.4.4 // indirect +	github.com/ganigeorgiev/fexpr v0.4.1 // indirect +	github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect +	github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect +	github.com/goccy/go-json v0.10.3 // indirect +	github.com/golang-jwt/jwt/v4 v4.5.0 // indirect +	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect +	github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect +	github.com/google/uuid v1.6.0 // indirect +	github.com/googleapis/gax-go/v2 v2.12.4 // indirect +	github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect +	github.com/inconshreveable/mousetrap v1.1.0 // indirect +	github.com/jmespath/go-jmespath v0.4.0 // indirect +	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect  	github.com/mattn/go-colorable v0.1.13 // indirect  	github.com/mattn/go-isatty v0.0.20 // indirect -	golang.org/x/crypto v0.17.0 // indirect -	golang.org/x/net v0.19.0 // indirect -	golang.org/x/sys v0.15.0 // indirect -	golang.org/x/text v0.14.0 // indirect -	google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect +	github.com/mattn/go-sqlite3 v1.14.22 // indirect +	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect +	github.com/ncruces/go-strftime v0.1.9 // indirect +	github.com/pocketbase/dbx v1.10.1 // indirect +	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect +	github.com/spf13/cast v1.6.0 // indirect +	github.com/spf13/cobra v1.8.0 // indirect +	github.com/spf13/pflag v1.0.5 // indirect +	github.com/stretchr/testify v1.8.4 // indirect +	github.com/technoweenie/multipartstreamer v1.0.1 // indirect +	github.com/valyala/bytebufferpool v1.0.0 // indirect +	github.com/valyala/fasttemplate v1.2.2 // indirect +	go.opencensus.io v0.24.0 // indirect +	gocloud.dev v0.37.0 // indirect +	golang.org/x/crypto v0.23.0 // indirect +	golang.org/x/image v0.16.0 // indirect +	golang.org/x/net v0.25.0 // indirect +	golang.org/x/oauth2 v0.20.0 // indirect +	golang.org/x/sync v0.7.0 // indirect +	golang.org/x/sys v0.20.0 // indirect +	golang.org/x/term v0.20.0 // indirect +	golang.org/x/text v0.15.0 // indirect +	golang.org/x/time v0.5.0 // indirect +	golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect +	google.golang.org/api v0.182.0 // indirect +	google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect +	modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect +	modernc.org/libc v1.51.0 // indirect +	modernc.org/mathutil v1.6.0 // indirect +	modernc.org/memory v1.8.0 // indirect +	modernc.org/sqlite v1.30.0 // indirect +	modernc.org/strutil v1.2.0 // indirect +	modernc.org/token v1.1.0 // indirect  ) diff --git a/hived/go.sum b/hived/go.sum index 2a70c3b..0bc72a3 100644 --- a/hived/go.sum +++ b/hived/go.sum @@ -1,13 +1,79 @@  cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=  cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.114.0 h1:OIPFAdfrFDFO2ve2U7r/H5SwSbBzEdrBdE7xkgwc+kY= +cloud.google.com/go v0.114.0/go.mod h1:ZV9La5YYxctro1HTPug5lXH/GefROyW8PPD4T8n9J8E= +cloud.google.com/go/auth v0.4.2 h1:sb0eyLkhRtpq5jA+a8KWw0W70YcdVca7KJ8TM0AFYDg= +cloud.google.com/go/auth v0.4.2/go.mod h1:Kqvlz1cf1sNA0D+sYJnkPQOP+JMHkuHeIgVmCRtZOLc= +cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY= +cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=  github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=  github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=  github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=  github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.51.11 h1:El5VypsMIz7sFwAAj/j06JX9UGs4KAbAIEaZ57bNY4s= +github.com/aws/aws-sdk-go v1.51.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo= +github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= +github.com/aws/aws-sdk-go-v2/config v1.27.16 h1:knpCuH7laFVGYTNd99Ns5t+8PuRjDn4HnnZK48csipM= +github.com/aws/aws-sdk-go-v2/config v1.27.16/go.mod h1:vutqgRhDUktwSge3hrC3nkuirzkJ4E/mLj5GvI0BQas= +github.com/aws/aws-sdk-go-v2/credentials v1.17.16 h1:7d2QxY83uYl0l58ceyiSpxg9bSbStqBC6BeEeHEchwo= +github.com/aws/aws-sdk-go-v2/credentials v1.17.16/go.mod h1:Ae6li/6Yc6eMzysRL2BXlPYvnrLLBg3D11/AmOjw50k= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 h1:dQLK4TjtnlRGb0czOht2CevZ5l6RSyRWAnKeGd7VAFE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3/go.mod h1:TL79f2P6+8Q7dTsILpiVST+AL9lkF6PPGI167Ny0Cjw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.21 h1:1v8Ii0MRVGYB/sdhkbxrtolCA7Tp+lGh+5OJTs5vmZ8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.21/go.mod h1:cxdd1rc8yxCjKz28hi30XN1jDXr2DxZvD44vLxTz/bg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7 h1:/FUtT3xsoHO3cfh+I/kCbcMCN98QZRsiFet/V8QkWSs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.7/go.mod h1:MaCAgWpGooQoCWZnMur97rGn5dp350w2+CeiV5406wE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9 h1:UXqEWQI0n+q0QixzU0yUUQBZXRd5037qdInTIHFTl98= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.9/go.mod h1:xP6Gq6fzGZT8w/ZN+XvGMZ2RU1LeEs7b2yUP5DN8NY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 h1:Wx0rlZoEJR7JwlSZcHnEa7CNjrSIyVxMFWGAaXy4fJY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7 h1:uO5XR6QGBcmPyo2gxofYJLFkcVQ4izOoGDNenlZhTEk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.7/go.mod h1:feeeAYfAcwTReM6vbwjEyDmiGho+YgBhaFULuXDW8kc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.54.3 h1:57NtjG+WLims0TxIQbjTqebZUKDM03DfM11ANAekW0s= +github.com/aws/aws-sdk-go-v2/service/s3 v1.54.3/go.mod h1:739CllldowZiPPsDFcJHNF4FXrVxaSGVnZ9Ez9Iz9hc= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.9 h1:aD7AGQhvPuAxlSUfo0CWU7s6FpkbyykMhGYMvlqTjVs= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.9/go.mod h1:c1qtZUWtygI6ZdvKppzCSXsDOq5I4luJPZ0Ud3juFCA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3 h1:Pav5q3cA260Zqez42T9UhIlsd9QeypszRPwC9LdSSsQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3/go.mod h1:9lmoVDVLz/yUZwLaQ676TK02fhCu4+PgRSmMaKR1ozk= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.10 h1:69tpbPED7jKPyzMcrwSvhWcJ9bPnZsZs18NT40JwM0g= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.10/go.mod h1:0Aqn1MnEuitqfsCNyKsdKLhDUOr4txD/g19EfiUqgws= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=  github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=  github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=  github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=  github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= +github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= +github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=  github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=  github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=  github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -16,41 +82,78 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH  github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=  github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=  github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=  github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=  github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= +github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8= +github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d h1:wi6jN5LVt/ljaBG4ue79Ekzb12QfJ52L9Q98tl8SWhw= +github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c h1:hLoodLRD4KLWIH8eyAQCLcH8EqIrjac7fCkp/fHnvuQ= +github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c/go.mod h1:bhGPmCgCCTSRfiMYWjpS46IDo9EUZXlsuUaPXSWGbv0= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=  github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=  github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=  github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=  github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=  github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=  github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k= +github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=  github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/form/v4 v4.2.1 h1:HjdRDKO0fftVMU5epjPW2SOREcZ6/wLUzEobqUGJuPw= -github.com/go-playground/form/v4 v4.2.1/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= -github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= +github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=  github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=  github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= -github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4= +github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=  github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=  github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=  github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=  github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=  github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=  github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=  github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -63,30 +166,71 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw  github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=  github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=  github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=  github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=  github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=  github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=  github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=  github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=  github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=  github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=  github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=  github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= +github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=  github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= -github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= +github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 h1:FwuzbVh87iLiUQj1+uQUsuw9x5t9m5n5g7rG7o4svW4= +github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61/go.mod h1:paQfF1YtHe+GrGg5fOgjsjoCX/UKDr9bc1DoWpZfns8= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=  github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=  github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=  github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=  github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=  github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=  github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=  github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -96,93 +240,134 @@ github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5h  github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polygon-io/client-go v1.16.4 h1:3hxFXAVOtbQ9EfzyI65f5qNMWYAAJ/SoBktk4al0YAY= -github.com/polygon-io/client-go v1.16.4/go.mod h1:jkG484PfMaqiubeFdoT38nrMOx1zclJcjccxDc/BEsE= +github.com/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA= +github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= +github.com/pocketbase/pocketbase v0.22.13 h1:6703U9aByDueyVCuASqTfvMUrH2Beq26WiohOXp/vk4= +github.com/pocketbase/pocketbase v0.22.13/go.mod h1:QrZElN3ifiRf9aCHv9ks6JGWYdY3nLO6uuf5/0cLXiI=  github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=  github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=  github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=  github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=  github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=  github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=  github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=  github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=  github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=  github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=  github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=  github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=  github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=  github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=  github.com/terminaldweller/grpc v1.0.3 h1:yCRm0HKRD4M87CBmmO5KjkSFRq4X2lzHLJRH1ApzeiE=  github.com/terminaldweller/grpc v1.0.3/go.mod h1:pYpuXZw8rHZwTABVEVZEfErFr+PyEhAaSrFm7y1yvTo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=  github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=  go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= +gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco=  golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=  golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=  golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=  golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw= +golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=  golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=  golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=  golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=  golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=  golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=  golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=  golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=  golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=  golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=  golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=  golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=  golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=  golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=  golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=  golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=  golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=  golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=  golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=  golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=  golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=  golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=  golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=  golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=  golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=  golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=  golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=  golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=  golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=  golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=  golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=  golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=  golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=  golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=  golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=  golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=  golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=  golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=  golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=  golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -190,27 +375,38 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3  golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=  golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=  golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=  golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=  golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=  golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +google.golang.org/api v0.182.0 h1:if5fPvudRQ78GeRx3RayIoiuV7modtErPIZC/T2bIvE= +google.golang.org/api v0.182.0/go.mod h1:cGhjy4caqA5yXRzEhkHI8Y9mfyC2VLTlER2l08xaqtM=  google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=  google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=  google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=  google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=  google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=  google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= +google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= +google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=  google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=  google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=  google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=  google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=  google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=  google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=  google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=  google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=  google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=  google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -223,13 +419,17 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba  google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=  google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=  google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=  gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=  gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=  gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=  gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=  gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=  gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -237,3 +437,29 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=  honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=  honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk= +modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs= +modernc.org/ccgo/v4 v4.17.8/go.mod h1:buJnJ6Fn0tyAdP/dqePbrrvLyr6qslFfTbFrCuaYvtA= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8= +modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.51.0 h1:kjSHjz1guHbI5iRdi6nEr/wIKSN6X4vzLd6TJMN+lHA= +modernc.org/libc v1.51.0/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.30.0 h1:8YhPUs/HTnlEgErn/jSYQTwHN/ex8CjHHjg+K9iG7LM= +modernc.org/sqlite v1.30.0/go.mod h1:cgkTARJ9ugeXSNaLBPK3CqbOe7Ec7ZhWPoMFGldEYEw= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/hived/hived.go b/hived/hived.go index f2764a4..c714cfd 100644 --- a/hived/hived.go +++ b/hived/hived.go @@ -2,35 +2,41 @@ package main  import (  	"context" -	"crypto/tls"  	"encoding/json"  	"errors"  	"flag"  	"fmt" +	"io"  	"net/http"  	"net/url"  	"os" -	"os/signal" +	"path/filepath"  	"strconv" +	"strings"  	"sync"  	"time" +	"github.com/BurntSushi/toml"  	"github.com/Knetic/govaluate"  	"github.com/go-redis/redis/v8" -	"github.com/gorilla/mux" +	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" +	"github.com/labstack/echo/v5" +	"github.com/pocketbase/pocketbase" +	"github.com/pocketbase/pocketbase/apis" +	"github.com/pocketbase/pocketbase/core" +	"github.com/pocketbase/pocketbase/plugins/ghupdate" +	"github.com/pocketbase/pocketbase/plugins/jsvm" +	"github.com/pocketbase/pocketbase/plugins/migratecmd"  	"github.com/rs/zerolog"  	"github.com/rs/zerolog/log" -	pb "github.com/terminaldweller/grpc/telebot/v1" -	"google.golang.org/grpc" -	"google.golang.org/protobuf/types/known/timestamppb"  )  const (  	cryptocomparePriceURL        = "https://min-api.cryptocompare.com/data/price?"  	polygonCryptoTickerURL       = "https://api.polygon.io/v2/snapshot/locale/global/markets/crypto/tickers"  	cmcCryptoTickerURL           = "https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest" -	telegramBotTokenEnvVar       = "TELEGRAM_BOT_TOKEN" //nolint: gosec -	serverDeploymentType         = "SERVER_DEPLOYMENT_TYPE" +	coingeckoAPIURLv3            = "https://api.coingecko.com/api/v3" +	coincapAPIURLv2              = "https://api.coincap.io/v2"  	httpClientTimeout            = 5  	getTimeout                   = 5  	serverTLSReadTimeout         = 15 @@ -61,6 +67,86 @@ var (  	errUnknownDeploymentKind = errors.New("unknown deployment kind")  ) +type HivedConfig struct { +	KeydbAddress        string `toml:"keydbAddress"` +	KeydbPassword       string `toml:"keydbPassword"` +	KeydbDB             int    `toml:"keydbDB"` +	AlertsCheckInterval int64  `toml:"alertsCheckInterval"` +	TickerCheckInterval int64  `toml:"tickerCheckInterval"` +	CacheDuration       int64  `toml:"cacheDuration"` +	TelegramChannelID   int64  `toml:"telegramChannelID"` +} + +type appWrapper struct { +	app *pocketbase.PocketBase +} + +// https://docs.coincap.io/ +type CoinCapAssetGetResponseData struct { +	ID                string `json:"id"` +	Rank              string `json:"rank"` +	Symbol            string `json:"symbol"` +	Name              string `json:"name"` +	Supply            string `json:"supply"` +	MaxSupply         string `json:"maxSupply"` +	MarketCapUsd      string `json:"marketCapUsd"` +	VolumeUsd24Hr     string `json:"volumeUsd24Hr"` +	PriceUsd          string `json:"priceUsd"` +	ChangePercent24Hr string `json:"changePercent24Hr"` +	Vwap24Hr          string `json:"vwap24Hr"` +} + +type RootCmds struct { +	hooksDir      string +	hooksWatch    bool +	hooksPool     int +	hooksPoolSize int +	migrationsDir string +	automigrate   bool +	publicDir     string +	indexFallback bool +	queryTimeout  int +} + +type priceResponseData struct { +	Name         string  `json:"name"` +	Price        float64 `json:"price"` +	Unit         string  `json:"unit"` +	Err          string  `json:"err"` +	IsSuccessful bool    `json:"isSuccessful"` +} + +type CoinCapAssetGetResponse struct { +	Data      CoinCapAssetGetResponseData `json:"data"` +	TimeStamp int64                       `json:"timestamp"` +} + +type HTTPHandlerFunc func(http.ResponseWriter, *http.Request) + +type HTTPHandler struct { +	name     string +	function HTTPHandlerFunc +} + +func getTGBot() *tgbotapi.BotAPI { +	token := os.Getenv("TELEGRAM_BOT_TOKEN") +	fmt.Println("YYY:", token) + +	bot, err := tgbotapi.NewBotAPI(token) +	if err != nil { +		log.Fatal().Err(err).Send() +	} + +	return bot +} + +func sendMessage(bot *tgbotapi.BotAPI, msgText string, channelID int64) error { +	msg := tgbotapi.NewMessage(channelID, msgText) +	_, err := bot.Send(msg) + +	return err +} +  func GetProxiedClient() *http.Client {  	transport := &http.Transport{  		DisableKeepAlives: true, @@ -86,30 +172,13 @@ func addSecureHeaders(writer *http.ResponseWriter) {  	(*writer).Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")  } -func sendToTg(address, msg string, channelID int64) { -	conn, err := grpc.Dial(address, grpc.WithInsecure()) -	if err != nil { -		log.Fatal().Err(err) -	} -	defer conn.Close() - -	c := pb.NewNotificationServiceClient(conn) +func sendToTg(msg string, channelID int64) { +	tgbotapi := getTGBot() -	ctx, cancel := context.WithTimeout(context.Background(), telegramTimeout*time.Second) -	defer cancel() - -	response, err := c.Notify( -		ctx, -		&pb.NotificationRequest{ -			NotificationText: msg, -			ChannelId:        channelID, -			RequestTime:      timestamppb.Now(), -		}) +	err := sendMessage(tgbotapi, msg, channelID)  	if err != nil { -		log.Error().Err(err) +		log.Info().Err(err)  	} - -	log.Info().Msg(fmt.Sprintf("%v", response))  }  type priceChanStruct struct { @@ -175,6 +244,8 @@ func getPriceFromCryptoCompare(  		"tsyms=" + url.QueryEscape(unit)  	path := cryptocomparePriceURL + params +	log.Print(path) +  	client := GetProxiedClient()  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil) @@ -326,7 +397,160 @@ func getPriceFromCMC(  	errChan <- errorChanStruct{hasError: false, err: nil}  } -func PriceHandler(writer http.ResponseWriter, request *http.Request) { +func GetPriceFromCoinGecko( +	ctx context.Context, +	name, unit string, +	wg *sync.WaitGroup, +	priceChan chan<- priceChanStruct, +	errChan chan<- errorChanStruct, +) { +	defer wg.Done() + +	priceFloat := 0. + +	params := "/simple/price?ids=" + url.QueryEscape(name) + "&" + +		"vs_currencies=" + url.QueryEscape(unit) +	path := coingeckoAPIURLv3 + params + +	client := GetProxiedClient() + +	req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err) + +		return +	} + +	resp, err := client.Do(req) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err).Send() + +		return +	} +	defer resp.Body.Close() + +	body, err := io.ReadAll(resp.Body) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err).Send() +	} + +	jsonBody := make(map[string]interface{}) + +	err = json.Unmarshal(body, &jsonBody) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err).Send() +	} + +	price, isOk := jsonBody[name].(map[string]interface{}) +	if !isOk { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err) + +		return +	} + +	log.Info().Msg(string(body)) + +	priceFloat, isOk = price[unit].(float64) +	if !isOk { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err) + +		return +	} + +	priceChan <- priceChanStruct{name: name, price: priceFloat} +	errChan <- errorChanStruct{hasError: false, err: nil} +} + +func GetPriceFromCoinCap( +	ctx context.Context, +	name string, +	wg *sync.WaitGroup, +	priceChan chan<- priceChanStruct, +	errChan chan<- errorChanStruct, +) { +	defer wg.Done() + +	priceFloat := 0. + +	params := "/assets/" + url.QueryEscape(name) +	path := coincapAPIURLv2 + params + +	client := GetProxiedClient() + +	req, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err) + +		return +	} + +	resp, err := client.Do(req) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err).Send() + +		return +	} +	defer resp.Body.Close() + +	body, err := io.ReadAll(resp.Body) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err) +	} + +	var coinCapAssetGetResponse CoinCapAssetGetResponse + +	err = json.Unmarshal(body, &coinCapAssetGetResponse) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err).Send() +	} + +	priceFloat, err = strconv.ParseFloat(coinCapAssetGetResponse.Data.PriceUsd, 64) +	if err != nil { +		priceChan <- priceChanStruct{name: name, price: priceFloat} +		errChan <- errorChanStruct{hasError: true, err: err} + +		log.Error().Err(err).Send() +	} + +	log.Info().Msg(string(body)) + +	priceChan <- priceChanStruct{name: name, price: priceFloat} +	errChan <- errorChanStruct{hasError: false, err: nil} +} + +func (aw appWrapper) PriceHandler(echoCtx echo.Context) error { +	writer := echoCtx.Response().Writer +	request := echoCtx.Request()  	writer.Header().Add("Content-Type", "application/json")  	if request.Method != http.MethodGet { @@ -361,7 +585,7 @@ func PriceHandler(writer http.ResponseWriter, request *http.Request) {  			http.Error(writer, "internal server error", http.StatusInternalServerError)  		} -		return +		return nil  	}  	var waitGroup sync.WaitGroup @@ -407,19 +631,26 @@ func PriceHandler(writer http.ResponseWriter, request *http.Request) {  	if err != nil {  		log.Error().Err(err)  		http.Error(writer, "internal server error", http.StatusInternalServerError) + +		return err  	} + +	return nil  } -func PairHandler(w http.ResponseWriter, r *http.Request) { +func (aw appWrapper) PairHandler(echoCtx echo.Context) error {  	var err error -	w.Header().Add("Content-Type", "application/json") +	writer := echoCtx.Response().Writer +	request := echoCtx.Request() -	if r.Method != http.MethodGet { -		http.Error(w, "Method is not supported.", http.StatusNotFound) +	writer.Header().Add("Content-Type", "application/json") + +	if request.Method != http.MethodGet { +		http.Error(writer, "Method is not supported.", http.StatusNotFound)  	} -	addSecureHeaders(&w) +	addSecureHeaders(&writer)  	var one string @@ -427,7 +658,7 @@ func PairHandler(w http.ResponseWriter, r *http.Request) {  	var multiplier float64 -	params := r.URL.Query() +	params := request.URL.Query()  	for key, value := range params {  		switch key {  		case "one": @@ -456,7 +687,7 @@ func PairHandler(w http.ResponseWriter, r *http.Request) {  	defer close(priceChan)  	defer close(errChan) -	ctx, cancel := context.WithTimeout(r.Context(), getTimeout*time.Second) +	ctx, cancel := context.WithTimeout(request.Context(), getTimeout*time.Second)  	defer cancel()  	waitGroup.Add(2) //nolint: mnd,gomnd @@ -500,11 +731,15 @@ func PairHandler(w http.ResponseWriter, r *http.Request) {  	log.Info().Msg(fmt.Sprintf("%v", ratio)) -	err = json.NewEncoder(w).Encode(map[string]interface{}{"ratio": ratio}) +	err = json.NewEncoder(writer).Encode(map[string]interface{}{"ratio": ratio})  	if err != nil {  		log.Error().Err(err).Send() -		http.Error(w, "internal server error", http.StatusInternalServerError) +		http.Error(writer, "internal server error", http.StatusInternalServerError) + +		return err  	} + +	return nil  }  type alertType struct { @@ -563,7 +798,7 @@ func getTickers() tickersType {  	return tickers  } -func alertManagerWorker(alert alertType) { +func alertManagerWorker(alert alertType, tgChannelID int64) {  	expression, err := govaluate.NewEvaluableExpression(alert.Expr)  	if err != nil {  		log.Error().Err(err) @@ -633,47 +868,44 @@ func alertManagerWorker(alert alertType) {  		return  	} -	token := os.Getenv(telegramBotTokenEnvVar)  	msgText := "notification " + alert.Expr + " has been triggered" -	tokenInt, err := strconv.ParseInt(token[1:len(token)-1], 10, 64) -  	if err == nil {  		log.Error().Err(err)  	} -	sendToTg("telebot:8000", msgText, tokenInt) +	sendToTg(msgText, tgChannelID)  } -func alertManager(alertsCheckInterval int64) { +func alertManager(alertsCheckInterval int64, tgChannelID int64) {  	for {  		alerts := getAlerts()  		log.Info().Msg(fmt.Sprintf("%v", alerts))  		for alertIndex := range alerts.Alerts { -			go alertManagerWorker(alerts.Alerts[alertIndex]) +			go alertManagerWorker(alerts.Alerts[alertIndex], tgChannelID)  		}  		time.Sleep(time.Second * time.Duration(alertsCheckInterval))  	}  } -func tickerManager(tickerCheckInterval int64) { +func tickerManager(tickerCheckInterval int64, tgChannelID int64) {  	for {  		tickers := getTickers()  		log.Info().Msg(fmt.Sprintf("%v", tickers))  		for tickerIndex := range tickers.Tickers { -			go tickerManagerWorker(tickers.Tickers[tickerIndex]) +			go tickerManagerWorker(tickers.Tickers[tickerIndex], tgChannelID)  		}  		time.Sleep(time.Second * time.Duration(tickerCheckInterval))  	}  } -func tickerManagerWorker(ticker tickerType) { +func tickerManagerWorker(ticker tickerType, tgChannelID int64) {  	var waitGroup sync.WaitGroup  	priceChan := make(chan priceChanStruct, 1) @@ -707,17 +939,11 @@ func tickerManagerWorker(ticker tickerType) {  		log.Error().Err(errBadLogic)  	} -	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)  	log.Print(msgText) -	if err == nil { -		log.Error().Err(err) -	} - -	sendToTg("telebot:8000", msgText, tokenInt) +	sendToTg(msgText, tgChannelID)  }  type addAlertJSONType struct { @@ -729,7 +955,10 @@ type tickerJSONType struct {  	Name string `json:"name"`  } -func tickerHandler(writer http.ResponseWriter, request *http.Request) { +func (aw appWrapper) tickerHandler(echoCtx echo.Context) error { +	writer := echoCtx.Response().Writer +	request := echoCtx.Request() +  	addSecureHeaders(&writer)  	handler := Handler{rdb: rdb} @@ -748,9 +977,13 @@ func tickerHandler(writer http.ResponseWriter, request *http.Request) {  	default:  		http.Error(writer, "Method is not supported.", http.StatusNotFound)  	} + +	return nil  } -func healthHandler(writer http.ResponseWriter, request *http.Request) { +func (aw appWrapper) healthHandler(echoCtx echo.Context) error { +	writer := echoCtx.Response().Writer +	request := echoCtx.Request()  	var RedisError string  	var HivedError string @@ -799,117 +1032,197 @@ func healthHandler(writer http.ResponseWriter, request *http.Request) {  	if request.Method != http.MethodGet {  		http.Error(writer, "internal server error", http.StatusInternalServerError)  		log.Error().Err(err) + +		return err  	} + +	return nil  } -func robotsHandler(writer http.ResponseWriter, _ *http.Request) { -	writer.Header().Add("Content-Type", "text/plain") -	addSecureHeaders(&writer) +func setupLogging() { +	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix +} -	_, err := writer.Write([]byte("User-Agents: *\nDisallow: /\n")) +func (aw appWrapper) postHandler(context echo.Context) error { +	user, pass, ok := context.Request().BasicAuth() +	if !ok { +		return context.JSON(http.StatusUnauthorized, "unauthorized") //nolint: wrapcheck +	} + +	userRecord, err := aw.app.Dao().FindAuthRecordByUsername("users", user)  	if err != nil { -		log.Error().Err(err) +		return context.JSON(http.StatusUnauthorized, "unauthorized") //nolint: wrapcheck  	} -	http.Error(writer, "internal server error", http.StatusInternalServerError) -} +	if !userRecord.ValidatePassword(pass) { +		return context.JSON(http.StatusUnauthorized, "unauthorized") //nolint: wrapcheck +	} -func startServer(gracefulWait time.Duration, flagPort string) { -	router := mux.NewRouter() +	return context.JSON(http.StatusOK, "OK") //nolint: wrapcheck +} -	cfg := &tls.Config{ -		MinVersion:               tls.VersionTLS13, -		PreferServerCipherSuites: true, +func defaultPublicDir() string { +	if strings.HasPrefix(os.Args[0], os.TempDir()) { +		return "./pb_public"  	} -	srv := &http.Server{ -		Addr:         "0.0.0.0:" + flagPort, -		WriteTimeout: time.Second * serverTLSWriteTimeout, -		ReadTimeout:  time.Second * serverTLSReadTimeout, -		Handler:      router, -		TLSConfig:    cfg, -	} +	return filepath.Join(os.Args[0], "../pb_public") +} -	router.HandleFunc("/crypto/v1/health", healthHandler) -	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) +func setRootCmds(app *pocketbase.PocketBase) RootCmds { +	var rootCmds RootCmds -	go func() { -		var certPath, keyPath string +	app.RootCmd.PersistentFlags().StringVar( +		&rootCmds.hooksDir, +		"hooksDir", +		"", +		"the directory with the JS app hooks", +	) -		switch os.Getenv(serverDeploymentType) { -		case "deployment": -			certPath = "/etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem" -			keyPath = "/etc/letsencrypt/live/api.terminaldweller.com/privkey.pem" -		case "test": -			certPath = "/certs/server.cert" -			keyPath = "/certs/server.key" -		default: -			log.Fatal().Err(errUnknownDeploymentKind) -		} +	app.RootCmd.PersistentFlags().BoolVar( +		&rootCmds.hooksWatch, +		"hooksWatch", +		true, +		"auto restart the app on pb_hooks file change", +	) -		if err := srv.ListenAndServeTLS(certPath, keyPath); err != nil { -			log.Fatal().Err(err).Send() -		} -	}() +	app.RootCmd.PersistentFlags().IntVar( +		&rootCmds.hooksPool, +		"hooksPool", +		25, +		"the total prewarm goja.Runtime instances for the JS app hooks execution", +	) -	c := make(chan os.Signal, 1) +	app.RootCmd.PersistentFlags().StringVar( +		&rootCmds.migrationsDir, +		"migrationsDir", +		"", +		"the directory with the user defined migrations", +	) -	signal.Notify(c, os.Interrupt) -	<-c +	app.RootCmd.PersistentFlags().BoolVar( +		&rootCmds.automigrate, +		"automigrate", +		true, +		"enable/disable auto migrations", +	) -	ctx, cancel := context.WithTimeout(context.Background(), gracefulWait) -	defer cancel() +	app.RootCmd.PersistentFlags().StringVar( +		&rootCmds.publicDir, +		"publicDir", +		defaultPublicDir(), +		"the directory to serve static files", +	) -	if err := srv.Shutdown(ctx); err != nil { -		log.Error().Err(err) -	} else { -		log.Info().Msg("gracefully shut down the server") -	} +	app.RootCmd.PersistentFlags().BoolVar( +		&rootCmds.indexFallback, +		"indexFallback", +		true, +		"fallback the request to index.html on missing static path (eg. when pretty urls are used with SPA)", +	) + +	app.RootCmd.PersistentFlags().IntVar( +		&rootCmds.queryTimeout, +		"queryTimeout", +		30, +		"the default SELECT queries timeout in seconds", +	) + +	return rootCmds  } -func setupLogging() { -	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix +func startPocketbaseApp() { +	app := pocketbase.New() + +	aw := appWrapper{app: app} + +	app.OnBeforeServe().Add(func(e *core.ServeEvent) error { +		e.Router.POST("/", aw.postHandler) +		e.Router.GET("/health", aw.healthHandler) +		e.Router.GET("/api/crypto/v1/price", aw.PriceHandler) +		e.Router.GET("/api/crypto/v1/pair", aw.PairHandler) + +		e.Router.GET("/api/crypto/v1/alert", aw.alertHandler) +		e.Router.PUT("/api/crypto/v1/alert", aw.alertHandler) +		e.Router.POST("/api/crypto/v1/alert", aw.alertHandler) +		e.Router.PATCH("/api/crypto/v1/alert", aw.alertHandler) +		e.Router.DELETE("/api/crypto/v1/alert", aw.alertHandler) + +		e.Router.GET("/api/crypto/v1/ticker", aw.tickerHandler) +		e.Router.PUT("/api/crypto/v1/ticker", aw.tickerHandler) +		e.Router.POST("/api/crypto/v1/ticker", aw.tickerHandler) +		e.Router.PATCH("/api/crypto/v1/ticker", aw.tickerHandler) +		e.Router.DELETE("/api/crypto/v1/ticker", aw.tickerHandler) + +		return nil +	}) + +	rootCmds := setRootCmds(app) + +	err := app.RootCmd.ParseFlags(os.Args[1:]) +	if err != nil { +		log.Fatal().Err(err) +	} + +	jsvm.MustRegister(app, jsvm.Config{ +		MigrationsDir: rootCmds.migrationsDir, +		HooksDir:      rootCmds.hooksDir, +		HooksWatch:    rootCmds.hooksWatch, +		HooksPoolSize: rootCmds.hooksPoolSize, +	}) + +	migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{ +		TemplateLang: migratecmd.TemplateLangJS, +		Automigrate:  rootCmds.automigrate, +		Dir:          rootCmds.migrationsDir, +	}) + +	ghupdate.MustRegister(app, app.RootCmd, ghupdate.Config{}) + +	app.OnAfterBootstrap().PreAdd(func(_ *core.BootstrapEvent) error { +		app.Dao().ModelQueryTimeout = time.Duration(rootCmds.queryTimeout) * time.Second + +		return nil +	}) + +	app.OnBeforeServe().Add(func(e *core.ServeEvent) error { +		e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS(rootCmds.publicDir), rootCmds.indexFallback)) + +		return nil +	}) + +	if err := app.Start(); err != nil { +		log.Fatal().Err(err) +	}  }  func main() { -	var gracefulWait time.Duration - -	flagPort := flag.String("port", "8008", "determined the port the sercice runs on") -	redisAddress := flag.String("redisaddress", "redis:6379", "determines the address of the redis instance") -	redisPassword := flag.String("redispassword", "", "determines the password of the redis db") -	redisDB := flag.Int64("redisdb", 0, "determines the db number") -	alertsCheckInterval := flag.Int64( -		"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", -		time.Second*defaultGracefulShutdown, -		"the duration to wait during the graceful shutdown") - -	flag.Parse() +	data, err := os.ReadFile("/hived/hived.toml") +	if err != nil { +		log.Fatal().Err(err) +	} + +	var config HivedConfig + +	_, err = toml.Decode(string(data), &config) +	if err != nil { +		log.Fatal().Err(err) +	} + +	fmt.Println("XXX:", config)  	rdb = redis.NewClient(&redis.Options{ -		Addr:     *redisAddress, -		Password: *redisPassword, -		DB:       int(*redisDB), +		Addr:     config.KeydbAddress, +		Password: config.KeydbPassword, +		DB:       config.KeydbDB,  	})  	defer rdb.Close()  	setupLogging() -	go alertManager(*alertsCheckInterval) +	go alertManager(config.AlertsCheckInterval, config.TelegramChannelID) -	go tickerManager(*tickerCheckInterval) +	go tickerManager(config.TickerCheckInterval, config.TelegramChannelID) -	startServer(gracefulWait, *flagPort) +	startPocketbaseApp()  } diff --git a/hived/hived.toml b/hived/hived.toml new file mode 100644 index 0000000..abddb19 --- /dev/null +++ b/hived/hived.toml @@ -0,0 +1,7 @@ +keydbAddress = "keydb:6379" +keydbPassword = "" +keydbDB = 0 +alertsCheckInterval = 600 +tickerCheckInterval = 600 +cacheDuration = 600 +telegramChannelID =  diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..f6afdd2 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,35 @@ +events { +  worker_connections 1024; +} + +http { +  include /etc/nginx/mime.types; +  server_tokens off; +  limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m; +  server { +    listen 443 ssl; +    keepalive_timeout 60; +    charset utf-8; +    ssl_certificate /etc/letsencrypt/live/api.terminaldweller.com/fullchain.pem; +    ssl_certificate_key /etc/letsencrypt/live/api.terminaldweller.com/privkey.pem; +    ssl_ciphers HIGH:!aNULL:!MD5:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; +    ssl_protocols TLSv1.3; +    ssl_session_cache shared:SSL:50m; +    ssl_session_timeout 1d; +    ssl_session_tickets off; +    ssl_prefer_server_ciphers on; +    sendfile on; +    tcp_nopush on; +    add_header X-Content-Type-Options "nosniff" always; +    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; +    add_header X-Frame-Options SAMEORIGIN always; +    add_header X-XSS-Protection "1; mode=block" always; +    add_header Referrer-Policy "no-referrer"; +    fastcgi_hide_header X-Powered-By; + +    error_page 401 403 404 /404.html; +    location / { +      proxy_pass http://hived:8090; +    } +  } +} diff --git a/telebot/.golangci.yml b/telebot/.golangci.yml deleted file mode 100644 index c31a774..0000000 --- a/telebot/.golangci.yml +++ /dev/null @@ -1,19 +0,0 @@ -run: -  concurrency: 16 -  timeout: 5m -  modules-download-mode: readonly -  allow-parallel-runners: true -  allow-serial-runners: true -  go: '1.22' -linters-settings: -  depguard: -    rules: -      srcs: -        listMode: "Strict" -        allow: -        - $gostd -        - github.com/go-telegram-bot-api/telegram-bot-api -        - github.com/rs/zerolog/log -        - github.com/terminaldweller/grpc/telebot/v1 -        - golang.org/x/net/proxy -        - google.golang.org/grpc diff --git a/telebot/Dockerfile b/telebot/Dockerfile deleted file mode 100644 index 5b573f1..0000000 --- a/telebot/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM golang:1.22-alpine3.19 as builder -RUN apk update && apk upgrade -RUN apk add go git -COPY go.* /telebot/ -RUN cd /telebot && go mod download -COPY *.go /telebot/ -RUN cd /telebot && go build - -FROM alpine:3.19 as certbuilder -RUN apk add openssl -WORKDIR /certs -RUN openssl req -nodes -new -x509 -subj="/C=US/ST=Denial/L=springfield/O=Dis/CN=localhost" -keyout server.key -out server.cert - -# FROM gcr.io/distroless/static-debian10 -FROM alpine:3.19 -COPY --from=certbuilder /certs /certs -COPY --from=builder /telebot/telebot /telebot/ -COPY ./docker-entrypoint.sh /telebot/ -ENV ALL_PROXY= -ENV HTTPS_PROXY= -ENTRYPOINT ["/telebot/docker-entrypoint.sh"] diff --git a/telebot/docker-entrypoint.sh b/telebot/docker-entrypoint.sh deleted file mode 100755 index c2a6d0a..0000000 --- a/telebot/docker-entrypoint.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env sh -set -ex - -export $(cat /run/secrets/tg_bot_token) - -"/telebot/telebot" "$@" diff --git a/telebot/go.mod b/telebot/go.mod deleted file mode 100644 index 32444e9..0000000 --- a/telebot/go.mod +++ /dev/null @@ -1,22 +0,0 @@ -module telebot - -go 1.22 - -require ( -	github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible -	github.com/rs/zerolog v1.31.0 -	github.com/terminaldweller/grpc v1.0.3 -	golang.org/x/net v0.19.0 -	google.golang.org/grpc v1.59.0 -) - -require ( -	github.com/golang/protobuf v1.5.3 // indirect -	github.com/mattn/go-colorable v0.1.13 // indirect -	github.com/mattn/go-isatty v0.0.20 // indirect -	github.com/technoweenie/multipartstreamer v1.0.1 // indirect -	golang.org/x/sys v0.15.0 // indirect -	golang.org/x/text v0.14.0 // indirect -	google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect -	google.golang.org/protobuf v1.31.0 // indirect -) diff --git a/telebot/go.sum b/telebot/go.sum deleted file mode 100644 index d720e6d..0000000 --- a/telebot/go.sum +++ /dev/null @@ -1,149 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= -github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= -github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= -github.com/terminaldweller/grpc v1.0.3 h1:yCRm0HKRD4M87CBmmO5KjkSFRq4X2lzHLJRH1ApzeiE= -github.com/terminaldweller/grpc v1.0.3/go.mod h1:pYpuXZw8rHZwTABVEVZEfErFr+PyEhAaSrFm7y1yvTo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/telebot/telebot.go b/telebot/telebot.go deleted file mode 100644 index 91eebcb..0000000 --- a/telebot/telebot.go +++ /dev/null @@ -1,167 +0,0 @@ -package main - -import ( -	"context" -	"flag" -	"fmt" -	"net" -	"net/http" -	"os" -	"strconv" -	"time" - -	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" -	"github.com/rs/zerolog/log" -	pb "github.com/terminaldweller/grpc/telebot/v1" -	"golang.org/x/net/proxy" -	"google.golang.org/grpc" -) - -var botChannelID = flag.Int64( -	"botchannelid", -	146328407, //nolint: mnd,gomnd -	"determines the channel id the telgram bot should send messages to") - -const ( -	telegramBotTokenEnvVar = "TELEGRAM_BOT_TOKEN" //nolint: gosec -	httpClientTimeout      = 5 -) - -type server struct { -	pb.UnimplementedNotificationServiceServer -} - -func GetProxiedClient() (*http.Client, error) { -	var isProxied bool - -	proxyURL := os.Getenv("ALL_PROXY") -	if proxyURL == "" { -		proxyURL = os.Getenv("HTTPS_PROXY") -	} - -	if proxyURL == "" { -		isProxied = false -	} - -	var dialerProxy proxy.Dialer - -	var dialer net.Dialer - -	var err error - -	if isProxied { -		dialerProxy, err = proxy.SOCKS5("tcp", proxyURL, nil, proxy.Direct) -		if err != nil { -			return nil, fmt.Errorf("[GetProxiedClient] : %w", err) -		} -	} else { -		dialer = net.Dialer{ -			Timeout: 5 * time.Second, //nolint: mnd,gomnd -		} - -		if err != nil { -			return nil, fmt.Errorf("[GetProxiedClient] : %w", err) -		} -	} - -	dialContext := func(ctx context.Context, network, address string) (net.Conn, error) { -		if isProxied { -			netConn, err := dialerProxy.Dial(network, address) -			if err == nil { -				return netConn, nil -			} - -			return netConn, fmt.Errorf("[dialContext] : %w", err) -		} else { -			netConn, err := dialer.Dial(network, address) -			if err == nil { -				return netConn, nil -			} - -			return netConn, fmt.Errorf("[dialContext] : %w", err) -		} -	} - -	transport := &http.Transport{ -		DialContext:       dialContext, -		DisableKeepAlives: true, -	} -	client := &http.Client{ -		Transport:     transport, -		Timeout:       httpClientTimeout * time.Second, -		CheckRedirect: nil, -		Jar:           nil, -	} - -	return client, nil -} - -func getTGBot() *tgbotapi.BotAPI { -	token := os.Getenv(telegramBotTokenEnvVar) - -	// client, err := GetProxiedClient() -	// if err != nil { -	// 	log.Fatal().Err(err) -	// } - -	// bot, err := tgbotapi.NewBotAPIWithClient(token[1:len(token)-1], client) -	bot, err := tgbotapi.NewBotAPI(token[1 : len(token)-1]) -	if err != nil { -		log.Fatal().Err(err).Send() -	} - -	return bot -} - -func sendMessage(bot *tgbotapi.BotAPI, msgText string, channelID int64) error { -	msg := tgbotapi.NewMessage(channelID, msgText) -	_, err := bot.Send(msg) - -	return err -} - -func (s *server) Notify( -	ctx context.Context, -	NotificationRequest *pb.NotificationRequest, -) (*pb.NotificationResponse, error) { -	var err error - -	tgbotapi := getTGBot() - -	if NotificationRequest.ChannelId == 0 { -		err = sendMessage(tgbotapi, NotificationRequest.NotificationText, *botChannelID) -	} else { -		err = sendMessage(tgbotapi, NotificationRequest.NotificationText, NotificationRequest.ChannelId) -	} - -	if err != nil { -		return &pb.NotificationResponse{Error: err.Error(), IsOK: false}, err -	} - -	return &pb.NotificationResponse{Error: "", IsOK: true}, nil -} - -func startServer(port uint16) { -	listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) -	if err != nil { -		log.Fatal().Err(err).Send() -	} - -	var opts []grpc.ServerOption - -	grpcServer := grpc.NewServer(opts...) -	pb.RegisterNotificationServiceServer(grpcServer, &server{}) - -	if err := grpcServer.Serve(listener); err != nil { -		log.Fatal().Err(err).Send() -	} -} - -func main() { -	flagPort := flag.String("port", "8000", "determines the port the service runs on") -	flag.Parse() - -	port, _ := strconv.Atoi(*flagPort) - -	startServer(uint16(port)) -} diff --git a/test/endpoints.sh b/test/endpoints.sh index 2b73614..0e7a96c 100755 --- a/test/endpoints.sh +++ b/test/endpoints.sh @@ -1,22 +1,23 @@ -#!/usr/bin/env sh -set -e -set -x +#!/bin/sh +set -ex -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 "https://localhost:8009/crypto/v1/arb/gecko?name=ethereum&unit=usd" +# curl -k -X GET "https://localhost:8009/crypto/v1/arb/coincap?name=ethereum" +curl -k -X GET "https://localhost:10008/api/crypto/v1/price?name=PEPE&unit=USD" +curl -k -X GET "https://localhost:10008/api/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/api/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 +curl -k -X GET -H "Content-Type: application/json" "https://localhost:10008/api/crypto/v1/alert?key=alert1" +curl -k -X DELETE -H "Content-Type: application/json" "https://localhost:10008/api/crypto/v1/alert?key=alert1" +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"alert1", "expr":"ETH>CAKE"}' https://localhost:10008/api/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 +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"ETH"}' https://localhost:10008/api/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"BTC"}' https://localhost:10008/api/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"XMR"}' https://localhost:10008/api/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"STX"}' https://localhost:10008/api/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"LINK"}' https://localhost:10008/api/crypto/v1/ticker +curl -k -X POST -H "Content-Type: application/json" -d '{"name":"PEPE"}' https://localhost:10008/api/crypto/v1/ticker +curl -k -X GET -H "Content-Type: application/json" https://localhost:10008/api/crypto/v1/ticker?key=ETH +curl -k -X DELETE -H "Content-Type: application/json" https://localhost:10008/api/crypto/v1/ticker?key=ETH  | 
