grim/hgkeeper

Add a caching layer to the hgweb portion. This should take some strain off of mercurial anf our cpu quota
//go:generate esc -o files.go -pkg hgweb -include files\/.+ -prefix files/ .
package hgweb
import (
"io/ioutil"
"net/http"
"net/http/cgi"
"os"
"text/template"
log "github.com/sirupsen/logrus"
"bitbucket.org/rw_grim/hgkeeper/access"
)
type Server struct {
listenAddr string
server *http.Server
cgiPath string
cacheSize int
}
func NewServer(listenAddr string, cacheSize int) (*Server, error) {
return &Server{
listenAddr: listenAddr,
cacheSize: cacheSize,
server: &http.Server{
Addr: listenAddr,
},
}, nil
}
func (s *Server) createCGI() error {
cgiPath, err := ioutil.TempFile("", "hgkeeper-hgweb-*.cgi")
if err != nil {
return err
}
defer cgiPath.Close()
// make the cgi file executable
if err := cgiPath.Chmod(0755); err != nil {
return err
}
// create a template based for the cgi file
t := template.Must(template.New("cgi").Parse(FSMustString(false, "/hgweb.cgi")))
// create our data
data := map[string]string{
"HGWEB_CONFIG": access.HgwebConfigPath(),
}
if err := t.Execute(cgiPath, data); err != nil {
return err
}
s.cgiPath = cgiPath.Name()
return nil
}
func (s *Server) Listen() error {
if err := s.createCGI(); err != nil {
return err
}
cache, err := newCache(s.cacheSize)
if err != nil {
return err
}
s.server.Handler = cache.middleware(&cgi.Handler{Path: s.cgiPath})
log.Infof("http listening on %s", s.listenAddr)
return s.server.ListenAndServe()
}
func (s *Server) Close() {
if err := os.Remove(s.cgiPath); err != nil {
log.Warnf("failed to remove temporary cgi file %q: %v", s.cgiPath, err)
}
if err := s.server.Close(); err != nil {
log.Warnf("failed to shutdown http server: %v", err)
}
}