diff --git a/v2/internal/frontend/assetserver/assethandler.go b/v2/internal/frontend/assetserver/assethandler.go index 6edc0d524..d96681eab 100644 --- a/v2/internal/frontend/assetserver/assethandler.go +++ b/v2/internal/frontend/assetserver/assethandler.go @@ -2,7 +2,6 @@ package assetserver import ( "bytes" - "context" "embed" "errors" "fmt" @@ -13,11 +12,14 @@ import ( "path" "strings" - "github.com/wailsapp/wails/v2/internal/fs" - "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options/assetserver" ) +type Logger interface { + Debug(message string, args ...interface{}) + Error(message string, args ...interface{}) +} + //go:embed defaultindex.html var defaultHTML []byte @@ -29,16 +31,12 @@ type assetHandler struct { fs iofs.FS handler http.Handler - logger *logger.Logger + logger Logger retryMissingFiles bool } -func NewAssetHandler(ctx context.Context, options assetserver.Options) (http.Handler, error) { - var log *logger.Logger - if _logger := ctx.Value("logger"); _logger != nil { - log = _logger.(*logger.Logger) - } +func NewAssetHandler(options assetserver.Options, log Logger) (http.Handler, error) { vfs := options.Assets if vfs != nil { @@ -46,12 +44,12 @@ func NewAssetHandler(ctx context.Context, options assetserver.Options) (http.Han return nil, err } - subDir, err := fs.FindPathToFile(vfs, indexHTML) + subDir, err := FindPathToFile(vfs, indexHTML) if err != nil { if errors.Is(err, os.ErrNotExist) { msg := "no `index.html` could be found in your Assets fs.FS" if embedFs, isEmbedFs := vfs.(embed.FS); isEmbedFs { - rootFolder, _ := fs.FindEmbedRootPath(embedFs) + rootFolder, _ := FindEmbedRootPath(embedFs) msg += fmt.Sprintf(", please make sure the embedded directory '%s' is correct and contains your assets", rootFolder) } diff --git a/v2/internal/frontend/assetserver/assetserver.go b/v2/internal/frontend/assetserver/assetserver.go index 64ae77002..f02163b59 100644 --- a/v2/internal/frontend/assetserver/assetserver.go +++ b/v2/internal/frontend/assetserver/assetserver.go @@ -2,7 +2,6 @@ package assetserver import ( "bytes" - "context" "fmt" "net/http" "net/http/httptest" @@ -10,8 +9,6 @@ import ( "golang.org/x/net/html" - "github.com/wailsapp/wails/v2/internal/frontend/runtime" - "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/assetserver" ) @@ -21,41 +18,48 @@ const ( ipcJSPath = "/wails/ipc.js" ) +type RuntimeAssets interface { + DesktopIPC() []byte + WebsocketIPC() []byte + RuntimeDesktopJS() []byte +} + type AssetServer struct { handler http.Handler wsHandler http.Handler runtimeJS []byte ipcJS func(*http.Request) []byte - logger *logger.Logger + logger Logger + runtime RuntimeAssets servingFromDisk bool appendSpinnerToBody bool } -func NewAssetServerMainPage(ctx context.Context, bindingsJSON string, options *options.App) (*AssetServer, error) { +func NewAssetServerMainPage(bindingsJSON string, options *options.App, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { assetOptions, err := BuildAssetServerConfig(options) if err != nil { return nil, err } - return NewAssetServer(ctx, bindingsJSON, assetOptions) + return NewAssetServer(bindingsJSON, assetOptions, servingFromDisk, logger, runtime) } -func NewAssetServer(ctx context.Context, bindingsJSON string, options assetserver.Options) (*AssetServer, error) { - handler, err := NewAssetHandler(ctx, options) +func NewAssetServer(bindingsJSON string, options assetserver.Options, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { + handler, err := NewAssetHandler(options, logger) if err != nil { return nil, err } - return NewAssetServerWithHandler(ctx, handler, bindingsJSON) + return NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime) } -func NewAssetServerWithHandler(ctx context.Context, handler http.Handler, bindingsJSON string) (*AssetServer, error) { +func NewAssetServerWithHandler(handler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { var buffer bytes.Buffer if bindingsJSON != "" { buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n") } - buffer.Write(runtime.RuntimeDesktopJS) + buffer.Write(runtime.RuntimeDesktopJS()) result := &AssetServer{ handler: handler, @@ -65,11 +69,9 @@ func NewAssetServerWithHandler(ctx context.Context, handler http.Handler, bindin // 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) + servingFromDisk: servingFromDisk, + logger: logger, + runtime: runtime, } return result, nil @@ -121,7 +123,7 @@ func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { d.writeBlob(rw, path, d.runtimeJS) case ipcJSPath: - content := runtime.DesktopIPC + content := d.runtime.DesktopIPC() if d.ipcJS != nil { content = d.ipcJS(req) } diff --git a/v2/internal/frontend/assetserver/assetserver_dev.go b/v2/internal/frontend/assetserver/assetserver_dev.go index 5d83cf5fe..fb13b3a23 100644 --- a/v2/internal/frontend/assetserver/assetserver_dev.go +++ b/v2/internal/frontend/assetserver/assetserver_dev.go @@ -4,11 +4,8 @@ package assetserver import ( - "context" "net/http" "strings" - - "github.com/wailsapp/wails/v2/internal/frontend/runtime" ) /* @@ -16,8 +13,8 @@ The assetserver for the dev mode. Depending on the UserAgent it injects a websocket based IPC script into `index.html` or the default desktop IPC. The default desktop IPC is injected when the webview accesses the devserver. */ -func NewDevAssetServer(ctx context.Context, handler http.Handler, wsHandler http.Handler, bindingsJSON string) (*AssetServer, error) { - result, err := NewAssetServerWithHandler(ctx, handler, bindingsJSON) +func NewDevAssetServer(handler http.Handler, wsHandler http.Handler, bindingsJSON string, servingFromDisk bool, logger Logger, runtime RuntimeAssets) (*AssetServer, error) { + result, err := NewAssetServerWithHandler(handler, bindingsJSON, servingFromDisk, logger, runtime) if err != nil { return nil, err } @@ -26,9 +23,9 @@ func NewDevAssetServer(ctx context.Context, handler http.Handler, wsHandler http result.appendSpinnerToBody = true result.ipcJS = func(req *http.Request) []byte { if strings.Contains(req.UserAgent(), WailsUserAgentValue) { - return runtime.DesktopIPC + return runtime.DesktopIPC() } - return runtime.WebsocketIPC + return runtime.WebsocketIPC() } return result, nil diff --git a/v2/internal/frontend/assetserver/fs.go b/v2/internal/frontend/assetserver/fs.go new file mode 100644 index 000000000..7ecc9cec8 --- /dev/null +++ b/v2/internal/frontend/assetserver/fs.go @@ -0,0 +1,75 @@ +package assetserver + +import ( + "embed" + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" +) + +// FindEmbedRootPath finds the root path in the embed FS. It's the directory which contains all the files. +func FindEmbedRootPath(fsys embed.FS) (string, error) { + stopErr := fmt.Errorf("files or multiple dirs found") + + fPath := "" + err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if d.IsDir() { + fPath = path + if entries, dErr := fs.ReadDir(fsys, path); dErr != nil { + return dErr + } else if len(entries) <= 1 { + return nil + } + } + + return stopErr + }) + + if err != nil && err != stopErr { + return "", err + } + + return fPath, nil +} + +func FindPathToFile(fsys fs.FS, file string) (string, error) { + stat, _ := fs.Stat(fsys, file) + if stat != nil { + return ".", nil + } + var indexFiles []string + err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if strings.HasSuffix(path, file) { + indexFiles = append(indexFiles, path) + } + return nil + }) + if err != nil { + return "", err + } + + if len(indexFiles) > 1 { + selected := indexFiles[0] + for _, f := range indexFiles { + if len(f) < len(selected) { + selected = f + } + } + path, _ := filepath.Split(selected) + return path, nil + } + if len(indexFiles) > 0 { + path, _ := filepath.Split(indexFiles[0]) + return path, nil + } + return "", fmt.Errorf("%s: %w", file, os.ErrNotExist) +} diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index 671145702..062c9307e 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -26,6 +26,7 @@ import ( "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend/assetserver" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options" ) @@ -86,7 +87,8 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. } else { appBindings.DB().UpdateObfuscatedCallMap() } - assets, err := assetserver.NewAssetServerMainPage(ctx, bindings, appoptions) + + assets, err := assetserver.NewAssetServerMainPage(bindings, appoptions, ctx.Value("assetdir") != nil, myLogger, runtime.RuntimeAssetsBundle) if err != nil { log.Fatal(err) } diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index 0e1c1de39..fc39cd836 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -91,6 +91,7 @@ import ( "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend/assetserver" + wailsruntime "github.com/wailsapp/wails/v2/internal/frontend/runtime" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options" ) @@ -159,7 +160,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. } else { appBindings.DB().UpdateObfuscatedCallMap() } - assets, err := assetserver.NewAssetServerMainPage(ctx, bindings, appoptions) + assets, err := assetserver.NewAssetServerMainPage(bindings, appoptions, ctx.Value("assetdir") != nil, myLogger, wailsruntime.RuntimeAssetsBundle) if err != nil { log.Fatal(err) } diff --git a/v2/internal/frontend/desktop/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go index b65358860..d60e33fc3 100644 --- a/v2/internal/frontend/desktop/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -27,6 +27,7 @@ import ( "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/win32" "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" + wailsruntime "github.com/wailsapp/wails/v2/internal/frontend/runtime" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/internal/system/operatingsystem" "github.com/wailsapp/wails/v2/pkg/options" @@ -102,7 +103,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. appBindings.DB().UpdateObfuscatedCallMap() } - assets, err := assetserver.NewAssetServerMainPage(ctx, bindings, appoptions) + assets, err := assetserver.NewAssetServerMainPage(bindings, appoptions, ctx.Value("assetdir") != nil, myLogger, wailsruntime.RuntimeAssetsBundle) if err != nil { log.Fatal(err) } diff --git a/v2/internal/frontend/devserver/devserver.go b/v2/internal/frontend/devserver/devserver.go index 88a2d971e..7b5f50ce4 100644 --- a/v2/internal/frontend/devserver/devserver.go +++ b/v2/internal/frontend/devserver/devserver.go @@ -18,6 +18,8 @@ import ( "sync" "time" + "github.com/wailsapp/wails/v2/internal/frontend/runtime" + "github.com/labstack/echo/v4" "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" @@ -61,6 +63,8 @@ func (d *DevWebServer) Run(ctx context.Context) error { var assetHandler http.Handler var wsHandler http.Handler + var myLogger *logger.Logger + _fronendDevServerURL, _ := ctx.Value("frontenddevserverurl").(string) if _fronendDevServerURL == "" { assetdir, _ := ctx.Value("assetdir").(string) @@ -68,8 +72,11 @@ func (d *DevWebServer) Run(ctx context.Context) error { return c.String(http.StatusOK, assetdir) }) + if _logger := ctx.Value("logger"); _logger != nil { + myLogger = _logger.(*logger.Logger) + } var err error - assetHandler, err = assetserver.NewAssetHandler(ctx, assetServerConfig) + assetHandler, err = assetserver.NewAssetHandler(assetServerConfig, myLogger) if err != nil { log.Fatal(err) } @@ -101,7 +108,7 @@ func (d *DevWebServer) Run(ctx context.Context) error { log.Fatal(err) } - assetServer, err := assetserver.NewDevAssetServer(ctx, assetHandler, wsHandler, bindingsJSON) + assetServer, err := assetserver.NewDevAssetServer(assetHandler, wsHandler, bindingsJSON, ctx.Value("assetdir") != nil, myLogger, runtime.RuntimeAssetsBundle) if err != nil { log.Fatal(err) } diff --git a/v2/internal/frontend/runtime/assets.go b/v2/internal/frontend/runtime/assets.go new file mode 100644 index 000000000..465452a18 --- /dev/null +++ b/v2/internal/frontend/runtime/assets.go @@ -0,0 +1,26 @@ +//go:build !dev + +package runtime + +var RuntimeAssetsBundle = &RuntimeAssets{ + desktopIPC: DesktopIPC, + runtimeDesktopJS: RuntimeDesktopJS, +} + +type RuntimeAssets struct { + desktopIPC []byte + websocketIPC []byte + runtimeDesktopJS []byte +} + +func (r *RuntimeAssets) DesktopIPC() []byte { + return r.desktopIPC +} + +func (r *RuntimeAssets) WebsocketIPC() []byte { + return r.websocketIPC +} + +func (r *RuntimeAssets) RuntimeDesktopJS() []byte { + return r.runtimeDesktopJS +} diff --git a/v2/internal/frontend/runtime/assets_dev.go b/v2/internal/frontend/runtime/assets_dev.go new file mode 100644 index 000000000..5821403e0 --- /dev/null +++ b/v2/internal/frontend/runtime/assets_dev.go @@ -0,0 +1,27 @@ +//go:build dev + +package runtime + +var RuntimeAssetsBundle = &RuntimeAssets{ + desktopIPC: DesktopIPC, + websocketIPC: WebsocketIPC, + runtimeDesktopJS: RuntimeDesktopJS, +} + +type RuntimeAssets struct { + desktopIPC []byte + websocketIPC []byte + runtimeDesktopJS []byte +} + +func (r *RuntimeAssets) DesktopIPC() []byte { + return r.desktopIPC +} + +func (r *RuntimeAssets) WebsocketIPC() []byte { + return r.websocketIPC +} + +func (r *RuntimeAssets) RuntimeDesktopJS() []byte { + return r.runtimeDesktopJS +} diff --git a/v2/internal/fs/fs.go b/v2/internal/fs/fs.go index 778c8704a..5bfa71b1c 100644 --- a/v2/internal/fs/fs.go +++ b/v2/internal/fs/fs.go @@ -2,7 +2,6 @@ package fs import ( "crypto/md5" - "embed" "fmt" "io" "io/fs" @@ -403,32 +402,3 @@ func FindFileInParents(path string, filename string) string { } return pathToFile } - -// FindEmbedRootPath finds the root path in the embed FS. It's the directory which contains all the files. -func FindEmbedRootPath(fsys embed.FS) (string, error) { - stopErr := fmt.Errorf("files or multiple dirs found") - - fPath := "" - err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - - if d.IsDir() { - fPath = path - if entries, dErr := fs.ReadDir(fsys, path); dErr != nil { - return dErr - } else if len(entries) <= 1 { - return nil - } - } - - return stopErr - }) - - if err != nil && err != stopErr { - return "", err - } - - return fPath, nil -}