简单的markdown在线解析服务

说明

以前要写一个项目文档,须要给上级审核以后才能push到线上。直接扔markdown文件有些不合适,但将它转为pdf文件发送有点麻烦,每次修改都须要转一次,再发送。所以就有了写一个简单的markdown在线解析服务的想法。在本地搭一个服务,到时候直接给地址,意见反馈后,直接本地修改,服务更新后就能看到新版本了。html

dependences

  • github.com/microcosm-cc/bluemonday
  • gopkg.in/russross/blackfriday.v2

文件目录

  • ./markdowns/* 存放须要解析的markdown文件
  • ./templates/* 存放工程须要的html模板

接口

  • / index显示扫描到的文件列表
  • /read?file=${fileName} 显示markdown转换后的HTML页面
  • /update 调用后,从新扫描文件目录

基本思路

简单的在main.go里增长一个全局以文件名称为key,具体路径为value的map。index页面就遍历这个map,read接口就从这里获取文件路径,读取返回。update也是更新这个表。后期若是增长缓存,将路径string改成自定义的struck。git

实现

index.html模板

<!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>

main.go

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

ennn

如下是新版本pro的代码,主要是增长了一些锁加强并发和易用性的东西,与功能无大关系 下载地址缓存

相关文章
相关标签/搜索