package server import ( "../client" "../config" "encoding/json" "github.com/auth0/go-jwt-middleware" "github.com/dgrijalva/jwt-go" "github.com/gorilla/mux" "github.com/justinas/alice" "github.com/justinas/nosurf" "github.com/throttled/throttled" "github.com/throttled/throttled/store/memstore" cache "github.com/victorspringer/http-cache" "github.com/victorspringer/http-cache/adapter/memory" "log" "net/http" "strconv" "time" ) func StartServer() { conf := config.LoadConfiguration() port := strconv.Itoa(conf.Port) log.Println("starting server on port " + port) store, err := memstore.New(65536) if err != nil { log.Fatal(err) } quota := throttled.RateQuota{ MaxRate: throttled.PerMin(20), MaxBurst: 30, } rateLimiter, err := throttled.NewGCRARateLimiter(store, quota) if err != nil { log.Fatal(err) } httpRateLimiter := throttled.HTTPRateLimiter{ RateLimiter: rateLimiter, VaryBy: &throttled.VaryBy{Path: true}, } memcached, err := memory.NewAdapter( memory.AdapterWithAlgorithm(memory.LRU), memory.AdapterWithCapacity(10000000), ) if err != nil { log.Fatal(err) } cacheClient, err := cache.NewClient( cache.ClientWithAdapter(memcached), cache.ClientWithTTL(10*time.Minute), cache.ClientWithRefreshKey("opn"), ) if err != nil { log.Fatal(err) } jwtAuth := jwtmiddleware.New(jwtmiddleware.Options{ ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { return []byte(conf.JwtSecret), nil }, SigningMethod: jwt.SigningMethodHS512, }) chain := alice.New(jwtAuth.Handler, timeoutHandler, httpRateLimiter.RateLimit, nosurf.NewPure, cacheClient.Middleware) router := mux.NewRouter() router.HandleFunc("/city/{city}", chain.ThenFunc(cityHandler).ServeHTTP) router.HandleFunc("/coordinates/{latitude},{longitude}", chain.ThenFunc(coordinatesHandler).ServeHTTP) router.HandleFunc("/zip/{zip},{country}", chain.ThenFunc(zipCodeHandler).ServeHTTP) _ = http.ListenAndServe(":"+port, router) } func cityHandler(writer http.ResponseWriter, req *http.Request) { writer.Header().Set("Content-Type", "application/json") vars := mux.Vars(req) data := client.GetByCityName(vars["city"]) writer.WriteHeader(http.StatusOK) _ = json.NewEncoder(writer).Encode(convert(data)) } func coordinatesHandler(writer http.ResponseWriter, req *http.Request) { writer.Header().Set("Content-Type", "application/json") vars := mux.Vars(req) longitude, err := strconv.ParseFloat(vars["longitude"], 32) if err != nil { log.Fatal(err) } latitude, err := strconv.ParseFloat(vars["latitude"], 32) if err != nil { log.Fatal(err) } data := client.GetByCoordinates(longitude, latitude) writer.WriteHeader(http.StatusOK) _ = json.NewEncoder(writer).Encode(convert(data)) } func zipCodeHandler(writer http.ResponseWriter, req *http.Request) { writer.Header().Set("Content-Type", "application/json") vars := mux.Vars(req) zip, err := strconv.Atoi(vars["zip"]) if err != nil { log.Fatal(err) } data := client.GetByZipCode(zip, vars["country"]) writer.WriteHeader(http.StatusOK) _ = json.NewEncoder(writer).Encode(convert(data)) } func timeoutHandler(h http.Handler) http.Handler { return http.TimeoutHandler(h, 1*time.Second, "timed out") } func convert(weatherData client.WeatherResponse) Weather { return Weather{ TemperatureCurrent: weatherData.Main.Temperature, TemperatureMin: weatherData.Main.TemperatureMin, TemperatureMax: weatherData.Main.TemperatureMax, FeelsLike: weatherData.Main.FeelsLike, Pressure: weatherData.Main.Pressure, Humidity: weatherData.Main.Humidity, WindSpeeed: weatherData.Wind.Speed, WindDegree: weatherData.Wind.Degree, Clouds: weatherData.Clouds.All, Rain: weatherData.Rain.OneHour, Snow: weatherData.Snow.OneHour, } }