feat(t240): cache freight item images
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
package shunyunbao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cmroubao/backend-api/internal/domain"
|
||||
"cmroubao/backend-api/internal/usecase"
|
||||
)
|
||||
|
||||
const (
|
||||
ProductImagePath = "/api/p/file"
|
||||
maxProductImageBytes = 20 << 20
|
||||
)
|
||||
|
||||
func (manager *SessionManager) FetchProductImage(
|
||||
ctx context.Context,
|
||||
productThumbRef string,
|
||||
) (usecase.FreightSourceImage, error) {
|
||||
productThumbRef = strings.TrimSpace(productThumbRef)
|
||||
value, err := strconv.ParseUint(productThumbRef, 10, 64)
|
||||
if err != nil || value == 0 ||
|
||||
strconv.FormatUint(value, 10) != productThumbRef {
|
||||
return usecase.FreightSourceImage{}, domain.ErrFreightImageInvalid
|
||||
}
|
||||
|
||||
manager.mu.Lock()
|
||||
if !manager.configuredLocked() {
|
||||
manager.mu.Unlock()
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightSourceNotConfigured
|
||||
}
|
||||
if !manager.authenticated {
|
||||
manager.mu.Unlock()
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightSourceSessionNeeded
|
||||
}
|
||||
baseURL := manager.baseURL
|
||||
headers := manager.headers.Clone()
|
||||
client := manager.http
|
||||
manager.mu.Unlock()
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("id", productThumbRef)
|
||||
request, err := http.NewRequestWithContext(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
baseURL+ProductImagePath+"?"+query.Encode(),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightSourceUnavailable
|
||||
}
|
||||
for name, values := range headers {
|
||||
request.Header[name] = append([]string(nil), values...)
|
||||
}
|
||||
request.Header.Set("Accept", "image/jpeg, image/png, image/webp")
|
||||
manager.logERPRequest(request)
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
manager.logERPTransportFailure(request)
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightSourceUnavailable
|
||||
}
|
||||
if response.StatusCode < http.StatusOK ||
|
||||
response.StatusCode >= http.StatusMultipleChoices {
|
||||
defer response.Body.Close()
|
||||
manager.logERPBinaryResponse(request, response)
|
||||
switch response.StatusCode {
|
||||
case http.StatusUnauthorized, http.StatusForbidden:
|
||||
manager.mu.Lock()
|
||||
manager.clearAuthenticatedLocked()
|
||||
manager.mu.Unlock()
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightSourceSessionNeeded
|
||||
case http.StatusNotFound:
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightImageNotFound
|
||||
default:
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightSourceUnavailable
|
||||
}
|
||||
}
|
||||
mediaType, _, err := mime.ParseMediaType(
|
||||
response.Header.Get("Content-Type"),
|
||||
)
|
||||
if err != nil || !supportedProductImageType(mediaType) ||
|
||||
response.ContentLength > maxProductImageBytes {
|
||||
response.Body.Close()
|
||||
manager.logERPBinaryResponse(request, response)
|
||||
return usecase.FreightSourceImage{},
|
||||
domain.ErrFreightImageInvalid
|
||||
}
|
||||
manager.logERPBinaryResponse(request, response)
|
||||
return usecase.FreightSourceImage{
|
||||
Content: response.Body,
|
||||
MediaType: mediaType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func supportedProductImageType(value string) bool {
|
||||
switch strings.ToLower(value) {
|
||||
case "image/jpeg", "image/png", "image/webp":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SessionManager) logERPBinaryResponse(
|
||||
request *http.Request,
|
||||
response *http.Response,
|
||||
) {
|
||||
if !manager.diagnosticsOn {
|
||||
return
|
||||
}
|
||||
byteCount := "unknown"
|
||||
if response.ContentLength >= 0 {
|
||||
byteCount = strconv.FormatInt(response.ContentLength, 10)
|
||||
}
|
||||
manager.diagnosticLog(
|
||||
"erp_response method=" + request.Method +
|
||||
" path=" + request.URL.EscapedPath() +
|
||||
" status=" + strconv.Itoa(response.StatusCode) +
|
||||
" content_type=" +
|
||||
diagnosticContentType(response.Header.Get("Content-Type")) +
|
||||
" bytes=" + byteCount + " body=omitted_binary",
|
||||
)
|
||||
}
|
||||
|
||||
var _ usecase.FreightImageSource = (*SessionManager)(nil)
|
||||
Reference in New Issue
Block a user