package usecase import ( "context" "fmt" "net/http" "net/url" "gitea.maximumdirect.net/eric/promptkit/internal/domain" "gitea.maximumdirect.net/eric/promptkit/internal/generation" "gitea.maximumdirect.net/eric/promptkit/internal/llm" ) type smokeHTTPGetter interface { GetWithEvidence(context.Context, string, int) (*http.Response, llm.HTTPExecutionEvidence, error) GetWithAuthenticationEvidence(context.Context, string, int, domain.ExecutionTarget) (*http.Response, llm.HTTPExecutionEvidence, error) } type reachabilityProbe struct { client smokeHTTPGetter } type reachabilityProbeOutcome struct { supported bool reason domain.SmokeTestReason initialEndpoint string reachable *bool evidence llm.HTTPExecutionEvidence failure domain.ExecutionFailureKind } func (p reachabilityProbe) run( ctx context.Context, endpoint string, timeoutSeconds int, ) (reachabilityProbeOutcome, error) { if p.client == nil { return reachabilityProbeOutcome{ reason: domain.SmokeTestReasonHTTPDiagnosticsUnavailable, }, nil } endpoint, err := endpointWithoutUserInfo(endpoint) if err != nil { return reachabilityProbeOutcome{}, fmt.Errorf("prepare reachability endpoint: %w", err) } result := reachabilityProbeOutcome{supported: true, initialEndpoint: endpoint} response, evidence, requestErr := p.client.GetWithEvidence(ctx, endpoint, timeoutSeconds) if response != nil && response.Body != nil { _ = response.Body.Close() } result.evidence = evidence if evidence.ResponseReceived || response != nil { result.reachable = boolPointer(true) return result, nil } if evidence.DispatchInvoked { result.reachable = boolPointer(false) } if requestErr != nil { result.failure = generation.ClassifyFailure(fmt.Errorf("%w: %w", llm.ErrTransport, requestErr)) if !evidence.DispatchInvoked { return result, fmt.Errorf("execute reachability request: %w", requestErr) } } return result, nil } func endpointWithoutUserInfo(endpoint string) (string, error) { parsed, err := url.Parse(endpoint) if err != nil { return "", err } parsed.User = nil return parsed.String(), nil } func boolPointer(value bool) *bool { return &value }