(function () {
const { core, primordials } = __bootstrap;
const {
Array,
FunctionPrototypeCall,
MapPrototypeGet,
Symbol,
SymbolFor,
} = primordials;
const lazyNet = core.createLazyLoader("node:net");
const lazyTimers = core.createLazyLoader("node:timers");
const { nextTick } = core.loadExtScript("ext:deno_node/_next_tick.ts");
const { codeMap, UV_ECANCELED } = core.loadExtScript(
"ext:deno_node/internal_binding/uv.ts",
);
const {
kArrayBufferOffset,
kBytesWritten,
kLastWriteWasAsync,
kReadBytesOrError,
streamBaseState,
} = core.loadExtScript("ext:deno_node/internal_binding/stream_wrap.ts");
const { Buffer } = core.loadExtScript("ext:deno_node/internal/buffer.mjs");
const { ERR_STREAM_WRAP } = core.loadExtScript(
"ext:deno_node/internal/errors.ts",
);
const kCurrentWriteRequest = Symbol("kCurrentWriteRequest");
const kCurrentShutdownRequest = Symbol("kCurrentShutdownRequest");
const kPendingShutdownRequest = Symbol("kPendingShutdownRequest");
const kPendingClose = Symbol("kPendingClose");
const kJSStreamHandle = SymbolFor("kJSStreamHandle");
function isClosing() {
return this[kOwner].isClosing();
}
function onreadstart() {
return this[kOwner].readStart();
}
function onreadstop() {
return this[kOwner].readStop();
}
const kOwner = SymbolFor("kJSStreamOwner");
class JSStreamSocket extends lazyNet().Socket {
constructor(stream) {
const handle = {
[kJSStreamHandle]: true,
[kOwner]: null, close(cb) {
handle[kOwner].doClose(cb);
},
isClosing,
onreadstart,
onreadstop,
readStart() {
return handle[kOwner].readStart();
},
readStop() {
return handle[kOwner].readStop();
},
writeBuffer(req, data) {
const len = data.byteLength ?? data.length ?? 0;
streamBaseState[kBytesWritten] = len;
streamBaseState[kLastWriteWasAsync] = 1;
return handle[kOwner].doWrite(req, [data]);
},
writev(req, chunks, allBuffers) {
let bufs;
let total = 0;
if (allBuffers) {
bufs = chunks;
for (let i = 0; i < bufs.length; i++) {
total += bufs[i].byteLength ?? bufs[i].length ?? 0;
}
} else {
bufs = new Array(chunks.length >> 1);
for (let i = 0; i < chunks.length; i += 2) {
const chunk = chunks[i];
const enc = chunks[i + 1];
const buf = typeof chunk === "string"
? Buffer.from(chunk, enc)
: chunk;
bufs[i >> 1] = buf;
total += buf.byteLength ?? buf.length ?? 0;
}
}
streamBaseState[kBytesWritten] = total;
streamBaseState[kLastWriteWasAsync] = 1;
return handle[kOwner].doWrite(req, bufs);
},
writeAsciiString(req, data) {
return this.writeBuffer(req, Buffer.from(data, "ascii"));
},
writeUtf8String(req, data) {
return this.writeBuffer(req, Buffer.from(data, "utf8"));
},
writeLatin1String(req, data) {
return this.writeBuffer(req, Buffer.from(data, "latin1"));
},
writeUcs2String(req, data) {
return this.writeBuffer(req, Buffer.from(data, "utf16le"));
},
shutdown(req) {
return handle[kOwner].doShutdown(req);
},
readBuffer(chunk) {
if (!handle.onread) return;
const len = chunk.byteLength ?? chunk.length ?? 0;
if (len === 0) return;
streamBaseState[kArrayBufferOffset] = chunk.byteOffset ?? 0;
streamBaseState[kReadBytesOrError] = len;
FunctionPrototypeCall(handle.onread, handle, chunk, len);
},
emitEOF() {
if (!handle.onread) return;
FunctionPrototypeCall(
handle.onread,
handle,
null,
MapPrototypeGet(codeMap, "EOF"),
);
},
reading: false,
};
stream.pause();
stream.on("error", (err) => this.emit("error", err));
const ondata = (chunk) => {
if (
typeof chunk === "string" ||
stream.readableObjectMode === true
) {
stream.pause();
stream.removeListener("data", ondata);
this.emit("error", new ERR_STREAM_WRAP());
return;
}
if (this._handle && this._handle.readBuffer) {
this._handle.readBuffer(chunk);
}
};
stream.on("data", ondata);
stream.once("end", () => {
if (this._handle && this._handle.emitEOF) {
this._handle.emitEOF();
}
});
stream.once("close", () => {
this.destroy();
});
super({ handle, manualStart: true });
handle[kOwner] = this;
this.stream = stream;
this[kCurrentWriteRequest] = null;
this[kCurrentShutdownRequest] = null;
this[kPendingShutdownRequest] = null;
this[kPendingClose] = false;
this.readable = stream.readable;
this.writable = stream.writable;
this.read(0);
}
isClosing() {
return !this.readable || !this.writable;
}
readStart() {
this.stream.resume();
return 0;
}
readStop() {
this.stream.pause();
return 0;
}
doShutdown(req) {
if (this[kCurrentWriteRequest] !== null) {
this[kPendingShutdownRequest] = req;
return 0;
}
this[kCurrentShutdownRequest] = req;
if (this[kPendingClose]) {
return 0;
}
const handle = this._handle;
nextTick(() => {
this.stream.end(() => {
this.finishShutdown(handle, 0);
});
});
return 0;
}
finishShutdown(_handle, errCode) {
const req = this[kCurrentShutdownRequest];
if (req === null) return;
this[kCurrentShutdownRequest] = null;
if (typeof req.oncomplete === "function") {
req.oncomplete(errCode | 0);
}
}
doWrite(req, bufs) {
if (this[kPendingClose]) {
this[kCurrentWriteRequest] = req;
return 0;
} else if (this._handle === null) {
return 0;
}
const handle = this._handle;
const self = this;
let pending = bufs.length;
this.stream.cork();
for (let i = 0; i < bufs.length; ++i) {
this.stream.write(bufs[i], done);
}
this.stream.uncork();
this[kCurrentWriteRequest] = req;
function done(err) {
if (!err && --pending !== 0) return;
pending = 0;
let errCode = 0;
if (err) {
errCode = MapPrototypeGet(codeMap, err.code) ||
MapPrototypeGet(codeMap, "EPIPE");
}
lazyTimers().setImmediate(() => {
self.finishWrite(handle, errCode);
});
}
return 0;
}
finishWrite(_handle, errCode) {
const req = this[kCurrentWriteRequest];
if (req === null) return;
this[kCurrentWriteRequest] = null;
if (typeof req.oncomplete === "function") {
req.oncomplete(errCode | 0);
}
if (this[kPendingShutdownRequest]) {
const sreq = this[kPendingShutdownRequest];
this[kPendingShutdownRequest] = null;
this.doShutdown(sreq);
}
}
doClose(cb) {
this[kPendingClose] = true;
const handle = this._handle;
this.stream.destroy();
lazyTimers().setImmediate(() => {
this.finishWrite(handle, UV_ECANCELED);
this.finishShutdown(handle, UV_ECANCELED);
this[kPendingClose] = false;
if (cb) cb();
});
}
}
JSStreamSocket.StreamWrap = JSStreamSocket;
return { JSStreamSocket, kJSStreamHandle, kOwner, default: JSStreamSocket };
})();