5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 23:02:19 +08:00
wails/v2/internal/frontend/assetserver/assethandler.go
stffabi 65fb42d9e7
[v2] Add support for external frontend dev servers (#1290)
* [v2] Consolidate AssetServers

* [v2] Support starturl for webview on linux and darwin

* [v2] Add support for frontend DevServer

* [v2] Activate frontend DevServer in svelte template

* [website] Add bleeding edge guide for PRs

* DoNotMerge: Bump Version for testing

Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
2022-03-31 00:40:44 +11:00

125 lines
2.6 KiB
Go

package assetserver
import (
"context"
_ "embed"
iofs "io/fs"
"net/http"
"os"
"path"
"strings"
"time"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/pkg/options"
)
//go:embed defaultindex.html
var defaultHTML []byte
type assetHandler struct {
fs iofs.FS
logger *logger.Logger
servingFromDisk bool
}
func NewAsssetHandler(ctx context.Context, options *options.App) (http.Handler, error) {
vfs := options.Assets
if vfs != nil {
if _, err := vfs.Open("."); err != nil {
return nil, err
}
subDir, err := fs.FindPathToFile(vfs, "index.html")
if err != nil {
return nil, err
}
vfs, err = iofs.Sub(vfs, path.Clean(subDir))
if err != nil {
return nil, err
}
}
result := &assetHandler{
fs: vfs,
// Check if we have been given a directory to serve assets from.
// If so, this means we are in dev mode and are serving assets off disk.
// We indicate this through the `servingFromDisk` flag to ensure requests
// aren't cached in dev mode.
servingFromDisk: ctx.Value("assetdir") != nil,
}
if _logger := ctx.Value("logger"); _logger != nil {
result.logger = _logger.(*logger.Logger)
}
return result, nil
}
func (d *assetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if d.fs == nil {
rw.WriteHeader(http.StatusNotFound)
return
}
filename := strings.TrimPrefix(req.URL.Path, "/")
if d.logger != nil {
d.logger.Debug("[AssetHandler] Loading file '%s'", filename)
}
var content []byte
var err error
switch filename {
case "", "index.html":
content, err = d.loadFile("index.html")
if err != nil {
err = nil
content = defaultHTML
}
default:
content, err = d.loadFile(filename)
}
if os.IsNotExist(err) {
rw.WriteHeader(http.StatusNotFound)
return
}
if err == nil {
mimeType := GetMimetype(filename, content)
rw.Header().Set(HeaderContentType, mimeType)
rw.WriteHeader(http.StatusOK)
_, err = rw.Write(content)
}
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
if d.logger != nil {
d.logger.Error("[AssetHandler] Unable to load file '%s': %s", filename, err)
}
}
}
// loadFile will try to load the file from disk. If there is an error
// it will retry until eventually it will give up and error.
func (d *assetHandler) loadFile(filename string) ([]byte, error) {
if !d.servingFromDisk {
return iofs.ReadFile(d.fs, filename)
}
var result []byte
var err error
for tries := 0; tries < 50; tries++ {
result, err = iofs.ReadFile(d.fs, filename)
if err != nil {
time.Sleep(100 * time.Millisecond)
}
}
return result, err
}