11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci JSONParse, 51cb0ef41Sopenharmony_ci JSONStringify, 61cb0ef41Sopenharmony_ci StringPrototypeSplit, 71cb0ef41Sopenharmony_ci ArrayPrototypePush, 81cb0ef41Sopenharmony_ci Symbol, 91cb0ef41Sopenharmony_ci TypedArrayPrototypeSubarray, 101cb0ef41Sopenharmony_ci} = primordials; 111cb0ef41Sopenharmony_ciconst { Buffer } = require('buffer'); 121cb0ef41Sopenharmony_ciconst { StringDecoder } = require('string_decoder'); 131cb0ef41Sopenharmony_ciconst v8 = require('v8'); 141cb0ef41Sopenharmony_ciconst { isArrayBufferView } = require('internal/util/types'); 151cb0ef41Sopenharmony_ciconst assert = require('internal/assert'); 161cb0ef41Sopenharmony_ciconst { streamBaseState, kLastWriteWasAsync } = internalBinding('stream_wrap'); 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciconst kMessageBuffer = Symbol('kMessageBuffer'); 191cb0ef41Sopenharmony_ciconst kMessageBufferSize = Symbol('kMessageBufferSize'); 201cb0ef41Sopenharmony_ciconst kJSONBuffer = Symbol('kJSONBuffer'); 211cb0ef41Sopenharmony_ciconst kStringDecoder = Symbol('kStringDecoder'); 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci// Extend V8's serializer APIs to give more JSON-like behaviour in 241cb0ef41Sopenharmony_ci// some cases; in particular, for native objects this serializes them the same 251cb0ef41Sopenharmony_ci// way that JSON does rather than throwing an exception. 261cb0ef41Sopenharmony_ciconst kArrayBufferViewTag = 0; 271cb0ef41Sopenharmony_ciconst kNotArrayBufferViewTag = 1; 281cb0ef41Sopenharmony_ciclass ChildProcessSerializer extends v8.DefaultSerializer { 291cb0ef41Sopenharmony_ci _writeHostObject(object) { 301cb0ef41Sopenharmony_ci if (isArrayBufferView(object)) { 311cb0ef41Sopenharmony_ci this.writeUint32(kArrayBufferViewTag); 321cb0ef41Sopenharmony_ci return super._writeHostObject(object); 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci this.writeUint32(kNotArrayBufferViewTag); 351cb0ef41Sopenharmony_ci this.writeValue({ ...object }); 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci} 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ciclass ChildProcessDeserializer extends v8.DefaultDeserializer { 401cb0ef41Sopenharmony_ci _readHostObject() { 411cb0ef41Sopenharmony_ci const tag = this.readUint32(); 421cb0ef41Sopenharmony_ci if (tag === kArrayBufferViewTag) 431cb0ef41Sopenharmony_ci return super._readHostObject(); 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci assert(tag === kNotArrayBufferViewTag); 461cb0ef41Sopenharmony_ci return this.readValue(); 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci} 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci// Messages are parsed in either of the following formats: 511cb0ef41Sopenharmony_ci// - Newline-delimited JSON, or 521cb0ef41Sopenharmony_ci// - V8-serialized buffers, prefixed with their length as a big endian uint32 531cb0ef41Sopenharmony_ci// (aka 'advanced') 541cb0ef41Sopenharmony_ciconst advanced = { 551cb0ef41Sopenharmony_ci initMessageChannel(channel) { 561cb0ef41Sopenharmony_ci channel[kMessageBuffer] = []; 571cb0ef41Sopenharmony_ci channel[kMessageBufferSize] = 0; 581cb0ef41Sopenharmony_ci channel.buffering = false; 591cb0ef41Sopenharmony_ci }, 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci *parseChannelMessages(channel, readData) { 621cb0ef41Sopenharmony_ci if (readData.length === 0) return; 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci ArrayPrototypePush(channel[kMessageBuffer], readData); 651cb0ef41Sopenharmony_ci channel[kMessageBufferSize] += readData.length; 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci // Index 0 should always be present because we just pushed data into it. 681cb0ef41Sopenharmony_ci let messageBufferHead = channel[kMessageBuffer][0]; 691cb0ef41Sopenharmony_ci while (messageBufferHead.length >= 4) { 701cb0ef41Sopenharmony_ci // We call `readUInt32BE` manually here, because this is faster than first converting 711cb0ef41Sopenharmony_ci // it to a buffer and using `readUInt32BE` on that. 721cb0ef41Sopenharmony_ci const fullMessageSize = ( 731cb0ef41Sopenharmony_ci messageBufferHead[0] << 24 | 741cb0ef41Sopenharmony_ci messageBufferHead[1] << 16 | 751cb0ef41Sopenharmony_ci messageBufferHead[2] << 8 | 761cb0ef41Sopenharmony_ci messageBufferHead[3] 771cb0ef41Sopenharmony_ci ) + 4; 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci if (channel[kMessageBufferSize] < fullMessageSize) break; 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci const concatenatedBuffer = channel[kMessageBuffer].length === 1 ? 821cb0ef41Sopenharmony_ci channel[kMessageBuffer][0] : 831cb0ef41Sopenharmony_ci Buffer.concat( 841cb0ef41Sopenharmony_ci channel[kMessageBuffer], 851cb0ef41Sopenharmony_ci channel[kMessageBufferSize], 861cb0ef41Sopenharmony_ci ); 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci const deserializer = new ChildProcessDeserializer( 891cb0ef41Sopenharmony_ci TypedArrayPrototypeSubarray(concatenatedBuffer, 4, fullMessageSize), 901cb0ef41Sopenharmony_ci ); 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci messageBufferHead = TypedArrayPrototypeSubarray(concatenatedBuffer, fullMessageSize); 931cb0ef41Sopenharmony_ci channel[kMessageBufferSize] = messageBufferHead.length; 941cb0ef41Sopenharmony_ci channel[kMessageBuffer] = 951cb0ef41Sopenharmony_ci channel[kMessageBufferSize] !== 0 ? [messageBufferHead] : []; 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci deserializer.readHeader(); 981cb0ef41Sopenharmony_ci yield deserializer.readValue(); 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci channel.buffering = channel[kMessageBufferSize] > 0; 1021cb0ef41Sopenharmony_ci }, 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci writeChannelMessage(channel, req, message, handle) { 1051cb0ef41Sopenharmony_ci const ser = new ChildProcessSerializer(); 1061cb0ef41Sopenharmony_ci // Add 4 bytes, to later populate with message length 1071cb0ef41Sopenharmony_ci ser.writeRawBytes(Buffer.allocUnsafe(4)); 1081cb0ef41Sopenharmony_ci ser.writeHeader(); 1091cb0ef41Sopenharmony_ci ser.writeValue(message); 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci const serializedMessage = ser.releaseBuffer(); 1121cb0ef41Sopenharmony_ci const serializedMessageLength = serializedMessage.length - 4; 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci serializedMessage.set([ 1151cb0ef41Sopenharmony_ci serializedMessageLength >> 24 & 0xFF, 1161cb0ef41Sopenharmony_ci serializedMessageLength >> 16 & 0xFF, 1171cb0ef41Sopenharmony_ci serializedMessageLength >> 8 & 0xFF, 1181cb0ef41Sopenharmony_ci serializedMessageLength & 0xFF, 1191cb0ef41Sopenharmony_ci ], 0); 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci const result = channel.writeBuffer(req, serializedMessage, handle); 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci // Mirror what stream_base_commons.js does for Buffer retention. 1241cb0ef41Sopenharmony_ci if (streamBaseState[kLastWriteWasAsync]) 1251cb0ef41Sopenharmony_ci req.buffer = serializedMessage; 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci return result; 1281cb0ef41Sopenharmony_ci }, 1291cb0ef41Sopenharmony_ci}; 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ciconst json = { 1321cb0ef41Sopenharmony_ci initMessageChannel(channel) { 1331cb0ef41Sopenharmony_ci channel[kJSONBuffer] = ''; 1341cb0ef41Sopenharmony_ci channel[kStringDecoder] = undefined; 1351cb0ef41Sopenharmony_ci }, 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci *parseChannelMessages(channel, readData) { 1381cb0ef41Sopenharmony_ci if (readData.length === 0) return; 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci if (channel[kStringDecoder] === undefined) 1411cb0ef41Sopenharmony_ci channel[kStringDecoder] = new StringDecoder('utf8'); 1421cb0ef41Sopenharmony_ci const chunks = 1431cb0ef41Sopenharmony_ci StringPrototypeSplit(channel[kStringDecoder].write(readData), '\n'); 1441cb0ef41Sopenharmony_ci const numCompleteChunks = chunks.length - 1; 1451cb0ef41Sopenharmony_ci // Last line does not have trailing linebreak 1461cb0ef41Sopenharmony_ci const incompleteChunk = chunks[numCompleteChunks]; 1471cb0ef41Sopenharmony_ci if (numCompleteChunks === 0) { 1481cb0ef41Sopenharmony_ci channel[kJSONBuffer] += incompleteChunk; 1491cb0ef41Sopenharmony_ci } else { 1501cb0ef41Sopenharmony_ci chunks[0] = channel[kJSONBuffer] + chunks[0]; 1511cb0ef41Sopenharmony_ci for (let i = 0; i < numCompleteChunks; i++) 1521cb0ef41Sopenharmony_ci yield JSONParse(chunks[i]); 1531cb0ef41Sopenharmony_ci channel[kJSONBuffer] = incompleteChunk; 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci channel.buffering = channel[kJSONBuffer].length !== 0; 1561cb0ef41Sopenharmony_ci }, 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci writeChannelMessage(channel, req, message, handle) { 1591cb0ef41Sopenharmony_ci const string = JSONStringify(message) + '\n'; 1601cb0ef41Sopenharmony_ci return channel.writeUtf8String(req, string, handle); 1611cb0ef41Sopenharmony_ci }, 1621cb0ef41Sopenharmony_ci}; 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_cimodule.exports = { advanced, json }; 165