diff --git a/.gitignore b/.gitignore index ae2eae1..2a2559b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ main.db debug *db.lock static/bower_components -config.json \ No newline at end of file +config.json +static.go \ No newline at end of file diff --git a/handlers/handlers.go b/handlers/handlers.go index decea4a..02456da 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -1,11 +1,16 @@ // Package handlers provides the http functionality +//go:generate esc -o static.go -pkg handlers -prefix ../static/build ../static/build +//go:generate esc -o tmpls/tmpls.go -pkg tmpls -include ^*\.tmpl -prefix tmpls tmpls package handlers import ( "crypto/rand" + "html/template" + "net/http" "github.com/gin-gonic/gin" "github.com/maxibanki/golang-url-shortener/config" + "github.com/maxibanki/golang-url-shortener/handlers/tmpls" "github.com/maxibanki/golang-url-shortener/store" "github.com/pkg/errors" "golang.org/x/oauth2" @@ -27,7 +32,9 @@ func New(handlerConfig config.Handlers, store store.Store) (*Handler, error) { store: store, engine: gin.Default(), } - h.setHandlers() + if err := h.setHandlers(); err != nil { + return nil, errors.Wrap(err, "could not set handlers") + } if err := h.checkIfSecretExist(); err != nil { return nil, errors.Wrap(err, "could not check if secret exist") } @@ -35,6 +42,19 @@ func New(handlerConfig config.Handlers, store store.Store) (*Handler, error) { return h, nil } +func (h *Handler) setTemplateFromFS(name string) error { + tokenTemplate, err := tmpls.FSString(false, "/"+name) + if err != nil { + return errors.Wrap(err, "could not read token template file") + } + templ, err := template.New(name).Funcs(h.engine.FuncMap).Parse(tokenTemplate) + if err != nil { + return errors.Wrap(err, "could not create template from file content") + } + h.engine.SetHTMLTemplate(templ) + return nil +} + func (h *Handler) checkIfSecretExist() error { conf := config.Get() if conf.Handlers.Secret == nil { @@ -50,7 +70,7 @@ func (h *Handler) checkIfSecretExist() error { return nil } -func (h *Handler) setHandlers() { +func (h *Handler) setHandlers() error { if !h.config.EnableGinDebugMode { gin.SetMode(gin.ReleaseMode) } @@ -58,9 +78,13 @@ func (h *Handler) setHandlers() { protected.Use(h.authMiddleware) protected.POST("/create", h.handleCreate) protected.POST("/info", h.handleInfo) - // h.engine.Static("/static", "static/src") - h.engine.NoRoute(h.handleAccess) - h.engine.LoadHTMLGlob("templates/*") + + h.engine.NoRoute(h.handleAccess, gin.WrapH(http.FileServer(FS(false)))) + + if err := h.setTemplateFromFS("token.tmpl"); err != nil { + return errors.Wrap(err, "could not set template from FS") + } + return nil } // Listen starts the http server diff --git a/handlers/tmpls/tmpls.go b/handlers/tmpls/tmpls.go new file mode 100644 index 0000000..85a1eda --- /dev/null +++ b/handlers/tmpls/tmpls.go @@ -0,0 +1,211 @@ +// Code generated by "esc -o tmpls/tmpls.go -pkg tmpls -include ^*\.tmpl -prefix tmpls tmpls"; DO NOT EDIT. + +package tmpls + +import ( + "bytes" + "compress/gzip" + "encoding/base64" + "io/ioutil" + "net/http" + "os" + "path" + "sync" + "time" +) + +type _escLocalFS struct{} + +var _escLocal _escLocalFS + +type _escStaticFS struct{} + +var _escStatic _escStaticFS + +type _escDirectory struct { + fs http.FileSystem + name string +} + +type _escFile struct { + compressed string + size int64 + modtime int64 + local string + isDir bool + + once sync.Once + data []byte + name string +} + +func (_escLocalFS) Open(name string) (http.File, error) { + f, present := _escData[path.Clean(name)] + if !present { + return nil, os.ErrNotExist + } + return os.Open(f.local) +} + +func (_escStaticFS) prepare(name string) (*_escFile, error) { + f, present := _escData[path.Clean(name)] + if !present { + return nil, os.ErrNotExist + } + var err error + f.once.Do(func() { + f.name = path.Base(name) + if f.size == 0 { + return + } + var gr *gzip.Reader + b64 := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(f.compressed)) + gr, err = gzip.NewReader(b64) + if err != nil { + return + } + f.data, err = ioutil.ReadAll(gr) + }) + if err != nil { + return nil, err + } + return f, nil +} + +func (fs _escStaticFS) Open(name string) (http.File, error) { + f, err := fs.prepare(name) + if err != nil { + return nil, err + } + return f.File() +} + +func (dir _escDirectory) Open(name string) (http.File, error) { + return dir.fs.Open(dir.name + name) +} + +func (f *_escFile) File() (http.File, error) { + type httpFile struct { + *bytes.Reader + *_escFile + } + return &httpFile{ + Reader: bytes.NewReader(f.data), + _escFile: f, + }, nil +} + +func (f *_escFile) Close() error { + return nil +} + +func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) { + return nil, nil +} + +func (f *_escFile) Stat() (os.FileInfo, error) { + return f, nil +} + +func (f *_escFile) Name() string { + return f.name +} + +func (f *_escFile) Size() int64 { + return f.size +} + +func (f *_escFile) Mode() os.FileMode { + return 0 +} + +func (f *_escFile) ModTime() time.Time { + return time.Unix(f.modtime, 0) +} + +func (f *_escFile) IsDir() bool { + return f.isDir +} + +func (f *_escFile) Sys() interface{} { + return f +} + +// FS returns a http.Filesystem for the embedded assets. If useLocal is true, +// the filesystem's contents are instead used. +func FS(useLocal bool) http.FileSystem { + if useLocal { + return _escLocal + } + return _escStatic +} + +// Dir returns a http.Filesystem for the embedded assets on a given prefix dir. +// If useLocal is true, the filesystem's contents are instead used. +func Dir(useLocal bool, name string) http.FileSystem { + if useLocal { + return _escDirectory{fs: _escLocal, name: name} + } + return _escDirectory{fs: _escStatic, name: name} +} + +// FSByte returns the named file from the embedded assets. If useLocal is +// true, the filesystem's contents are instead used. +func FSByte(useLocal bool, name string) ([]byte, error) { + if useLocal { + f, err := _escLocal.Open(name) + if err != nil { + return nil, err + } + b, err := ioutil.ReadAll(f) + _ = f.Close() + return b, err + } + f, err := _escStatic.prepare(name) + if err != nil { + return nil, err + } + return f.data, nil +} + +// FSMustByte is the same as FSByte, but panics if name is not present. +func FSMustByte(useLocal bool, name string) []byte { + b, err := FSByte(useLocal, name) + if err != nil { + panic(err) + } + return b +} + +// FSString is the string version of FSByte. +func FSString(useLocal bool, name string) (string, error) { + b, err := FSByte(useLocal, name) + return string(b), err +} + +// FSMustString is the string version of FSMustByte. +func FSMustString(useLocal bool, name string) string { + return string(FSMustByte(useLocal, name)) +} + +var _escData = map[string]*_escFile{ + + "/token.tmpl": { + local: "tmpls/token.tmpl", + size: 506, + modtime: 1510047272, + compressed: ` +H4sIAAAAAAAC/2RRwW7qMBC8R8o/7PMFkEjyeqtoHAml9NoeQCpHx16RFY6dJptEFeLfqwCl0M7FMzvr +ka1J/z2/5uvt2wpKrmwWBul4glVuJwU6kYXBOENlsjAAAEgrZAW6VE2LLMVm/RI9ijvPqQql6AmH2jcs +QHvH6FiKgQyX0mBPGqOTmAM5YlI2arWyKB/i//dZJXMd4UdHvRTv0WYZ5b6qFVNh8SaYUKLZ4fUqE1vM +tr6DgayFAqFBQw1qRpMmZ/ey2uqGar6oEQM544fY1+iwiQ21tWJdrnp0PHU4QN617Kuznni37LjMlbWF +0vvJHA4/QSMMsiK7+D0ewX6PbgGHA8QnCsfj/dKNPM5mT39eqK1vcfptpMn1J2lyqSsM0sKbzzNLbuip +6q8AAAD//46JN836AQAA +`, + }, + + "/": { + isDir: true, + local: "tmpls", + }, +} diff --git a/templates/token.tmpl b/handlers/tmpls/token.tmpl similarity index 100% rename from templates/token.tmpl rename to handlers/tmpls/token.tmpl diff --git a/static/package.json b/static/package.json index 4790b4a..2366e7b 100644 --- a/static/package.json +++ b/static/package.json @@ -26,4 +26,4 @@ "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } -} +} \ No newline at end of file diff --git a/static/src/index.js b/static/src/index.js index 062194e..7e5acb0 100644 --- a/static/src/index.js +++ b/static/src/index.js @@ -1,4 +1,4 @@ -import registerServiceWorker from './registerServiceWorker'; +// import registerServiceWorker from './registerServiceWorker'; import React, { Component } from 'react' import ReactDOM from 'react-dom'; import { HashRouter, Route, Link } from 'react-router-dom' @@ -131,4 +131,4 @@ ReactDOM.render(( ), document.getElementById('root')) -registerServiceWorker(); \ No newline at end of file +// registerServiceWorker(); \ No newline at end of file