arnaucube
arnaucube/md-live-serverPublic Self-hosted repository
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		return
 72	}
 73
 74	content, err := fileToHTML(path)
 75	check(err)
 76
 77	var page PageModel
 78	page.Title = path
 79	page.Content = template.HTML(content)
 80
 81	tmplPage := template.Must(template.New("t").Parse(htmlTemplate))
 82	tmplPage.Execute(w, page)
 83}
 84
 85func serveWs(w http.ResponseWriter, r *http.Request) {
 86	vars := mux.Vars(r)
 87	path := vars["path"]
 88	path = strings.Replace(path, "%", "/", -1)
 89	log.Println("websocket", path)
 90
 91	ws, err := upgrader.Upgrade(w, r, nil)
 92	if err != nil {
 93		if _, ok := err.(websocket.HandshakeError); !ok {
 94			log.Println(err)
 95		}
 96		return
 97	}
 98
 99	// watch file
100	watcher, err := fsnotify.NewWatcher()
101	if err != nil {
102		log.Fatal(err)
103	}
104	defer watcher.Close()
105
106	done := make(chan bool)
107	go func() {
108		for {
109			select {
110			case event, ok := <-watcher.Events:
111				if !ok {
112					return
113				}
114				log.Println("event:", event)
115				if event.Op&fsnotify.Write == fsnotify.Write {
116					log.Println("modified file:", event.Name)
117					writer(ws, path)
118				}
119			case err, ok := <-watcher.Errors:
120				if !ok {
121					return
122				}
123				log.Println("error:", err)
124			}
125		}
126	}()
127
128	err = watcher.Add(path)
129	if err != nil {
130		log.Fatal(err)
131	}
132	<-done
133}
134
135func writer(ws *websocket.Conn, path string) {
136	content, err := fileToHTML(path)
137	check(err)
138	if err := ws.WriteMessage(websocket.TextMessage, []byte(content)); err != nil {
139		return
140	}
141}