113 lines
2.5 KiB
Go
113 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
)
|
|
|
|
var (
|
|
templates = template.Must(template.ParseGlob("./tpl/*.gohtml"))
|
|
packages = Packages{}
|
|
)
|
|
|
|
func main() {
|
|
addr := os.Getenv("ADDR")
|
|
if addr == "" {
|
|
addr = ":8080"
|
|
}
|
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
|
defer cancel()
|
|
|
|
cfg := &Config{}
|
|
|
|
fp, err := os.Open("./config.json")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if err := json.NewDecoder(fp).Decode(cfg); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
r := chi.NewRouter()
|
|
|
|
r.Use(middleware.RequestID)
|
|
r.Use(middleware.StripSlashes)
|
|
r.Use(middleware.RealIP)
|
|
r.Use(middleware.Logger)
|
|
r.Use(middleware.Recoverer)
|
|
|
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
templates.ExecuteTemplate(w, "index.gohtml", indexRenderContext{
|
|
Title: cfg.Title,
|
|
Packages: cfg.Packages,
|
|
Host: cfg.Host,
|
|
Doc: "//pkg.go.dev/",
|
|
})
|
|
})
|
|
|
|
r.Get("/{pkg}", func(w http.ResponseWriter, r *http.Request) {
|
|
pkgID := chi.URLParam(r, "pkg")
|
|
pkg, ok := (*cfg.Packages)[pkgID]
|
|
if !ok {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
templates.ExecuteTemplate(w, "package.gohtml", pageRenderContext{
|
|
Title: cfg.Title,
|
|
Package: &pkg,
|
|
Host: cfg.Host,
|
|
Doc: "//pkg.go.dev/",
|
|
})
|
|
})
|
|
|
|
workDir, _ := os.Getwd()
|
|
filesDir := http.Dir(filepath.Join(workDir, "static"))
|
|
FileServer(r, "/static", filesDir)
|
|
|
|
srv := &http.Server{
|
|
Handler: r,
|
|
Addr: addr,
|
|
}
|
|
go func() {
|
|
<-ctx.Done()
|
|
srv.Shutdown(context.Background())
|
|
}()
|
|
log.Println("Start at", addr)
|
|
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// FileServer conveniently sets up a http.FileServer handler to serve
|
|
// static files from a http.FileSystem.
|
|
func FileServer(r chi.Router, path string, root http.FileSystem) {
|
|
if strings.ContainsAny(path, "{}*") {
|
|
panic("FileServer does not permit any URL parameters.")
|
|
}
|
|
|
|
if path != "/" && path[len(path)-1] != '/' {
|
|
r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
|
|
path += "/"
|
|
}
|
|
path += "*"
|
|
|
|
r.Get(path, func(w http.ResponseWriter, r *http.Request) {
|
|
rctx := chi.RouteContext(r.Context())
|
|
pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*")
|
|
fs := http.StripPrefix(pathPrefix, http.FileServer(root))
|
|
fs.ServeHTTP(w, r)
|
|
})
|
|
}
|