mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 20:40:33 +08:00

* [assetserver] Add support for HTTP Middlewares * [dev] Disable frontend DevServer if no Assets has been defined and inform user * [dev] Consistent WebSocket behaviour in dev and prod mode for assets handler and middleware In prod mode we can't support WebSockets so make sure the assets handler and middleware never see WebSockets in dev mode. * [templates] Migrate to new AssetServer option * [docs] Add assetserver.Options to the reference
133 lines
3.1 KiB
Go
133 lines
3.1 KiB
Go
package assetserver
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/wailsapp/wails/v2/pkg/options"
|
|
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
|
"golang.org/x/net/html"
|
|
)
|
|
|
|
func BuildAssetServerConfig(options *options.App) assetserver.Options {
|
|
if opts := options.AssetServer; opts != nil {
|
|
if options.Assets != nil || options.AssetsHandler != nil {
|
|
panic("It's not possible to use the deprecated Assets and AssetsHandler options and the new AssetServer option at the same time. Please migrate all your Assets options to the AssetServer option.")
|
|
}
|
|
|
|
return *opts
|
|
}
|
|
|
|
return assetserver.Options{
|
|
Assets: options.Assets,
|
|
Handler: options.AssetsHandler,
|
|
}
|
|
}
|
|
|
|
const (
|
|
HeaderHost = "Host"
|
|
HeaderContentType = "Content-Type"
|
|
HeaderContentLength = "Content-Length"
|
|
HeaderUserAgent = "User-Agent"
|
|
HeaderCacheControl = "Cache-Control"
|
|
HeaderUpgrade = "Upgrade"
|
|
|
|
WailsUserAgentValue = "wails.io"
|
|
)
|
|
|
|
func serveFile(rw http.ResponseWriter, filename string, blob []byte) error {
|
|
header := rw.Header()
|
|
header.Set(HeaderContentLength, fmt.Sprintf("%d", len(blob)))
|
|
if mimeType := header.Get(HeaderContentType); mimeType == "" {
|
|
mimeType = GetMimetype(filename, blob)
|
|
header.Set(HeaderContentType, mimeType)
|
|
}
|
|
|
|
rw.WriteHeader(http.StatusOK)
|
|
_, err := io.Copy(rw, bytes.NewReader(blob))
|
|
return err
|
|
}
|
|
|
|
func createScriptNode(scriptName string) *html.Node {
|
|
return &html.Node{
|
|
Type: html.ElementNode,
|
|
Data: "script",
|
|
Attr: []html.Attribute{
|
|
{
|
|
Key: "src",
|
|
Val: scriptName,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func createDivNode(id string) *html.Node {
|
|
return &html.Node{
|
|
Type: html.ElementNode,
|
|
Data: "div",
|
|
Attr: []html.Attribute{
|
|
{
|
|
Namespace: "",
|
|
Key: "id",
|
|
Val: id,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func insertScriptInHead(htmlNode *html.Node, scriptName string) error {
|
|
headNode := findFirstTag(htmlNode, "head")
|
|
if headNode == nil {
|
|
return errors.New("cannot find head in HTML")
|
|
}
|
|
scriptNode := createScriptNode(scriptName)
|
|
if headNode.FirstChild != nil {
|
|
headNode.InsertBefore(scriptNode, headNode.FirstChild)
|
|
} else {
|
|
headNode.AppendChild(scriptNode)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func appendSpinnerToBody(htmlNode *html.Node) error {
|
|
bodyNode := findFirstTag(htmlNode, "body")
|
|
if bodyNode == nil {
|
|
return errors.New("cannot find body in HTML")
|
|
}
|
|
scriptNode := createDivNode("wails-spinner")
|
|
bodyNode.AppendChild(scriptNode)
|
|
return nil
|
|
}
|
|
|
|
func getHTMLNode(htmldata []byte) (*html.Node, error) {
|
|
return html.Parse(bytes.NewReader(htmldata))
|
|
}
|
|
|
|
func findFirstTag(htmlnode *html.Node, tagName string) *html.Node {
|
|
var extractor func(*html.Node) *html.Node
|
|
var result *html.Node
|
|
extractor = func(node *html.Node) *html.Node {
|
|
if node.Type == html.ElementNode && node.Data == tagName {
|
|
return node
|
|
}
|
|
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
|
result := extractor(child)
|
|
if result != nil {
|
|
return result
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
result = extractor(htmlnode)
|
|
return result
|
|
}
|
|
|
|
func isWebSocket(req *http.Request) bool {
|
|
upgrade := req.Header.Get(HeaderUpgrade)
|
|
return strings.EqualFold(upgrade, "websocket")
|
|
}
|