以前要写一个项目文档,须要给上级审核以后才能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的代码,主要是增长了一些锁加强并发和易用性的东西,与功能无大关系 下载地址缓存