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	}
 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}