parent
97b2901e7d
commit
75234ebd31
40
main.go
40
main.go
|
@ -15,41 +15,36 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"flag"
|
||||||
"github.com/Sirupsen/logrus"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
"flag"
|
|
||||||
"amuz.es/go/mnemonics/route"
|
"amuz.es/go/mnemonics/route"
|
||||||
"amuz.es/go/mnemonics/util"
|
"amuz.es/go/mnemonics/util"
|
||||||
"net/http"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/flosch/pongo2"
|
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var argIp = flag.String("listen_ip", "", "IP to listen on, defaults to all IPs")
|
var argIp = flag.String("listen_ip", "", "IP to listen on, defaults to all IPs")
|
||||||
var argPort = flag.Int("port", 8080, "port to listen")
|
var argPort = flag.Int("port", 8080, "port to listen")
|
||||||
var maxProcs = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores).")
|
var maxProcs = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores).")
|
||||||
var logger = logrus.New()
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
setMaxProcs()
|
setMaxProcs()
|
||||||
|
util.InitLogger()
|
||||||
|
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
|
// middleware settings
|
||||||
|
r.Use(util.Ginrus(time.RFC3339, true))
|
||||||
r.Use(util.Ginrus(logrus.StandardLogger(), time.RFC3339, true))
|
|
||||||
|
|
||||||
r.Use(gin.Recovery())
|
r.Use(gin.Recovery())
|
||||||
|
|
||||||
|
// not found handler
|
||||||
r.NoRoute(func(c *gin.Context) {
|
r.NoRoute(func(c *gin.Context) {
|
||||||
c.HTML(http.StatusOK, "page_404.html", pongo2.Context{})
|
c.HTML(http.StatusOK, "page_404.html", util.Context{})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
logger.Level = logrus.ErrorLevel
|
|
||||||
logger.Out=os.Stderr
|
|
||||||
r.Use(util.Ginrus(logger, time.RFC3339, false))
|
|
||||||
r.StaticFS("/static", route.Static(""))
|
r.StaticFS("/static", route.Static(""))
|
||||||
|
|
||||||
r.GET("/api", route.Api)
|
r.GET("/api", route.Api)
|
||||||
|
@ -59,12 +54,15 @@ func main() {
|
||||||
c.String(200, "OK! - mnemonics services are fully operational!")
|
c.String(200, "OK! - mnemonics services are fully operational!")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Use pongo2gin.Default() for default options or pongo2gin.New()
|
if gin.IsDebugging() {
|
||||||
// if you need to use custom RenderOptions.
|
r.HTMLRender = util.TemplateSourceDebug("asset/template")
|
||||||
r.HTMLRender = util.Default()
|
} else {
|
||||||
|
r.HTMLRender = util.TemplateSourceRelease("")
|
||||||
|
}
|
||||||
|
|
||||||
r.GET("/", route.Index)
|
r.GET("/", route.Index)
|
||||||
|
|
||||||
logger.Error("bootstrapped application")
|
util.Log().Error("bootstrapped application")
|
||||||
|
|
||||||
r.Run() // listen and server on 0.0.0.0:8080
|
r.Run() // listen and server on 0.0.0.0:8080
|
||||||
}
|
}
|
||||||
|
@ -83,6 +81,6 @@ func setMaxProcs() {
|
||||||
// Check if the setting was successful.
|
// Check if the setting was successful.
|
||||||
actualNumProcs := runtime.GOMAXPROCS(0)
|
actualNumProcs := runtime.GOMAXPROCS(0)
|
||||||
if actualNumProcs != numProcs {
|
if actualNumProcs != numProcs {
|
||||||
logger.Warnf("Specified max procs of %v but using %v", numProcs, actualNumProcs)
|
util.Log().Warnf("Specified max procs of %v but using %v", numProcs, actualNumProcs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,12 @@ package route
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/flosch/pongo2"
|
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"amuz.es/go/mnemonics/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Index(c *gin.Context) {
|
func Index(c *gin.Context) {
|
||||||
c.HTML(http.StatusOK, "index.html", pongo2.Context{})
|
c.HTML(http.StatusOK, "index.html", util.Context{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,25 @@ package util
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logger = logrus.New()
|
||||||
|
|
||||||
|
func InitLogger() {
|
||||||
|
// logging framework
|
||||||
|
logger.Level = logrus.ErrorLevel
|
||||||
|
logger.Out = os.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
func Log() *logrus.Logger {
|
||||||
|
// logging framework
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
// Ginrus returns a gin.HandlerFunc (middleware) that logs requests using logrus.
|
// Ginrus returns a gin.HandlerFunc (middleware) that logs requests using logrus.
|
||||||
//
|
//
|
||||||
// Requests with errors are logged using logrus.Error().
|
// Requests with errors are logged using logrus.Error().
|
||||||
|
@ -18,7 +33,7 @@ import (
|
||||||
// It receives:
|
// It receives:
|
||||||
// 1. A time package format string (e.g. time.RFC3339).
|
// 1. A time package format string (e.g. time.RFC3339).
|
||||||
// 2. A boolean stating whether to use UTC time zone or local.
|
// 2. A boolean stating whether to use UTC time zone or local.
|
||||||
func Ginrus(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc {
|
func Ginrus(timeFormat string, utc bool) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
// some evil middlewares modify this values
|
// some evil middlewares modify this values
|
119
util/renderer.go
119
util/renderer.go
|
@ -2,70 +2,99 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"amuz.es/go/mnemonics/bind/template"
|
"amuz.es/go/mnemonics/bind/template"
|
||||||
"github.com/flosch/pongo2"
|
"github.com/flosch/pongo2"
|
||||||
"github.com/gin-gonic/gin/render"
|
"github.com/gin-gonic/gin/render"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RenderOptions is used to configure the renderer.
|
type (
|
||||||
type RenderOptions struct {
|
PongoRelease struct {
|
||||||
ContentType string
|
templateSet *pongo2.TemplateSet
|
||||||
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pongo2Render is a custom Gin template renderer using Pongo2.
|
PongoDebug struct {
|
||||||
type Pongo2Render struct {
|
Path string
|
||||||
Options *RenderOptions
|
}
|
||||||
|
|
||||||
|
Pongo struct {
|
||||||
Template *pongo2.Template
|
Template *pongo2.Template
|
||||||
|
Name string
|
||||||
|
Data interface{}
|
||||||
|
}
|
||||||
|
|
||||||
Context pongo2.Context
|
Context pongo2.Context
|
||||||
|
)
|
||||||
|
|
||||||
|
func TemplateSourceRelease(path string) *PongoRelease {
|
||||||
|
ts := pongo2.NewSet(path, &memoryTemplateLoader{loaderFunc: template.Asset})
|
||||||
|
return &PongoRelease{ts, path}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Pongo2Render instance with custom Options.
|
func (p PongoRelease) Instance(name string, data interface{}) render.Render {
|
||||||
func New(options RenderOptions) *Pongo2Render {
|
t := pongo2.Must(p.templateSet.FromFile(path.Join(p.Path, name)))
|
||||||
return &Pongo2Render{
|
|
||||||
Options: &options,
|
return Pongo{
|
||||||
|
Template: t,
|
||||||
|
Name: name,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TemplateSourceDebug(path string) *PongoDebug {
|
||||||
|
return &PongoDebug{path}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PongoDebug) Instance(name string, data interface{}) render.Render {
|
||||||
|
|
||||||
|
t := pongo2.Must(pongo2.FromFile(path.Join(p.Path, name)))
|
||||||
|
return Pongo{
|
||||||
|
Template: t,
|
||||||
|
Name: name,
|
||||||
|
Data: data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default creates a Pongo2Render instance with default options.
|
func (p Pongo) Render(w http.ResponseWriter) error {
|
||||||
func Default() *Pongo2Render {
|
ctx := pongo2.Context(p.Data.(Context))
|
||||||
return New(RenderOptions{
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
ContentType: "text/html; charset=utf-8",
|
return p.Template.ExecuteWriter(ctx, w)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance should return a new Pongo2Render struct per request and prepare
|
type memoryTemplateLoader struct {
|
||||||
// the template by either loading it from disk or using pongo2's cache.
|
loaderFunc func(path string) ([]byte, error)
|
||||||
func (p Pongo2Render) Instance(name string, data interface{}) render.Render {
|
fallbackLoader *pongo2.TemplateLoader
|
||||||
var templateResult *pongo2.Template
|
|
||||||
// always read template files from disk if in debug mode, use cache otherwise.
|
|
||||||
//if gin.Mode() == "debug" {Render
|
|
||||||
// template = pongo2.Must(pongo2.FromFile(filename))
|
|
||||||
//} else {
|
|
||||||
// template = pongo2.Must(pongo2.FromCache(filename))
|
|
||||||
//}
|
|
||||||
templateContent:=template.MustAsset(name)
|
|
||||||
|
|
||||||
templateResult=pongo2.Must(pongo2.FromString(string(templateContent[:])))
|
|
||||||
|
|
||||||
return Pongo2Render{
|
|
||||||
Template: templateResult,
|
|
||||||
Context: data.(pongo2.Context),
|
|
||||||
Options: p.Options,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render should render the template to the response.
|
func (m memoryTemplateLoader) Abs(base, name string) string {
|
||||||
func (p Pongo2Render) Render(w http.ResponseWriter) error {
|
if filepath.IsAbs(name) || base == "" {
|
||||||
writeContentType(w, []string{p.Options.ContentType})
|
return name
|
||||||
err := p.Template.ExecuteWriter(p.Context, w)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeContentType is also in the gin/render package but it has not been made
|
if name == "" {
|
||||||
// pubic so is repeated here, maybe convince the author to make this public.
|
return base
|
||||||
func writeContentType(w http.ResponseWriter, value []string) {
|
|
||||||
header := w.Header()
|
|
||||||
if val := header["Content-Type"]; len(val) == 0 {
|
|
||||||
header["Content-Type"] = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return filepath.Dir(base) + string(filepath.Separator) + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m memoryTemplateLoader) Get(path string) (io.Reader, error) {
|
||||||
|
|
||||||
|
Log().Errorf("hello template %s", filepath.Clean(path))
|
||||||
|
// t := pongo2.Must(p.templateSet.FromFile(path.Join(p.Path, name)))
|
||||||
|
data, err := m.loaderFunc(path)
|
||||||
|
if err != nil {
|
||||||
|
if m.fallbackLoader != nil {
|
||||||
|
return (*m.fallbackLoader).Get(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.NewReader(data), nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue