Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The new FileServer #1283

Closed
kataras opened this issue Jun 20, 2019 · 0 comments
Closed

The new FileServer #1283

kataras opened this issue Jun 20, 2019 · 0 comments

Comments

@kataras
Copy link
Owner

kataras commented Jun 20, 2019

Greetings to all of you beloved Gophers and Iris Devs,

As you probably already noticed the upcoming version 11.2 is not released yet and that's very rare for us, usually new release cyrcle is every 2 months.

There are plenty of reasons that I am not allowing myself to push the new version just yet. Mostly because of my feeling to push a complete and perfect release instead of some new features and bug fixes.

All reported bugs are fixed long time ago, usually in the same day they were reported by users, there are in the PR commit list.

Honestly, the plan was to push the release when the new websocket library was done too and finally after 3 months I can now tell you that it is fully functional and ready for the public ( it will live as kataras/iris/webscoket as previously, see here).

The new websocket module requires breaking-changes for the best result we can achieve, so this v11.2.0 release will contain breaking changes on the websocket level. The websocket library is far better and faster at all use cases than we had previously and without the bugs and the compromises we had to deal brecause of the no-breaking-changes rule of the previous versions. Unlike the previous one which had only a simple go client that new one provides clients for Go and Typescript/Javascript(both nodejs and browser-side) and anyone can make a client for any language, C++ for example with ease. I can say that our new websocket module is very unique but feels like home with a lot of preparation and prototyping under the hoods. It's the best ever written high-level webscoket library in the Go community and not only, the result worth the days and nights I spent on this thing -- of course, you - as community will prove that point, based on your feedback in the end of the day.

However, after that I came up with some other interesting ideas and improvements about different things inside Iris, so the release was delayed even more.

One of the features that needed improvements and had a long time to touch is how Iris helps you serving static system/physical and embedded files.

Let's start by looking what functions we currently have as version 11.1.1:

  1. func (api *APIBuilder) StaticWeb(requestPath string, systemPath string) *Route {
    (the most commonly used)
  2. func NewStaticHandlerBuilder(dir string) StaticHandlerBuilder {
  3. func StaticHandler(systemPath string, showList bool, gzip bool) context.Handler {
  4. func (api *APIBuilder) StaticHandler(systemPath string, showList bool, gzip bool) context.Handler {
  5. func (api *APIBuilder) StaticServe(systemPath string, requestPath ...string) *Route {
  6. func StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string, assetsGziped bool) context.Handler {
  7. func (api *APIBuilder) StaticEmbeddedGzip(requestPath string, vdir string, gzipAssetFn func(name string) ([]byte, error), gzipNamesFn func() []string) *Route {
  8. func (api *APIBuilder) StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) *Route {
  9. iris/iris.go

    Line 481 in 6564922

    func (app *Application) SPA(assetHandler context.Handler) *router.SPABuilder {

That is a hell of functions that doing slightly differnet things but all resulting to the same functionality that an Iris-Dev wants in the end. Also, the embedded file server was missing an important feature that a (physical) system's file server had, serve by content range (to be fair with ourselves, we weren't alone, the rest of third party tools and frameworks don't even have or think the half features that we provided to our users for embedded files, including this one).

So, I was wondering, in the spirit that we are free of the no-breaking-changes rule for this release on the websocket level, to bring some break changes outside of the websocket module too by not just replacing but also removing all existing static handler functions, however I came up to the decision that it's better to let them exist for one major version more and call the new methods under the hoods but with a deprecation warning that will be logged to the dev's terminal. Supposedly you had a main.go and on its line 18 app.StaticWeb("/static", "./assets") exists, the error will look like that:

deprecation_output_example

Note the hover, most code editors will navigate you to the source of the problem, the deprecation log takes the parameter values of the deprecated method, in that case the StaticWeb and suggests the new way.

All those functions can be replaced with a single one package-level and one Party method. The package-level function gives you an iris.Handler to work with and the other Party method will register routes on subdomain, subrouter and etc. At this point I am writing the issue I already completed this feature locally, not yet pushed but will be soon. It looks like that:

iris.FileServer(directory string, options ...DirOptions) iris/context.Handler
iris.Party#HandleDir(requestPath string, directory string, options ...DirOptions) *Route

Where the DirOptions are:

type DirOptions struct {
// Defaults to "/index.html", if request path is ending with **/*/$IndexName
// then it redirects to **/*(/) which another handler is handling it,
// that another handler, called index handler, is auto-registered by the framework
// if end developer wasn't managed to handle it manually/by hand.
IndexName string
// Should files served under gzip compression?
Gzip bool

// List the files inside the current requested directory if `IndexName` not found.
ShowList bool
// If `ShowList` is true then this function will be used instead
// of the default one to show the list of files of a current requested directory(dir).
DirList func(ctx context.Context, dirName string, dir http.File) error

// When embedded.
Asset      func(name string) ([]byte, error)   
AssetInfo  func(name string) (os.FileInfo, error)
AssetNames func() []string

// Optional validator that loops through each found requested resource.
AssetValidator func(ctx context.Context, name string) bool
}

If you used one of the above methods, refactoring your project's static file serving code blocks is highly recommended, it's quite easy in fact, here is how you can do it:

Party#StaticWeb and Party#StaticServe

v11.1.x

app.StaticWeb("/static", "./assets")

v11.2.x

app.HandleDir("/static", "./assets")

If you used the StaticWeb/StaticServe, just make a replace-to-all-files to HandleDir operation in your code editor and you're done.

StaticHandler

v11.1.x

handler := iris.StaticHandler("./assets", true, true)

v11.2.x

handler := iris.FileServer("./assets", iris.DirOptions {ShowList: true, Gzip: true})

StaticEmbeddedHandler

v11.1.x

handler := iris.StaticEmbeddedHandler("./assets", Asset, AssetNames, true)

v11.2.x

handler := iris.FileServer("./assets", iris.DirOptions {
  Asset: Asset,
  AssetInfo: AssetInfo,
  AssetNames: AssetNames,
  Gzip: true})

Party#StaticEmbedded and Party#StaticEmbeddedGzip

v11.1.x

app.StaticEmbedded("/static", "./assets", Asset, AssetNames)

v11.2.x

app.HandleDir("/static", "./assets", iris.DirOptions {
  Asset: Asset,
  AssetInfo: AssetInfo,
  AssetNames: AssetNames,
  Gzip: true/false})

Application#SPA

v11.1.x

app.RegisterView(iris.HTML("./public", ".html"))

app.Get("/", func(ctx iris.Context) {
	ctx.ViewData("Page", page)
	ctx.View("index.html")
})

assetHandler := app.StaticHandler("./public", false, false)
app.SPA(assetHandler)

v11.2.x

app.RegisterView(iris.HTML("./public", ".html"))

// Overrides the file server's index route. 
// Order of this route registration does not matter.
app.Get("/", func(ctx iris.Context) {
	ctx.ViewData("Page", page)
	ctx.View("index.html")
})

app.HandleDir("/", "./public")

The above changes are not only syntactical. Unlike the standard net/http design we give the chance and the features to the end-developer to use different handlers for index files to customize the middlewares and any other options and code that required on Single Page Applications.
Previously something like /static/index.html -> /static must be handled by developer to serve a directory's index.html file (and if not a miss-redirection would be caused, ugly). So index files have different handlers and if not registered manually by app.Get(...) then the framework will register them automatically (as of the new 11.2 release) , order of route registration does not even matter, Iris handles them on build state. Another new feature is that now the file server can handle content-range embedded files and also show a list of files in an embedded directory via the DirOptions.ShowList like the physical directories).

The above FileServer function and HandleDir method handles every case in a single spot, all previous and new features are live inside those two.

As a result from the 9(nine) functions and methods we had, we end up with just 2(two) with less code, more improvements and new features. That fact gives any user, experienced or newcomer an ideal place to start working without searching and reading more than they need to. To be honest, it makes my job easier too; any future questions and issues about static file handlers can be answered and be more understable a lot easier.

You are totally free to post any ideas and feature requests regarding this subject, transparency helps us improve the framework even more.

That's all for now, the release changelog/history will contain the old and new syntax as well for those who may missed that post. Have fun and be happy whenever you are and always stay tuned.

Until next time,
Gerasimos (Makis) Maropoulos. Open-source contributor and author of Iris.

@kataras kataras added this to the v11.2.0 milestone Jun 20, 2019
@kataras kataras pinned this issue Jun 20, 2019
kataras added a commit that referenced this issue Jun 21, 2019
@kataras kataras mentioned this issue Jun 25, 2019
@kataras kataras closed this as completed Jul 23, 2019
@kataras kataras unpinned this issue Jul 23, 2019
github-actions bot pushed a commit to goproxies/github.com-kataras-iris that referenced this issue Jul 27, 2020
…r/Party static methods and more

relative: kataras#1283 and removing pongo2 from vendor: https://github.com/kataras/iris/issues/1284

Former-commit-id: 3ec57b349f99faca2b8e36d9f7252db0b6ea080d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant