Compare commits
15
Commits
033017864e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b92aabb052 | ||
|
|
77f26a3e2c | ||
|
|
9458840292 | ||
|
|
ed4cf064e3 | ||
|
|
c816d15b1a | ||
|
|
2fced6bd11 | ||
|
|
b2bb8ae69e | ||
|
|
c5067f1696 | ||
|
|
de8f5368a5 | ||
|
|
2a6641f03c | ||
|
|
a5b20519d4 | ||
|
|
e000a90456 | ||
|
|
b5c8576ab5 | ||
|
|
e2039a15b1 | ||
|
|
492ae56d48 |
@@ -1,27 +1,26 @@
|
|||||||
.PHONY: build build-web build-wfa-js clean clean-wfa-js ensure-dist workflow-init
|
.PHONY: build build-web build-wfa clean clean-wfa clean-web
|
||||||
|
|
||||||
build: clean ensure-dist build-web build-wfa-js
|
build: clean ensure-dist build-wfa build-web
|
||||||
@echo "======================== Building Binary ======================="
|
@echo "======================== Building Binary ======================="
|
||||||
# resolve symbolic links in web by copying it into dist/web/
|
# resolve symbolic links in web by copying it into dist/web/
|
||||||
CGO_ENABLED=0 go build -tags release -ldflags="-s -w" -v -o dist/ .
|
CGO_ENABLED=0 go build -tags release -ldflags="-s -w" -v -o dist/ .
|
||||||
|
|
||||||
build-web: ensure-dist
|
clean: clean-wfa clean-web
|
||||||
cp -rL web/ dist/web/
|
|
||||||
|
|
||||||
build-wfa-js: ensure-dist
|
|
||||||
$(MAKE) -C WFA-JS
|
|
||||||
cp -f WFA-JS/dist/* web/modules
|
|
||||||
|
|
||||||
clean: clean-wfa-js
|
|
||||||
@echo "======================== Cleaning Project ======================"
|
@echo "======================== Cleaning Project ======================"
|
||||||
go clean
|
go clean
|
||||||
rm -rf dist/*
|
rm -rf dist/*
|
||||||
|
|
||||||
clean-wfa-js:
|
|
||||||
$(MAKE) clean -C WFA-JS
|
|
||||||
|
|
||||||
ensure-dist:
|
ensure-dist:
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
|
|
||||||
workflow-init: ensure-dist build-web
|
build-web: ensure-dist
|
||||||
cp -r dev_config/. .
|
cp -rL web/ dist/web/
|
||||||
|
|
||||||
|
clean-web:
|
||||||
|
|
||||||
|
build-wfa:
|
||||||
|
$(MAKE) -C WFA-JS
|
||||||
|
cp -f WFA-JS/dist/* web/modules
|
||||||
|
|
||||||
|
clean-wfa:
|
||||||
|
$(MAKE) clean -C WFA-JS
|
||||||
@@ -13,7 +13,7 @@ ProxmoxAAS Dashboard provides users of a proxmox based compute on demand service
|
|||||||
|
|
||||||
## ProxmoxAAS System Installation Overview
|
## ProxmoxAAS System Installation Overview
|
||||||
|
|
||||||
The ProxmoxAAS project is large and is split into multiple components. There are four required components, the Dashboard, API, Fabric, and access-manager-api. The instalation order should start with the Dashboard and then proceed to the other backend components. This will require some foresight into the setup process.
|
The ProxmoxAAS project is large and is split into multiple components. There are four required components, the Dashboard, API, Fabric, and access-manager-api. The installation order should start with the Dashboard and then proceed to the other backend components. This will require some foresight into the setup process.
|
||||||
|
|
||||||
The supported setup is to use a reverse proxy to serve both the original Proxmox web interface and ProxmoxAAS components. It is possible other setups can work. Rather than provide specific steps to duplicate a certain setup, the steps included are intended as a guideline of steps required for proper function in most setups. Consequently, the examples provided are only to highlight key settings and do not represent complete working configurations. The instructions also assume you have your own domain name which will substitute `domain.net` in some of the configs.
|
The supported setup is to use a reverse proxy to serve both the original Proxmox web interface and ProxmoxAAS components. It is possible other setups can work. Rather than provide specific steps to duplicate a certain setup, the steps included are intended as a guideline of steps required for proper function in most setups. Consequently, the examples provided are only to highlight key settings and do not represent complete working configurations. The instructions also assume you have your own domain name which will substitute `domain.net` in some of the configs.
|
||||||
|
|
||||||
|
|||||||
+1
-1
Submodule WFA-JS updated: f53f344fb3...b0aacd5f9c
+7
-1
@@ -18,9 +18,11 @@ func Run() {
|
|||||||
|
|
||||||
common.Global = common.GetConfig(*configPath)
|
common.Global = common.GetConfig(*configPath)
|
||||||
|
|
||||||
// setup static resources
|
// setup gin
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
|
||||||
|
// setup static resources
|
||||||
m := common.InitMinify()
|
m := common.InitMinify()
|
||||||
ServeStatic(router, m)
|
ServeStatic(router, m)
|
||||||
html := common.MinifyStatic(m, web.Templates)
|
html := common.MinifyStatic(m, web.Templates)
|
||||||
@@ -51,24 +53,28 @@ func ServeStatic(router *gin.Engine, m *minify.M) {
|
|||||||
router.GET("/css/*css", func(c *gin.Context) {
|
router.GET("/css/*css", func(c *gin.Context) {
|
||||||
path, _ := c.Params.Get("css")
|
path, _ := c.Params.Get("css")
|
||||||
data := css[fmt.Sprintf("css%s", path)]
|
data := css[fmt.Sprintf("css%s", path)]
|
||||||
|
c.Header("Content-Encoding", data.MimeType.Encoding)
|
||||||
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
||||||
})
|
})
|
||||||
images := common.MinifyStatic(m, web.Images_fs)
|
images := common.MinifyStatic(m, web.Images_fs)
|
||||||
router.GET("/images/*image", func(c *gin.Context) {
|
router.GET("/images/*image", func(c *gin.Context) {
|
||||||
path, _ := c.Params.Get("image")
|
path, _ := c.Params.Get("image")
|
||||||
data := images[fmt.Sprintf("images%s", path)]
|
data := images[fmt.Sprintf("images%s", path)]
|
||||||
|
c.Header("Content-Encoding", data.MimeType.Encoding)
|
||||||
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
||||||
})
|
})
|
||||||
modules := common.MinifyStatic(m, web.Modules_fs)
|
modules := common.MinifyStatic(m, web.Modules_fs)
|
||||||
router.GET("/modules/*module", func(c *gin.Context) {
|
router.GET("/modules/*module", func(c *gin.Context) {
|
||||||
path, _ := c.Params.Get("module")
|
path, _ := c.Params.Get("module")
|
||||||
data := modules[fmt.Sprintf("modules%s", path)]
|
data := modules[fmt.Sprintf("modules%s", path)]
|
||||||
|
c.Header("Content-Encoding", data.MimeType.Encoding)
|
||||||
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
||||||
})
|
})
|
||||||
scripts := common.MinifyStatic(m, web.Scripts_fs)
|
scripts := common.MinifyStatic(m, web.Scripts_fs)
|
||||||
router.GET("/scripts/*script", func(c *gin.Context) {
|
router.GET("/scripts/*script", func(c *gin.Context) {
|
||||||
path, _ := c.Params.Get("script")
|
path, _ := c.Params.Get("script")
|
||||||
data := scripts[fmt.Sprintf("scripts%s", path)]
|
data := scripts[fmt.Sprintf("scripts%s", path)]
|
||||||
|
c.Header("Content-Encoding", data.MimeType.Encoding)
|
||||||
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
c.Data(200, data.MimeType.Type, []byte(data.Data))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
// defines mime type and associated minifier
|
// defines mime type and associated minifier
|
||||||
type MimeType struct {
|
type MimeType struct {
|
||||||
Type string
|
Type string
|
||||||
|
Encoding string
|
||||||
Minifier func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error
|
Minifier func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +45,11 @@ var MimeTypes = map[string]MimeType{
|
|||||||
Type: "application/wasm",
|
Type: "application/wasm",
|
||||||
Minifier: nil,
|
Minifier: nil,
|
||||||
},
|
},
|
||||||
|
"gz": {
|
||||||
|
Type: "application/wasm",
|
||||||
|
Encoding: "gzip",
|
||||||
|
Minifier: nil,
|
||||||
|
},
|
||||||
"*": {
|
"*": {
|
||||||
Type: "text/plain",
|
Type: "text/plain",
|
||||||
Minifier: nil,
|
Minifier: nil,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
// defines mime type and associated minifier
|
// defines mime type and associated minifier
|
||||||
type MimeType struct {
|
type MimeType struct {
|
||||||
Type string
|
Type string
|
||||||
|
Encoding string
|
||||||
Minifier func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error
|
Minifier func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +49,11 @@ var MimeTypes = map[string]MimeType{
|
|||||||
Type: "application/wasm",
|
Type: "application/wasm",
|
||||||
Minifier: nil,
|
Minifier: nil,
|
||||||
},
|
},
|
||||||
|
"gz": {
|
||||||
|
Type: "application/wasm",
|
||||||
|
Encoding: "gzip",
|
||||||
|
Minifier: nil,
|
||||||
|
},
|
||||||
"*": {
|
"*": {
|
||||||
Type: "text/plain",
|
Type: "text/plain",
|
||||||
Minifier: nil,
|
Minifier: nil,
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
web/modules/*
|
|
||||||
WFA-JS/*
|
|
||||||
dist/*
|
|
||||||
@@ -1,25 +1,26 @@
|
|||||||
module proxmoxaas-dashboard
|
module proxmoxaas-dashboard
|
||||||
|
|
||||||
go 1.26.5
|
go 1.27.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gerow/go-color v0.0.0-20140219113758-125d37f527f1
|
github.com/gerow/go-color v0.0.0-20140219113758-125d37f527f1
|
||||||
github.com/gin-gonic/gin v1.12.0
|
github.com/gin-gonic/gin v1.12.0
|
||||||
github.com/go-viper/mapstructure/v2 v2.5.0
|
github.com/go-viper/mapstructure/v2 v2.5.0
|
||||||
github.com/tdewolff/minify/v2 v2.24.13
|
github.com/tdewolff/minify/v2 v2.24.17
|
||||||
proxmoxaas-common-lib v0.0.0
|
proxmoxaas-common-lib v0.0.0
|
||||||
web v0.0.0
|
web v0.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
replace proxmoxaas-common-lib => ./proxmoxaas-common-lib
|
replace proxmoxaas-common-lib => ./proxmoxaas-common-lib
|
||||||
|
|
||||||
replace web => ./dist/web
|
replace web => ./dist/web
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/gopkg v0.1.4 // indirect
|
github.com/bytedance/gopkg v0.1.4 // indirect
|
||||||
github.com/bytedance/sonic v1.15.2 // indirect
|
github.com/bytedance/sonic v1.15.2 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.5.1 // indirect
|
github.com/bytedance/sonic/loader v0.5.2 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.7 // indirect
|
github.com/cloudwego/base64x v0.1.7 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.15 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.1 // indirect
|
github.com/gin-contrib/sse v1.1.1 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
@@ -28,21 +29,21 @@ require (
|
|||||||
github.com/goccy/go-yaml v1.19.2 // indirect
|
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.4.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.4.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.5.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.23 // indirect
|
github.com/mattn/go-isatty v0.0.24 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
|
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
|
||||||
github.com/quic-go/qpack v0.6.0 // indirect
|
github.com/quic-go/qpack v0.6.0 // indirect
|
||||||
github.com/quic-go/quic-go v0.60.0 // indirect
|
github.com/quic-go/quic-go v0.61.0 // indirect
|
||||||
github.com/tdewolff/parse/v2 v2.8.13 // indirect
|
github.com/tdewolff/parse/v2 v2.8.16 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
github.com/ugorji/go/codec v1.3.2 // indirect
|
||||||
go.mongodb.org/mongo-driver/v2 v2.8.0 // indirect
|
go.mongodb.org/mongo-driver/v2 v2.8.1 // indirect
|
||||||
golang.org/x/arch v0.29.0 // indirect
|
golang.org/x/arch v0.30.0 // indirect
|
||||||
golang.org/x/crypto v0.54.0 // indirect
|
golang.org/x/crypto v0.55.0 // indirect
|
||||||
golang.org/x/net v0.57.0 // indirect
|
golang.org/x/net v0.58.0 // indirect
|
||||||
golang.org/x/sys v0.47.0 // indirect
|
golang.org/x/sys v0.47.0 // indirect
|
||||||
golang.org/x/text v0.40.0 // indirect
|
golang.org/x/text v0.41.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.12 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
Submodule proxmoxaas-common-lib updated: f4deeb1ab6...8284ffbc43
+3
-3
@@ -191,18 +191,18 @@ hr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* add hide large class similar to w3-hide-medium and w3-hide-small */
|
/* add hide large class similar to w3-hide-medium and w3-hide-small */
|
||||||
@media screen and (width >=993px) {
|
@media screen and (width >= 993px) {
|
||||||
.hide-large {display: none !important;}
|
.hide-large {display: none !important;}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fixes edge case in w3-hide-medium where width between 992 and 993 */
|
/* fixes edge case in w3-hide-medium where width between 992 and 993 */
|
||||||
@media screen and (width <=993px) and (width >=601px){
|
@media screen and (width <= 993px) and (width >= 601px){
|
||||||
.hide-large {display: none !important;}
|
.hide-large {display: none !important;}
|
||||||
.hide-medium {display:none !important}
|
.hide-medium {display:none !important}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fixes edge case in w3-hide-small when width between 600 and 601 */
|
/* fixes edge case in w3-hide-small when width between 600 and 601 */
|
||||||
@media screen and (width <=601px) {
|
@media screen and (width <= 601px) and (width >= 440px) {
|
||||||
.hide-large {display: none !important;}
|
.hide-large {display: none !important;}
|
||||||
.hide-medium {display:none !important}
|
.hide-medium {display:none !important}
|
||||||
.hide-small {display:none !important}
|
.hide-small {display:none !important}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="controls" class="w3-center w3-container">
|
<div id="controls" class="w3-center w3-container">
|
||||||
<button id="cancel" type="submit" value="cancel" form="form" class="w3-button w3-margin" formnovalidate>CANCEL</button>
|
<button id="cancel" type="submit" value="cancel" form="form" class="w3-button w3-margin" formnovalidate>CANCEL</button>
|
||||||
<button id="confirm" type="submit" value="confirm" form="form" class="w3-button w3-margin" >CONFIRM</button>
|
<button id="confirm" type="submit" value="confirm" form="form" class="w3-button w3-margin">CONFIRM</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
+321
-296
@@ -1,53 +1,26 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
//
|
|
||||||
// This file has been modified for use by the TinyGo compiler.
|
"use strict";
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
// Map multiple JavaScript environments to a single common API,
|
|
||||||
// preferring web standards over Node.js API.
|
|
||||||
//
|
|
||||||
// Environments considered:
|
|
||||||
// - Browsers
|
|
||||||
// - Node.js
|
|
||||||
// - Electron
|
|
||||||
// - Parcel
|
|
||||||
|
|
||||||
if (typeof global !== "undefined") {
|
|
||||||
// global already exists
|
|
||||||
} else if (typeof window !== "undefined") {
|
|
||||||
window.global = window;
|
|
||||||
} else if (typeof self !== "undefined") {
|
|
||||||
self.global = self;
|
|
||||||
} else {
|
|
||||||
throw new Error("cannot export Go (neither global, window nor self is defined)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!global.require && typeof require !== "undefined") {
|
|
||||||
global.require = require;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!global.fs && global.require) {
|
|
||||||
global.fs = require("node:fs");
|
|
||||||
}
|
|
||||||
|
|
||||||
const enosys = () => {
|
const enosys = () => {
|
||||||
const err = new Error("not implemented");
|
const err = new Error("not implemented");
|
||||||
err.code = "ENOSYS";
|
err.code = "ENOSYS";
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!global.fs) {
|
if (!globalThis.fs) {
|
||||||
let outputBuf = "";
|
let outputBuf = "";
|
||||||
global.fs = {
|
globalThis.fs = {
|
||||||
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
|
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1, O_DIRECTORY: -1 }, // unused
|
||||||
writeSync(fd, buf) {
|
writeSync(fd, buf) {
|
||||||
outputBuf += decoder.decode(buf);
|
outputBuf += decoder.decode(buf);
|
||||||
const nl = outputBuf.lastIndexOf("\n");
|
const nl = outputBuf.lastIndexOf("\n");
|
||||||
if (nl != -1) {
|
if (nl != -1) {
|
||||||
console.log(outputBuf.substr(0, nl));
|
console.log(outputBuf.substring(0, nl));
|
||||||
outputBuf = outputBuf.substr(nl + 1);
|
outputBuf = outputBuf.substring(nl + 1);
|
||||||
}
|
}
|
||||||
return buf.length;
|
return buf.length;
|
||||||
},
|
},
|
||||||
@@ -85,8 +58,8 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.process) {
|
if (!globalThis.process) {
|
||||||
global.process = {
|
globalThis.process = {
|
||||||
getuid() { return -1; },
|
getuid() { return -1; },
|
||||||
getgid() { return -1; },
|
getgid() { return -1; },
|
||||||
geteuid() { return -1; },
|
geteuid() { return -1; },
|
||||||
@@ -100,53 +73,66 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.crypto) {
|
if (!globalThis.path) {
|
||||||
const nodeCrypto = require("node:crypto");
|
globalThis.path = {
|
||||||
global.crypto = {
|
resolve(...pathSegments) {
|
||||||
getRandomValues(b) {
|
return pathSegments.join("/");
|
||||||
nodeCrypto.randomFillSync(b);
|
}
|
||||||
},
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.performance) {
|
if (!globalThis.crypto) {
|
||||||
global.performance = {
|
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
|
||||||
now() {
|
|
||||||
const [sec, nsec] = process.hrtime();
|
|
||||||
return sec * 1000 + nsec / 1000000;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.TextEncoder) {
|
if (!globalThis.performance) {
|
||||||
global.TextEncoder = require("node:util").TextEncoder;
|
throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.TextDecoder) {
|
if (!globalThis.TextEncoder) {
|
||||||
global.TextDecoder = require("node:util").TextDecoder;
|
throw new Error("globalThis.TextEncoder is not available, polyfill required");
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of polyfills for common API.
|
if (!globalThis.TextDecoder) {
|
||||||
|
throw new Error("globalThis.TextDecoder is not available, polyfill required");
|
||||||
|
}
|
||||||
|
|
||||||
const encoder = new TextEncoder("utf-8");
|
const encoder = new TextEncoder("utf-8");
|
||||||
const decoder = new TextDecoder("utf-8");
|
const decoder = new TextDecoder("utf-8");
|
||||||
let reinterpretBuf = new DataView(new ArrayBuffer(8));
|
|
||||||
var logLine = [];
|
|
||||||
const wasmExit = {}; // thrown to exit via proc_exit (not an error)
|
|
||||||
|
|
||||||
global.Go = class {
|
globalThis.Go = class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._callbackTimeouts = new Map();
|
this.argv = ["js"];
|
||||||
|
this.env = {};
|
||||||
|
this.exit = (code) => {
|
||||||
|
if (code !== 0) {
|
||||||
|
console.warn("exit code:", code);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._exitPromise = new Promise((resolve) => {
|
||||||
|
this._resolveExitPromise = resolve;
|
||||||
|
});
|
||||||
|
this._pendingEvent = null;
|
||||||
|
this._scheduledTimeouts = new Map();
|
||||||
this._nextCallbackTimeoutID = 1;
|
this._nextCallbackTimeoutID = 1;
|
||||||
|
|
||||||
const mem = () => {
|
const setInt64 = (addr, v) => {
|
||||||
// The buffer may change when requesting more memory.
|
this.mem.setUint32(addr + 0, v, true);
|
||||||
return new DataView(this._inst.exports.memory.buffer);
|
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unboxValue = (v_ref) => {
|
const setInt32 = (addr, v) => {
|
||||||
reinterpretBuf.setBigInt64(0, v_ref, true);
|
this.mem.setUint32(addr + 0, v, true);
|
||||||
const f = reinterpretBuf.getFloat64(0, true);
|
}
|
||||||
|
|
||||||
|
const getInt64 = (addr) => {
|
||||||
|
const low = this.mem.getUint32(addr + 0, true);
|
||||||
|
const high = this.mem.getInt32(addr + 4, true);
|
||||||
|
return low + high * 4294967296;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadValue = (addr) => {
|
||||||
|
const f = this.mem.getFloat64(addr, true);
|
||||||
if (f === 0) {
|
if (f === 0) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -154,77 +140,69 @@
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = v_ref & 0xffffffffn;
|
const id = this.mem.getUint32(addr, true);
|
||||||
return this._values[id];
|
return this._values[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const storeValue = (addr, v) => {
|
||||||
|
const nanHead = 0x7FF80000;
|
||||||
|
|
||||||
const loadValue = (addr) => {
|
if (typeof v === "number" && v !== 0) {
|
||||||
let v_ref = mem().getBigUint64(addr, true);
|
|
||||||
return unboxValue(v_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
const boxValue = (v) => {
|
|
||||||
const nanHead = 0x7FF80000n;
|
|
||||||
|
|
||||||
if (typeof v === "number") {
|
|
||||||
if (isNaN(v)) {
|
if (isNaN(v)) {
|
||||||
return nanHead << 32n;
|
this.mem.setUint32(addr + 4, nanHead, true);
|
||||||
|
this.mem.setUint32(addr, 0, true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (v === 0) {
|
this.mem.setFloat64(addr, v, true);
|
||||||
return (nanHead << 32n) | 1n;
|
return;
|
||||||
}
|
|
||||||
reinterpretBuf.setFloat64(0, v, true);
|
|
||||||
return reinterpretBuf.getBigInt64(0, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (v) {
|
if (v === undefined) {
|
||||||
case undefined:
|
this.mem.setFloat64(addr, 0, true);
|
||||||
return 0n;
|
return;
|
||||||
case null:
|
|
||||||
return (nanHead << 32n) | 2n;
|
|
||||||
case true:
|
|
||||||
return (nanHead << 32n) | 3n;
|
|
||||||
case false:
|
|
||||||
return (nanHead << 32n) | 4n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = this._ids.get(v);
|
let id = this._ids.get(v);
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
id = this._idPool.pop();
|
id = this._idPool.pop();
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
id = BigInt(this._values.length);
|
id = this._values.length;
|
||||||
}
|
}
|
||||||
this._values[id] = v;
|
this._values[id] = v;
|
||||||
this._goRefCounts[id] = 0;
|
this._goRefCounts[id] = 0;
|
||||||
this._ids.set(v, id);
|
this._ids.set(v, id);
|
||||||
}
|
}
|
||||||
this._goRefCounts[id]++;
|
this._goRefCounts[id]++;
|
||||||
let typeFlag = 1n;
|
let typeFlag = 0;
|
||||||
switch (typeof v) {
|
switch (typeof v) {
|
||||||
|
case "object":
|
||||||
|
if (v !== null) {
|
||||||
|
typeFlag = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "string":
|
case "string":
|
||||||
typeFlag = 2n;
|
typeFlag = 2;
|
||||||
break;
|
break;
|
||||||
case "symbol":
|
case "symbol":
|
||||||
typeFlag = 3n;
|
typeFlag = 3;
|
||||||
break;
|
break;
|
||||||
case "function":
|
case "function":
|
||||||
typeFlag = 4n;
|
typeFlag = 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return id | ((nanHead | typeFlag) << 32n);
|
this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
|
||||||
|
this.mem.setUint32(addr, id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const storeValue = (addr, v) => {
|
const loadSlice = (addr) => {
|
||||||
let v_ref = boxValue(v);
|
const array = getInt64(addr + 0);
|
||||||
mem().setBigUint64(addr, v_ref, true);
|
const len = getInt64(addr + 8);
|
||||||
|
return new Uint8Array(this._inst.exports.mem.buffer, array, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadSlice = (array, len, cap) => {
|
const loadSliceOfValues = (addr) => {
|
||||||
return new Uint8Array(this._inst.exports.memory.buffer, array, len);
|
const array = getInt64(addr + 0);
|
||||||
}
|
const len = getInt64(addr + 8);
|
||||||
|
|
||||||
const loadSliceOfValues = (array, len, cap) => {
|
|
||||||
const a = new Array(len);
|
const a = new Array(len);
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
a[i] = loadValue(array + i * 8);
|
a[i] = loadValue(array + i * 8);
|
||||||
@@ -232,81 +210,109 @@
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadString = (ptr, len) => {
|
const loadString = (addr) => {
|
||||||
return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
|
const saddr = getInt64(addr + 0);
|
||||||
|
const len = getInt64(addr + 8);
|
||||||
|
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
const testCallExport = (a, b) => {
|
||||||
|
this._inst.exports.testExport0();
|
||||||
|
return this._inst.exports.testExport(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeOrigin = Date.now() - performance.now();
|
const timeOrigin = Date.now() - performance.now();
|
||||||
this.importObject = {
|
this.importObject = {
|
||||||
wasi_snapshot_preview1: {
|
_gotest: {
|
||||||
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
|
add: (a, b) => a + b,
|
||||||
fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {
|
callExport: testCallExport,
|
||||||
let nwritten = 0;
|
|
||||||
if (fd == 1) {
|
|
||||||
for (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {
|
|
||||||
let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
|
|
||||||
let ptr = mem().getUint32(iov_ptr + 0, true);
|
|
||||||
let len = mem().getUint32(iov_ptr + 4, true);
|
|
||||||
nwritten += len;
|
|
||||||
for (let i=0; i<len; i++) {
|
|
||||||
let c = mem().getUint8(ptr+i);
|
|
||||||
if (c == 13) { // CR
|
|
||||||
// ignore
|
|
||||||
} else if (c == 10) { // LF
|
|
||||||
// write line
|
|
||||||
let line = decoder.decode(new Uint8Array(logLine));
|
|
||||||
logLine = [];
|
|
||||||
console.log(line);
|
|
||||||
} else {
|
|
||||||
logLine.push(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.error('invalid file descriptor:', fd);
|
|
||||||
}
|
|
||||||
mem().setUint32(nwritten_ptr, nwritten, true);
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
fd_close: () => 0, // dummy
|
|
||||||
fd_fdstat_get: () => 0, // dummy
|
|
||||||
fd_seek: () => 0, // dummy
|
|
||||||
proc_exit: (code) => {
|
|
||||||
this.exited = true;
|
|
||||||
this.exitCode = code;
|
|
||||||
this._resolveExitPromise();
|
|
||||||
throw wasmExit;
|
|
||||||
},
|
|
||||||
random_get: (bufPtr, bufLen) => {
|
|
||||||
crypto.getRandomValues(loadSlice(bufPtr, bufLen));
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
gojs: {
|
gojs: {
|
||||||
// func ticks() int64
|
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
||||||
"runtime.ticks": () => {
|
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
|
||||||
return BigInt((timeOrigin + performance.now()) * 1e6);
|
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
|
||||||
|
// This changes the SP, thus we have to update the SP used by the imported function.
|
||||||
|
|
||||||
|
// func wasmExit(code int32)
|
||||||
|
"runtime.wasmExit": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const code = this.mem.getInt32(sp + 8, true);
|
||||||
|
this.exited = true;
|
||||||
|
delete this._inst;
|
||||||
|
delete this._values;
|
||||||
|
delete this._goRefCounts;
|
||||||
|
delete this._ids;
|
||||||
|
delete this._idPool;
|
||||||
|
this.exit(code);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func sleepTicks(timeout int64)
|
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
||||||
"runtime.sleepTicks": (timeout) => {
|
"runtime.wasmWrite": (sp) => {
|
||||||
// Do not sleep, only reactivate scheduler after the given timeout.
|
sp >>>= 0;
|
||||||
setTimeout(() => {
|
const fd = getInt64(sp + 8);
|
||||||
if (this.exited) return;
|
const p = getInt64(sp + 16);
|
||||||
try {
|
const n = this.mem.getInt32(sp + 24, true);
|
||||||
this._inst.exports.go_scheduler();
|
fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
|
||||||
} catch (e) {
|
},
|
||||||
if (e !== wasmExit) throw e;
|
|
||||||
|
// func resetMemoryDataView()
|
||||||
|
"runtime.resetMemoryDataView": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func nanotime1() int64
|
||||||
|
"runtime.nanotime1": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func walltime() (sec int64, nsec int32)
|
||||||
|
"runtime.walltime": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const msec = (new Date).getTime();
|
||||||
|
setInt64(sp + 8, msec / 1000);
|
||||||
|
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func scheduleTimeoutEvent(delay int64) int32
|
||||||
|
"runtime.scheduleTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this._nextCallbackTimeoutID;
|
||||||
|
this._nextCallbackTimeoutID++;
|
||||||
|
this._scheduledTimeouts.set(id, setTimeout(
|
||||||
|
() => {
|
||||||
|
this._resume();
|
||||||
|
while (this._scheduledTimeouts.has(id)) {
|
||||||
|
// for some reason Go failed to register the timeout event, log and try again
|
||||||
|
// (temporary workaround for https://github.com/golang/go/issues/28975)
|
||||||
|
console.warn("scheduleTimeoutEvent: missed timeout event");
|
||||||
|
this._resume();
|
||||||
}
|
}
|
||||||
}, Number(timeout)/1e6);
|
},
|
||||||
|
getInt64(sp + 8),
|
||||||
|
));
|
||||||
|
this.mem.setInt32(sp + 16, id, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func clearTimeoutEvent(id int32)
|
||||||
|
"runtime.clearTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
const id = this.mem.getInt32(sp + 8, true);
|
||||||
|
clearTimeout(this._scheduledTimeouts.get(id));
|
||||||
|
this._scheduledTimeouts.delete(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
// func getRandomData(r []byte)
|
||||||
|
"runtime.getRandomData": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
|
crypto.getRandomValues(loadSlice(sp + 8));
|
||||||
},
|
},
|
||||||
|
|
||||||
// func finalizeRef(v ref)
|
// func finalizeRef(v ref)
|
||||||
"syscall/js.finalizeRef": (v_ref) => {
|
"syscall/js.finalizeRef": (sp) => {
|
||||||
// Note: TinyGo does not support finalizers so this is only called
|
sp >>>= 0;
|
||||||
// for one specific case, by js.go:jsString. and can/might leak memory.
|
const id = this.mem.getUint32(sp + 8, true);
|
||||||
const id = v_ref & 0xffffffffn;
|
|
||||||
if (this._goRefCounts?.[id] !== undefined) {
|
|
||||||
this._goRefCounts[id]--;
|
this._goRefCounts[id]--;
|
||||||
if (this._goRefCounts[id] === 0) {
|
if (this._goRefCounts[id] === 0) {
|
||||||
const v = this._values[id];
|
const v = this._values[id];
|
||||||
@@ -314,205 +320,243 @@
|
|||||||
this._ids.delete(v);
|
this._ids.delete(v);
|
||||||
this._idPool.push(id);
|
this._idPool.push(id);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.error("syscall/js.finalizeRef: unknown id", id);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// func stringVal(value string) ref
|
// func stringVal(value string) ref
|
||||||
"syscall/js.stringVal": (value_ptr, value_len) => {
|
"syscall/js.stringVal": (sp) => {
|
||||||
value_ptr >>>= 0;
|
sp >>>= 0;
|
||||||
const s = loadString(value_ptr, value_len);
|
storeValue(sp + 24, loadString(sp + 8));
|
||||||
return boxValue(s);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueGet(v ref, p string) ref
|
// func valueGet(v ref, p string) ref
|
||||||
"syscall/js.valueGet": (v_ref, p_ptr, p_len) => {
|
"syscall/js.valueGet": (sp) => {
|
||||||
let prop = loadString(p_ptr, p_len);
|
sp >>>= 0;
|
||||||
let v = unboxValue(v_ref);
|
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
|
||||||
let result = Reflect.get(v, prop);
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
return boxValue(result);
|
storeValue(sp + 32, result);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueSet(v ref, p string, x ref)
|
// func valueSet(v ref, p string, x ref)
|
||||||
"syscall/js.valueSet": (v_ref, p_ptr, p_len, x_ref) => {
|
"syscall/js.valueSet": (sp) => {
|
||||||
const v = unboxValue(v_ref);
|
sp >>>= 0;
|
||||||
const p = loadString(p_ptr, p_len);
|
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
|
||||||
const x = unboxValue(x_ref);
|
|
||||||
Reflect.set(v, p, x);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueDelete(v ref, p string)
|
// func valueDelete(v ref, p string)
|
||||||
"syscall/js.valueDelete": (v_ref, p_ptr, p_len) => {
|
"syscall/js.valueDelete": (sp) => {
|
||||||
const v = unboxValue(v_ref);
|
sp >>>= 0;
|
||||||
const p = loadString(p_ptr, p_len);
|
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
|
||||||
Reflect.deleteProperty(v, p);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueIndex(v ref, i int) ref
|
// func valueIndex(v ref, i int) ref
|
||||||
"syscall/js.valueIndex": (v_ref, i) => {
|
"syscall/js.valueIndex": (sp) => {
|
||||||
return boxValue(Reflect.get(unboxValue(v_ref), i));
|
sp >>>= 0;
|
||||||
|
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
||||||
},
|
},
|
||||||
|
|
||||||
// valueSetIndex(v ref, i int, x ref)
|
// valueSetIndex(v ref, i int, x ref)
|
||||||
"syscall/js.valueSetIndex": (v_ref, i, x_ref) => {
|
"syscall/js.valueSetIndex": (sp) => {
|
||||||
Reflect.set(unboxValue(v_ref), i, unboxValue(x_ref));
|
sp >>>= 0;
|
||||||
|
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||||
"syscall/js.valueCall": (ret_addr, v_ref, m_ptr, m_len, args_ptr, args_len, args_cap) => {
|
"syscall/js.valueCall": (sp) => {
|
||||||
const v = unboxValue(v_ref);
|
sp >>>= 0;
|
||||||
const name = loadString(m_ptr, m_len);
|
|
||||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
||||||
try {
|
try {
|
||||||
const m = Reflect.get(v, name);
|
const v = loadValue(sp + 8);
|
||||||
storeValue(ret_addr, Reflect.apply(m, v, args));
|
const m = Reflect.get(v, loadString(sp + 16));
|
||||||
mem().setUint8(ret_addr + 8, 1);
|
const args = loadSliceOfValues(sp + 32);
|
||||||
|
const result = Reflect.apply(m, v, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 56, result);
|
||||||
|
this.mem.setUint8(sp + 64, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
storeValue(ret_addr, err);
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
mem().setUint8(ret_addr + 8, 0);
|
storeValue(sp + 56, err);
|
||||||
|
this.mem.setUint8(sp + 64, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueInvoke(v ref, args []ref) (ref, bool)
|
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||||
"syscall/js.valueInvoke": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
|
"syscall/js.valueInvoke": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
try {
|
try {
|
||||||
const v = unboxValue(v_ref);
|
const v = loadValue(sp + 8);
|
||||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
const args = loadSliceOfValues(sp + 16);
|
||||||
storeValue(ret_addr, Reflect.apply(v, undefined, args));
|
const result = Reflect.apply(v, undefined, args);
|
||||||
mem().setUint8(ret_addr + 8, 1);
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, result);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
storeValue(ret_addr, err);
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
mem().setUint8(ret_addr + 8, 0);
|
storeValue(sp + 40, err);
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueNew(v ref, args []ref) (ref, bool)
|
// func valueNew(v ref, args []ref) (ref, bool)
|
||||||
"syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
|
"syscall/js.valueNew": (sp) => {
|
||||||
const v = unboxValue(v_ref);
|
sp >>>= 0;
|
||||||
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
||||||
try {
|
try {
|
||||||
storeValue(ret_addr, Reflect.construct(v, args));
|
const v = loadValue(sp + 8);
|
||||||
mem().setUint8(ret_addr + 8, 1);
|
const args = loadSliceOfValues(sp + 16);
|
||||||
|
const result = Reflect.construct(v, args);
|
||||||
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
|
storeValue(sp + 40, result);
|
||||||
|
this.mem.setUint8(sp + 48, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
storeValue(ret_addr, err);
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
mem().setUint8(ret_addr+ 8, 0);
|
storeValue(sp + 40, err);
|
||||||
|
this.mem.setUint8(sp + 48, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueLength(v ref) int
|
// func valueLength(v ref) int
|
||||||
"syscall/js.valueLength": (v_ref) => {
|
"syscall/js.valueLength": (sp) => {
|
||||||
return unboxValue(v_ref).length;
|
sp >>>= 0;
|
||||||
|
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
||||||
},
|
},
|
||||||
|
|
||||||
// valuePrepareString(v ref) (ref, int)
|
// valuePrepareString(v ref) (ref, int)
|
||||||
"syscall/js.valuePrepareString": (ret_addr, v_ref) => {
|
"syscall/js.valuePrepareString": (sp) => {
|
||||||
const s = String(unboxValue(v_ref));
|
sp >>>= 0;
|
||||||
const str = encoder.encode(s);
|
const str = encoder.encode(String(loadValue(sp + 8)));
|
||||||
storeValue(ret_addr, str);
|
storeValue(sp + 16, str);
|
||||||
mem().setInt32(ret_addr + 8, str.length, true);
|
setInt64(sp + 24, str.length);
|
||||||
},
|
},
|
||||||
|
|
||||||
// valueLoadString(v ref, b []byte)
|
// valueLoadString(v ref, b []byte)
|
||||||
"syscall/js.valueLoadString": (v_ref, slice_ptr, slice_len, slice_cap) => {
|
"syscall/js.valueLoadString": (sp) => {
|
||||||
const str = unboxValue(v_ref);
|
sp >>>= 0;
|
||||||
loadSlice(slice_ptr, slice_len, slice_cap).set(str);
|
const str = loadValue(sp + 8);
|
||||||
|
loadSlice(sp + 16).set(str);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueInstanceOf(v ref, t ref) bool
|
// func valueInstanceOf(v ref, t ref) bool
|
||||||
"syscall/js.valueInstanceOf": (v_ref, t_ref) => {
|
"syscall/js.valueInstanceOf": (sp) => {
|
||||||
return unboxValue(v_ref) instanceof unboxValue(t_ref);
|
sp >>>= 0;
|
||||||
|
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||||
"syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, src_ref) => {
|
"syscall/js.copyBytesToGo": (sp) => {
|
||||||
let num_bytes_copied_addr = ret_addr;
|
sp >>>= 0;
|
||||||
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
const dst = loadSlice(sp + 8);
|
||||||
|
const src = loadValue(sp + 32);
|
||||||
const dst = loadSlice(dest_addr, dest_len);
|
|
||||||
const src = unboxValue(src_ref);
|
|
||||||
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||||
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
this.mem.setUint8(sp + 48, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const toCopy = src.subarray(0, dst.length);
|
const toCopy = src.subarray(0, dst.length);
|
||||||
dst.set(toCopy);
|
dst.set(toCopy);
|
||||||
mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
|
setInt64(sp + 40, toCopy.length);
|
||||||
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
this.mem.setUint8(sp + 48, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
// copyBytesToJS(dst ref, src []byte) (int, bool)
|
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||||
// Originally copied from upstream Go project, then modified:
|
"syscall/js.copyBytesToJS": (sp) => {
|
||||||
// https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
|
sp >>>= 0;
|
||||||
"syscall/js.copyBytesToJS": (ret_addr, dst_ref, src_addr, src_len, src_cap) => {
|
const dst = loadValue(sp + 8);
|
||||||
let num_bytes_copied_addr = ret_addr;
|
const src = loadSlice(sp + 16);
|
||||||
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
|
||||||
|
|
||||||
const dst = unboxValue(dst_ref);
|
|
||||||
const src = loadSlice(src_addr, src_len);
|
|
||||||
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||||
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
this.mem.setUint8(sp + 48, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const toCopy = src.subarray(0, dst.length);
|
const toCopy = src.subarray(0, dst.length);
|
||||||
dst.set(toCopy);
|
dst.set(toCopy);
|
||||||
mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
|
setInt64(sp + 40, toCopy.length);
|
||||||
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
this.mem.setUint8(sp + 48, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
"debug": (value) => {
|
||||||
|
console.log(value);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Go 1.20 uses 'env'. Go 1.21 uses 'gojs'.
|
|
||||||
// For compatibility, we use both as long as Go 1.20 is supported.
|
|
||||||
this.importObject.env = this.importObject.gojs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(instance) {
|
async run(instance) {
|
||||||
|
if (!(instance instanceof WebAssembly.Instance)) {
|
||||||
|
throw new Error("Go.run: WebAssembly.Instance expected");
|
||||||
|
}
|
||||||
this._inst = instance;
|
this._inst = instance;
|
||||||
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||||
NaN,
|
NaN,
|
||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
global,
|
globalThis,
|
||||||
this,
|
this,
|
||||||
];
|
];
|
||||||
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
|
||||||
this._ids = new Map(); // mapping from JS values to reference ids
|
this._ids = new Map([ // mapping from JS values to reference ids
|
||||||
|
[0, 1],
|
||||||
|
[null, 2],
|
||||||
|
[true, 3],
|
||||||
|
[false, 4],
|
||||||
|
[globalThis, 5],
|
||||||
|
[this, 6],
|
||||||
|
]);
|
||||||
this._idPool = []; // unused ids that have been garbage collected
|
this._idPool = []; // unused ids that have been garbage collected
|
||||||
this.exited = false; // whether the Go program has exited
|
this.exited = false; // whether the Go program has exited
|
||||||
this.exitCode = 0;
|
|
||||||
|
|
||||||
if (this._inst.exports._start) {
|
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
|
||||||
let exitPromise = new Promise((resolve, reject) => {
|
let offset = 4096;
|
||||||
this._resolveExitPromise = resolve;
|
|
||||||
|
const strPtr = (str) => {
|
||||||
|
const ptr = offset;
|
||||||
|
const bytes = encoder.encode(str + "\0");
|
||||||
|
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
|
||||||
|
offset += bytes.length;
|
||||||
|
if (offset % 8 !== 0) {
|
||||||
|
offset += 8 - (offset % 8);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const argc = this.argv.length;
|
||||||
|
|
||||||
|
const argvPtrs = [];
|
||||||
|
this.argv.forEach((arg) => {
|
||||||
|
argvPtrs.push(strPtr(arg));
|
||||||
|
});
|
||||||
|
argvPtrs.push(0);
|
||||||
|
|
||||||
|
const keys = Object.keys(this.env).sort();
|
||||||
|
keys.forEach((key) => {
|
||||||
|
argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
|
||||||
|
});
|
||||||
|
argvPtrs.push(0);
|
||||||
|
|
||||||
|
const argv = offset;
|
||||||
|
argvPtrs.forEach((ptr) => {
|
||||||
|
this.mem.setUint32(offset, ptr, true);
|
||||||
|
this.mem.setUint32(offset + 4, 0, true);
|
||||||
|
offset += 8;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Run program, but catch the wasmExit exception that's thrown
|
// The linker guarantees global data starts from at least wasmMinDataAddr.
|
||||||
// to return back here.
|
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
|
||||||
try {
|
const wasmMinDataAddr = 4096 + 8192;
|
||||||
this._inst.exports._start();
|
if (offset >= wasmMinDataAddr) {
|
||||||
} catch (e) {
|
throw new Error("total length of command line and environment variables exceeds limit");
|
||||||
if (e !== wasmExit) throw e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await exitPromise;
|
this._inst.exports.run(argc, argv);
|
||||||
return this.exitCode;
|
if (this.exited) {
|
||||||
} else {
|
this._resolveExitPromise();
|
||||||
this._inst.exports._initialize();
|
|
||||||
}
|
}
|
||||||
|
await this._exitPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
_resume() {
|
_resume() {
|
||||||
if (this.exited) {
|
if (this.exited) {
|
||||||
throw new Error("Go program has already exited");
|
throw new Error("Go program has already exited");
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
this._inst.exports.resume();
|
this._inst.exports.resume();
|
||||||
} catch (e) {
|
|
||||||
if (e !== wasmExit) throw e;
|
|
||||||
}
|
|
||||||
if (this.exited) {
|
if (this.exited) {
|
||||||
this._resolveExitPromise();
|
this._resolveExitPromise();
|
||||||
}
|
}
|
||||||
@@ -528,32 +572,13 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
global.require &&
|
|
||||||
global.require.main === module &&
|
|
||||||
global.process &&
|
|
||||||
global.process.versions &&
|
|
||||||
!global.process.versions.electron
|
|
||||||
) {
|
|
||||||
if (process.argv.length != 3) {
|
|
||||||
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const go = new Go();
|
|
||||||
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then(async (result) => {
|
|
||||||
let exitCode = await go.run(result.instance);
|
|
||||||
process.exit(exitCode);
|
|
||||||
}).catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// wasm setup code
|
// wasm setup code
|
||||||
export default function init (path) {
|
export default function init (path) {
|
||||||
|
if (typeof global === "undefined") {
|
||||||
|
var global = globalThis;
|
||||||
|
}
|
||||||
return new Promise ((res) => {
|
return new Promise ((res) => {
|
||||||
const go = new Go();
|
const go = new Go();
|
||||||
const run = (obj) => {
|
const run = (obj) => {
|
||||||
|
|||||||
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
import { requestPVE, requestAPI, goToPage, getURIData, setAppearance, setIconSrc, requestDash } from "./utils.js";
|
import { requestPVE, requestAPI, goToPage, getURIData, setAppearance, setIconSrc, requestDash, getCookie } from "./utils.js";
|
||||||
import { error, dialog } from "./dialog.js";
|
import { error, dialog } from "./dialog.js";
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", init);
|
window.addEventListener("DOMContentLoaded", init);
|
||||||
@@ -221,7 +221,7 @@ async function handleCDAdd () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isos = await requestAPI("/user/vm-isos", "GET");
|
const isos = await requestAPI(`/access/users/${getCookie("username")}/vm-isos`, "GET");
|
||||||
const select = d.querySelector("#iso-select");
|
const select = d.querySelector("#iso-select");
|
||||||
|
|
||||||
for (const iso of isos.data) {
|
for (const iso of isos.data) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { requestPVE, requestAPI, setAppearance, getSetting, requestDash, setIconSrc, setIconAlt } from "./utils.js";
|
import { requestPVE, requestAPI, setAppearance, getSetting, requestDash, setIconSrc, setIconAlt, getCookie } from "./utils.js";
|
||||||
import { dialog, error } from "./dialog.js";
|
import { dialog, error } from "./dialog.js";
|
||||||
import { setupClientSync } from "./clientsync.js";
|
import { setupClientSync } from "./clientsync.js";
|
||||||
import wfaInit from "../modules/wfa.js";
|
import wfaInit from "../modules/wfa.js";
|
||||||
@@ -10,7 +10,7 @@ var wfa;
|
|||||||
async function init () {
|
async function init () {
|
||||||
setAppearance();
|
setAppearance();
|
||||||
|
|
||||||
wfa = await wfaInit("modules/wfa.wasm");
|
wfa = await wfaInit("modules/wfa.wasm.gz");
|
||||||
initInstances();
|
initInstances();
|
||||||
|
|
||||||
document.querySelector("#instance-add").addEventListener("click", handleInstanceAddButton);
|
document.querySelector("#instance-add").addEventListener("click", handleInstanceAddButton);
|
||||||
@@ -418,7 +418,7 @@ async function handleInstanceAddButton () {
|
|||||||
// setup templateImage depending on selected image storage
|
// setup templateImage depending on selected image storage
|
||||||
const templateImage = d.querySelector("#template-image");
|
const templateImage = d.querySelector("#template-image");
|
||||||
// add template images to selector
|
// add template images to selector
|
||||||
const templates = await requestAPI("/user/ct-templates", "GET");
|
const templates = await requestAPI(`/access/users/${getCookie("username")}/ct-templates`, "GET");
|
||||||
for (const template of templates.data) {
|
for (const template of templates.data) {
|
||||||
templateImage.append(new Option(template.name, template.volid));
|
templateImage.append(new Option(template.name, template.volid));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{{/* <head> common across all pages*/}}
|
{{/* <head> common across all pages */}}
|
||||||
{{define "head"}}
|
{{define "head"}}
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<link rel="stylesheet" href="css/form.css">
|
<link rel="stylesheet" href="css/form.css">
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{/* <header> common across all pages*/}}
|
{{/* <header> common across all pages */}}
|
||||||
{{define "header"}}
|
{{define "header"}}
|
||||||
<header>
|
<header>
|
||||||
<h1>{{.global.Organization}}</h1>
|
<h1>{{.global.Organization}}</h1>
|
||||||
|
|||||||
Reference in New Issue
Block a user