feat(t230): use OCR for ERP session login

This commit is contained in:
QiuSW
2026-07-29 10:48:06 +08:00
parent 8c84b81d48
commit f887bc4882
30 changed files with 512 additions and 205 deletions
@@ -39,6 +39,11 @@ type SessionConfig struct {
Timeout time.Duration
CaptchaTTL time.Duration
AllowInsecureHTTP bool // Used only by isolated httptest contracts.
CaptchaRecognizer CaptchaRecognizer
}
type CaptchaRecognizer interface {
Recognize(context.Context, []byte, string) (string, error)
}
type SessionStatus struct {
@@ -54,6 +59,7 @@ type CaptchaImage struct {
}
type SessionManager struct {
authMu sync.Mutex
mu sync.Mutex
baseURL string
username string
@@ -62,6 +68,7 @@ type SessionManager struct {
captchaTTL time.Duration
headers http.Header
http *http.Client
recognizer CaptchaRecognizer
authenticated bool
captchaTicket string
captchaContent []byte
@@ -111,9 +118,39 @@ func NewSessionManager(config SessionConfig) (*SessionManager, error) {
return http.ErrUseLastResponse
},
},
recognizer: config.CaptchaRecognizer,
}, nil
}
// EnsureAuthenticated establishes the single in-memory ERP session only when
// the current cookie jar cannot be validated.
func (manager *SessionManager) EnsureAuthenticated(ctx context.Context) error {
manager.authMu.Lock()
defer manager.authMu.Unlock()
if _, err := manager.Validate(ctx); err == nil {
return nil
} else if !errors.Is(err, domain.ErrFreightSourceSessionNeeded) {
return err
}
if manager.recognizer == nil {
return domain.ErrFreightSourceOCRInvalid
}
status, err := manager.FetchCaptcha(ctx)
if err != nil {
return err
}
image, err := manager.OpenCaptcha(status.CaptchaTicket)
if err != nil {
return domain.ErrFreightSourceProtocol
}
code, err := manager.recognizer.Recognize(ctx, image.Content, image.ContentType)
if err != nil || !validCaptchaCode(code) {
return domain.ErrFreightSourceOCRInvalid
}
_, err = manager.Login(ctx, status.CaptchaTicket, code)
return err
}
func (manager *SessionManager) Status() SessionStatus {
manager.mu.Lock()
defer manager.mu.Unlock()