commit 8daaa1b33042482ef96ec5d48e1b0cc148a96dbd Author: Naman Sood Date: Sat Feb 6 16:27:00 2021 -0500 Initial commit - read and serve markdown and static files diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7c793e --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Prose + +Prose is a blogging platform written in Go, which I am building to serve my own blog. + +## Usage + +Blog posts should be created in the format `DATE-title-slug.md`. Work in progress posts should be stored as `WIP-title-slug.md`. Static content should be stored in the `static/` folder, appropriately arranged. + +Posts will be served as `/title-slug`, and files like `static/random/file/structure.txt` will be served as `/random/file/structure.txt`. When title slugs and static files conflict, slugs will have higher precdence. + +To start the server: + + go run . + +Server will be live on port 8080. \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e90b934 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module prose + +go 1.15 + +require github.com/yuin/goldmark v1.3.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..de9bccb --- /dev/null +++ b/go.sum @@ -0,0 +1,24 @@ +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/yuin/goldmark v1.3.1 h1:eVwehsLsZlCJCwXyGLgg+Q4iFWE/eTIMG0e8waCmm/I= +github.com/yuin/goldmark v1.3.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181 h1:K+bMSIx9A7mLES1rtG+qKduLIXq40DAzYHtb0XuCukA= +gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181/go.mod h1:dzYhVIwWCtzPAa4QP98wfB9+mzt33MSmM8wsKiMi2ow= +gitlab.com/golang-commonmark/linkify v0.0.0-20191026162114-a0c2df6c8f82 h1:oYrL81N608MLZhma3ruL8qTM4xcpYECGut8KSxRY59g= +gitlab.com/golang-commonmark/linkify v0.0.0-20191026162114-a0c2df6c8f82/go.mod h1:Gn+LZmCrhPECMD3SOKlE+BOHwhOYD9j7WT9NUtkCrC8= +gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3 h1:1Coh5BsUBlXoEJmIEaNzVAWrtg9k7/eJzailMQr1grw= +gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3/go.mod h1:Gn+LZmCrhPECMD3SOKlE+BOHwhOYD9j7WT9NUtkCrC8= +gitlab.com/golang-commonmark/markdown v0.0.0-20191127184510-91b5b3c99c19 h1:HsZm6XaTpEgZiZqcXZkUbG6BNtSZE3XyCTfo52YBoDY= +gitlab.com/golang-commonmark/markdown v0.0.0-20191127184510-91b5b3c99c19/go.mod h1:CRIzp0wh6PvKEAeEOtp9wEpNKJJ1VFTNfHO4+ToRgVA= +gitlab.com/golang-commonmark/mdurl v0.0.0-20191124015652-932350d1cb84 h1:qqjvoVXdWIcZCLPMlzgA7P9FZWdPGPvP/l3ef8GzV6o= +gitlab.com/golang-commonmark/mdurl v0.0.0-20191124015652-932350d1cb84/go.mod h1:IJZ+fdMvbW2qW6htJx7sLJ04FEs4Ldl/MDsJtMKywfw= +gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= +gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= +gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638/go.mod h1:EGRJaqe2eO9XGmFtQCvV3Lm9NLico3UhFwUpCG/+mVU= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/page.go b/page.go new file mode 100644 index 0000000..56da3bf --- /dev/null +++ b/page.go @@ -0,0 +1,37 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/renderer/html" +) + +type page struct { + slug string +} + +func (p *page) render() ([]byte, error) { + data, err := ioutil.ReadFile("posts/" + p.slug + ".md") + if err != nil { + return nil, fmt.Errorf("Could not read from %s.md: %s", p.slug, err) + } + + md := goldmark.New( + goldmark.WithExtensions(extension.Linkify), + goldmark.WithRendererOptions( + html.WithUnsafe(), + ), + ) + + var converted bytes.Buffer + err = md.Convert(data, &converted) + if err != nil { + return nil, fmt.Errorf("Could not parse markdown from %s.md: %s", p.slug, err) + } + + return converted.Bytes(), nil +} diff --git a/posts/.gitignore b/posts/.gitignore new file mode 100644 index 0000000..cfcc04b --- /dev/null +++ b/posts/.gitignore @@ -0,0 +1 @@ +WIP-* \ No newline at end of file diff --git a/prose.go b/prose.go new file mode 100644 index 0000000..94d736b --- /dev/null +++ b/prose.go @@ -0,0 +1,20 @@ +package main + +import ( + "log" + "net/http" +) + +func main() { + log.Printf("Hello, world! This is Prose.") + + s, err := newServer() + + if err != nil { + log.Fatal(err) + } + + http.HandleFunc("/", s.router) + + log.Fatal(http.ListenAndServe(":8080", nil)) +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..06441f7 --- /dev/null +++ b/server.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "strings" +) + +type server struct { + pages []page + staticHandler http.Handler +} + +func newServer() (*server, error) { + files, err := ioutil.ReadDir("posts/") + + if err != nil { + return nil, err + } + + s := &server{ + pages: make([]page, 0, len(files)), + staticHandler: http.FileServer(http.Dir("static/")), + } + + for _, f := range files { + filename := f.Name() + + if strings.HasSuffix(filename, ".md") { + s.pages = append(s.pages, page{slug: strings.TrimSuffix(filename, ".md")}) + } + } + + return s, nil +} + +func (s *server) logRequest(req *http.Request) { + log.Printf("%s %s from %s", req.Method, req.URL.Path, req.RemoteAddr) +} + +func (s *server) router(res http.ResponseWriter, req *http.Request) { + s.logRequest(req) + slug := req.URL.Path[1:] + + if slug == "" { + s.homePage(res, req) + return + } + + for _, p := range s.pages { + if p.slug == slug { + buf, err := p.render() + + if err != nil { + res.WriteHeader(http.StatusInternalServerError) + res.Write([]byte("oh no")) + } + + res.Write(buf) + + return + } + } + + s.staticHandler.ServeHTTP(res, req) +} + +func (s *server) homePage(res http.ResponseWriter, req *http.Request) { + res.Header().Add("content-type", "text/html") + + res.Write([]byte("

blog

")) + + for _, p := range s.pages { + fmt.Fprintf(res, "%s
", p.slug, p.slug) + } +} diff --git a/static/img/blog-init/line-height.png b/static/img/blog-init/line-height.png new file mode 100644 index 0000000..c764275 Binary files /dev/null and b/static/img/blog-init/line-height.png differ