Documentation
¶
Overview ¶
Package execwasm pkg/wasmhv/execwasm/embed_native.go c3-wasm-embed
Package execwasm pkg/wasmhv/execwasm/execwasm.go c3-wasm-embed
The full skywire command module for GOOS=js, embedded in the native binary by the two-stage build: the module is built first (GOOS=js GOARCH=wasm go build .), gzipped into blob/skywire.wasm.gz, then the native binary is built with it inside. It is the desk's `skywire` command and the tab visor; hv serve and the native hypervisor serve it at /skywire.wasm.
A source build without that step embeds only blob/README: Present() is false and the servers fall back to an on-disk module (ExecWasmPath) or to the legacy page. The gzipped bytes are what is embedded and what is served when the client accepts gzip (every browser does); the module is never held inflated in memory.
It is never held GZIPPED in memory either. embed.FS keeps the blob in the binary's read-only data — file-backed pages the kernel shares and evicts — and every accessor here stays out of the Go heap: Present/Size are a directory lookup, Stamp reads the gzip trailer's last 8 bytes, and serving streams from the mapping (serve.go). Materializing it with embed.FS.ReadFile, as this package did until a heap profile of a live exit visor showed it, put 37 MB of anonymous, GC-tracked memory in every visor for the life of the process, whether or not a browser ever asked for the module: Present() alone, called from the UI server's startup, was enough.
Package execwasm pkg/wasmhv/execwasm/serve.go c3-wasm-embed
Index ¶
- Constants
- func Gz() []byte
- func LoaderJS(execJS []byte, role string) []byte
- func Open() (fs.File, error)
- func Present() bool
- func Revision() string
- func Serve(w http.ResponseWriter, r *http.Request)
- func ServeEmbedded(w http.ResponseWriter, r *http.Request)
- func ServeGz(w http.ResponseWriter, r *http.Request, gz []byte, stamp string)
- func Size() int64
- func Stamp() string
Constants ¶
const OriginPath = "/skywire.wasm"
OriginPath is where every page origin that carries the module serves it: `hv serve` and the native hypervisor both answer it at the root. The surfaces that run the module in a ROLE (the tpviz WebGL view, the wallet cipher) fetch it under their own paths; Serve sends them here when this server holds no copy.
Variables ¶
This section is empty.
Functions ¶
func Gz ¶
func Gz() []byte
Gz returns a COPY of the embedded module — ~37 MB of fresh heap on every call, and nothing here caches it. It is for the one consumer that cannot take a stream: skycoin-web's RegisterCipherWasm, which keeps the bytes itself, in the `skywire skycoin web` command. Everything that serves the module over HTTP uses Open or ServeEmbedded instead.
func LoaderJS ¶
LoaderJS returns Go's wasm_exec.js (execJS, as embedded by pkg/wasmhv) with a prelude that fixes the contract of every instance the page creates: `Go` is replaced by a subclass whose constructor sets this.argv to ["skywire", "desk-host", "--role", role] and gives this.env the same HOME/USER/PWD the desk's process layer spawns every command with (browseui/skywire-exec.js) — package inits in the root binary resolve the current user and directory, and the stock loader hands them nothing. It is for a page whose loader script is not ours to change — the vendored skycoin-web wallet instantiates assets/scripts/skycoin-lite.wasm with a bare `new Go()` — and it is what the tpviz and skysocks status pages get too, so one place spells the contract; those pages set go.argv as well, to the same value.
func Open ¶
Open returns a handle on the embedded module's gzipped bytes, for a caller that streams them (io.Copy is enough; the embed handle is also an io.Seeker and io.ReaderAt). Close it. The error is fs.ErrNotExist when this build embeds no module.
func Revision ¶
func Revision() string
Revision is the commit the embedded module was built from, or "" when that is not recorded (a source build with no staged module, or one staged before this was written).
It exists because the two failure modes here are silent. `go build .` embeds whatever blob/ already holds rather than rebuilding it, so a native binary happily serves a module many commits older than itself; and the served page reports the module's own version, which simply looks like a different number rather than a stale one. Comparing this to buildinfo.Commit() is the only cheap way to notice.
func Serve ¶
func Serve(w http.ResponseWriter, r *http.Request)
Serve answers a GET for the module from the EMBEDDED copy alone — for a server that holds no on-disk path of its own (pkg/tpviz, the wallet routes, `skywire skycoin web`), as opposed to pkg/visor's /skywire.wasm which may also serve a configured file.
When nothing is embedded the request is redirected to OriginPath. That is the one behavior both builds want: the js build never embeds anything (it IS the module — see embed_js.go), so a tpviz or wallet route running inside a tab's wasm hypervisor can only hand the browser back to the origin that delivered the module in the first place, which serves it at OriginPath; a native source build without `make embed-exec-wasm` hands it to the same place, where the operator's on-disk module answers, or a 404 does. Under a /vnet/<port>/ page the browser resolves the redirect against the page's real origin, which is exactly the outer server. Never mount Serve AT OriginPath: it would redirect to itself.
func ServeEmbedded ¶
func ServeEmbedded(w http.ResponseWriter, r *http.Request)
ServeEmbedded is ServeGz for the EMBEDDED module, streamed straight out of the binary's read-only mapping instead of a heap copy of it: same ETag, same 304, same gzip-or-inflate behavior, but nothing here allocates more than an io.Copy buffer no matter how many requests arrive. Content-Type and Cache-Control are the caller's to set, as with ServeGz. No module embedded is a 404 (Serve turns that into the redirect its callers want).
func ServeGz ¶
ServeGz answers a GET for the module from gz, the gzipped module bytes, with stamp as its ETag (a conditional request short-circuits to 304). The bytes go out as-is with Content-Encoding: gzip when the client accepts it and are inflated on the fly otherwise, so the module is never held inflated in memory. len(gz)==0 is a 404. Content-Type and Cache-Control are the caller's to set (Serve sets them).
func Size ¶
func Size() int64
Size is the embedded module's gzipped size in bytes, 0 when none. It is the Content-Length of what Serve sends a gzip-accepting client.
func Stamp ¶
func Stamp() string
Stamp is a short content fingerprint of the embedded module, "" when none: it changes with every build, so pages polling the served version reload.
It is the gzip member's own trailer — the CRC32 of the uncompressed module and its length, as 16 hex characters — read from the last 8 bytes of the blob. A hash over the whole blob would be just as good an ETag and would mean reading 37 MB at startup on every visor, including the Orange Pis; pkg/geoip identifies its embedded database the same way.
Types ¶
This section is empty.