说明
之前要写一个项目文档,需要给上级审核之后才能push到线上。直接扔markdown文件有些不合适,但将它转为pdf文件发送有点麻烦,每次修改都需要转一次,再发送。因此就有了写一个简单的markdown在线解析服务的想法。到时候直接给地址,意见反馈后,直接本地修改,服务更新后就能看到新版本了。
dependences
- github.com/microcosm-cc/bluemonday
- gopkg.in/russross/blackfriday.v2
文件目录
- ./markdowns/* 存放需要解析的markdown文件
- ./templates/* 存放工程需要的html模板
接口
- / index显示扫描到的文件列表
- /read?file=${fileName} 显示markdown转换后的HTML页面
- /update 调用后,重新扫描文件目录
实现
··· 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接口更新的问题。