123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- package xweb
- import (
- "fmt"
- "html/template"
- "io/ioutil"
- "log"
- "os"
- "path/filepath"
- "reflect"
- "regexp"
- "strings"
- "sync"
- "time"
- "app.yhyue.com/moapp/jybase/date"
- "app.yhyue.com/moapp/jybase/encrypt"
- "github.com/howeyc/fsnotify"
- )
- func IsNil(a interface{}) bool {
- if a == nil {
- return true
- }
- aa := reflect.ValueOf(a)
- return !aa.IsValid() || (aa.Type().Kind() == reflect.Ptr && aa.IsNil())
- }
- //替换函数
- func Replace(s interface{}, os, ns string, n int) string {
- return strings.Replace(fmt.Sprintf("%s", s), os, ns, n)
- }
- //正则
- func Regexp(s interface{}, os, ns string) string {
- return regexp.MustCompile(os).ReplaceAllString(fmt.Sprintf("%s", s), ns)
- }
- //long转日期
- func LongToDate(s interface{}, n int) string {
- if n == 0 {
- return date.FormatDateWithObj(&s, date.Date_Short_Layout)
- } else {
- return date.FormatDateWithObj(&s, date.Date_Full_Layout)
- }
- }
- //文本加密
- func ConEncode(con interface{}) string {
- if con == nil {
- return ""
- }
- log.Println(con)
- se := encrypt.SimpleEncrypt{Key: "#topnet@con$temp#"}
- return se.EncodeString(fmt.Sprint(con))
- }
- //文本加密
- func ConDecode(con interface{}) string {
- if con == nil {
- return ""
- }
- se := encrypt.SimpleEncrypt{Key: "#topnet@con$temp#"}
- return se.DecodeString(fmt.Sprint(con))
- }
- func Add(left interface{}, right interface{}) interface{} {
- var rleft, rright int64
- var fleft, fright float64
- var isInt bool = true
- switch left.(type) {
- case int:
- rleft = int64(left.(int))
- case int8:
- rleft = int64(left.(int8))
- case int16:
- rleft = int64(left.(int16))
- case int32:
- rleft = int64(left.(int32))
- case int64:
- rleft = left.(int64)
- case float32:
- fleft = float64(left.(float32))
- isInt = false
- case float64:
- fleft = left.(float64)
- isInt = false
- }
- switch right.(type) {
- case int:
- rright = int64(right.(int))
- case int8:
- rright = int64(right.(int8))
- case int16:
- rright = int64(right.(int16))
- case int32:
- rright = int64(right.(int32))
- case int64:
- rright = right.(int64)
- case float32:
- fright = float64(left.(float32))
- isInt = false
- case float64:
- fleft = left.(float64)
- isInt = false
- }
- var intSum int64 = rleft + rright
- if isInt {
- return intSum
- } else {
- return fleft + fright + float64(intSum)
- }
- }
- func Subtract(left interface{}, right interface{}) interface{} {
- var rleft, rright int64
- var fleft, fright float64
- var isInt bool = true
- switch left.(type) {
- case int:
- rleft = int64(left.(int))
- case int8:
- rleft = int64(left.(int8))
- case int16:
- rleft = int64(left.(int16))
- case int32:
- rleft = int64(left.(int32))
- case int64:
- rleft = left.(int64)
- case float32:
- fleft = float64(left.(float32))
- isInt = false
- case float64:
- fleft = left.(float64)
- isInt = false
- }
- switch right.(type) {
- case int:
- rright = int64(right.(int))
- case int8:
- rright = int64(right.(int8))
- case int16:
- rright = int64(right.(int16))
- case int32:
- rright = int64(right.(int32))
- case int64:
- rright = right.(int64)
- case float32:
- fright = float64(left.(float32))
- isInt = false
- case float64:
- fleft = left.(float64)
- isInt = false
- }
- if isInt {
- return rleft - rright
- } else {
- return fleft + float64(rleft) - (fright + float64(rright))
- }
- }
- func Now() time.Time {
- return time.Now()
- }
- func FormatDate(t time.Time, format string) string {
- return t.Format(format)
- }
- func Eq(left interface{}, right interface{}) bool {
- leftIsNil := (left == nil)
- rightIsNil := (right == nil)
- if leftIsNil || rightIsNil {
- if leftIsNil && rightIsNil {
- return true
- }
- return false
- }
- return fmt.Sprintf("%v", left) == fmt.Sprintf("%v", right)
- }
- func Html(raw string) template.HTML {
- return template.HTML(raw)
- }
- func Js(raw string) template.JS {
- return template.JS(raw)
- }
- //Usage:UrlFor("main:root:/user/login") or UrlFor("root:/user/login") or UrlFor("/user/login") or UrlFor()
- func UrlFor(args ...string) string {
- s := [3]string{"main", "root", ""}
- var u []string
- size := len(args)
- if size > 0 {
- u = strings.Split(args[0], ":")
- } else {
- u = []string{""}
- }
- var appUrl string = ""
- switch len(u) {
- case 1:
- s[2] = u[0]
- case 2:
- s[1] = u[0]
- s[2] = u[1]
- default:
- s[0] = u[0]
- s[1] = u[1]
- s[2] = u[2]
- }
- var url, prefix, suffix string
- if server, ok := Servers[s[0]]; ok {
- url += server.Config.Url
- prefix = server.Config.UrlPrefix
- suffix = server.Config.UrlSuffix
- if appPath, ok := server.AppsNamePath[s[1]]; ok {
- appUrl = appPath
- }
- }
- url = strings.TrimRight(url, "/") + "/"
- if size == 0 {
- return url
- }
- if appUrl != "/" {
- appUrl = strings.TrimLeft(appUrl, "/")
- if length := len(appUrl); length > 0 && appUrl[length-1] != '/' {
- appUrl = appUrl + "/"
- }
- } else {
- appUrl = ""
- }
- url += prefix + appUrl
- if s[2] == "" {
- return url
- }
- url += strings.TrimLeft(s[2], "/") + suffix
- return url
- }
- var (
- defaultFuncs template.FuncMap = template.FuncMap{
- "Now": Now,
- "Eq": Eq,
- "FormatDate": FormatDate,
- "Html": Html,
- "Add": Add,
- "Subtract": Subtract,
- "IsNil": IsNil,
- "UrlFor": UrlFor,
- "Js": Js,
- "Replace": Replace,
- "Regexp": Regexp,
- "LongToDate": LongToDate,
- "ConDecode": ConDecode, //文本解密
- "ConEncode": ConEncode, //文本加密
- }
- )
- type TemplateMgr struct {
- Caches map[string][]byte
- mutex *sync.Mutex
- RootDir string
- Ignores map[string]bool
- IsReload bool
- app *App
- Preprocessor func([]byte) []byte
- }
- func (self *TemplateMgr) Moniter(rootDir string) error {
- watcher, err := fsnotify.NewWatcher()
- if err != nil {
- return err
- }
- done := make(chan bool)
- go func() {
- for {
- select {
- case ev := <-watcher.Event:
- if ev == nil {
- break
- }
- if _, ok := self.Ignores[filepath.Base(ev.Name)]; ok {
- break
- }
- d, err := os.Stat(ev.Name)
- if err != nil {
- break
- }
- if ev.IsCreate() {
- if d.IsDir() {
- watcher.Watch(ev.Name)
- } else {
- tmpl := ev.Name[len(self.RootDir)+1:]
- content, err := ioutil.ReadFile(ev.Name)
- if err != nil {
- self.app.Errorf("loaded template %v failed: %v", tmpl, err)
- break
- }
- self.app.Infof("loaded template file %v success", tmpl)
- self.CacheTemplate(tmpl, content)
- }
- } else if ev.IsDelete() {
- if d.IsDir() {
- watcher.RemoveWatch(ev.Name)
- } else {
- tmpl := ev.Name[len(self.RootDir)+1:]
- self.CacheDelete(tmpl)
- }
- } else if ev.IsModify() {
- if d.IsDir() {
- } else {
- tmpl := ev.Name[len(self.RootDir)+1:]
- content, err := ioutil.ReadFile(ev.Name)
- if err != nil {
- self.app.Errorf("reloaded template %v failed: %v", tmpl, err)
- break
- }
- content = newIncludeIntmpl(rootDir, content)
- self.CacheTemplate(tmpl, content)
- self.app.Infof("reloaded template %v success", tmpl)
- }
- } else if ev.IsRename() {
- if d.IsDir() {
- watcher.RemoveWatch(ev.Name)
- } else {
- tmpl := ev.Name[len(self.RootDir)+1:]
- self.CacheDelete(tmpl)
- }
- }
- case err := <-watcher.Error:
- self.app.Error("error:", err)
- }
- }
- }()
- err = filepath.Walk(self.RootDir, func(f string, info os.FileInfo, err error) error {
- if info.IsDir() {
- return watcher.Watch(f)
- }
- return nil
- })
- if err != nil {
- self.app.Error(err.Error())
- return err
- }
- <-done
- watcher.Close()
- return nil
- }
- func newIncludeIntmpl(rootDir string, content []byte) []byte {
- for i := 0; i < 4; i++ {
- b := false
- newcontent := regInclude.ReplaceAllFunc(content, func(m []byte) []byte {
- b = true
- tpl := regInclude.FindSubmatch(m)[1]
- fpath := filepath.Join(rootDir, string(tpl))
- if strings.Contains(string(m), "OUTSIDE") {
- fpath = string(tpl)
- }
- c, err := ioutil.ReadFile(fpath)
- if err != nil {
- return []byte{}
- }
- //c, _ := c.getTemplate(tpl)
- return c
- })
- if !b {
- break
- }
- content = newcontent
- }
- return content
- }
- func (self *TemplateMgr) CacheAll(rootDir string) error {
- self.mutex.Lock()
- defer self.mutex.Unlock()
- //fmt.Print("Reading the contents of the template files, please wait... ")
- err := filepath.Walk(rootDir, func(f string, info os.FileInfo, err error) error {
- if info.IsDir() {
- return nil
- }
- tmpl := f[len(rootDir)+1:]
- tmpl = strings.Replace(tmpl, "\\", "/", -1) //[SWH|+]fix windows env
- if _, ok := self.Ignores[filepath.Base(tmpl)]; !ok {
- fpath := filepath.Join(self.RootDir, tmpl)
- content, err := ioutil.ReadFile(fpath)
- if err != nil {
- self.app.Debugf("load template %s error: %v", fpath, err)
- return err
- }
- content = newIncludeIntmpl(rootDir, content)
- self.app.Debug("loaded template", fpath)
- self.Caches[tmpl] = content
- }
- return nil
- })
- //fmt.Println("Complete.")
- return err
- }
- func (self *TemplateMgr) Init(app *App, rootDir string, reload bool) error {
- self.RootDir = rootDir
- self.Caches = make(map[string][]byte)
- self.Ignores = make(map[string]bool)
- self.mutex = &sync.Mutex{}
- self.app = app
- if dirExists(rootDir) {
- self.CacheAll(rootDir)
- if reload {
- go self.Moniter(rootDir)
- }
- }
- if len(self.Ignores) == 0 {
- self.Ignores["*.tmp"] = false
- }
- return nil
- }
- func (self *TemplateMgr) GetTemplate(tmpl string) ([]byte, error) {
- self.mutex.Lock()
- defer self.mutex.Unlock()
- if content, ok := self.Caches[tmpl]; ok {
- self.app.Debugf("load template %v from cache", tmpl)
- return content, nil
- }
- content, err := ioutil.ReadFile(filepath.Join(self.RootDir, tmpl))
- if err == nil {
- content = newIncludeIntmpl(self.RootDir, content)
- self.app.Debugf("load template %v from the file:", tmpl)
- self.Caches[tmpl] = content
- }
- return content, err
- }
- func (self *TemplateMgr) CacheTemplate(tmpl string, content []byte) {
- if self.Preprocessor != nil {
- content = self.Preprocessor(content)
- }
- self.mutex.Lock()
- defer self.mutex.Unlock()
- tmpl = strings.Replace(tmpl, "\\", "/", -1)
- self.app.Debugf("update template %v on cache", tmpl)
- self.Caches[tmpl] = content
- return
- }
- func (self *TemplateMgr) CacheDelete(tmpl string) {
- self.mutex.Lock()
- defer self.mutex.Unlock()
- tmpl = strings.Replace(tmpl, "\\", "/", -1)
- self.app.Debugf("delete template %v from cache", tmpl)
- delete(self.Caches, tmpl)
- return
- }
|