hoo's notebooks

  • Line Number - /hoo/line-number
    Last edited 6 years ago
    const fs = require('fs'); const {StringDecoder} = require('string_decoder'); const {Transform} = require('stream'); // Usage: // fs.createReadStream(sourcePath) // .pipe(new LineNumber()) // .pipe(fs.createWriteStream(destPath)); class Line extends Transform { constructor() { Object.assign(super(), { decoder: new StringDecoder(), buffer: [], }); } flush() { const line = this.buffer.join(''); this.buffer = []; this.push(line); } _transform(chunk, encoding, callback) { let previous; for (const c of this.decoder.write(chunk)) { if (c === '\n') { this.buffer.push(c); this.flush(); } else { if (previous === '\r') { this.flush(); } this.buffer.push(c); } previous = c; } callback(); } _flush(callback) { this.flush(); callback(); } } class LineNumber extends Line { constructor({length = 4, fill = '0'} = {}) { Object.assign(super(), { length, fill, count: 0, }); } push(data) { if (data || data === 'string') { const prefix = `${++this.count}`.padStart(this.length, this.fill); data = `${prefix}: ${data}`; } super.push(data); } } // TEST const assert = require('assert'); const {Writable, PassThrough} = require('stream'); const writeByteByByte = (stream, buffer) => { for (let i = 0; i < buffer.length; i++) { stream.write(Buffer.from([buffer[i]])); } }; async function test(source, options, expected) { const actual = await new Promise((resolve, reject) => { const sourceStream = new PassThrough(); const chunks = []; sourceStream .pipe(new LineNumber(options)) .pipe(new Writable({ write(chunk, encoding, callback) { chunks.push(chunk); callback(); }, final(callback) { resolve(Buffer.concat(chunks).toString()); }, })); writeByteByByte(sourceStream, Buffer.from(source)); sourceStream.end(); }); assert.equal(actual, expected); console.log(actual); } Promise.all( [ [ 'ABC\nDEF\n', undefined, '0001: ABC\n0002: DEF\n0003: ', ], [ '😀\r\n😁\n😂🤣\r\n😆', {length: 2, fill: ' '}, ' 1: 😀\r\n 2: 😁\n 3: 😂🤣\r\n 4: 😆', ], ] .map(([source, options, expected]) => test(source, options, expected)) ) .catch((error) => { console.error(error); process.exit(1); });
  • HTTP-HTTP - /hoo/http-http
    Last edited 6 years ago
    const console = require('console'); const http = require('http'); const server = http.createServer() .on('error', console.error) .on('request', (req, res) => { const chunks = []; console.log(`req.headers: ${JSON.stringify(req.headers, null, 2)}`); req .on('error', console.error) .on('data', (chunk) => chunks.push(chunk)) .once('end', () => { const receivedData = Buffer.concat(chunks); const responseBody = Buffer.concat([ Buffer.from('##START##\n'), receivedData, Buffer.from('\n##END##'), ]); res.writeHead(200, 'GOOD', { 'content-type': 'text/plain', 'content-length': `${responseBody.length}`, }); res.write(responseBody); res.end(); }); }) .once('listening', () => { const requestBody = Buffer.from('Hello!!!'); const req = http.request({ host: '127.0.0.1', port: server.address().port, method: 'POST', headers: { 'content-type': 'text/plain', 'content-length': `${requestBody.length}`, }, }) .on('error', console.error) .once('response', (res) => { console.log(`${res.statusCode} ${res.statusMessage}`); console.log(`res.headers: ${JSON.stringify(res.headers, null, 2)}`); const chunks = []; res .on('error', console.error) .on('data', (chunk) => chunks.push(chunk)) .once('end', () => { console.log(`${Buffer.concat(chunks)}`); }) }); req.write(requestBody); req.end(); }) .listen(3000);
  • HTTP-NET - /hoo/http-net
    Last edited 6 years ago
    This is a playground to test JavaScript. It runs a completely standard copy of Node.js on a virtual server created just for you. Every one of npm’s 300,000+ packages are pre-installed, so try it out:
  • NET-HTTP - /hoo/net-http
    Last edited 6 years ago
    const CRLFCRLF = Buffer.from('\r\n\r\n'); const EOF = Buffer.from('\0'); const console = require('console'); const net = require('net'); const http = require('http'); const server = net.createServer() .on('error', console.error) .on('connection', (socket) => { let chunks = Buffer.from([]); const data = {}; socket .on('error', console.error) .on('data', (chunk) => { chunks = Buffer.concat([chunks, chunk]); if (!data.headers) { const index = chunks.indexOf(CRLFCRLF); if (0 <= index) { const [requestLine, ...headerLines] = chunks.slice(0, index).toString().split('\r\n'); chunks = chunks.slice(index + CRLFCRLF.length); const [method, uri, version] = requestLine.split(/\s+/); Object.assign(data, {method, uri, version}); const headers = data.headers = {}; for (const line of headerLines) { const delimiterIndex = line.indexOf(':'); const key = line.slice(0, delimiterIndex).trim().toLowerCase(); const value = line.slice(delimiterIndex + 1).trim(); headers[key] = value; } data.contentLength = parseInt(headers['content-length'], 10); data.checkEOF = 0 <= data.contentLength ? (chunks) => data.contentLength <= chunks.length : (chunks) => 0 <= chunks.indexOf(EOF); } } if (data.checkEOF && data.checkEOF(chunks)) { const responseBody = Buffer.concat([ Buffer.from('##START##\n'), chunks, Buffer.from('\n##END##'), ]); socket.write(Buffer.from([ 'HTTP/1.0 200 GOOD', 'content-type: text/plain', `content-length: ${responseBody.length}`, '\r\n', ].join('\r\n'))); socket.write(responseBody); socket.end(); } }); }) .once('listening', () => { const requestBody = Buffer.from('Hello!!!'); const req = http.request({ host: '127.0.0.1', port: server.address().port, method: 'POST', headers: { 'content-type': 'text/plain', 'content-length': `${requestBody.length}`, }, }) .on('error', console.error) .once('response', (res) => { console.log(`${res.statusCode} ${res.statusMessage}`); console.log(`res.headers: ${JSON.stringify(res.headers, null, 2)}`); const chunks = []; res .on('error', console.error) .on('data', (chunk) => chunks.push(chunk)) .once('end', () => { console.log(`${Buffer.concat(chunks)}`); }) }); req.write(requestBody); req.end(); }) .listen(3000);