template.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. package xweb
  2. import (
  3. "fmt"
  4. "html/template"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "path/filepath"
  9. "reflect"
  10. "regexp"
  11. "strings"
  12. "sync"
  13. "time"
  14. "app.yhyue.com/moapp/jybase/date"
  15. "app.yhyue.com/moapp/jybase/encrypt"
  16. "github.com/howeyc/fsnotify"
  17. )
  18. func IsNil(a interface{}) bool {
  19. if a == nil {
  20. return true
  21. }
  22. aa := reflect.ValueOf(a)
  23. return !aa.IsValid() || (aa.Type().Kind() == reflect.Ptr && aa.IsNil())
  24. }
  25. //替换函数
  26. func Replace(s interface{}, os, ns string, n int) string {
  27. return strings.Replace(fmt.Sprintf("%s", s), os, ns, n)
  28. }
  29. //正则
  30. func Regexp(s interface{}, os, ns string) string {
  31. return regexp.MustCompile(os).ReplaceAllString(fmt.Sprintf("%s", s), ns)
  32. }
  33. //long转日期
  34. func LongToDate(s interface{}, n int) string {
  35. if n == 0 {
  36. return date.FormatDateWithObj(&s, date.Date_Short_Layout)
  37. } else {
  38. return date.FormatDateWithObj(&s, date.Date_Full_Layout)
  39. }
  40. }
  41. //文本加密
  42. func ConEncode(con interface{}) string {
  43. if con == nil {
  44. return ""
  45. }
  46. log.Println(con)
  47. se := encrypt.SimpleEncrypt{Key: "#topnet@con$temp#"}
  48. return se.EncodeString(fmt.Sprint(con))
  49. }
  50. //文本加密
  51. func ConDecode(con interface{}) string {
  52. if con == nil {
  53. return ""
  54. }
  55. se := encrypt.SimpleEncrypt{Key: "#topnet@con$temp#"}
  56. return se.DecodeString(fmt.Sprint(con))
  57. }
  58. func Add(left interface{}, right interface{}) interface{} {
  59. var rleft, rright int64
  60. var fleft, fright float64
  61. var isInt bool = true
  62. switch left.(type) {
  63. case int:
  64. rleft = int64(left.(int))
  65. case int8:
  66. rleft = int64(left.(int8))
  67. case int16:
  68. rleft = int64(left.(int16))
  69. case int32:
  70. rleft = int64(left.(int32))
  71. case int64:
  72. rleft = left.(int64)
  73. case float32:
  74. fleft = float64(left.(float32))
  75. isInt = false
  76. case float64:
  77. fleft = left.(float64)
  78. isInt = false
  79. }
  80. switch right.(type) {
  81. case int:
  82. rright = int64(right.(int))
  83. case int8:
  84. rright = int64(right.(int8))
  85. case int16:
  86. rright = int64(right.(int16))
  87. case int32:
  88. rright = int64(right.(int32))
  89. case int64:
  90. rright = right.(int64)
  91. case float32:
  92. fright = float64(left.(float32))
  93. isInt = false
  94. case float64:
  95. fleft = left.(float64)
  96. isInt = false
  97. }
  98. var intSum int64 = rleft + rright
  99. if isInt {
  100. return intSum
  101. } else {
  102. return fleft + fright + float64(intSum)
  103. }
  104. }
  105. func Subtract(left interface{}, right interface{}) interface{} {
  106. var rleft, rright int64
  107. var fleft, fright float64
  108. var isInt bool = true
  109. switch left.(type) {
  110. case int:
  111. rleft = int64(left.(int))
  112. case int8:
  113. rleft = int64(left.(int8))
  114. case int16:
  115. rleft = int64(left.(int16))
  116. case int32:
  117. rleft = int64(left.(int32))
  118. case int64:
  119. rleft = left.(int64)
  120. case float32:
  121. fleft = float64(left.(float32))
  122. isInt = false
  123. case float64:
  124. fleft = left.(float64)
  125. isInt = false
  126. }
  127. switch right.(type) {
  128. case int:
  129. rright = int64(right.(int))
  130. case int8:
  131. rright = int64(right.(int8))
  132. case int16:
  133. rright = int64(right.(int16))
  134. case int32:
  135. rright = int64(right.(int32))
  136. case int64:
  137. rright = right.(int64)
  138. case float32:
  139. fright = float64(left.(float32))
  140. isInt = false
  141. case float64:
  142. fleft = left.(float64)
  143. isInt = false
  144. }
  145. if isInt {
  146. return rleft - rright
  147. } else {
  148. return fleft + float64(rleft) - (fright + float64(rright))
  149. }
  150. }
  151. func Now() time.Time {
  152. return time.Now()
  153. }
  154. func FormatDate(t time.Time, format string) string {
  155. return t.Format(format)
  156. }
  157. func Eq(left interface{}, right interface{}) bool {
  158. leftIsNil := (left == nil)
  159. rightIsNil := (right == nil)
  160. if leftIsNil || rightIsNil {
  161. if leftIsNil && rightIsNil {
  162. return true
  163. }
  164. return false
  165. }
  166. return fmt.Sprintf("%v", left) == fmt.Sprintf("%v", right)
  167. }
  168. func Html(raw string) template.HTML {
  169. return template.HTML(raw)
  170. }
  171. func Js(raw string) template.JS {
  172. return template.JS(raw)
  173. }
  174. //Usage:UrlFor("main:root:/user/login") or UrlFor("root:/user/login") or UrlFor("/user/login") or UrlFor()
  175. func UrlFor(args ...string) string {
  176. s := [3]string{"main", "root", ""}
  177. var u []string
  178. size := len(args)
  179. if size > 0 {
  180. u = strings.Split(args[0], ":")
  181. } else {
  182. u = []string{""}
  183. }
  184. var appUrl string = ""
  185. switch len(u) {
  186. case 1:
  187. s[2] = u[0]
  188. case 2:
  189. s[1] = u[0]
  190. s[2] = u[1]
  191. default:
  192. s[0] = u[0]
  193. s[1] = u[1]
  194. s[2] = u[2]
  195. }
  196. var url, prefix, suffix string
  197. if server, ok := Servers[s[0]]; ok {
  198. url += server.Config.Url
  199. prefix = server.Config.UrlPrefix
  200. suffix = server.Config.UrlSuffix
  201. if appPath, ok := server.AppsNamePath[s[1]]; ok {
  202. appUrl = appPath
  203. }
  204. }
  205. url = strings.TrimRight(url, "/") + "/"
  206. if size == 0 {
  207. return url
  208. }
  209. if appUrl != "/" {
  210. appUrl = strings.TrimLeft(appUrl, "/")
  211. if length := len(appUrl); length > 0 && appUrl[length-1] != '/' {
  212. appUrl = appUrl + "/"
  213. }
  214. } else {
  215. appUrl = ""
  216. }
  217. url += prefix + appUrl
  218. if s[2] == "" {
  219. return url
  220. }
  221. url += strings.TrimLeft(s[2], "/") + suffix
  222. return url
  223. }
  224. var (
  225. defaultFuncs template.FuncMap = template.FuncMap{
  226. "Now": Now,
  227. "Eq": Eq,
  228. "FormatDate": FormatDate,
  229. "Html": Html,
  230. "Add": Add,
  231. "Subtract": Subtract,
  232. "IsNil": IsNil,
  233. "UrlFor": UrlFor,
  234. "Js": Js,
  235. "Replace": Replace,
  236. "Regexp": Regexp,
  237. "LongToDate": LongToDate,
  238. "ConDecode": ConDecode, //文本解密
  239. "ConEncode": ConEncode, //文本加密
  240. }
  241. )
  242. type TemplateMgr struct {
  243. Caches map[string][]byte
  244. mutex *sync.Mutex
  245. RootDir string
  246. Ignores map[string]bool
  247. IsReload bool
  248. app *App
  249. Preprocessor func([]byte) []byte
  250. }
  251. func (self *TemplateMgr) Moniter(rootDir string) error {
  252. watcher, err := fsnotify.NewWatcher()
  253. if err != nil {
  254. return err
  255. }
  256. done := make(chan bool)
  257. go func() {
  258. for {
  259. select {
  260. case ev := <-watcher.Event:
  261. if ev == nil {
  262. break
  263. }
  264. if _, ok := self.Ignores[filepath.Base(ev.Name)]; ok {
  265. break
  266. }
  267. d, err := os.Stat(ev.Name)
  268. if err != nil {
  269. break
  270. }
  271. if ev.IsCreate() {
  272. if d.IsDir() {
  273. watcher.Watch(ev.Name)
  274. } else {
  275. tmpl := ev.Name[len(self.RootDir)+1:]
  276. content, err := ioutil.ReadFile(ev.Name)
  277. if err != nil {
  278. self.app.Errorf("loaded template %v failed: %v", tmpl, err)
  279. break
  280. }
  281. self.app.Infof("loaded template file %v success", tmpl)
  282. self.CacheTemplate(tmpl, content)
  283. }
  284. } else if ev.IsDelete() {
  285. if d.IsDir() {
  286. watcher.RemoveWatch(ev.Name)
  287. } else {
  288. tmpl := ev.Name[len(self.RootDir)+1:]
  289. self.CacheDelete(tmpl)
  290. }
  291. } else if ev.IsModify() {
  292. if d.IsDir() {
  293. } else {
  294. tmpl := ev.Name[len(self.RootDir)+1:]
  295. content, err := ioutil.ReadFile(ev.Name)
  296. if err != nil {
  297. self.app.Errorf("reloaded template %v failed: %v", tmpl, err)
  298. break
  299. }
  300. content = newIncludeIntmpl(rootDir, content)
  301. self.CacheTemplate(tmpl, content)
  302. self.app.Infof("reloaded template %v success", tmpl)
  303. }
  304. } else if ev.IsRename() {
  305. if d.IsDir() {
  306. watcher.RemoveWatch(ev.Name)
  307. } else {
  308. tmpl := ev.Name[len(self.RootDir)+1:]
  309. self.CacheDelete(tmpl)
  310. }
  311. }
  312. case err := <-watcher.Error:
  313. self.app.Error("error:", err)
  314. }
  315. }
  316. }()
  317. err = filepath.Walk(self.RootDir, func(f string, info os.FileInfo, err error) error {
  318. if info.IsDir() {
  319. return watcher.Watch(f)
  320. }
  321. return nil
  322. })
  323. if err != nil {
  324. self.app.Error(err.Error())
  325. return err
  326. }
  327. <-done
  328. watcher.Close()
  329. return nil
  330. }
  331. func newIncludeIntmpl(rootDir string, content []byte) []byte {
  332. for i := 0; i < 4; i++ {
  333. b := false
  334. newcontent := regInclude.ReplaceAllFunc(content, func(m []byte) []byte {
  335. b = true
  336. tpl := regInclude.FindSubmatch(m)[1]
  337. fpath := filepath.Join(rootDir, string(tpl))
  338. if strings.Contains(string(m), "OUTSIDE") {
  339. fpath = string(tpl)
  340. }
  341. c, err := ioutil.ReadFile(fpath)
  342. if err != nil {
  343. return []byte{}
  344. }
  345. //c, _ := c.getTemplate(tpl)
  346. return c
  347. })
  348. if !b {
  349. break
  350. }
  351. content = newcontent
  352. }
  353. return content
  354. }
  355. func (self *TemplateMgr) CacheAll(rootDir string) error {
  356. self.mutex.Lock()
  357. defer self.mutex.Unlock()
  358. //fmt.Print("Reading the contents of the template files, please wait... ")
  359. err := filepath.Walk(rootDir, func(f string, info os.FileInfo, err error) error {
  360. if info.IsDir() {
  361. return nil
  362. }
  363. tmpl := f[len(rootDir)+1:]
  364. tmpl = strings.Replace(tmpl, "\\", "/", -1) //[SWH|+]fix windows env
  365. if _, ok := self.Ignores[filepath.Base(tmpl)]; !ok {
  366. fpath := filepath.Join(self.RootDir, tmpl)
  367. content, err := ioutil.ReadFile(fpath)
  368. if err != nil {
  369. self.app.Debugf("load template %s error: %v", fpath, err)
  370. return err
  371. }
  372. content = newIncludeIntmpl(rootDir, content)
  373. self.app.Debug("loaded template", fpath)
  374. self.Caches[tmpl] = content
  375. }
  376. return nil
  377. })
  378. //fmt.Println("Complete.")
  379. return err
  380. }
  381. func (self *TemplateMgr) Init(app *App, rootDir string, reload bool) error {
  382. self.RootDir = rootDir
  383. self.Caches = make(map[string][]byte)
  384. self.Ignores = make(map[string]bool)
  385. self.mutex = &sync.Mutex{}
  386. self.app = app
  387. if dirExists(rootDir) {
  388. self.CacheAll(rootDir)
  389. if reload {
  390. go self.Moniter(rootDir)
  391. }
  392. }
  393. if len(self.Ignores) == 0 {
  394. self.Ignores["*.tmp"] = false
  395. }
  396. return nil
  397. }
  398. func (self *TemplateMgr) GetTemplate(tmpl string) ([]byte, error) {
  399. self.mutex.Lock()
  400. defer self.mutex.Unlock()
  401. if content, ok := self.Caches[tmpl]; ok {
  402. self.app.Debugf("load template %v from cache", tmpl)
  403. return content, nil
  404. }
  405. content, err := ioutil.ReadFile(filepath.Join(self.RootDir, tmpl))
  406. if err == nil {
  407. content = newIncludeIntmpl(self.RootDir, content)
  408. self.app.Debugf("load template %v from the file:", tmpl)
  409. self.Caches[tmpl] = content
  410. }
  411. return content, err
  412. }
  413. func (self *TemplateMgr) CacheTemplate(tmpl string, content []byte) {
  414. if self.Preprocessor != nil {
  415. content = self.Preprocessor(content)
  416. }
  417. self.mutex.Lock()
  418. defer self.mutex.Unlock()
  419. tmpl = strings.Replace(tmpl, "\\", "/", -1)
  420. self.app.Debugf("update template %v on cache", tmpl)
  421. self.Caches[tmpl] = content
  422. return
  423. }
  424. func (self *TemplateMgr) CacheDelete(tmpl string) {
  425. self.mutex.Lock()
  426. defer self.mutex.Unlock()
  427. tmpl = strings.Replace(tmpl, "\\", "/", -1)
  428. self.app.Debugf("delete template %v from cache", tmpl)
  429. delete(self.Caches, tmpl)
  430. return
  431. }