aboutsummaryrefslogtreecommitdiff
path: root/site.go
diff options
context:
space:
mode:
Diffstat (limited to 'site.go')
-rw-r--r--site.go268
1 files changed, 268 insertions, 0 deletions
diff --git a/site.go b/site.go
new file mode 100644
index 0000000..ab1d850
--- /dev/null
+++ b/site.go
@@ -0,0 +1,268 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "text/template"
+)
+
+type Post struct {
+ Meta []byte
+ Thumbnail []byte
+ Content []byte
+}
+
+type Posts struct {
+ Contents []*Post
+}
+
+func trimLeftChars(s string, n int) string {
+ m := 0
+ for i := range s {
+ if m >= n {
+ return s[i:]
+ }
+ m++
+ }
+ return s[:0]
+}
+
+func loadPost(path string) (p *Posts, err error) {
+
+ var section = 0
+ var tmp *Post = new(Post)
+
+ file, err := os.Open(path + ".html")
+ if err != nil {
+ file.Close()
+ var tmpPosts []*Post
+ tmpPosts = append(tmpPosts, tmp)
+ return &Posts{Contents: tmpPosts}, err
+ }
+
+ scanner := bufio.NewScanner(file)
+
+LineLoop:
+ for scanner.Scan() {
+ var line = scanner.Text()
+ var lineByte = []byte(line + "\n")
+
+ if line == "!@#" {
+ section++
+ goto LineLoop
+ }
+
+ switch section {
+ case 0:
+ tmp.Meta = append(tmp.Meta, lineByte...)
+ case 1:
+ tmp.Thumbnail = append(tmp.Thumbnail, lineByte...)
+ case 2:
+ tmp.Content = append(tmp.Content, lineByte...)
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ log.Fatal(err)
+ }
+
+ file.Close()
+
+ if err != nil {
+ return nil, err
+ }
+
+ var tmpPosts []*Post
+ tmpPosts = append(tmpPosts, tmp)
+
+ return &Posts{Contents: tmpPosts}, nil
+}
+
+func loadPosts(location string, postCount int) (p *Posts, err error) {
+ if postCount == 0 || postCount < -1 {
+ return nil, os.ErrInvalid
+ }
+
+ var tmpPosts []*Post
+ var depthCount = 0
+
+ // TODO - Use less computationally heavy opperation for scalability
+ err = filepath.Walk(location, func(path string, _ os.FileInfo, _ error) error {
+ var directory, err = regexp.MatchString("^data/(projects|blog)$", path)
+ if err != nil {
+ return err
+ }
+
+ if directory {
+ depthCount++
+ } else if postCount == -1 || depthCount < postCount+1 {
+ file, err := os.Open(path)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ scanner := bufio.NewScanner(file)
+
+ var section = 0
+ var tmp *Post = new(Post)
+
+ LineLoop:
+ for scanner.Scan() {
+ var line = scanner.Text()
+ var lineByte = []byte(line + "\n")
+
+ if line == "!@#" {
+ section++
+ goto LineLoop
+ }
+
+ switch section {
+ case 0:
+ tmp.Meta = append(tmp.Meta, lineByte...)
+ case 1:
+ tmp.Thumbnail = append(tmp.Thumbnail, lineByte...)
+ case 2:
+ tmp.Content = append(tmp.Content, lineByte...)
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ log.Fatal(err)
+ }
+
+ file.Close()
+
+ tmpPosts = append(tmpPosts, tmp)
+ depthCount++
+
+ } else {
+ depthCount++
+ }
+
+ return nil
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ return &Posts{Contents: tmpPosts}, nil
+}
+
+func renderTemplate(w http.ResponseWriter, tmpl string, p *Posts) {
+ if tmpl == "post" {
+ t, err := template.ParseFiles("templates/master.html", "templates/postHelp.tmpl")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ err = t.Execute(w, p.Contents[0])
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ } else {
+ t, err := template.ParseFiles("templates/master.html", "templates/"+tmpl+".html")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ err = t.Execute(w, p)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ }
+}
+
+func rootHandler(w http.ResponseWriter, r *http.Request) {
+ path := strings.Split(r.URL.Path, "/")
+ if path[1] != "" {
+ http.NotFound(w, r)
+ } else {
+ p, err := loadPosts("data/projects", 3)
+ if err != nil {
+ http.NotFound(w, r)
+ }
+
+ renderTemplate(w, "index", p)
+ }
+}
+
+func aboutHandler(w http.ResponseWriter, r *http.Request) {
+ renderTemplate(w, "about", nil)
+}
+
+func agHandler(w http.ResponseWriter, r *http.Request) {
+ p, err := loadPosts("data"+strings.TrimSuffix(r.URL.Path, "/"), -1)
+ if err != nil {
+ http.NotFound(w, r)
+ }
+
+ renderTemplate(w, trimLeftChars(strings.TrimSuffix(r.URL.Path, "/"), 1), p)
+}
+
+func postHandler(w http.ResponseWriter, r *http.Request) {
+ path := strings.Split(r.URL.Path, "/")
+ if path[2] == "" {
+ agHandler(w, r)
+ } else {
+ p, err := loadPost("data/" + path[1] + "/" + path[2])
+ if p == nil || err != nil {
+ http.NotFound(w, r)
+ } else {
+ renderTemplate(w, "post", p)
+ }
+ }
+}
+
+func fileHandler(w http.ResponseWriter, r *http.Request) {
+ body, _ := os.ReadFile("data/www/" + r.URL.Path)
+
+ w.Header().Set("Content-Type", "text/css; charset=utf-8")
+ fmt.Fprintf(w, "%s", body)
+}
+
+func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ fn(w, r)
+ }
+}
+
+func httpsRedirect(w http.ResponseWriter, req *http.Request) {
+ // remove/add not default ports from req.Host
+ target := "https://" + req.Host + req.URL.Path
+ if len(req.URL.RawQuery) > 0 {
+ target += "?" + req.URL.RawQuery
+ }
+ log.Printf("redirect to: %s", target)
+ http.Redirect(w, req, target,
+ // see comments below and consider the codes 308, 302, or 301
+ http.StatusMovedPermanently)
+}
+
+func main() {
+ /* hostValid, _ := regexp.MatchString("^alexscerba.com$", r.URL.Path)
+ if !hostValid {
+ req, _ := http.NewRequest(r.Method, "alexscerba.com"+r.URL.Path, r.Body)
+ redirect(w, req)
+ } */
+
+ fs := http.FileServer(http.Dir("./data/static"))
+ http.Handle("/static/", http.StripPrefix("/static/", fs))
+
+ http.HandleFunc("/projects/", postHandler)
+ http.HandleFunc("/blog/", postHandler)
+ http.HandleFunc("/about/", aboutHandler)
+ http.HandleFunc("/", rootHandler)
+
+ go http.ListenAndServe(":80", http.HandlerFunc(httpsRedirect))
+ log.Fatal(http.ListenAndServe(":443", nil))
+
+ //http.Handle("/", http.FileServer(http.Dir("/data/www")))
+ //log.Fatal(http.ListenAndServe(":8080", nil))
+}