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.

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