Documentation
¶
Overview ¶
Package nodehost holds the host functions the AOT-compiled Node builtins call into. A factory in pkg/node/js references a bare __bento_* callee for work that needs the Go runtime, os detail or an object inspector, and the lowerer emits a call to the matching function here. The package imports only the standard library, never pkg/engine, so an AOT binary that calls into it stays free of the interpreter the way the whole AOT path is; the interpreter's own pkg/node host layer delegates to the same functions so the two share one implementation and never drift. pkg/value depends on this package rather than the other way about, which is what lets a value helper answer os.freemem from the same measurement the interpreter reads, so nothing here may import it back. It also reaches for golang.org/x/sys, which is where the per-platform system calls the os module's numbers come from live; that is the standard library by another name and not a step toward the interpreter.
Index ¶
- func NetError(err error, call, address string, port int) (message, props string)
- func OSArch() string
- func OSAvailableParallelism() float64
- func OSEndianness() string
- func OSFreemem() float64
- func OSHomedir() string
- func OSHostname() string
- func OSInfoJSON() string
- func OSLoadavg() [3]float64
- func OSMachine() string
- func OSNetworkInterfaces() map[string][]NetInterface
- func OSPlatform() string
- func OSRelease() string
- func OSTotalmem() float64
- func OSType() string
- func OSUptime() float64
- func OSVersion() string
- func URLParseJSON(input, base string) string
- type CPUInfo
- type CPUTimes
- type NetInterface
- type URLComponents
- type UVError
- type UserInfo
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NetError ¶
NetError builds the error a failed network call raises in Node: the message the Error carries and the properties Node hangs off it, as a JSON object ready for the JavaScript side to assign.
call is the syscall Node blames, "connect" or "listen" or "bind". address and port are what the call named; pass an empty address when there is none to report, and the Go error's own text stands in for the message, since a Node message without an address is not a shape Node produces.
The address is the host the caller asked for rather than the address the resolver returned. They differ only when a name resolved and then the connect failed, which is rare enough next to the connect-refused case that reporting the name is worth more than a second lookup.
func OSArch ¶
func OSArch() string
OSArch is os.arch(), Node's name for the processor architecture the binary was built for, which is not the name uname gives it. See OSMachine.
func OSAvailableParallelism ¶
func OSAvailableParallelism() float64
OSAvailableParallelism is os.availableParallelism(), the count of cores this process may run on.
func OSEndianness ¶
func OSEndianness() string
OSEndianness is os.endianness(), the byte order of the processor this binary runs on, measured rather than assumed from the architecture name.
func OSFreemem ¶
func OSFreemem() float64
OSFreemem is os.freemem(), the memory not in use, in bytes. It is measured on each call, since it is the one number here that moves while a program runs.
func OSHomedir ¶
func OSHomedir() string
OSHomedir is os.homedir(), the current user's home directory.
func OSHostname ¶
func OSHostname() string
OSHostname is os.hostname(). A machine that will not answer its own name yields the empty string, which is what Node reports when the lookup fails.
func OSInfoJSON ¶
func OSInfoJSON() string
OSInfoJSON returns the os module snapshot marshaled to a JSON string, the value the os.js factory parses back into the numbers and strings os.platform, os.cpus, and the rest report. A marshal error yields "{}", so the JavaScript JSON.parse always has a well-formed object to read.
func OSLoadavg ¶
func OSLoadavg() [3]float64
OSLoadavg is os.loadavg(), the one, five and fifteen minute run queue averages. Windows keeps no such thing and Node reports three zeros there.
func OSMachine ¶
func OSMachine() string
OSMachine is os.machine(), the hardware name uname reports. It is a different question from OSArch and has a different answer on a 64-bit Intel machine, where uname says x86_64 and Node's arch says x64.
func OSNetworkInterfaces ¶
func OSNetworkInterfaces() map[string][]NetInterface
OSNetworkInterfaces is os.networkInterfaces(), the addresses of each interface keyed by its name, measured on each call because an interface can come up or go away while a program runs.
func OSPlatform ¶
func OSPlatform() string
OSPlatform is os.platform(), Node's name for the operating system.
func OSTotalmem ¶
func OSTotalmem() float64
OSTotalmem is os.totalmem(), the machine's physical memory in bytes. It is a float64 because that is the only number JavaScript has, and it is the type the compiled program does arithmetic on; a byte count of physical memory is far inside the range a float64 counts exactly.
func OSType ¶
func OSType() string
OSType is os.type(), the operating system name uname reports: Linux, Darwin, Windows_NT.
func OSUptime ¶
func OSUptime() float64
OSUptime is os.uptime(), the seconds since the machine booted.
func OSVersion ¶
func OSVersion() string
OSVersion is os.version(), the kernel version string, which on Windows is the product name instead since there is no kernel version string there.
func URLParseJSON ¶
URLParseJSON is URLParse marshaled for the interpreter's host bridge, which moves strings and not structs. On failure it returns {"ok":false}.
Types ¶
type CPUInfo ¶
type CPUInfo struct {
Model string `json:"model"`
Speed int `json:"speed"`
Times CPUTimes `json:"times"`
}
CPUInfo is one entry of the array os.cpus() answers: the processor's model name, its clock in megahertz, and the time its core has spent in each of the scheduler's states since the machine booted.
type CPUTimes ¶
type CPUTimes struct {
User int `json:"user"`
Nice int `json:"nice"`
Sys int `json:"sys"`
Idle int `json:"idle"`
IRQ int `json:"irq"`
}
CPUTimes counts milliseconds, which is the unit Node reports and not the unit any kernel keeps. Every platform counts in something else, ticks on Linux and hundreds of nanoseconds on Windows, and converts on the way out.
type NetInterface ¶
type NetInterface struct {
Address string `json:"address"`
Netmask string `json:"netmask"`
Family string `json:"family"`
MAC string `json:"mac"`
Internal bool `json:"internal"`
CIDR string `json:"cidr"`
}
NetInterface is one address of one interface, an entry of the arrays os.networkInterfaces() keys by interface name. An interface with four addresses is four of these under one key, which is the shape Node reports.
type URLComponents ¶
type URLComponents struct {
OK bool `json:"ok"`
Href string `json:"href"`
Protocol string `json:"protocol"`
Username string `json:"username"`
Password string `json:"password"`
Host string `json:"host"`
Hostname string `json:"hostname"`
Port string `json:"port"`
Pathname string `json:"pathname"`
Search string `json:"search"`
Hash string `json:"hash"`
Origin string `json:"origin"`
}
URLComponents is a parsed URL projected onto the WHATWG property set. The JSON tags are the interpreter's wire format, so they are part of the contract with pkg/node/js/url.js.
func URLParse ¶
func URLParse(input, base string) (URLComponents, bool)
URLParse resolves input against an optional base and returns the parsed WHATWG components. base is the empty string when there is no base. ok is false for an input that is not a valid absolute URL, which both callers turn into the TypeError the WHATWG contract requires: an invalid URL is a hard error, not a null result.
Parsing a URL correctly (percent encoding, IDNA hosts, default ports, base resolution) is a lot of surface to reimplement, and Go's net/url already does it, so this is the one implementation. The interpreter reaches it through URLParseJSON below; the AOT path calls it directly, since it has no bridge to cross and no reason to pay for a marshal and a parse to move a struct across a package boundary.
type UVError ¶
type UVError struct {
// Code is libuv's name for the failure, the string err.code carries: ENOENT,
// EEXIST, ENOTEMPTY and so on, or UNKNOWN for a failure no table names.
Code string
// Errno is libuv's number for that code, the value err.errno carries. It is
// always negative.
Errno int
// Desc is libuv's description of the code, the middle of Node's message:
// "no such file or directory" in "ENOENT: no such file or directory, open
// '/nope'". For an unclassified failure it is the Go error's own text, which
// says more than "unknown error" does.
Desc string
}
UVError is one failure in the shape a Node program reads it: the code it branches on, the number err.errno carries, and the description that goes in the message. Filesystem and socket errors are the same shape because they are the same vocabulary, libuv's, so one type answers for both.
Why this is not a raw errno comparison ¶
Node's filesystem errors are libuv's, and libuv has one set of codes on every platform. Underneath, an error on Windows is a Win32 error number that has nothing to do with the POSIX one: a missing file is ERROR_FILE_NOT_FOUND, which is 2, and so is POSIX ENOENT, but a directory that is not empty is ERROR_DIR_NOT_EMPTY at 145 where POSIX ENOTEMPTY is 39, and access denied is ERROR_ACCESS_DENIED at 5 where POSIX EACCES is 13. Comparing the number an error carries against syscall.ENOENT and friends therefore answers by accident on Windows: right for the two numbers that happen to coincide, wrong or UNKNOWN for the rest. A program that branches on err.code === "ENOTEMPTY" got UNKNOWN.
So the translation is per platform, the way libuv's own is: uvCode lives in a pair of build-tagged files, one reading POSIX errnos and one reading Win32 error numbers, and both answer in libuv's vocabulary. The tables and the descriptions come from libuv itself, include/uv/errno.h and src/win/error.c, so bento reports what Node reports rather than an approximation of it.
Why errno is not just the code's POSIX number ¶
Because err.errno is libuv's number, not the platform's. On every platform but Windows that is the negated POSIX errno (UV__ERR(x) is -x), so ENOENT is -2. On Windows libuv does not trust the C runtime's errno values at all and assigns its own block, where ENOENT is -4058. Both are in the platform files next to the code translation they belong with.
func ClassifyFSError ¶
ClassifyFSError maps a Go filesystem error to the Node error it stands for.
The platform's errno is asked first and the standard library's sentinels are the fallback, which is the opposite of the obvious order and is deliberate. The errno is the precise answer: fs.ErrPermission matches both EACCES and EPERM, which are one sentinel in Go and two different codes in Node, and there is no sentinel at all for ENOTEMPTY, EISDIR or ENOTDIR. The sentinels still matter, because an error that never came from a syscall carries no errno: one an io/fs implementation returned, or a bare os.ErrNotExist a helper wrapped.
func ClassifySocketError ¶
ClassifySocketError maps a Go network error to the Node error it stands for.
It is ClassifyFSError's sibling and works the same way, by asking the errno rather than reading the message. Reading the message is what bento used to do here, matching on "address already in use" and "permission denied", and that is wrong twice over on Windows: the text comes from the Winsock error, which says "Only one usage of each socket address is normally permitted", so nothing matched and every socket error arrived with no code at all.
The errno on Windows is a Winsock number rather than a POSIX one, WSAECONNREFUSED being 10061 where POSIX ECONNREFUSED is 111, which is the other half of the same problem and is handled where the codes are translated, in the platform files.
Name resolution is asked before the errno rather than after it, which is the reverse of ClassifyFSError and matters on Windows. A failed lookup there does carry an errno, WSAHOST_NOT_FOUND, and libuv translates that to ENOENT, so asking the number first would answer ENOENT where Node says ENOTFOUND. A *net.DNSError is unambiguous about what failed, so it decides on its own.
A deadline is the other failure with no errno behind it: Go reports a dial timeout through os.ErrDeadlineExceeded and Node calls it ETIMEDOUT.
type UserInfo ¶
type UserInfo struct {
Username string `json:"username"`
UID int `json:"uid"`
GID int `json:"gid"`
Shell string `json:"shell"`
Homedir string `json:"homedir"`
}
UserInfo is what os.userInfo() answers about the user this process runs as. The two Windows fields have no meaning there and Node reports minus one for them, which is what the platform's own lookup answers.
func OSUserInfo ¶
func OSUserInfo() UserInfo
OSUserInfo is os.userInfo(), the user this process runs as.