Source File
fetch.go
Belonging Package
golang.org/x/pkgsite/internal/frontend
package frontend
import (
)
errPathDoesNotExistInModule = errors.New("path does not exist in module")
fetchTimeout = 30 * time.Second
pollEvery = 1 * time.Second
frontendFetchLatency = stats.Float64(
"go-discovery/frontend-fetch/latency",
"Latency of a frontend fetch request.",
stats.UnitMilliseconds,
)
FetchLatencyDistribution = &view.View{
Name: "go-discovery/frontend-fetch/latency",
Aggregation: view.Distribution(
1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100,
130, 160, 200, 250, 300, 400, 500, 650, 800, 1000,
30*60, // half hour: the max time an HTTP task can run
60*60),
Description: "FrontendFetch latency, by result source query type.",
TagKeys: []tag.Key{keyFetchStatus},
FetchResponseCount = &view.View{
Name: "go-discovery/frontend-fetch/count",
Measure: frontendFetchLatency,
Aggregation: view.Count(),
Description: "Frontend fetch request count",
TagKeys: []tag.Key{keyFetchStatus},
statusNotFoundInVersionMap = 470
)
return proxydatasourceNotSupportedErr()
}
return &serverError{status: http.StatusNotFound}
, := extractURLPathInfo(strings.TrimPrefix(.URL.Path, "/fetch"))
if != nil {
return &serverError{status: http.StatusBadRequest}
}
(stdlib.Contains(.fullPath) && .requestedVersion == internal.LatestVersion) {
return &serverError{status: http.StatusBadRequest}
}
, := .fetchAndPoll(.Context(), , .modulePath, .fullPath, .requestedVersion)
if != http.StatusOK {
return &serverError{status: , responseText: }
}
return nil
}
type fetchResult struct {
modulePath string
goModPath string
status int
err error
responseText string
updatedAt time.Time
}
func ( *Server) ( context.Context, internal.DataSource, , , string) ( int, string) {
:= time.Now()
defer func() {
log.Infof(, "fetchAndPoll(ctx, ds, q, %q, %q, %q): status=%d, responseText=%q",
, , , , )
recordFrontendFetchMetric(, , time.Since())
}()
(stdlib.Contains() && == internal.LatestVersion) {
return http.StatusBadRequest, http.StatusText(http.StatusBadRequest)
}
:= .(*postgres.DB)
, := modulePathsToFetch(, , , )
if != nil {
var *serverError
if errors.As(, &) {
return .status, http.StatusText(.status)
}
log.Errorf(, "fetchAndPoll(ctx, ds, q, %q, %q, %q): %v", , , , )
return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)
}
:= .checkPossibleModulePaths(, , , , , true)
, := resultFromFetchRequest(, , )
if != nil {
log.Errorf(, "fetchAndPoll(ctx, ds, q, %q, %q, %q): %v", , , , )
return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)
}
if .status == derrors.ToStatus(derrors.AlternativeModule) {
.status = http.StatusNotFound
}
return .status, .responseText
}
:= checkForPath(, , , , , .taskIDChangeInterval)
log.Debugf(, "initial checkForPath(ctx, db, %q, %q, %q, %d): status=%d, err=%v", , , , .taskIDChangeInterval, .status, .err)
if ! || .status != statusNotFoundInVersionMap {
[] =
return
}
if , := .queue.ScheduleFetch(, , , "", false); != nil {
.err =
.status = http.StatusInternalServerError
}
log.Debugf(, "queued %s@%s to frontend-fetch task queue", , )
.responseText = fmt.Sprintf("We're still working on ā%sā. Check back in a few minutes!", displayPath(, ))
return , nil
case http.StatusInternalServerError:
.responseText = "Oops! Something went wrong."
return , nil
case derrors.ToStatus(derrors.AlternativeModule):
if := module.CheckPath(.goModPath); != nil {
.status = http.StatusNotFound
.responseText = fmt.Sprintf(`%q does not have a valid module path (%q).`, , .goModPath)
return , nil
}
:= template.Must(template.New("").Parse(`{{.}}`))
, := .ExecuteToHTML(fmt.Sprintf("%s is not a valid path. Were you looking for ā<a href='https://pkg.go.dev/%s'>%s</a>ā?",
displayPath(, ), .goModPath, .goModPath))
if != nil {
.status = http.StatusInternalServerError
return ,
}
.responseText = .String()
return , nil
.status = http.StatusNotFound
:=
if != internal.LatestVersion {
= + "@" +
}
.responseText = fmt.Sprintf("%s could not be processed.", )
if .err != nil && strings.Contains(.err.Error(), fetch.ErrModuleContainsNoPackages.Error()) {
.responseText = fmt.Sprintf("There are no packages in module %s.", )
}
return , nil
}
if errors.Is(.err, errPathDoesNotExistInModule) && == "" {
= .modulePath
}
}
:= [0]
if != "" {
:= template.Must(template.New("").Parse(`{{.}}`))
, := .ExecuteToHTML(fmt.Sprintf(`
<div class="Error-message">%s could not be found.</div>
<div class="Error-message">However, you can view <a href="https://pkg.go.dev/%s">module %s</a>.</div>`,
displayPath(, ),
displayPath(, ),
displayPath(, ),
))
if != nil {
.status = http.StatusInternalServerError
return ,
}
.status = http.StatusNotFound
.responseText = .String()
return , nil
}
:=
if != internal.LatestVersion {
= + "@" +
}
.status = http.StatusNotFound
.responseText = fmt.Sprintf("%q could not be found.", )
return , nil
}
func (, string) string {
if == internal.LatestVersion {
return
}
return fmt.Sprintf("%s@%s", , )
}
.status = http.StatusRequestTimeout
.err = .Err()
return
case <-.C:
, := context.WithTimeout(, )
defer ()
= checkForPath(, , , , , )
if .status != statusNotFoundInVersionMap {
return
}
}
}
}
, := .GetVersionMap(, , )
= &fetchResult{
modulePath: ,
status: derrors.ToStatus(),
err: ,
}
if errors.Is(, derrors.NotFound) {
.status = statusNotFoundInVersionMap
}
return
}
= fetchResultFromVersionMap()
switch .status {
case http.StatusNotFound,
derrors.ToStatus(derrors.DBModuleInsertInvalid),
http.StatusInternalServerError:
.status = statusNotFoundInVersionMap
return
}
if .status == http.StatusInternalServerError {
.err = fmt.Errorf("%q: %v", http.StatusText(.status), .Error)
.err = errModuleDoesNotExist
}
return
.err = derrors.AlternativeModule
return
if .status >= 400 {
.status = http.StatusNotFound
.err = errModuleDoesNotExist
return
}
}
if , := .GetUnitMeta(, , , .ResolvedVersion); != nil {
.err = errPathDoesNotExistInModule
.status = http.StatusNotFound
return
.status = http.StatusInternalServerError
.err =
return
func ( context.Context, internal.DataSource, , string) ( []string, error) {
defer derrors.Wrap(&, "modulePathsToFetch(ctx, ds, %q, %q)", , )
if != internal.UnknownModulePath {
return []string{}, nil
}
, := .GetUnitMeta(, , , internal.LatestVersion)
if != nil && !errors.Is(, derrors.NotFound) {
return nil, &serverError{
status: http.StatusInternalServerError,
err: ,
}
}
if == nil {
return []string{.ModulePath}, nil
}
return candidateModulePaths()
}
var vcsHostsWithThreeElementRepoName = map[string]bool{
"bitbucket.org": true,
"gitea.com": true,
"gitee.com": true,
"github.com": true,
"gitlab.com": true,
}
var maxPathsToFetch = 10
func ( string) ( []string, error) {
if !isValidPath() {
return nil, &serverError{
status: http.StatusBadRequest,
err: fmt.Errorf("isValidPath(%q): false", ),
}
}
:= internal.CandidateModulePaths()
if == nil {
return nil, &serverError{
status: http.StatusBadRequest,
err: fmt.Errorf("invalid path: %q", ),
}
}
if len() > maxPathsToFetch {
return [len()-maxPathsToFetch:], nil
}
return , nil
}
func ( context.Context, , string, *proxy.Client, *source.Client, *postgres.DB) ( int, error) {
defer func() {
if != nil {
log.Infof(, "FetchAndUpdateState(%q, %q) completed with err: %v. ", , , )
} else {
log.Infof(, "FetchAndUpdateState(%q, %q) succeeded", , )
}
derrors.Wrap(&, "FetchAndUpdateState(%q, %q)", , )
}()
:= fetch.FetchModule(, , , , )
defer .Defer()
if , := .InsertModule(, .Module, nil); != nil {
.Status = http.StatusInternalServerError
log.Errorf(, "FetchAndUpdateState(%q, %q): db.InsertModule failed: %v", , , )
}
log.Infof(, "FetchAndUpdateState(%q, %q): db.InsertModule succeeded", , )
}
var string
if .Error != nil {
= .Error.Error()
}
:= &internal.VersionMap{
ModulePath: .ModulePath,
RequestedVersion: .RequestedVersion,
ResolvedVersion: .ResolvedVersion,
GoModPath: .GoModPath,
Status: .Status,
Error: ,
}
if := .UpsertVersionMap(, ); != nil {
return http.StatusInternalServerError,
}
if .Error != nil {
return .Status, .Error
}
return http.StatusOK, nil
}
func ( context.Context, int, time.Duration) {
:= float64() / float64(time.Millisecond)
stats.RecordWithTags(, []tag.Mutator{
tag.Upsert(keyFetchStatus, strconv.Itoa()),
}, frontendFetchLatency.M())
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |