diff --git a/gitea/apiclient.go b/gitea/apiclient.go index ef44f8b..ba048bf 100644 --- a/gitea/apiclient.go +++ b/gitea/apiclient.go @@ -4,21 +4,27 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io/ioutil" "net/http" "net/url" "strings" + "sync/atomic" "time" "golang.org/x/sync/semaphore" ) +const MarkdownFailureCooldownSeconds = 3600 // 1 hour + type APIClient struct { urlBase string orgName string token string apiSem *semaphore.Weighted + + lastMarkdownFailure atomic.Int64 } // NewAPIClient creates a new Gitea API client for a single Gitea organization. @@ -297,8 +303,22 @@ func (ac *APIClient) topicsForRepo(ctx context.Context, repo string) ([]string, return tr.Topics, nil } +var ErrMarkdownCooldown = errors.New("Markdown API was recently not functional") + +func (ac *APIClient) checkMarkdownCooldown() error { + if ac.lastMarkdownFailure.Load()+MarkdownFailureCooldownSeconds > time.Now().Unix() { + return ErrMarkdownCooldown + } + + return nil +} + // renderMarkdown calls the remote Gitea server's own markdown renderer. func (ac *APIClient) RenderMarkdown(ctx context.Context, repoName string, body string) ([]byte, error) { + if err := ac.checkMarkdownCooldown(); err != nil { + return nil, err + } + err := ac.apiSem.Acquire(ctx, 1) if err != nil { return nil, err // e.g. ctx closed @@ -328,6 +348,7 @@ func (ac *APIClient) RenderMarkdown(ctx context.Context, repoName string, body s defer resp.Body.Close() if resp.StatusCode != 200 { + ac.lastMarkdownFailure.Store(time.Now().Unix()) return nil, fmt.Errorf("HTTP %d", resp.StatusCode) } @@ -336,6 +357,10 @@ func (ac *APIClient) RenderMarkdown(ctx context.Context, repoName string, body s // renderMarkdownRaw calls the remote Gitea server's own markdown renderer. func (ac *APIClient) renderMarkdownRaw(ctx context.Context, body []byte) ([]byte, error) { + if err := ac.checkMarkdownCooldown(); err != nil { + return nil, err + } + err := ac.apiSem.Acquire(ctx, 1) if err != nil { return nil, err // e.g. ctx closed @@ -356,6 +381,7 @@ func (ac *APIClient) renderMarkdownRaw(ctx context.Context, body []byte) ([]byte defer resp.Body.Close() if resp.StatusCode != 200 { + ac.lastMarkdownFailure.Store(time.Now().Unix()) return nil, fmt.Errorf("HTTP %d", resp.StatusCode) } diff --git a/page_repository.go b/page_repository.go index aad8417..7df9dd7 100644 --- a/page_repository.go +++ b/page_repository.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "errors" "fmt" "html" "log" @@ -9,6 +10,8 @@ import ( "net/url" "strings" + "teafolio/gitea" + "github.com/yuin/goldmark" ) @@ -59,7 +62,9 @@ func (this *Application) Repopage(w http.ResponseWriter, r *http.Request, repoNa readmeHtml, err := this.gitea.RenderMarkdown(ctx, repoName, strings.Join(lines, "\n")) if err != nil { - log.Printf("%s %s: %s", r.Method, r.URL.Path, fmt.Errorf("rendering markdown: %w", err)) + if !errors.Is(err, gitea.ErrMarkdownCooldown) { + log.Printf("%s %s: %s", r.Method, r.URL.Path, fmt.Errorf("rendering markdown: %w", err)) + } // Failed to use Gitea's markdown renderer // HTTP 401 (Unauthorized) started happening with this API sometime