mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 17:22:01 +08:00
[assetserver] Inject runtime/IPC into all index html files (#2203)
It will also be injected into all html files returned when requesting a folder path.
This commit is contained in:
parent
6c46f6b41c
commit
30d17a760d
@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
@ -111,23 +110,60 @@ func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
header := rw.Header()
|
|
||||||
if d.servingFromDisk {
|
if d.servingFromDisk {
|
||||||
header.Add(HeaderCacheControl, "no-cache")
|
rw.Header().Add(HeaderCacheControl, "no-cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
handler := d.handler
|
||||||
|
if req.Method != http.MethodGet {
|
||||||
|
handler.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
path := req.URL.Path
|
path := req.URL.Path
|
||||||
switch path {
|
if path == runtimeJSPath {
|
||||||
case "", "/", "/index.html":
|
d.writeBlob(rw, path, d.runtimeJS)
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
d.handler.ServeHTTP(recorder, req)
|
} else if path == runtimePath && d.runtimeHandler != nil {
|
||||||
for k, v := range recorder.HeaderMap {
|
d.runtimeHandler.HandleRuntimeCall(rw, req)
|
||||||
header[k] = v
|
|
||||||
|
} else if path == ipcJSPath {
|
||||||
|
content := d.runtime.DesktopIPC()
|
||||||
|
if d.ipcJS != nil {
|
||||||
|
content = d.ipcJS(req)
|
||||||
|
}
|
||||||
|
d.writeBlob(rw, path, content)
|
||||||
|
|
||||||
|
} else if script, ok := d.pluginScripts[path]; ok {
|
||||||
|
d.writeBlob(rw, path, []byte(script))
|
||||||
|
|
||||||
|
} else if d.isRuntimeInjectionMatch(path) {
|
||||||
|
recorder := &bodyRecorder{
|
||||||
|
ResponseWriter: rw,
|
||||||
|
doRecord: func(code int, h http.Header) bool {
|
||||||
|
if code == http.StatusNotFound {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if code != http.StatusOK {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Contains(h.Get(HeaderContentType), "text/html")
|
||||||
|
}}
|
||||||
|
|
||||||
|
handler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
body := recorder.Body()
|
||||||
|
if body == nil {
|
||||||
|
// The body has been streamed and not recorded, we are finished
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch recorder.Code {
|
code := recorder.Code()
|
||||||
|
switch code {
|
||||||
case http.StatusOK:
|
case http.StatusOK:
|
||||||
content, err := d.processIndexHTML(recorder.Body.Bytes())
|
content, err := d.processIndexHTML(body.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.serveError(rw, err, "Unable to processIndexHTML")
|
d.serveError(rw, err, "Unable to processIndexHTML")
|
||||||
return
|
return
|
||||||
@ -138,34 +174,12 @@ func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
d.writeBlob(rw, indexHTML, defaultHTML)
|
d.writeBlob(rw, indexHTML, defaultHTML)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rw.WriteHeader(recorder.Code)
|
rw.WriteHeader(code)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case runtimeJSPath:
|
} else {
|
||||||
d.writeBlob(rw, path, d.runtimeJS)
|
handler.ServeHTTP(rw, req)
|
||||||
|
|
||||||
case runtimePath:
|
|
||||||
if d.runtimeHandler != nil {
|
|
||||||
d.runtimeHandler.HandleRuntimeCall(rw, req)
|
|
||||||
} else {
|
|
||||||
d.handler.ServeHTTP(rw, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ipcJSPath:
|
|
||||||
content := d.runtime.DesktopIPC()
|
|
||||||
if d.ipcJS != nil {
|
|
||||||
content = d.ipcJS(req)
|
|
||||||
}
|
|
||||||
d.writeBlob(rw, path, content)
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Check if this is a plugin script
|
|
||||||
if script, ok := d.pluginScripts[path]; ok {
|
|
||||||
d.writeBlob(rw, path, []byte(script))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
d.handler.ServeHTTP(rw, req)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,3 +243,12 @@ func (d *AssetServer) logError(message string, args ...interface{}) {
|
|||||||
d.logger.Error("[AssetServer] "+message, args...)
|
d.logger.Error("[AssetServer] "+message, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (AssetServer) isRuntimeInjectionMatch(path string) bool {
|
||||||
|
if path == "" {
|
||||||
|
path = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.HasSuffix(path, "/") ||
|
||||||
|
strings.HasSuffix(path, "/"+indexHTML)
|
||||||
|
}
|
||||||
|
61
v2/pkg/assetserver/body_recorder.go
Normal file
61
v2/pkg/assetserver/body_recorder.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package assetserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bodyRecorder struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
doRecord func(code int, header http.Header) bool
|
||||||
|
|
||||||
|
body *bytes.Buffer
|
||||||
|
code int
|
||||||
|
wroteHeader bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *bodyRecorder) Write(buf []byte) (int, error) {
|
||||||
|
rw.writeHeader(buf, http.StatusOK)
|
||||||
|
if rw.body != nil {
|
||||||
|
return rw.body.Write(buf)
|
||||||
|
}
|
||||||
|
return rw.ResponseWriter.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *bodyRecorder) WriteHeader(code int) {
|
||||||
|
rw.writeHeader(nil, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *bodyRecorder) Code() int {
|
||||||
|
return rw.code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *bodyRecorder) Body() *bytes.Buffer {
|
||||||
|
return rw.body
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *bodyRecorder) writeHeader(buf []byte, code int) {
|
||||||
|
if rw.wroteHeader {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rw.doRecord != nil {
|
||||||
|
header := rw.Header()
|
||||||
|
if len(buf) != 0 {
|
||||||
|
if _, hasType := header[HeaderContentType]; !hasType {
|
||||||
|
header.Set(HeaderContentType, http.DetectContentType(buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rw.doRecord(code, header) {
|
||||||
|
rw.body = bytes.NewBuffer(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rw.body == nil {
|
||||||
|
rw.ResponseWriter.WriteHeader(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
rw.code = code
|
||||||
|
rw.wroteHeader = true
|
||||||
|
}
|
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- New task created for linting v2 `task v2:lint`. Workflow updated to run the task. Added by @mikeee in [PR](https://github.com/wailsapp/wails/pull/2957)
|
- New task created for linting v2 `task v2:lint`. Workflow updated to run the task. Added by @mikeee in [PR](https://github.com/wailsapp/wails/pull/2957)
|
||||||
- Added new community template wails-htmx-templ-chi-tailwind. Added by [@pylotlight](https://github.com/pylotlight) in [PR](https://github.com/wailsapp/wails/pull/2984)
|
- Added new community template wails-htmx-templ-chi-tailwind. Added by [@pylotlight](https://github.com/pylotlight) in [PR](https://github.com/wailsapp/wails/pull/2984)
|
||||||
- Added CPU/GPU/Memory detection for `wails doctor`. Added by @leaanthony in #d51268b8d0680430f3a614775b13e6cd2b906d1c
|
- Added CPU/GPU/Memory detection for `wails doctor`. Added by @leaanthony in #d51268b8d0680430f3a614775b13e6cd2b906d1c
|
||||||
|
- The [AssetServer](/docs/reference/options#assetserver) now injects the runtime/IPC into all index html files and into all html files returned when requesting a folder path. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2203)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user