md-live-server/main.go
main.goRaw
1package main
2
3import (
4 "fmt"
5 "html/template"
6 "log"
7 "net/http"
8 "strings"
9 "time"
10
11 "github.com/fsnotify/fsnotify"
12 "github.com/gorilla/mux"
13 "github.com/gorilla/websocket"
14)
15
16var (
17 upgrader = websocket.Upgrader{
18 ReadBufferSize: 1024,
19 WriteBufferSize: 1024,
20 }
21)
22
23type PageModel struct {
24 Title string
25 Content template.HTML
26 LastMod time.Time
27}
28
29func main() {
30 router := mux.NewRouter()
31 router.HandleFunc("/", getDir).Methods("GET")
32 router.HandleFunc("/{path}", getPage).Methods("GET")
33 router.HandleFunc("/ws/{path}", serveWs)
34
35 log.Println("md-live-server web server running")
36 log.Print("port: 8080")
37 log.Fatal(http.ListenAndServe(":8080", router))
38}
39
40func getDir(w http.ResponseWriter, r *http.Request) {
41 elements := readDir("./")
42 var content string
43 content = `<ul>`
44 for _, elem := range elements {
45 content += `
46 <li><a href="` + elem + `">` + elem + `</a></li>
47 `
48 }
49 content += `</ul>`
50 var page PageModel
51 page.Title = "dir"
52 page.Content = template.HTML(content)
53
54 tmplPage := template.Must(template.New("t").Parse(dirTemplate))
55 tmplPage.Execute(w, page)
56}
57
58func getPage(w http.ResponseWriter, r *http.Request) {
59 vars := mux.Vars(r)
60 path := vars["path"]
61 path = strings.Replace(path, "%", "/", -1)
62 log.Println(path)
63
64 if len(strings.Split(path, ".")) < 2 {
65 fmt.Fprintf(w, errTemplate)
66 return
67 }
68
69 if strings.Split(path, ".")[1] != "md" {
70 http.ServeFile(w, r, path)
71 }
72
73 content, err := fileToHTML(path)
74 check(err)
75
76 var page PageModel
77 page.Title = path
78 page.Content = template.HTML(content)
79
80 tmplPage := template.Must(template.New("t").Parse(htmlTemplate))
81 tmplPage.Execute(w, page)
82}
83
84func serveWs(w http.ResponseWriter, r *http.Request) {
85 vars := mux.Vars(r)
86 path := vars["path"]
87 path = strings.Replace(path, "%", "/", -1)
88 log.Println("websocket", path)
89
90 ws, err := upgrader.Upgrade(w, r, nil)
91 if err != nil {
92 if _, ok := err.(websocket.HandshakeError); !ok {
93 log.Println(err)
94 }
95 return
96 }
97
98 // watch file
99 watcher, err := fsnotify.NewWatcher()
100 if err != nil {
101 log.Fatal(err)
102 }
103 defer watcher.Close()
104
105 done := make(chan bool)
106 go func() {
107 for {
108 select {
109 case event, ok := <-watcher.Events:
110 if !ok {
111 return
112 }
113 log.Println("event:", event)
114 if event.Op&fsnotify.Write == fsnotify.Write {
115 log.Println("modified file:", event.Name)
116 writer(ws, path)
117 }
118 case err, ok := <-watcher.Errors:
119 if !ok {
120 return
121 }
122 log.Println("error:", err)
123 }
124 }
125 }()
126
127 err = watcher.Add(path)
128 if err != nil {
129 log.Fatal(err)
130 }
131 <-done
132}
133
134func writer(ws *websocket.Conn, path string) {
135 content, err := fileToHTML(path)
136 check(err)
137 if err := ws.WriteMessage(websocket.TextMessage, []byte(content)); err != nil {
138 return
139 }
140}