134 lines
3.8 KiB
Go
134 lines
3.8 KiB
Go
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,
|
|
}
|
|
}
|