以前要寫一個項目文檔,須要給上級審覈以後才能push到線上。直接扔markdown文件有些不合適,但將它轉爲pdf文件發送有點麻煩,每次修改都須要轉一次,再發送。所以就有了寫一個簡單的markdown在線解析服務的想法。在本地搭一個服務,到時候直接給地址,意見反饋後,直接本地修改,服務更新後就能看到新版本了。html
簡單的在main.go裏增長一個全局以文件名稱爲key,具體路徑爲value的map。index頁面就遍歷這個map,read接口就從這裏獲取文件路徑,讀取返回。update也是更新這個表。後期若是增長緩存,將路徑string改成自定義的struck。git
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>markdownlist</h1> {{range $key, $value := .}} <a href="/read?file={{$key}}">{{$key}}</a><br/> {{end}} </body> </html>
package main import ( "fmt" "html/template" "io/ioutil" "net/http" "os" "path/filepath" "strings" "sync" "github.com/microcosm-cc/bluemonday" "gopkg.in/russross/blackfriday.v2" ) var ( MARK_DOWNS_PATH = "markdowns" TEMPLATES_PATH = "templates" fileMap map[string]string globalLock *sync.RWMutex ) func init() { globalLock = new(sync.RWMutex) updateMarkdownFileList() } func updateMarkdownFileList() { globalLock.Lock() defer globalLock.Unlock() fileMap = make(map[string]string) files, _ := filepath.Glob(fmt.Sprintf("%s/*", MARK_DOWNS_PATH)) for _, f := range files { fileName := f[strings.LastIndex(f, string(os.PathSeparator))+1 : len(f)-3] fileMap[fileName] = f } } func readMarkdownFile(fileName string) ([]byte, error) { globalLock.RLock() defer globalLock.RUnlock() markdownFile, ok := fileMap[fileName] if !ok { return nil, fmt.Errorf("file(%s)NotExist", fileName) } if fileread, err := ioutil.ReadFile(markdownFile); err == nil { unsafe := blackfriday.Run(fileread) html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) return html, nil } else { return nil, fmt.Errorf("file(%s)ReadFail", fileName) } } func indexHandler(w http.ResponseWriter, r *http.Request) { t := template.New("index.html") t, _ = t.ParseFiles(fmt.Sprintf("%s%sindex.html", TEMPLATES_PATH, string(os.PathSeparator))) t.Execute(w, fileMap) } func readerHander(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("file") body, err := readMarkdownFile(name) if err != nil { w.WriteHeader(http.StatusNotFound) } else { w.Write(body) } } func updateHandler(w http.ResponseWriter, req *http.Request) { updateMarkdownFileList() w.Write([]byte("success")) } func main() { http.HandleFunc("/", indexHandler) http.HandleFunc("/read", readerHander) http.HandleFunc("/update", updateHandler) http.ListenAndServe(":8000", nil) }
項目的重點就在於markdown解析成html,既然都直接使用現成的第三方包,就基本沒有什麼技術性。惟一須要考慮的就是鎖的問題。後期還能夠增長緩存來提升性能,增長trylock限制update接口更新的問題。github
如下是新版本pro的代碼,主要是增長了一些鎖加強併發和易用性的東西,與功能無大關係 下載地址緩存