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

Is it possible to integrate pkger for embeded resources? #1575

Closed
tuhao1020 opened this issue Aug 11, 2020 · 9 comments
Closed

Is it possible to integrate pkger for embeded resources? #1575

tuhao1020 opened this issue Aug 11, 2020 · 9 comments

Comments

@tuhao1020
Copy link
Contributor

pkger is a tool for embedding static files into Go binaries. It can integrate with Gin, but I dont know how to integrate with Iris. If possible, can you give some example code?

@kataras
Copy link
Owner

kataras commented Aug 11, 2020

Of coruse it can @tuhao1020 give me some time and I will provide you an example.

Actually, it's easy the pkger.Dir is a compatible http.FileSystem, with the latest Iris (master branch) you can just pass it to your .HandleDir method:

app := iris.New()
// ...
app.HandleDir("/", pkger.Dir("./public"))

However as I can see, this library converts the files on-fly(?), the files should be available in your current directory. Iris can do it using the Cache Option, you don't need pkger:

app.HandleDir("/", iris.Dir("./public"), iris.DirOptions{
	Cache: iris.DirCacheOptions{
		Enable:true,
	},
})

If they have an option for embedded files (no need of physical files to be exist in the drive for a file-server) then you can just pass their http.FileSystem to Iris' HandleDir's second input argument. The thing with Iris is that anything is compatible by-design because it's written in a way that all net/http external packages can just work, no need to add examples for every thing Iris is capable of, everything you could use before Iris, you can still use with Iris and you can do more with them.

Indeed, Iris provides even more features here, take a look the full options of DirCacheOptions:

type DirCacheOptions struct {
	// Enable or disable cache.
	Enable bool
	// Minimum content size for compression in bytes.
	CompressMinSize int64
	// Ignore compress files that match this pattern.
	CompressIgnore *regexp.Regexp
	// The available sever's encodings to be negotiated with the client's needs,
	// common values: gzip, br.
	Encodings []string

	// If greater than zero then prints information about cached files to the stdout.
	// If it's 1 then it prints only the total cached and after-compression reduced file sizes
	// If it's 2 then it prints it per file too.
	Verbose uint8
}

If you need embedded assets as Go source code, you may want to use go-bindata, which returns a compatible http.FileSystem too you can pass in app.HandleDir too. That way you don't need to deploy your files, just the executable file and your server will serve those files.There are plenty of examples here.

Thanks.

@tuhao1020
Copy link
Contributor Author

thanks for your relpy!

the second parameter of app.HandleDir is string, so I change the code as below to eliminate syntax error:

app := iris.New()
app.HandleDir("/", string(pkger.Dir("./public")))
app.Listen(":8080")

everything seems ok, but resources in public directory were not packed into app, when I removed the public directory I got a Not Found error page

Compare the usage of Gin with pkger:

router := Gin.Default()
router.StaticFs("/", pkger.Dir("/public"))
router.Run(":8080")

the second parameter of router.StaticFs is http.FileSystem

do you consider adding a method that accept a http.FileSystem type for HandleDir/iris.HTML/...?

@kataras
Copy link
Owner

kataras commented Aug 12, 2020

Hello @tuhao1020, you are not watching me. You don't use the master version of Iris, that's why it accepts a string here. Update and you should be able to see that we already have the second input argument as http.FileSystem as explained above. Here you are:

$ cd your_project
$ go get -u github.com/kataras/iris/v12@master
$ go run .

Now, are you ready for a real comparison?

gin:

router := gin.New()
router.StaticFs("/", pkger.Dir("/public"))
router.Run(":8080")

That's all, you cannot customize it further.

iris:

app := iris.New()
app.HandleDir("/", pkger.Dir("/public"))
app.Listen(":8080")

app.HandleDir can accept a third parameter with these options!

// DirListFunc is the function signature for customizing directory and file listing.
// See `DirList` and `DirListRich` functions for its implementations.
type DirListFunc func(ctx *context.Context, dirOptions DirOptions, dirName string, dir http.File) error

// Attachments options for files to be downloaded and saved locally by the client.
// See `DirOptions`.
type Attachments struct {
	// Set to true to enable the files to be downloaded and
	// saved locally by the client, instead of serving the file.
	Enable bool
	// Options to send files with a limit of bytes sent per second.
	Limit float64
	Burst int
	// Use this function to change the sent filename.
	NameFunc func(systemName string) (attachmentName string)
}

// DirCacheOptions holds the options for the cached file system.
// See `DirOptions`structure for more.
type DirCacheOptions struct {
	// Enable or disable cache.
	Enable bool
	// Minimum content size for compression in bytes.
	CompressMinSize int64
	// Ignore compress files that match this pattern.
	CompressIgnore *regexp.Regexp
	// The available sever's encodings to be negotiated with the client's needs,
	// common values: gzip, br.
	Encodings []string

	// If greater than zero then prints information about cached files to the stdout.
	// If it's 1 then it prints only the total cached and after-compression reduced file sizes
	// If it's 2 then it prints it per file too.
	Verbose uint8
}

// DirOptions contains the settings that `FileServer` can use to serve files.
// See `DefaultDirOptions`.
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 does not managed to handle it by hand.
	IndexName string
	// PushTargets filenames (map's value) to
	// be served without additional client's requests (HTTP/2 Push)
	// when a specific request path (map's key WITHOUT prefix)
	// is requested and it's not a directory (it's an `IndexFile`).
	//
	// Example:
	// 	"/": {
	// 		"favicon.ico",
	// 		"js/main.js",
	// 		"css/main.css",
	// 	}
	PushTargets map[string][]string
	// PushTargetsRegexp like `PushTargets` but accepts regexp which
	// is compared against all files under a directory (recursively).
	// The `IndexName` should be set.
	//
	// Example:
	// "/": regexp.MustCompile("((.*).js|(.*).css|(.*).ico)$")
	// See `iris.MatchCommonAssets` too.
	PushTargetsRegexp map[string]*regexp.Regexp

	// Cache to enable in-memory cache and pre-compress files.
	Cache DirCacheOptions
	// When files should served under compression.
	Compress 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).
	// See `DirListRich` package-level function too.
	DirList DirListFunc

	// Files downloaded and saved locally.
	Attachments Attachments

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

Have fun :)

@tuhao1020
Copy link
Contributor Author

I got master branch and HandleDir worked perfect. That's awesome!
Another question is: why iris.HTML() method still has a directory parameter with string type not http.FileSystem?
Thanks for your patience!

@kataras
Copy link
Owner

kataras commented Aug 12, 2020

No worries @tuhao1020, I was thinking about it too but when you use templates inside bindata you usually have more data than the template files, or the bindata.go file may contain more templates that should be rendered using different parsers and engines. So, the iris.HTML/Django/Pug/Handlebars/Amber/Jet/Ace/Blocks all have a string for its directory for system files and embedded data (using HTML("/views", ".html").Binary(Asset, AsssetNames) because you can register more than one and they should point to a different directory inside the embedded file system itself. However if you think that it should be changed (by keeping the same functions for compability in the same time) let me know so I can start thinking how to support all cases.

@tuhao1020
Copy link
Contributor Author

All my projects use pkger to package static resources, so I prefer to use a http.FileSystem compatible type in iris.HTML/Django/Pug/Handlebars/Amber/Jet/Ace/Blocks. Other libraries such as go.rice, esc also provides an http.FileSystem interface.

On the other hand, HTML("/views", ".html").Binary(Asset, AsssetNames) is the usage of binding with go-bindata, that's less flexibility for developers who want to use a different library.

@kataras
Copy link
Owner

kataras commented Aug 13, 2020

Indeed you can convert anything to Asset func(string) ([]byte, error) and AssetNames func() []string (probably that's why this is the first issue about thi ssubject), but yes http.FileSystem can be useful on templates too - I totally agree and I was thinking of it myself - it will be ready soon. Don't forget that Iris was the first Go web framework supporting embedded data (as far as I remember) with functions like that, years ago, things are moving on and we become better.

@tuhao1020
Copy link
Contributor Author

I got it, thank you! @kataras

kataras added a commit that referenced this issue Sep 5, 2020
#1575

Also, the HandleDir accepts both string and http.FileSystem (interface{}) (like the view's fs)
@kataras
Copy link
Owner

kataras commented Sep 5, 2020

@tuhao1020 It's done, now you can pass http.FileSystem on all view engines instead of string. The .Binary method was also removed as it's now useless. Upgrade to the latest master commit.

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

2 participants