| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | // Copyright 2013 Martini Authors
 | 
					
						
							|  |  |  | // Copyright 2014 The Macaron Authors
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License"): you may
 | 
					
						
							|  |  |  | // not use this file except in compliance with the License. You may obtain
 | 
					
						
							|  |  |  | // a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
					
						
							|  |  |  | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
					
						
							|  |  |  | // License for the specific language governing permissions and limitations
 | 
					
						
							|  |  |  | // under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | package web | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"html/template" | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 	"io/fs" | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2024-06-10 19:30:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"golang.org/x/sync/singleflight" | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | // Renderer is a Middleware that injects a template renderer into the macaron context, enabling ctx.HTML calls in the handlers.
 | 
					
						
							|  |  |  | // If MACARON_ENV is set to "development" then templates will be recompiled on every request. For more performance, set the
 | 
					
						
							|  |  |  | // MACARON_ENV environment variable to "production".
 | 
					
						
							| 
									
										
										
										
											2022-08-09 20:58:50 +08:00
										 |  |  | func Renderer(dir, leftDelim, rightDelim string) Middleware { | 
					
						
							| 
									
										
										
										
											2024-06-10 19:30:17 +08:00
										 |  |  | 	var devEnvGr singleflight.Group | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 	fs := os.DirFS(dir) | 
					
						
							|  |  |  | 	t, err := compileTemplates(fs, leftDelim, rightDelim) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic("Renderer: " + err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return func(next http.Handler) http.Handler { | 
					
						
							|  |  |  | 		return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { | 
					
						
							|  |  |  | 			ctx := FromContext(req.Context()) | 
					
						
							| 
									
										
										
										
											2024-06-10 19:30:17 +08:00
										 |  |  | 			ctx.template = t | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 			if Env == DEV { | 
					
						
							| 
									
										
										
										
											2024-06-10 19:30:17 +08:00
										 |  |  | 				tt, err, _ := devEnvGr.Do("dev", func() (any, error) { | 
					
						
							|  |  |  | 					return compileTemplates(fs, leftDelim, rightDelim) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 					panic("Context.HTML:" + err.Error()) | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-06-10 19:30:17 +08:00
										 |  |  | 				ctx.template = tt.(*template.Template) | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 			next.ServeHTTP(rw, req) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | func compileTemplates(filesystem fs.FS, leftDelim, rightDelim string) (*template.Template, error) { | 
					
						
							|  |  |  | 	t := template.New("") | 
					
						
							|  |  |  | 	t.Delims(leftDelim, rightDelim) | 
					
						
							|  |  |  | 	err := fs.WalkDir(filesystem, ".", func(path string, d fs.DirEntry, e error) error { | 
					
						
							|  |  |  | 		if e != nil { | 
					
						
							|  |  |  | 			return nil // skip unreadable or erroneous filesystem items
 | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 		if d.IsDir() { | 
					
						
							|  |  |  | 			return nil | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 		ext := filepath.Ext(path) | 
					
						
							|  |  |  | 		if ext != ".html" && ext != ".tmpl" { | 
					
						
							|  |  |  | 			return nil | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 		data, err := fs.ReadFile(filesystem, path) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-10 19:29:46 +08:00
										 |  |  | 		basename := path[:len(path)-len(ext)] | 
					
						
							|  |  |  | 		_, err = t.New(basename).Parse(string(data)) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	return t, err | 
					
						
							| 
									
										
										
										
											2021-07-08 20:19:40 +08:00
										 |  |  | } |