Switch remote deploy to vendored source builds
Move remote deployment to a vendored source bundle built on the target host via Docker so redeploys no longer require local cross-compilation or host Go installation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
205
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assethandler.go
generated
vendored
Normal file
205
vendor/github.com/wailsapp/wails/v2/pkg/assetserver/assethandler.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
iofs "io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"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
|
||||
|
||||
const (
|
||||
indexHTML = "index.html"
|
||||
)
|
||||
|
||||
type assetHandler struct {
|
||||
fs iofs.FS
|
||||
handler http.Handler
|
||||
|
||||
logger Logger
|
||||
|
||||
retryMissingFiles bool
|
||||
}
|
||||
|
||||
func NewAssetHandler(options assetserver.Options, log Logger) (http.Handler, error) {
|
||||
vfs := options.Assets
|
||||
if vfs != nil {
|
||||
if _, err := vfs.Open("."); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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, _ := FindEmbedRootPath(embedFs)
|
||||
msg += fmt.Sprintf(", please make sure the embedded directory '%s' is correct and contains your assets", rootFolder)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vfs, err = iofs.Sub(vfs, path.Clean(subDir))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var result http.Handler = &assetHandler{
|
||||
fs: vfs,
|
||||
handler: options.Handler,
|
||||
logger: log,
|
||||
}
|
||||
|
||||
if middleware := options.Middleware; middleware != nil {
|
||||
result = middleware(result)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (d *assetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
url := req.URL.Path
|
||||
handler := d.handler
|
||||
if strings.EqualFold(req.Method, http.MethodGet) {
|
||||
filename := path.Clean(strings.TrimPrefix(url, "/"))
|
||||
|
||||
d.logDebug("Handling request '%s' (file='%s')", url, filename)
|
||||
if err := d.serveFSFile(rw, req, filename); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if handler != nil {
|
||||
d.logDebug("File '%s' not found, serving '%s' by AssetHandler", filename, url)
|
||||
handler.ServeHTTP(rw, req)
|
||||
err = nil
|
||||
} else {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
d.logError("Unable to handle request '%s': %s", url, err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
} else if handler != nil {
|
||||
d.logDebug("No GET request, serving '%s' by AssetHandler", url)
|
||||
handler.ServeHTTP(rw, req)
|
||||
} else {
|
||||
rw.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
// serveFSFile will try to load the file from the fs.FS and write it to the response
|
||||
func (d *assetHandler) serveFSFile(rw http.ResponseWriter, req *http.Request, filename string) error {
|
||||
if d.fs == nil {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
file, err := d.fs.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
statInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
url := req.URL.Path
|
||||
isDirectoryPath := url == "" || url[len(url)-1] == '/'
|
||||
if statInfo.IsDir() {
|
||||
if !isDirectoryPath {
|
||||
// If the URL doesn't end in a slash normally a http.redirect should be done, but that currently doesn't work on
|
||||
// WebKit WebViews (macOS/Linux).
|
||||
// So we handle this as a specific error
|
||||
return fmt.Errorf("a directory has been requested without a trailing slash, please add a trailing slash to your request")
|
||||
}
|
||||
|
||||
filename = path.Join(filename, indexHTML)
|
||||
|
||||
file, err = d.fs.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
statInfo, err = file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if isDirectoryPath {
|
||||
return fmt.Errorf("a file has been requested with a trailing slash, please remove the trailing slash from your request")
|
||||
}
|
||||
|
||||
var buf [512]byte
|
||||
var n int
|
||||
if _, haveType := rw.Header()[HeaderContentType]; !haveType {
|
||||
// Detect MimeType by sniffing the first 512 bytes
|
||||
n, err = file.Read(buf[:])
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// Do the custom MimeType sniffing even though http.ServeContent would do it in case
|
||||
// of an io.ReadSeeker. We would like to have a consistent behaviour in both cases.
|
||||
if contentType := GetMimetype(filename, buf[:n]); contentType != "" {
|
||||
rw.Header().Set(HeaderContentType, contentType)
|
||||
}
|
||||
}
|
||||
|
||||
if fileSeeker, _ := file.(io.ReadSeeker); fileSeeker != nil {
|
||||
if _, err := fileSeeker.Seek(0, io.SeekStart); err != nil {
|
||||
return fmt.Errorf("seeker can't seek")
|
||||
}
|
||||
|
||||
http.ServeContent(rw, req, statInfo.Name(), statInfo.ModTime(), fileSeeker)
|
||||
return nil
|
||||
}
|
||||
|
||||
size := strconv.FormatInt(statInfo.Size(), 10)
|
||||
rw.Header().Set(HeaderContentLength, size)
|
||||
|
||||
// Write the first 512 bytes used for MimeType sniffing
|
||||
_, err = io.Copy(rw, bytes.NewReader(buf[:n]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy the remaining content of the file
|
||||
_, err = io.Copy(rw, file)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *assetHandler) logDebug(message string, args ...interface{}) {
|
||||
if d.logger != nil {
|
||||
d.logger.Debug("[AssetHandler] "+message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *assetHandler) logError(message string, args ...interface{}) {
|
||||
if d.logger != nil {
|
||||
d.logger.Error("[AssetHandler] "+message, args...)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user