mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Fix chalk builder field calls and hot-shots send failures and tcp completion
This commit is contained in:
@@ -179,6 +179,8 @@ interface Transport {
|
||||
close(): void;
|
||||
onError(listener: (err: Error) => void): void;
|
||||
offError(listener: (err: Error) => void): void;
|
||||
/** Emits 'error' on the socket, as hot-shots' `socket.emit('error')`. */
|
||||
emitError(err: Error): void;
|
||||
onClose(listener: () => void): void;
|
||||
}
|
||||
|
||||
@@ -261,6 +263,9 @@ class UdpTransport implements Transport {
|
||||
offError(listener: (err: Error) => void): void {
|
||||
this.errors.remove(listener);
|
||||
}
|
||||
emitError(err: Error): void {
|
||||
this.errors.emit(err);
|
||||
}
|
||||
onClose(listener: () => void): void {
|
||||
this.socket.on("close", listener);
|
||||
}
|
||||
@@ -281,10 +286,10 @@ class TcpTransport implements Transport {
|
||||
this.socket.on("error", (err) => errors.emit(err));
|
||||
}
|
||||
send(buf: Buffer, callback: SendCallback): void {
|
||||
// The typed socket's write takes the data alone; the completion runs
|
||||
// on the next tick.
|
||||
this.socket.write(addEol(buf));
|
||||
process.nextTick(() => callback(null));
|
||||
// hot-shots writes the line with the 'ascii' encoding, which encodes
|
||||
// strings as 'latin1' does. The callback runs once the data is written,
|
||||
// so a message held back by a full socket buffer stays in flight.
|
||||
this.socket.write(Buffer.from(addEol(buf), "latin1"), (err) => callback(err ?? null));
|
||||
}
|
||||
close(): void {
|
||||
this.socket.destroy();
|
||||
@@ -295,6 +300,9 @@ class TcpTransport implements Transport {
|
||||
offError(listener: (err: Error) => void): void {
|
||||
this.errors.remove(listener);
|
||||
}
|
||||
emitError(err: Error): void {
|
||||
this.errors.emit(err);
|
||||
}
|
||||
onClose(listener: () => void): void {
|
||||
this.socket.on("close", () => listener());
|
||||
}
|
||||
@@ -376,6 +384,9 @@ class UdsTransport implements Transport {
|
||||
offError(listener: (err: Error) => void): void {
|
||||
this.errors.remove(listener);
|
||||
}
|
||||
emitError(err: Error): void {
|
||||
this.errors.emit(err);
|
||||
}
|
||||
onClose(listener: () => void): void {
|
||||
this.closeListeners.push(listener);
|
||||
}
|
||||
@@ -999,6 +1010,10 @@ export class StatsD {
|
||||
handler(errFormatted);
|
||||
} else {
|
||||
console.error(String(errFormatted));
|
||||
// hot-shots also emits the error on the current socket, where the
|
||||
// uds reconnection handler listens; with no listener it throws.
|
||||
const current = this.transport;
|
||||
if (current !== null) current.emitError(errFormatted);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9250,6 +9250,10 @@ export function lowerRecordFieldCall(
|
||||
if (callee.type.kind === "object" && !init) {
|
||||
const direct = callableInstanceStringCall(lowerer, call, callee, loc);
|
||||
if (direct) return direct;
|
||||
// Other argument counts call the %call closure through its value, as
|
||||
// a call on the builder itself does (`theme.error("a", "b")`).
|
||||
const closure = lowerer.hybridCallUnwrap(callee);
|
||||
if (closure !== callee) return lowerCallThroughValue(lowerer, call, closure, loc);
|
||||
}
|
||||
if (callee.type.kind === "record" || callee.type.kind === "object")
|
||||
callee = lowerer.hybridCallUnwrap(callee);
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/packages/compiler/shims/chalk/v5.ts",
|
||||
"<repo>/tests/fixtures/npm/cases/chalk5-builder/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/packages/compiler/shims/chalk/v5.ts",
|
||||
"<repo>/tests/fixtures/npm/cases/chalk5/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/packages/compiler/shims/hot-shots/client.ts",
|
||||
"<repo>/packages/compiler/shims/hot-shots/v8.ts",
|
||||
"<repo>/tests/fixtures/npm/cases/hot-shots-buffered/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/packages/compiler/shims/hot-shots/client.ts",
|
||||
"<repo>/packages/compiler/shims/hot-shots/v8.ts",
|
||||
"<repo>/tests/fixtures/npm/cases/hot-shots-send-error/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/packages/compiler/shims/hot-shots/client.ts",
|
||||
"<repo>/packages/compiler/shims/hot-shots/v8.ts",
|
||||
"<repo>/tests/fixtures/npm/cases/hot-shots-tcp/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/packages/compiler/shims/hot-shots/client.ts",
|
||||
"<repo>/packages/compiler/shims/hot-shots/v8.ts",
|
||||
"<repo>/tests/fixtures/npm/cases/hot-shots-udp/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
|
||||
@@ -55,6 +55,13 @@ double scr_dgram_addr_port(ScrDgramSocket *s);
|
||||
void scr_dgram_close(ScrDgramSocket *s, ScrClosure *cb /*moves, nullable*/); /* throws on closed */
|
||||
void scr_dgram_unref(ScrDgramSocket *s);
|
||||
void scr_dgram_ref(ScrDgramSocket *s);
|
||||
/* Unix datagram sockets for the hot-shots package shim (the unix-dgram
|
||||
* addon's surface): each answers its result (fd, 0) or a negative errno;
|
||||
* send answers 1 when the socket would block. */
|
||||
double scr_dgram_unix_socket(void);
|
||||
double scr_dgram_unix_connect(double fd, ScrStr *path /*borrowed*/);
|
||||
double scr_dgram_unix_send(double fd, ScrBytes *data /*borrowed*/);
|
||||
double scr_dgram_unix_close(double fd);
|
||||
/* Socket options: Node's checks and errors (ErrnoException "<syscall>
|
||||
* <CODE>", ERR_SOCKET_BAD_BUFFER_SIZE, ERR_SOCKET_BUFFER_SIZE, the
|
||||
* TypeError after close()). The TTL setters and setMulticastLoopback
|
||||
|
||||
+4
-1
@@ -1,6 +1,7 @@
|
||||
// chalk 5 builders used as values (the package compiles from scriptc's
|
||||
// built-in shim): builders in function slots and arrays, styles picked at
|
||||
// run time, visible at level 0, chalkStderr, and the root's own call.
|
||||
// run time, builders in record fields called with any number of arguments,
|
||||
// visible at level 0, chalkStderr, and the root's own call.
|
||||
import chalk, { Chalk, chalkStderr, type ChalkInstance, type ForegroundColorName } from "chalk";
|
||||
|
||||
const show = (label: string, value: string): void => {
|
||||
@@ -36,6 +37,8 @@ const off = new Chalk({ level: 0 });
|
||||
show("visible off", off.visible("v") + "|" + off.red.visible("v") + "|" + off.red("plain"));
|
||||
show("root call", c("a", 1, true) + "|" + c() + "|" + c(undefined) + "|" + c(null, "n"));
|
||||
show("builder args", c.red(undefined) + "|" + c.red(null) + "|" + c.red(1, 2) + "|" + c.red());
|
||||
const theme = { error: c.red, note: c.bold.blue };
|
||||
show("field args", theme.error("a", "b") + "|" + theme.note("x", 1, true) + "|" + theme.error("one") + "|" + theme.error());
|
||||
show("multiline", c.cyan("one\r\ntwo\nthree"));
|
||||
show("stderr level", String(chalkStderr.level >= 0));
|
||||
show("rgb levels", [1, 2, 3].map((level) => new Chalk({ level: level as 1 | 2 | 3 }).rgb(255, 136, 0)("o")).join("|"));
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// The hot-shots StatsD client (compiled from scriptc's built-in shim) when a
|
||||
// send fails: with a callback or an errorHandler the error goes there; with
|
||||
// neither, the client logs it and emits it on the socket, where an 'error'
|
||||
// event nobody listens for ends the process with status 1.
|
||||
import { StatsD } from "hot-shots";
|
||||
|
||||
// A datagram larger than udp allows fails with EMSGSIZE before it leaves
|
||||
// the host; port 9 keeps the message the same on every run.
|
||||
const big = "x".repeat(70000);
|
||||
|
||||
const withCallback = new StatsD({ host: "127.0.0.1", port: 9 });
|
||||
withCallback.increment(big, 1, 1, [], (err: Error | null | undefined) => {
|
||||
console.log("callback:", err ? err.message : "no error");
|
||||
withCallback.close();
|
||||
|
||||
const withHandler = new StatsD({
|
||||
host: "127.0.0.1",
|
||||
port: 9,
|
||||
errorHandler: (error: Error) => {
|
||||
console.log("errorHandler:", error.message);
|
||||
withHandler.close();
|
||||
console.log("without a callback or errorHandler");
|
||||
new StatsD({ host: "127.0.0.1", port: 9 }).increment(big);
|
||||
},
|
||||
});
|
||||
withHandler.increment(big);
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
{ "type": "module" }
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// The hot-shots StatsD client over tcp (compiled from scriptc's built-in
|
||||
// shim): a send completes once the socket has written its line, so close()
|
||||
// waits for lines that a full socket buffer holds back, and the receiver
|
||||
// gets every line before the connection ends.
|
||||
import * as net from "node:net";
|
||||
import { StatsD } from "hot-shots";
|
||||
|
||||
const LINES = 20000;
|
||||
const name = "m".repeat(1000);
|
||||
let bytes = 0;
|
||||
let ended: () => void = () => {};
|
||||
const serverDone = new Promise<void>((resolve) => {
|
||||
ended = resolve;
|
||||
});
|
||||
const server = net.createServer((socket) => {
|
||||
socket.pause();
|
||||
setTimeout(() => socket.resume(), 150);
|
||||
socket.on("data", (chunk: Buffer) => {
|
||||
bytes += chunk.length;
|
||||
});
|
||||
socket.on("end", () => ended());
|
||||
});
|
||||
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const port = (server.address() as net.AddressInfo).port;
|
||||
const client = new StatsD({ host: "127.0.0.1", port, protocol: "tcp" });
|
||||
for (let i = 0; i < LINES; i++) client.increment(name);
|
||||
const closed = new Promise<void>((resolve) => client.close(() => resolve()));
|
||||
void Promise.all([closed, serverDone]).then(() => {
|
||||
console.log("closed; received", bytes, "of", LINES * (name.length + 5), "bytes");
|
||||
server.close(() => console.log("server closed"));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
{ "type": "module" }
|
||||
Reference in New Issue
Block a user