Skip to content

Commit f467c35

Browse files
authored
Merge pull request #6 from phasehq/network--handle-rate-limits
feat: handle rate limits gracefully
2 parents 9ddd4b4 + 135ae47 commit f467c35

File tree

1 file changed

+23
-61
lines changed

1 file changed

+23
-61
lines changed

phase/network/network.go

Lines changed: 23 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"encoding/json"
77
"fmt"
88
"io"
9-
"io/ioutil"
109
"log"
1110
"net/http"
1211
"os"
@@ -58,22 +57,30 @@ func createHTTPClient() *http.Client {
5857
return client
5958
}
6059

60+
// handleHTTPResponse checks the HTTP response status and handles errors appropriately.
6161
func handleHTTPResponse(resp *http.Response) error {
62-
if resp.StatusCode == http.StatusForbidden {
63-
log.Println("🚫 Not authorized. Token expired or revoked.")
64-
return nil
65-
}
66-
67-
if resp.StatusCode != http.StatusOK {
68-
body, err := io.ReadAll(resp.Body)
69-
if err != nil {
70-
return fmt.Errorf("failed to read response body: %v", err)
71-
}
72-
errorMessage := fmt.Sprintf("🗿 Request failed with status code %d: %s", resp.StatusCode, string(body))
73-
return fmt.Errorf(errorMessage)
74-
}
75-
76-
return nil
62+
switch resp.StatusCode {
63+
case http.StatusOK:
64+
// If OK, nothing more to do.
65+
return nil
66+
case http.StatusForbidden:
67+
// Handle forbidden access.
68+
log.Println("🚫 Not authorized. Token expired or revoked.")
69+
return nil
70+
case http.StatusTooManyRequests:
71+
// Handle rate limiting.
72+
retryAfter := resp.Header.Get("Retry-After")
73+
log.Printf("⏳ Rate limit exceeded. Retry after %s seconds.", retryAfter)
74+
return fmt.Errorf("rate limit exceeded, retry after %s seconds", retryAfter)
75+
default:
76+
// Handle other unexpected statuses.
77+
body, err := io.ReadAll(resp.Body)
78+
if err != nil {
79+
return fmt.Errorf("failed to read response body: %v", err)
80+
}
81+
errorMessage := fmt.Sprintf("🗿 Request failed with status code %d: %s", resp.StatusCode, string(body))
82+
return fmt.Errorf(errorMessage)
83+
}
7784
}
7885

7986
func FetchPhaseUser(appToken, host string) (*http.Response, error) {
@@ -149,51 +156,6 @@ func FetchAppKey(appToken, host string) (string, error) {
149156
return jsonResp.WrappedKeyShare, nil
150157
}
151158

152-
// FetchWrappedKeyShare fetches the wrapped application key share from Phase KMS.
153-
func FetchWrappedKeyShare(appToken, host string) (string, error) {
154-
client := &http.Client{}
155-
156-
// Check if SSL verification should be skipped
157-
if !misc.VerifySSL {
158-
client.Transport = &http.Transport{
159-
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
160-
}
161-
}
162-
163-
url := fmt.Sprintf("%s/service/secrets/tokens/", host)
164-
req, err := http.NewRequest("GET", url, nil)
165-
if err != nil {
166-
return "", err
167-
}
168-
req.Header = ConstructHTTPHeaders(appToken)
169-
170-
resp, err := client.Do(req)
171-
if err != nil {
172-
return "", fmt.Errorf("network error: please check your internet connection. Detail: %v", err)
173-
}
174-
defer resp.Body.Close()
175-
176-
if resp.StatusCode != http.StatusOK {
177-
body, err := ioutil.ReadAll(resp.Body)
178-
if err != nil {
179-
return "", fmt.Errorf("request failed with status code %d: failed to read response body", resp.StatusCode)
180-
}
181-
return "", fmt.Errorf("request failed with status code %d: %s", resp.StatusCode, string(body))
182-
}
183-
184-
var jsonResp map[string]string
185-
if err := json.NewDecoder(resp.Body).Decode(&jsonResp); err != nil {
186-
return "", fmt.Errorf("failed to decode JSON from response: %v", err)
187-
}
188-
189-
wrappedKeyShare, ok := jsonResp["wrapped_key_share"]
190-
if !ok {
191-
return "", fmt.Errorf("wrapped key share not found in the response")
192-
}
193-
194-
return wrappedKeyShare, nil
195-
}
196-
197159
func FetchPhaseSecrets(appToken, environmentID, host, path string) ([]map[string]interface{}, error) {
198160
client := createHTTPClient()
199161
url := fmt.Sprintf("%s/service/secrets/", host)

0 commit comments

Comments
 (0)