mirror of
https://github.com/kataras/iris.git
synced 2025-03-12 01:34:14 +01:00
Implement feature request for embedded assets
Example: https://github.com/iris-contrib/examples/tree/master/static_files_embedded Read HISTORY.md
This commit is contained in:
parent
5ee987feb9
commit
1a913d45d4
71
HISTORY.md
71
HISTORY.md
|
@ -2,6 +2,77 @@
|
||||||
|
|
||||||
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
|
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
|
||||||
|
|
||||||
|
## 4.6.0 -> 4.6.1
|
||||||
|
|
||||||
|
- **NEW**: `iris.StaticEmbedded`/`app := iris.New(); app.StaticEmbedded` - Embed static assets into your executable with [go-bindata](https://github.com/jteeuwen/go-bindata) and serve them.
|
||||||
|
|
||||||
|
> Note: This was already buitl'n feature for templates using `iris.UseTemplate(html.New()).Directory("./templates",".html").Binary(Asset,AssetNames)`, after v4.6.1 you can do that for other static files too, with the `StaticEmbedded` function
|
||||||
|
|
||||||
|
**outline**
|
||||||
|
```go
|
||||||
|
|
||||||
|
// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly
|
||||||
|
// First parameter is the request path, the path which the files in the vdir(second parameter) will be served to, for example "/static"
|
||||||
|
// Second parameter is the (virtual) directory path, for example "./assets"
|
||||||
|
// Third parameter is the Asset function
|
||||||
|
// Forth parameter is the AssetNames function
|
||||||
|
//
|
||||||
|
// For more take a look at the
|
||||||
|
// example: https://github.com/iris-contrib/examples/tree/master/static_files_embedded
|
||||||
|
StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) RouteNameFunc
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**example**
|
||||||
|
|
||||||
|
You can view and run it from [here](https://github.com/iris-contrib/examples/tree/master/static_files_embedded) *
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
// First of all, execute: $ go get https://github.com/jteeuwen/go-bindata
|
||||||
|
// Secondly, execute the command: cd $GOPATH/src/github.com/iris-contrib/examples/static_files_embedded && go-bindata ./assets/...
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// executing this go-bindata command creates a source file named 'bindata.go' which
|
||||||
|
// gives you the Asset and AssetNames funcs which we will pass into .StaticAssets
|
||||||
|
// for more viist: https://github.com/jteeuwen/go-bindata
|
||||||
|
// Iris gives you a way to integrade these functions to your web app
|
||||||
|
|
||||||
|
// For the reason that you may use go-bindata to embed more than your assets, you should pass the 'virtual directory path', for example here is the : "./assets"
|
||||||
|
// and the request path, which these files will be served to, you can set as "/assets" or "/static" which resulting on http://localhost:8080/static/*anyfile.*extension
|
||||||
|
iris.StaticEmbedded("/static", "./assets", Asset, AssetNames)
|
||||||
|
|
||||||
|
|
||||||
|
// that's all
|
||||||
|
// this will serve the ./assets (embedded) files to the /static request path for example the favicon.ico will be served as :
|
||||||
|
// http://localhost:8080/static/favicon.ico
|
||||||
|
// Methods: GET and HEAD
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
iris.Get("/", func(ctx *iris.Context) {
|
||||||
|
ctx.HTML(iris.StatusOK, "<b> Hi from index</b>")
|
||||||
|
})
|
||||||
|
|
||||||
|
iris.Listen(":8080")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate to:
|
||||||
|
// http://localhost:8080/static/favicon.ico
|
||||||
|
// http://localhost:8080/static/js/jquery-2.1.1.js
|
||||||
|
// http://localhost:8080/static/css/bootstrap.min.css
|
||||||
|
|
||||||
|
// Now, these files are stored inside into your executable program, no need to keep it in the same location with your assets folder.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 4.5.2/.3 -> 4.6.0
|
## 4.5.2/.3 -> 4.6.0
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%204.6.0%20-blue.svg?style=flat-square" alt="Releases"></a>
|
<a href="https://github.com/kataras/iris/releases"><img src="https://img.shields.io/badge/%20version%20-%204.6.1%20-blue.svg?style=flat-square" alt="Releases"></a>
|
||||||
|
|
||||||
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
|
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
|
||||||
|
|
||||||
|
@ -869,7 +869,7 @@ I recommend writing your API tests using this new library, [httpexpect](https://
|
||||||
Versioning
|
Versioning
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Current: **v4.6.0**
|
Current: **v4.6.1**
|
||||||
|
|
||||||
> Iris is an active project
|
> Iris is an active project
|
||||||
|
|
||||||
|
@ -905,7 +905,7 @@ This project is licensed under the [Apache License, Version 2.0](LICENSE), Copyr
|
||||||
[Travis]: http://travis-ci.org/kataras/iris
|
[Travis]: http://travis-ci.org/kataras/iris
|
||||||
[License Widget]: https://img.shields.io/badge/license-Apache%20Version%202-E91E63.svg?style=flat-square
|
[License Widget]: https://img.shields.io/badge/license-Apache%20Version%202-E91E63.svg?style=flat-square
|
||||||
[License]: https://github.com/kataras/iris/blob/master/LICENSE
|
[License]: https://github.com/kataras/iris/blob/master/LICENSE
|
||||||
[Release Widget]: https://img.shields.io/badge/release-4.6.0%20-blue.svg?style=flat-square
|
[Release Widget]: https://img.shields.io/badge/release-4.6.1%20-blue.svg?style=flat-square
|
||||||
[Release]: https://github.com/kataras/iris/releases
|
[Release]: https://github.com/kataras/iris/releases
|
||||||
[Chat Widget]: https://img.shields.io/badge/community-chat%20-00BCD4.svg?style=flat-square
|
[Chat Widget]: https://img.shields.io/badge/community-chat%20-00BCD4.svg?style=flat-square
|
||||||
[Chat]: https://kataras.rocket.chat/channel/iris
|
[Chat]: https://kataras.rocket.chat/channel/iris
|
||||||
|
|
139
iris.go
139
iris.go
|
@ -76,7 +76,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Version is the current version of the Iris web framework
|
// Version is the current version of the Iris web framework
|
||||||
Version = "4.6.0"
|
Version = "4.6.1"
|
||||||
|
|
||||||
banner = ` _____ _
|
banner = ` _____ _
|
||||||
|_ _| (_)
|
|_ _| (_)
|
||||||
|
@ -1157,6 +1157,7 @@ type (
|
||||||
StaticWeb(string, string, int) RouteNameFunc
|
StaticWeb(string, string, int) RouteNameFunc
|
||||||
StaticServe(string, ...string) RouteNameFunc
|
StaticServe(string, ...string) RouteNameFunc
|
||||||
StaticContent(string, string, []byte) RouteNameFunc
|
StaticContent(string, string, []byte) RouteNameFunc
|
||||||
|
StaticEmbedded(string, string, func(string) ([]byte, error), func() []string) RouteNameFunc
|
||||||
Favicon(string, ...string) RouteNameFunc
|
Favicon(string, ...string) RouteNameFunc
|
||||||
|
|
||||||
// templates
|
// templates
|
||||||
|
@ -1702,8 +1703,8 @@ func (api *muxAPI) StaticHandler(systemPath string, stripSlashes int, compress b
|
||||||
// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
|
// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
|
||||||
// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
|
// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
|
||||||
// * stripSlashes = 2, original path: "/foo/bar", result: ""
|
// * stripSlashes = 2, original path: "/foo/bar", result: ""
|
||||||
func Static(relative string, systemPath string, stripSlashes int) RouteNameFunc {
|
func Static(reqPath string, systemPath string, stripSlashes int) RouteNameFunc {
|
||||||
return Default.Static(relative, systemPath, stripSlashes)
|
return Default.Static(reqPath, systemPath, stripSlashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static registers a route which serves a system directory
|
// Static registers a route which serves a system directory
|
||||||
|
@ -1716,15 +1717,15 @@ func Static(relative string, systemPath string, stripSlashes int) RouteNameFunc
|
||||||
// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
|
// * stripSlashes = 0, original path: "/foo/bar", result: "/foo/bar"
|
||||||
// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
|
// * stripSlashes = 1, original path: "/foo/bar", result: "/bar"
|
||||||
// * stripSlashes = 2, original path: "/foo/bar", result: ""
|
// * stripSlashes = 2, original path: "/foo/bar", result: ""
|
||||||
func (api *muxAPI) Static(relative string, systemPath string, stripSlashes int) RouteNameFunc {
|
func (api *muxAPI) Static(reqPath string, systemPath string, stripSlashes int) RouteNameFunc {
|
||||||
if relative[len(relative)-1] != slashByte { // if / then /*filepath, if /something then /something/*filepath
|
if reqPath[len(reqPath)-1] != slashByte { // if / then /*filepath, if /something then /something/*filepath
|
||||||
relative += slash
|
reqPath += slash
|
||||||
}
|
}
|
||||||
|
|
||||||
h := api.StaticHandler(systemPath, stripSlashes, false, false, nil)
|
h := api.StaticHandler(systemPath, stripSlashes, false, false, nil)
|
||||||
|
|
||||||
api.Head(relative+"*filepath", h)
|
api.Head(reqPath+"*filepath", h)
|
||||||
return api.Get(relative+"*filepath", h)
|
return api.Get(reqPath+"*filepath", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StaticFS registers a route which serves a system directory
|
// StaticFS registers a route which serves a system directory
|
||||||
|
@ -1877,6 +1878,128 @@ func (api *muxAPI) StaticContent(reqPath string, cType string, content []byte) R
|
||||||
return api.Get(reqPath, h)
|
return api.Get(reqPath, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly
|
||||||
|
// First parameter is the request path, the path which the files in the vdir(second parameter) will be served to, for example "/static"
|
||||||
|
// Second parameter is the (virtual) directory path, for example "./assets"
|
||||||
|
// Third parameter is the Asset function
|
||||||
|
// Forth parameter is the AssetNames function
|
||||||
|
//
|
||||||
|
// For more take a look at the
|
||||||
|
// example: https://github.com/iris-contrib/examples/tree/master/static_files_embedded
|
||||||
|
func StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) RouteNameFunc {
|
||||||
|
return Default.StaticEmbedded(requestPath, vdir, assetFn, namesFn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly
|
||||||
|
// First parameter is the request path, the path which the files in the vdir will be served to, for example "/static"
|
||||||
|
// Second parameter is the (virtual) directory path, for example "./assets"
|
||||||
|
// Third parameter is the Asset function
|
||||||
|
// Forth parameter is the AssetNames function
|
||||||
|
//
|
||||||
|
// For more take a look at the
|
||||||
|
// example: https://github.com/iris-contrib/examples/tree/master/static_files_embedded
|
||||||
|
func (api *muxAPI) StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) RouteNameFunc {
|
||||||
|
|
||||||
|
// check if requestPath already contains an asterix-match to anything symbol: /path/*
|
||||||
|
requestPath = strings.Replace(requestPath, "//", "/", -1)
|
||||||
|
matchEverythingIdx := strings.IndexByte(requestPath, matchEverythingByte)
|
||||||
|
paramName := "path"
|
||||||
|
|
||||||
|
if matchEverythingIdx != -1 {
|
||||||
|
// found so it should has a param name, take it
|
||||||
|
paramName = requestPath[matchEverythingIdx+1:]
|
||||||
|
} else {
|
||||||
|
// make the requestPath
|
||||||
|
if requestPath[len(requestPath)-1] == slashByte {
|
||||||
|
// ends with / remove it
|
||||||
|
requestPath = requestPath[0 : len(requestPath)-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
requestPath += slash + "*" + paramName // $requestPath/*path
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vdir) > 0 {
|
||||||
|
if vdir[0] == '.' { // first check for .wrong
|
||||||
|
vdir = vdir[1:]
|
||||||
|
}
|
||||||
|
if vdir[0] == '/' || vdir[0] == os.PathSeparator { // second check for /something, (or ./something if we had dot on 0 it will be removed
|
||||||
|
vdir = vdir[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect the names we are care for, because not all Asset used here, we need the vdir's assets.
|
||||||
|
allNames := namesFn()
|
||||||
|
|
||||||
|
var names []string
|
||||||
|
for _, path := range allNames {
|
||||||
|
// check if path is the path name we care for
|
||||||
|
if !strings.HasPrefix(path, vdir) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
path = strings.Replace(path, "\\", "/", -1) // replace system paths with double slashes
|
||||||
|
path = strings.Replace(path, "./", "/", -1) // replace ./assets/favicon.ico to /assets/favicon.ico in order to be ready for compare with the reqPath later
|
||||||
|
path = path[len(vdir):] // set it as the its 'relative' ( we should re-setted it when assetFn will be used)
|
||||||
|
names = append(names, path)
|
||||||
|
|
||||||
|
}
|
||||||
|
if len(names) == 0 {
|
||||||
|
// we don't start the server yet, so:
|
||||||
|
panic("iris.StaticEmbedded: Unable to locate any embedded files located to the (virutal) directory: " + vdir)
|
||||||
|
}
|
||||||
|
|
||||||
|
modtime := time.Now()
|
||||||
|
modtimeStr := ""
|
||||||
|
h := func(ctx *Context) {
|
||||||
|
|
||||||
|
reqPath := ctx.Param(paramName)
|
||||||
|
|
||||||
|
for _, path := range names {
|
||||||
|
|
||||||
|
if path != reqPath {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cType := fs.TypeByExtension(path)
|
||||||
|
fullpath := vdir + path
|
||||||
|
|
||||||
|
buf, err := assetFn(fullpath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if modtimeStr == "" {
|
||||||
|
modtimeStr = modtime.UTC().Format(ctx.framework.Config.TimeFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t, err := time.Parse(ctx.framework.Config.TimeFormat, ctx.RequestHeader(ifModifiedSince)); err == nil && modtime.Before(t.Add(StaticCacheDuration)) {
|
||||||
|
ctx.Response.Header.Del(contentType)
|
||||||
|
ctx.Response.Header.Del(contentLength)
|
||||||
|
ctx.SetStatusCode(StatusNotModified)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Response.Header.Set(contentType, cType)
|
||||||
|
ctx.Response.Header.Set(lastModified, modtimeStr)
|
||||||
|
|
||||||
|
ctx.SetStatusCode(StatusOK)
|
||||||
|
ctx.SetContentType(cType)
|
||||||
|
|
||||||
|
ctx.Response.SetBody(buf)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found
|
||||||
|
ctx.EmitError(StatusNotFound)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
api.Head(requestPath, h)
|
||||||
|
|
||||||
|
return api.Get(requestPath, h)
|
||||||
|
}
|
||||||
|
|
||||||
// Favicon serves static favicon
|
// Favicon serves static favicon
|
||||||
// accepts 2 parameters, second is optional
|
// accepts 2 parameters, second is optional
|
||||||
// favPath (string), declare the system directory path of the __.ico
|
// favPath (string), declare the system directory path of the __.ico
|
||||||
|
|
Loading…
Reference in New Issue
Block a user