diff --git a/src/api/hypixel.go b/src/api/hypixel.go index a7ca1785..00c1772b 100644 --- a/src/api/hypixel.go +++ b/src/api/hypixel.go @@ -5,6 +5,7 @@ import ( "io" "net/http" "os" + "time" redis "skycrypt/src/db" "skycrypt/src/models" "skycrypt/src/utility" @@ -15,14 +16,26 @@ import ( var HYPIXEL_API_KEY = os.Getenv("HYPIXEL_API_KEY") -func GetPlayer(uuid string) (*skycrypttypes.Player, error) { - var rawReponse models.HypixelPlayerResponse - var response skycrypttypes.Player +var json = jsoniter.ConfigCompatibleWithStandardLibrary + +var httpClient = &http.Client{ + Timeout: 10 * time.Second, + Transport: &http.Transport{ + MaxIdleConns: 100, + MaxIdleConnsPerHost: 10, + IdleConnTimeout: 90 * time.Second, + }, +} + + +func GetPlayer(uuid string) (*models.Player, error) { + rawReponse := &models.HypixelPlayerResponse{} + response := &models.Player{} if !utility.IsUUID(uuid) { respUUID, err := GetUUID(uuid) if err != nil { - return &response, err + return response, err } uuid = respUUID @@ -30,41 +43,43 @@ func GetPlayer(uuid string) (*skycrypttypes.Player, error) { cache, err := redis.Get(fmt.Sprintf(`player:%s`, uuid)) if err == nil && cache != "" { - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal([]byte(cache), &rawReponse) + err = json.Unmarshal([]byte(cache), rawReponse) if err == nil { - return &rawReponse.Player, nil + return rawReponse.Player, nil } } - resp, err := http.Get(fmt.Sprintf("https://api.hypixel.net/v2/player?key=%s&uuid=%s", HYPIXEL_API_KEY, uuid)) + resp, err := httpClient.Get(fmt.Sprintf("https://api.hypixel.net/v2/player?key=%s&uuid=%s", HYPIXEL_API_KEY, uuid)) if err != nil { - return &response, fmt.Errorf("error making request: %v", err) + return response, fmt.Errorf("error making request: %v", err) } defer resp.Body.Close() + + if resp.StatusCode != 200 { + return response, fmt.Errorf("API returned status %d", resp.StatusCode) + } body, err := io.ReadAll(resp.Body) if err != nil { - return &response, fmt.Errorf("error reading response: %v", err) + return response, fmt.Errorf("error reading response: %v", err) } - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal(body, &rawReponse) + err = json.Unmarshal(body, rawReponse) if err != nil { - return &rawReponse.Player, fmt.Errorf("error parsing JSON: %v", err) + return rawReponse.Player, fmt.Errorf("error parsing JSON: %v", err) } redis.Set(fmt.Sprintf(`player:%s`, uuid), string(body), 24*60*60) - return &rawReponse.Player, nil + return rawReponse.Player, nil } func GetProfiles(uuid string) (*models.HypixelProfilesResponse, error) { - var response models.HypixelProfilesResponse + response := &models.HypixelProfilesResponse{} if !utility.IsUUID(uuid) { respUUID, err := GetUUID(uuid) if err != nil { - return &response, err + return response, err } uuid = respUUID @@ -72,36 +87,38 @@ func GetProfiles(uuid string) (*models.HypixelProfilesResponse, error) { cache, err := redis.Get(fmt.Sprintf(`profiles:%s`, uuid)) if err == nil && cache != "" { - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal([]byte(cache), &response) + err = json.Unmarshal([]byte(cache), response) if err == nil { - return &response, nil + return response, nil } } - resp, err := http.Get(fmt.Sprintf("https://api.hypixel.net/v2/skyblock/profiles?key=%s&uuid=%s", HYPIXEL_API_KEY, uuid)) + resp, err := httpClient.Get(fmt.Sprintf("https://api.hypixel.net/v2/skyblock/profiles?key=%s&uuid=%s", HYPIXEL_API_KEY, uuid)) if err != nil { - return &response, fmt.Errorf("error making request: %v", err) + return response, fmt.Errorf("error making request: %v", err) } defer resp.Body.Close() + + if resp.StatusCode != 200 { + return response, fmt.Errorf("API returned status %d", resp.StatusCode) + } body, err := io.ReadAll(resp.Body) if err != nil { - return &response, fmt.Errorf("error reading response: %v", err) + return response, fmt.Errorf("error reading response: %v", err) } - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal(body, &response) + err = json.Unmarshal(body, response) if err != nil { - return &response, fmt.Errorf("error parsing JSON: %v", err) + return response, fmt.Errorf("error parsing JSON: %v", err) } if response.Cause != "" && !response.Success { - return &response, fmt.Errorf("error fetching profiles: %s", response.Cause) + return response, fmt.Errorf("error fetching profiles: %s", response.Cause) } redis.Set(fmt.Sprintf(`profiles:%s`, uuid), string(body), 5*60) // Cache for 5 minutes - return &response, nil + return response, nil } func GetProfile(uuid string, profileId ...string) (*skycrypttypes.Profile, error) { @@ -136,31 +153,35 @@ func GetProfile(uuid string, profileId ...string) (*skycrypttypes.Profile, error return &skycrypttypes.Profile{}, fmt.Errorf("profile with ID %s not found for UUID %s", targetProfileId, uuid) } -func GetMuseum(profileId string) (map[string]*skycrypttypes.Museum, error) { - var rawReponse models.HypixelMuseumResponse +func GetMuseum(profileId string) (map[string]*models.Museum, error) { + rawReponse := &models.HypixelMuseumResponse{} + cache, err := redis.Get(fmt.Sprintf(`museum:%s`, profileId)) if err == nil && cache != "" { var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal([]byte(cache), &rawReponse) + err = json.Unmarshal([]byte(cache), rawReponse) if err == nil { return rawReponse.Members, nil } } - resp, err := http.Get(fmt.Sprintf("https://api.hypixel.net/v2/skyblock/museum?key=%s&profile=%s", HYPIXEL_API_KEY, profileId)) + resp, err := httpClient.Get(fmt.Sprintf("https://api.hypixel.net/v2/skyblock/museum?key=%s&profile=%s", HYPIXEL_API_KEY, profileId)) if err != nil { return nil, fmt.Errorf("error making request: %v", err) } defer resp.Body.Close() + + if resp.StatusCode != 200 { + return nil, fmt.Errorf("API returned status %d", resp.StatusCode) + } body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("error reading response: %v", err) } - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal(body, &rawReponse) + err = json.Unmarshal(body, rawReponse) if err != nil { return nil, fmt.Errorf("error parsing JSON: %v", err) } @@ -169,35 +190,38 @@ func GetMuseum(profileId string) (map[string]*skycrypttypes.Museum, error) { return rawReponse.Members, nil } -func GetGarden(profileId string) (*skycrypttypes.Garden, error) { - var rawReponse models.HypixelGardenResponse +func GetGarden(profileId string) (*models.GardenRaw, error) { + rawReponse := &models.HypixelGardenResponse{} cache, err := redis.Get(fmt.Sprintf(`garden:%s`, profileId)) if err == nil && cache != "" { var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal([]byte(cache), &rawReponse) + err = json.Unmarshal([]byte(cache), rawReponse) if err == nil { - return &rawReponse.Garden, nil + return rawReponse.Garden, nil } } - resp, err := http.Get(fmt.Sprintf("https://api.hypixel.net/v2/skyblock/garden?key=%s&profile=%s", HYPIXEL_API_KEY, profileId)) + resp, err := httpClient.Get(fmt.Sprintf("https://api.hypixel.net/v2/skyblock/garden?key=%s&profile=%s", HYPIXEL_API_KEY, profileId)) if err != nil { return nil, fmt.Errorf("error making request: %v", err) } defer resp.Body.Close() + + if resp.StatusCode != 200 { + return nil, fmt.Errorf("API returned status %d", resp.StatusCode) + } body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("error reading response: %v", err) } - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal(body, &rawReponse) + err = json.Unmarshal(body, rawReponse) if err != nil { return nil, fmt.Errorf("error parsing JSON: %v", err) } redis.Set(fmt.Sprintf(`garden:%s`, profileId), string(body), 60*30) // Cache for 30 minutes - return &rawReponse.Garden, nil + return rawReponse.Garden, nil } diff --git a/src/api/mowojang.go b/src/api/mowojang.go index 89651085..22e896d3 100644 --- a/src/api/mowojang.go +++ b/src/api/mowojang.go @@ -3,37 +3,51 @@ package api import ( "fmt" "io" + "net/http" + "strings" + "time" redis "skycrypt/src/db" "skycrypt/src/models" "skycrypt/src/utility" - "net/http" - "strings" - jsoniter "github.com/json-iterator/go" ) +var json = jsoniter.ConfigCompatibleWithStandardLibrary + +var httpClient = &http.Client{ + Timeout: 10 * time.Second, + Transport: &http.Transport{ + MaxIdleConns: 100, + MaxIdleConnsPerHost: 10, + IdleConnTimeout: 90 * time.Second, + }, +} + func GetUUID(username string) (string, error) { - var post models.MowojangReponse + post := &models.MowojangReponse{} cache, err := redis.Get(fmt.Sprintf("uuid:%s", strings.ToLower(username))) if err == nil && cache != "" { return cache, nil } - resp, err := http.Get(fmt.Sprintf("https://mowojang.matdoes.dev/%s", username)) + resp, err := httpClient.Get(fmt.Sprintf("https://mowojang.matdoes.dev/%s", username)) if err != nil { return post.UUID, fmt.Errorf("error making request: %v", err) } defer resp.Body.Close() + + if resp.StatusCode != 200 { + return post.UUID, fmt.Errorf("API returned status %d", resp.StatusCode) + } body, err := io.ReadAll(resp.Body) if err != nil { return post.UUID, fmt.Errorf("error reading response: %v", err) } - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal(body, &post) + err = json.Unmarshal(body, post) if err != nil { return post.UUID, fmt.Errorf("error parsing JSON: %v", err) } @@ -45,26 +59,29 @@ func GetUUID(username string) (string, error) { } func GetUsername(uuid string) (string, error) { - var post models.MowojangReponse + post := &models.MowojangReponse{} cache, err := redis.Get(fmt.Sprintf("username:%s", uuid)) if err == nil && cache != "" { return cache, nil } - resp, err := http.Get(fmt.Sprintf("https://mowojang.matdoes.dev/%s", uuid)) + resp, err := httpClient.Get(fmt.Sprintf("https://mowojang.matdoes.dev/%s", uuid)) if err != nil { return post.Name, fmt.Errorf("error making request: %v", err) } defer resp.Body.Close() + + if resp.StatusCode != 200 { + return post.Name, fmt.Errorf("API returned status %d", resp.StatusCode) + } body, err := io.ReadAll(resp.Body) if err != nil { return post.Name, fmt.Errorf("error reading response: %v", err) } - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal(body, &post) + err = json.Unmarshal(body, post) if err != nil { return post.Name, fmt.Errorf("error parsing JSON: %v", err) } @@ -76,42 +93,44 @@ func GetUsername(uuid string) (string, error) { } func ResolvePlayer(uuid string) (*models.MowojangReponse, error) { - var post models.MowojangReponse + post := &models.MowojangReponse{} if !utility.IsUUID(uuid) { tempUUID, err := GetUUID(uuid) if err != nil { - return &post, fmt.Errorf("error resolving UUID for username '%s': %v", uuid, err) + return post, fmt.Errorf("error resolving UUID for username '%s': %v", uuid, err) } uuid = tempUUID } cache, err := redis.Get(fmt.Sprintf("mowojang:%s", uuid)) if err == nil && cache != "" { - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal([]byte(cache), &post) + err = json.Unmarshal([]byte(cache), post) if err == nil { - return &post, nil + return post, nil } } - resp, err := http.Get(fmt.Sprintf("https://mowojang.matdoes.dev/%s", uuid)) + resp, err := httpClient.Get(fmt.Sprintf("https://mowojang.matdoes.dev/%s", uuid)) if err != nil { - return &post, fmt.Errorf("error making request: %v", err) + return post, fmt.Errorf("error making request: %v", err) } defer resp.Body.Close() + + if resp.StatusCode != 200 { + return post, fmt.Errorf("API returned status %d", resp.StatusCode) + } body, err := io.ReadAll(resp.Body) if err != nil { - return &post, fmt.Errorf("error reading response: %v", err) + return post, fmt.Errorf("error reading response: %v", err) } - var json = jsoniter.ConfigCompatibleWithStandardLibrary - err = json.Unmarshal(body, &post) + err = json.Unmarshal(body, post) if err != nil { - return &post, fmt.Errorf("error parsing JSON: %v", err) + return post, fmt.Errorf("error parsing JSON: %v", err) } redis.Set(fmt.Sprintf("mowojang:%s", uuid), string(body), 24*60*60) // Cache for 24 hours - return &post, nil + return post, nil }