You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
2.7 KiB

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