Files
lingniu-vehicle-ingest/go/vehicle-gateway/internal/feichibridge/captcha.go

58 lines
1.4 KiB
Go

package feichibridge
import (
"bytes"
"context"
"errors"
"fmt"
"os/exec"
"regexp"
"strings"
"time"
)
var captchaPattern = regexp.MustCompile(`^[0-9A-Z]{4}$`)
type CaptchaSolver interface {
Solve(context.Context, []byte) (string, error)
}
type DockerCaptchaSolver struct {
Image string
Timeout time.Duration
}
func (s DockerCaptchaSolver) Solve(ctx context.Context, image []byte) (string, error) {
if len(image) == 0 {
return "", errors.New("captcha image is empty")
}
if strings.TrimSpace(s.Image) == "" {
return "", errors.New("captcha OCR image is required")
}
timeout := s.Timeout
if timeout <= 0 {
timeout = 20 * time.Second
}
solveCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
command := exec.CommandContext(
solveCtx,
"docker", "run", "--rm", "--network=none", "-i", strings.TrimSpace(s.Image),
)
command.Stdin = bytes.NewReader(image)
var stderr bytes.Buffer
command.Stderr = &stderr
output, err := command.Output()
if err != nil {
if solveCtx.Err() != nil {
return "", fmt.Errorf("captcha OCR timed out: %w", solveCtx.Err())
}
return "", fmt.Errorf("captcha OCR failed: %w: %s", err, strings.TrimSpace(stderr.String()))
}
code := strings.ToUpper(strings.TrimSpace(string(output)))
if !captchaPattern.MatchString(code) {
return "", fmt.Errorf("captcha OCR returned invalid result %q", code)
}
return code, nil
}