package elinps import ( "bytes" "fmt" "html/template" "net/http" "os" "strings" "sync" "time" "github.com/yuin/goldmark" ) // ReadmePage serve o README.md renderizado como HTML. // // Motivação: dar uma "home" simples para o serviço (documentação em tempo real). // Sem autenticação, conforme solicitado. // // Implementação: cache em memória por mtime para evitar renderização em toda request. type ReadmePage struct { caminho string mu sync.Mutex ultimoMTime time.Time html []byte errMsg string } func NewReadmePage(caminho string) *ReadmePage { return &ReadmePage{caminho: caminho} } func (p *ReadmePage) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Só respondemos GET/HEAD. if r.Method != http.MethodGet && r.Method != http.MethodHead { w.WriteHeader(http.StatusMethodNotAllowed) return } html, errMsg := p.renderIfNeeded() if errMsg != "" { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusNotFound) w.Write([]byte(errMsg)) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusOK) if r.Method == http.MethodHead { return } w.Write(html) } func (p *ReadmePage) renderIfNeeded() ([]byte, string) { p.mu.Lock() defer p.mu.Unlock() st, err := os.Stat(p.caminho) if err != nil { p.errMsg = fmt.Sprintf("README não encontrado: %s", p.caminho) p.html = nil p.ultimoMTime = time.Time{} return nil, p.errMsg } // Cache: se o arquivo não mudou, devolve o HTML já renderizado. if p.html != nil && st.ModTime().Equal(p.ultimoMTime) { return p.html, "" } md, err := os.ReadFile(p.caminho) if err != nil { p.errMsg = "erro ao ler README" p.html = nil p.ultimoMTime = time.Time{} return nil, p.errMsg } var buf bytes.Buffer if err := goldmark.Convert(md, &buf); err != nil { p.errMsg = "erro ao renderizar README" p.html = nil p.ultimoMTime = time.Time{} return nil, p.errMsg } // Envelopa em uma página com estilo básico. // Importante: NÃO usamos fmt.Sprintf com o HTML/CSS diretamente, // porque o CSS pode conter "%" (ex.: width:100%) e o fmt interpreta // como placeholders. page := `
Página gerada automaticamente a partir de README.md