package main import ( "encoding/json" "fmt" "github.com/gomarkdown/markdown" "github.com/gomarkdown/markdown/html" "github.com/gomarkdown/markdown/parser" "html/template" "io" "log" "net/http" "os" "slices" ) type Config struct { Port string Allowed []string HomeHtml string MainTemplate string ErrorTemplate string } var config Config func GetHome(w http.ResponseWriter, r *http.Request) { log.Println("Request for:", r.URL.String()) if r.URL.String() != "/" { ErrorPage(w, "Page Not Found.", 404) return } t := template.Must(template.ParseFiles(config.MainTemplate)) html, err := MarkdownToHTML(config.HomeHtml) if err != nil { ErrorPage(w, "Internal Server Error", 500) } else { t.Execute(w, template.HTML(html)) } } func GetFiles(w http.ResponseWriter, r *http.Request) { log.Println("Request for:", r.URL.String()) url := fmt.Sprintf("static%s", r.URL.String()) if slices.Contains(config.Allowed, url) { http.ServeFile(w, r, url) } else { ErrorPage(w, "Page Not Found.", 404) } } func MarkdownToHTML(path string) (string, error) { extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock p := parser.NewWithExtensions(extensions) f, err := os.Open(path) if err != nil { return "", err } defer f.Close() md, err := io.ReadAll(f) if err != nil { return "", err } doc := p.Parse(md) htmlFlags := html.CommonFlags | html.HrefTargetBlank opts := html.RendererOptions{Flags: htmlFlags} renderer := html.NewRenderer(opts) return string(markdown.Render(doc, renderer)), nil } func ErrorPage(w http.ResponseWriter, message string, code int) { log.Println(code, message) t := template.Must(template.ParseFiles(config.ErrorTemplate)) t.Execute(w, struct { Code int Message string }{ Code: code, Message: message, }) } func Usage() { fmt.Fprintf(os.Stderr, "%s [--port port]\n", os.Args[0]) } func main() { portFlagSet := false port := ":8000" for i := 1; i < len(os.Args); i++ { switch os.Args[i] { case "--port": if i+1 >= len(os.Args) { Usage() } else { portFlagSet = true port = ":" + os.Args[i+1] i++ } default: log.Println("Unknown option: ", os.Args[i]) Usage() } } configJson, err := os.ReadFile("config.json") if err != nil { panic(err) } err = json.Unmarshal(configJson, &config) if err != nil { panic(err) } if !portFlagSet { port = ":" + config.Port } fmt.Println(config.Port) for i, a := range config.Allowed { fmt.Printf("%d: %s\n", i, a) } fmt.Println(config.HomeHtml) fmt.Println(config.MainTemplate) fmt.Println(config.ErrorTemplate) http.HandleFunc("/robots.txt", GetFiles) http.HandleFunc("/rss.xml", GetFiles) http.HandleFunc("/card", GetFiles) http.HandleFunc("/css/", GetFiles) http.HandleFunc("/logos/", GetFiles) http.HandleFunc("/", GetHome) log.Fatal(http.ListenAndServe(port, nil)) }