137 lines
3.6 KiB
Go
137 lines
3.6 KiB
Go
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)
|