Skip to content

Commit

Permalink
Merge pull request #1 from maZahaca/feature-improved-easyjson-generation
Browse files Browse the repository at this point in the history
easyjson improvements
  • Loading branch information
maZahaca committed Mar 13, 2019
2 parents 646fe16 + 0166b51 commit 58fdb2d
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 203 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Original file line Diff line number Diff line change
@@ -1 +1,2 @@
.idea .idea
*_easyjson.go
17 changes: 11 additions & 6 deletions Dockerfile
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
# STEP 1 build executable binary # STEP 1 build executable binary
############################ ############################
# golang alpine 1.11.5 # golang alpine 1.11.5
FROM golang@sha256:8dea7186cf96e6072c23bcbac842d140fe0186758bcc215acb1745f584984857 as builder #FROM golang:1.11.4-alpine3.8 as builder

FROM golang:1.11.5-alpine3.8 as builder
ENV GO111MODULE=on


# Install git + SSL ca certificates. # Install git + SSL ca certificates.
# Git is required for fetching the dependencies. # Git is required for fetching the dependencies.
# Ca-certificates is required to call HTTPS endpoints. # Ca-certificates is required to call HTTPS endpoints.
RUN apk update && apk add --no-cache git ca-certificates tzdata && update-ca-certificates RUN apk add --update --no-cache make bash git openssh-client ca-certificates build-base musl-dev curl wget tzdata \
&& update-ca-certificates \
&& go get -u github.com/mailru/easyjson/easyjson

ENV GO111MODULE=on


# Create appuser # Create appuser
RUN adduser -D -g '' appuser RUN adduser -D -g '' appuser
Expand All @@ -22,9 +25,11 @@ COPY . .
# Using go mod. # Using go mod.
RUN go mod download RUN go mod download


# Generate easyjson files
RUN go generate ./dto/*

# Build the binary # Build the binary
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -installsuffix cgo -o /go/bin/exchange-rates-server RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -installsuffix cgo -o /go/bin/exchange-rates-server
#RUN go build -o /go/bin/exchange-rates-server


############################ ############################
# STEP 2 build a small image # STEP 2 build a small image
Expand All @@ -43,4 +48,4 @@ COPY --from=builder /go/bin/exchange-rates-server /go/bin/exchange-rates-server
USER appuser USER appuser


# Run binary. # Run binary.
ENTRYPOINT ["/go/bin/exchange-rates-server", "--base", "USD", "--", "GBP", "EUR", "CAD", "RUB", "CHF", "BTC", "ETH", "ETC"] ENTRYPOINT ["/go/bin/exchange-rates-server", "--base", "USD", "--", "GBP", "EUR", "CAD", "RUB", "CHF", "BTC", "ETH", "ETC", "ALF", "AGS", "AMC", "APEX", "ARCH", "ARI", "BCX", "BET", "BLK"]
28 changes: 28 additions & 0 deletions Makefile
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,28 @@
VERSION=`git rev-parse HEAD`
BUILD=`date +%FT%T%z`
LDFLAGS=-ldflags "-X main.Version=${VERSION} -X main.Build=${BUILD}"

.PHONY: help
help: ## - Show help message
@printf "\033[32m\xE2\x9c\x93 usage: make [target]\n\n\033[0m"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

.PHONY: build
build: ## - Build the smallest and secured golang docker image based on scratch
@printf "\033[32m\xE2\x9c\x93 Build the smallest and secured golang docker image based on scratch\n\033[0m"
@docker build -f Dockerfile -t exchange-rates-server .

.PHONY: build-no-cache
build-no-cache: ## - Build the smallest and secured golang docker image based on scratch with no cache
@printf "\033[32m\xE2\x9c\x93 Build the smallest and secured golang docker image based on scratch\n\033[0m"
@docker build --no-cache -f Dockerfile -t exchange-rates-server .

.PHONY: ls
ls: ## - List 'exchange-rates-server' docker images
@printf "\033[32m\xE2\x9c\x93 Look at the size dude !\n\033[0m"
@docker image ls exchange-rates-server

.PHONY: run
run: ## - Run the smallest and secured golang docker image based on scratch
@printf "\033[32m\xE2\x9c\x93 Run the smallest and secured golang docker image based on scratch\n\033[0m"
@docker run -p 8000:8000 exchange-rates-server:latest
20 changes: 19 additions & 1 deletion dto/Rates.go
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,10 @@
//go:generate easyjson -all
package dto package dto


import "sync" import (
"errors"
"sync"
)


//easyjson:json //easyjson:json
type Rates struct { type Rates struct {
Expand All @@ -21,3 +25,17 @@ func (r *Rates) Add(currency string, rate float32) {
r.Items[currency] = rate r.Items[currency] = rate
r.mu.Unlock() r.mu.Unlock()
} }

func (r *Rates) AddFromMap(jsonMap map[string]map[string]float32) error {
r.mu.Lock()
for currency, rate := range jsonMap {
var value float32
var ok bool
if value, ok = rate[r.Base]; !ok {
return errors.New("cannot fetch rate by base currency")
}
r.Items[currency] = 1 / value
}
r.mu.Unlock()
return nil
}
136 changes: 0 additions & 136 deletions dto/dto_easyjson.go

This file was deleted.

100 changes: 41 additions & 59 deletions main.go
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,107 +2,89 @@ package main


import ( import (
"bytes" "bytes"
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/maZahaca/go-exchange-rates-service/dto" "github.com/maZahaca/go-exchange-rates-service/pkg"
"io/ioutil"
"log" "log"
"net/http" "net/http"
"os"
"strconv"
"time" "time"
) )


var ( var (
baseCurrency = flag.String("base", "USD", "base currency to get rates base on it") baseCurrency = flag.String("base", "USD", "base currency to get rates base on it")
urlsChunk = 3
) )


func main() { func main() {
flag.Parse() flag.Parse()


var buf bytes.Buffer urlsChunk, err := strconv.ParseInt(getEnv("URL_CHUNKS", "3"), 10, 8)
var urls []string if err != nil {
args := flag.Args() log.Fatal(err)
for i := 1; i <= len(args); i++ { }
buf.WriteString(args[i-1]) urls, err := getUrlsFromArgs(flag.Args(), urlsChunk, *baseCurrency)
if i%urlsChunk == 0 || i == len(args) { if err != nil {
log.Println("i=", i) log.Fatal(err)
urls = append(
urls,
fmt.Sprintf("https://min-api.cryptocompare.com/data/pricemulti?fsyms=%s&tsyms=%s",
buf.String(), *baseCurrency),
)
buf.Reset()
continue
}
buf.WriteString(",")
} }


rates := dto.NewRates(*baseCurrency) manager := pkg.NewRatesManager(*baseCurrency, urls)

manager.Update()
updateRates(urls, *rates)


go func() { go func() {
for { for {
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
updateRates(urls, *rates) manager.Update()
} }
}() }()


r := mux.NewRouter() r := mux.NewRouter()


r.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { r.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
rawResponse, err := rates.MarshalJSON() rawResponse, err := manager.Get().MarshalJSON()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
writer.Write(rawResponse) if _, err = writer.Write(rawResponse); err != nil {
log.Fatal(err)
}
}) })


port := getEnv("PORT", "8000")
srv := &http.Server{ srv := &http.Server{
Handler: r, Handler: r,
Addr: ":8000", Addr: fmt.Sprintf(":%s", port),
// Good practice: enforce timeouts for servers you create!
WriteTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second,
} }


log.Fatal(srv.ListenAndServe()) log.Fatal(srv.ListenAndServe())
} }


func updateRates(urls []string, rates dto.Rates) { func getEnv(key string, defaultVal string) string {
done := make(chan string, len(urls)) val, ok := os.LookupEnv(key)

if !ok {
for i := 0; i < len(urls); i++ { return defaultVal
go fetch(urls[i], done)
}

for i := 0; i < len(urls); i++ {
res := <-done
jsonMap := make(map[string]map[string]float32)
err := json.Unmarshal([]byte(res), &jsonMap)
if err != nil {
panic(err)
}
for currency, rate := range jsonMap {
rates.Add(currency, 1/rate[*baseCurrency])
}
log.Println(rates)
log.Printf("Fetched result: %s", res)
} }
return val
} }


func fetch(url string, done chan string) { func getUrlsFromArgs(args []string, urlsChunk int64, base string) ([]string, error) {
log.Printf("fetching url: %s", url) var buf bytes.Buffer
resp, err := http.Get(url) var urls []string
defer resp.Body.Close() for i := 1; i <= len(args); i++ {
if err != nil { buf.WriteString(args[i-1])
log.Fatalf("Cannot fetch url: %+q", err) if i%int(urlsChunk) == 0 || i == len(args) {
} urls = append(
bodyBytes, err := ioutil.ReadAll(resp.Body) urls,
if err != nil { fmt.Sprintf("https://min-api.cryptocompare.com/data/pricemulti?fsyms=%s&tsyms=%s",
log.Fatalf("Cannot read response: %+q", err) buf.String(), base),
)
buf.Reset()
continue
}
buf.WriteString(",")
} }
done <- string(bodyBytes) return urls, nil
} }
Loading

0 comments on commit 58fdb2d

Please sign in to comment.