feat(t230): use OCR for ERP session login
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user