Files
goi18n/internal/external.go
2022-10-18 15:44:29 +03:00

94 lines
2.2 KiB
Go

package internal
import (
"context"
"net"
"net/http"
"net/url"
"time"
"github.com/pkg/errors"
"golang.org/x/text/language"
"golang.org/x/text/message/catalog"
)
var ErrInvalidResponseCode = errors.New("invalid response status code")
func NewExternalLoader(baseURL string, header http.Header) *ExternalLoader {
client := http.Client{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 2 * time.Second,
}).DialContext,
DisableKeepAlives: true,
MaxIdleConns: 1,
MaxIdleConnsPerHost: 1,
MaxConnsPerHost: 2,
IdleConnTimeout: 30 * time.Second,
ResponseHeaderTimeout: 5 * time.Second,
MaxResponseHeaderBytes: 1024 * 3,
WriteBufferSize: 100,
ReadBufferSize: 1024 * 8,
},
Timeout: time.Second * 10,
}
return NewExternalLoaderWithClient(baseURL, header, &client)
}
func NewExternalLoaderWithClient(baseURL string, header http.Header, client *http.Client) *ExternalLoader {
return &ExternalLoader{baseURL: baseURL, client: client, header: header}
}
type ExternalLoader struct {
baseURL string
header http.Header
client *http.Client
}
func (e *ExternalLoader) Load(builder *catalog.Builder) error {
languages := builder.Languages()
for _, lang := range languages {
if err := e.load(lang, builder); err != nil {
return errors.WithMessagef(err, "load translation for %s", lang.String())
}
}
return nil
}
func (e *ExternalLoader) load(lang language.Tag, builder *catalog.Builder) error {
langURL, err := url.JoinPath(e.baseURL, lang.String())
if err != nil {
return errors.Wrap(err, "join url path")
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, langURL, nil)
if err != nil {
return errors.Wrap(err, "new request")
}
if e.header != nil {
req.Header = e.header
}
response, err := e.client.Do(req)
if err != nil {
return errors.Wrap(err, "do request")
}
if response.StatusCode != http.StatusOK {
return errors.Wrapf(ErrInvalidResponseCode, "got status %d", response.StatusCode)
}
if err := load(response.Body, lang, builder); err != nil {
return errors.WithMessage(err, "load translation")
}
return nil
}