aboutsummaryrefslogtreecommitdiffstats
path: root/arbiter
diff options
context:
space:
mode:
Diffstat (limited to 'arbiter')
-rw-r--r--arbiter/Dockerfile6
-rw-r--r--arbiter/arbiter.go165
-rwxr-xr-xarbiter/tests.sh3
3 files changed, 150 insertions, 24 deletions
diff --git a/arbiter/Dockerfile b/arbiter/Dockerfile
index fe3fb31..849b345 100644
--- a/arbiter/Dockerfile
+++ b/arbiter/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.13 as builder
+FROM alpine:3.16 as builder
ENV GOPROXY=https://goproxy.io
RUN apk update && apk upgrade
RUN apk add go git
@@ -8,13 +8,13 @@ RUN cd /arbiter && go mod download
COPY *.go /arbiter/
RUN cd /arbiter && go build
-FROM alpine:3.15 as certbuilder
+FROM alpine:3.16 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.13
+FROM alpine:3.16
COPY --from=certbuilder /certs /certs
COPY --from=builder /arbiter/arbiter /arbiter/
ENTRYPOINT ["/arbiter/arbiter"]
diff --git a/arbiter/arbiter.go b/arbiter/arbiter.go
index 2806842..9cb3ad0 100644
--- a/arbiter/arbiter.go
+++ b/arbiter/arbiter.go
@@ -3,12 +3,16 @@ package main
import (
"context"
"crypto/tls"
+ "encoding/json"
"errors"
"flag"
"fmt"
+ "io/ioutil"
"net/http"
+ "net/url"
"os"
"os/signal"
+ "sync"
"time"
"github.com/go-redis/redis/v8"
@@ -28,8 +32,26 @@ var (
const (
SERVER_DEPLOYMENT_TYPE = "SERVER_DEPLOYMENT_TYPE"
+ coingeckoAPIURLv3 = "https://api.coingecko.com/api/v3"
)
+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
+}
+
// OWASP: https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html
func addSecureHeaders(w *http.ResponseWriter) {
(*w).Header().Set("Cache-Control", "no-store")
@@ -40,49 +62,152 @@ func addSecureHeaders(w *http.ResponseWriter) {
(*w).Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
}
+//binance
+func getPriceFromBinance(name, unit string,
+ wg *sync.WaitGroup,
+ priceChan chan<- priceChanStruct,
+ errChan chan<- errorChanStruct) {
+
+}
+
+//kucoin
+func getPriceFromKu(name, uni string,
+ wg *sync.WaitGroup,
+ priceChan chan<- priceChanStruct,
+ errChan chan<- errorChanStruct) {
+
+}
+
+func getPriceFromCoinGecko(
+ name, unit string,
+ wg *sync.WaitGroup,
+ priceChan chan<- priceChanStruct,
+ errChan chan<- errorChanStruct) {
+ defer wg.Done()
+
+ params := "/simple/price?ids=" + url.QueryEscape(name) + "&" +
+ "vs_currencies=" + url.QueryEscape(unit)
+ path := coingeckoAPIURLv3 + params
+ fmt.Println(path)
+ resp, err := http.Get(path)
+ if err != nil {
+ priceChan <- priceChanStruct{name: name, price: 0.}
+ errChan <- errorChanStruct{hasError: true, err: err}
+ log.Error().Err(err)
+ }
+ defer resp.Body.Close()
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ priceChan <- priceChanStruct{name: name, price: 0.}
+ errChan <- errorChanStruct{hasError: true, err: err}
+ log.Error().Err(err)
+ }
+
+ jsonBody := make(map[string]interface{})
+ err = json.Unmarshal(body, &jsonBody)
+ if err != nil {
+ priceChan <- priceChanStruct{name: name, price: 0.}
+ errChan <- errorChanStruct{hasError: true, err: err}
+ log.Error().Err(err)
+ }
+
+ price := jsonBody[name].(map[string]interface{})[unit].(float64)
+
+ log.Info().Msg(string(body))
+
+ priceChan <- priceChanStruct{name: name, price: price}
+ errChan <- errorChanStruct{hasError: false, err: nil}
+}
+
func arbHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
if r.Method != "GET" {
http.Error(w, "Method is not supported.", http.StatusNotFound)
}
addSecureHeaders(&w)
- //binance
- //kucoin
+
+ 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(errors.New("Got unexpected parameter."))
+ }
+ }
+
+ priceChan := make(chan priceChanStruct, 1)
+ errChan := make(chan errorChanStruct, 1)
+ var wg sync.WaitGroup
+ wg.Add(1)
+ getPriceFromCoinGecko(name, unit, &wg, priceChan, errChan)
+ wg.Wait()
+
+ select {
+ case err := <-errChan:
+ if err.hasError != false {
+ log.Error().Err(err.err)
+ }
+ default:
+ log.Error().Err(errors.New("We shouldnt be here"))
+ }
+
+ var price priceChanStruct
+ select {
+ case priceCh := <-priceChan:
+ price = priceCh
+ default:
+ log.Fatal().Err(errors.New("We shouldnt be here"))
+ }
+
+ json.NewEncoder(w).Encode(map[string]interface{}{
+ "name": price.name,
+ "price": price.price,
+ "unit": unit,
+ "err": "",
+ "isSuccessful": true,
+ })
}
-func startServer(gracefulWait time.Duration) {
+func setupLogging() {
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
+}
+
+func startServer(gracefulWait time.Duration,
+ handlers []HttpHandler,
+ serverDeploymentType string, port string) {
r := mux.NewRouter()
cfg := &tls.Config{
MinVersion: tls.VersionTLS13,
- // CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
- // PreferServerCipherSuites: true,
- // CipherSuites: []uint16{
- // tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- // tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- // tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
- // tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- // },
}
srv := &http.Server{
- Addr: "0.0.0.0:" + *flagPort,
+ Addr: "0.0.0.0:" + port,
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
Handler: r,
TLSConfig: cfg,
}
- r.HandleFunc("/crypto/arb", arbHandler)
+
+ for i := 0; i < len(handlers); i++ {
+ r.HandleFunc(handlers[i].name, handlers[i].function)
+ }
go func() {
var certPath, keyPath string
- if os.Getenv(SERVER_DEPLOYMENT_TYPE) == "deployment" {
+ if os.Getenv(serverDeploymentType) == "deployment" {
certPath = "/certs/fullchain1.pem"
keyPath = "/certs/privkey1.pem"
- } else if os.Getenv(SERVER_DEPLOYMENT_TYPE) == "test" {
+ } else if os.Getenv(serverDeploymentType) == "test" {
certPath = "/certs/server.cert"
keyPath = "/certs/server.key"
} else {
- log.Fatal().Err(errors.New(fmt.Sprintf("unknown deployment kind: %s", SERVER_DEPLOYMENT_TYPE)))
+ log.Fatal().Err(errors.New(fmt.Sprintf("unknown deployment kind: %s", serverDeploymentType)))
}
if err := srv.ListenAndServeTLS(certPath, keyPath); err != nil {
log.Fatal().Err(err)
@@ -99,10 +224,6 @@ func startServer(gracefulWait time.Duration) {
log.Info().Msg("gracefully shut down the server")
}
-func setupLogging() {
- zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
-}
-
func main() {
var gracefulWait time.Duration
flag.DurationVar(&gracefulWait, "gracefulwait", time.Second*15, "the duration to wait during the graceful shutdown")
@@ -115,5 +236,7 @@ func main() {
defer rdb.Close()
setupLogging()
- startServer(gracefulWait)
+ var handlerFuncs = []HttpHandler{{name: "/arb", function: arbHandler}}
+
+ startServer(gracefulWait, handlerFuncs, SERVER_DEPLOYMENT_TYPE, *flagPort)
}
diff --git a/arbiter/tests.sh b/arbiter/tests.sh
new file mode 100755
index 0000000..1fe9792
--- /dev/null
+++ b/arbiter/tests.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+
+curl -X GET "https://localhost:8009/arb?name=ethereum&unit=usd"