Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
7b94462388 | |||
b2c5d8f41c | |||
4d2c1622d3 | |||
82d1c5a8c8 |
57
main.go
57
main.go
@@ -1,9 +1,13 @@
|
|||||||
package cyutils
|
package cyutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
@@ -58,11 +62,10 @@ func (t *RateLimitedTransport) RoundTrip(req *http.Request) (*http.Response, err
|
|||||||
}
|
}
|
||||||
return t.base.RoundTrip(req)
|
return t.base.RoundTrip(req)
|
||||||
}
|
}
|
||||||
func LimitedHttp(rps float64, burst int, timeout time.Duration) *http.Client {
|
func LimitedHttp(rps float64, burst int) *http.Client {
|
||||||
baseTransport := &http.Transport{
|
baseTransport := &http.Transport{
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
MaxIdleConnsPerHost: 10,
|
MaxIdleConnsPerHost: 10,
|
||||||
IdleConnTimeout: 10 * time.Second,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize rate limiter
|
// Initialize rate limiter
|
||||||
@@ -77,6 +80,52 @@ func LimitedHttp(rps float64, burst int, timeout time.Duration) *http.Client {
|
|||||||
// Return configured client
|
// Return configured client
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
Timeout: timeout,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RequestCached[T any](req *http.Request, filename string) (T, error) {
|
||||||
|
var zero T
|
||||||
|
|
||||||
|
data, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return zero, fmt.Errorf("failed to read cache: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, httpErr := http.DefaultClient.Do(req)
|
||||||
|
if httpErr != nil {
|
||||||
|
return zero, fmt.Errorf("HTTP request failed: %w", httpErr)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
return zero, fmt.Errorf("failed to read response body: %w", readErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
if dir != "." && dir != "" {
|
||||||
|
if mkErr := os.MkdirAll(dir, 0o755); mkErr != nil {
|
||||||
|
return zero, fmt.Errorf("failed to create cache dir %s: %w", dir, mkErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if writeErr := os.WriteFile(filename, body, 0o644); writeErr != nil {
|
||||||
|
return zero, fmt.Errorf("failed to write cache %s: %w", filename, writeErr)
|
||||||
|
}
|
||||||
|
data = body
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := any(zero).([]byte); ok {
|
||||||
|
return any(data).(T), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var out T
|
||||||
|
if err := json.Unmarshal(data, &out); err != nil {
|
||||||
|
return zero, fmt.Errorf("failed to unmarshal cached response: %w", err)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RequestCachedBytes(req *http.Request, filename string) ([]byte, error) {
|
||||||
|
return RequestCached[[]byte](req, filename)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user