node_compat

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2021 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const PluginName = "node_compat"

Variables

View Source
var ChildProcess = &vm.Module{
	Name: "child_process",
	Main: "index",
	Path: "child_process",
	Body: `
import EventEmitter from 'events';

const runCommand = async (proc) => {
	proc.Run();
	await proc.Result();
	return proc;
}

export const spawn = (command, args, opts) => {
	if(typeof(exec) === 'undefined') {
		throw new Error("node_compat: cannot start child process: exec must be enabled");
	}
	let child = new class extends EventEmitter {
		constructor() {
			super();
			this.proc = exec.Command(command, ...(args || []));
			this.stdout = new EventEmitter();
			this.stderr = new EventEmitter();
			this.stdin = {
				write: (input) => {
					this.proc.Input(input);
				},
				end: () => {
					return this.proc.CloseInput();
				},
			};
		}
	};
	
	setTimeout(() => {
		runCommand(child.proc).catch((e) => {
			console.log('error running child_process', e);
		}).finally(res => {
			child.stdout.emit('data', child.proc.Output());
			child.stderr.emit('data', child.proc.Error());
			child.emit('close', child.proc.ExitCode());
		});
	}, 10);
	
	return child;
};
`,
}

ChildProcess is a polyfill for the child_process node module.

View Source
var Crypto = &vm.Module{
	Name: "crypto",
	Main: "index",
	Path: "crypto",
	Body: `
import {Buffer} from 'buffer';

class Sha1 {
	constructor() {
		this.data = Buffer.alloc(0);
	}

	update(data) {
		this.data.write(data);
		return this;
	}

	digest(kind) {
		switch(kind) {
			case 'hex':
				return sha1.Sum(this.data.toString());
			default:
				throw new Error('unsupported digest format: '+kind);
		}
	}
}

export const createHash = (kind) => {
	switch(kind) {
		case 'sha1':
			return new Sha1();
		default:
			throw new Error('unsupported hash algo: '+kind);
	}
};`,
}

Crypto is a polyfill providing some functionality from the node crypto module.

View Source
var EventEmitter = &vm.Module{
	Name: "events",
	Main: "index",
	Path: "events",
	Body: `/* Polyfill EventEmitter. */
var EventEmitter = function () {
    this.events = {};
};

EventEmitter.EventEmitter = EventEmitter;

EventEmitter.prototype.on = function (event, listener) {
    if (typeof this.events[event] !== 'object') {
        this.events[event] = [];
    }

    this.events[event].push(listener);
};

EventEmitter.prototype.removeListener = function (event, listener) {
    var idx;

    if (typeof this.events[event] === 'object') {
        idx = this.events[event].indexOf(listener);

        if (idx > -1) {
            this.events[event].splice(idx, 1);
        }
    }
};

EventEmitter.prototype.emit = function (event) {
    var i, listeners, length, args = [].slice.call(arguments, 1);

    if (typeof this.events[event] === 'object') {
        listeners = this.events[event].slice();
        length = listeners.length;

        for (i = 0; i < length; i++) {
            listeners[i].apply(this, args);
        }
    }
};

EventEmitter.prototype.once = function (event, listener) {
    this.on(event, function g () {
        this.removeListener(event, g);
        listener.apply(this, arguments);
    });
};

EventEmitter.prototype.listenerCount = function (event) {
	if(!this.events[event]) {
		return 0;
	}
	return this.events[event].length;
};

module.exports = EventEmitter;`,
}

EventEmitter is a polyfill for the node events module. See https://gist.github.com/mudge/5830382 Modified to add listenerCount instance method.

View Source
var Http = &vm.Module{
	Name: "http",
	Main: "index",
	Path: "http",
	Body: `
import EventEmitter from 'events';
import {Server as NetServer} from 'net';

export class Server extends NetServer {
    constructor(options, requestListener) {}

    setTimeout(timeout, callback = null) {}

    get maxHeadersCount() {}
    get timeout() {}
    get headersTimeout() {}
    get keepAliveTimeout() {}
}

export class OutgoingMessage {
    get upgrading() {}
    get chunkedEncoding() {}
    get shouldKeepAlive() {}
    get useChunkedEncodingByDefault() {}
    get sendDate() {}
    get finished() {}
    get headersSent() {}
    get connection() {}

    constructor() {}

    setTimeout(timeout, callback = null) {}
    setHeader(name, value) {}
    getHeader(name) {}
    getHeaders() {}
    getHeaderNames() {}
    hasHeader(name) {}
    removeHeader(name) {}
    addTrailers(headers) {}
    flushHeaders() {}
}

export class ServerResponse extends OutgoingMessage {
    get statusCode() {}
    get statusMessage() {}

    constructor(req) {}

    assignSocket(socket) {}
    detachSocket(socket) {}
    writeContinue(callback) {}
    writeHead(statusCode, reasonPhrase, headers = null) {}
}

export class ClientRequest extends OutgoingMessage {
    get connection() {}
    get socket() {}
    get aborted() {}

    constructor(uri, callback = null) {}

    get path() {}
    abort() {}
    onSocket(socket) {}
    setTimeout(timeout, callback = null) {}
    setNoDelay(noDelay) {}
    setSocketKeepAlive(enable, initialDelay = null) {}
}

class IncomingMessage {
    constructor(socket) {}

    get httpVersion() {}
    get httpVersionMajor() {}
    get httpVersionMinor() {}
    get connection() {}
    get headers() {}
    get rawHeaders() {}
    get trailers() {}
    get rawTrailers() {}
    setTimeout(timeout, callback = null) {}
    get method() {}
    get url() {}
    get statusCode() {}
    get statusMessage() {}
    get socket() {}

    destroy() {}
}

class Agent {
    get maxFreeSockets() {

    }
    get maxSockets() {}
    get sockets() {}
    get requests() {}

    constructor(options) {}

    destroy() {}
}

export const METHODS = [];
export const STATUS_CODES = {};

export function createServer(options, requestListener) {}

export function request(options, callback) {}
export function get(options, callback) {}

export let globalAgent;
export const maxHeaderSize;
`,
}

Http is a polyfill for the node http module.

View Source
var Net = &vm.Module{
	Name: "net",
	Main: "index",
	Path: "net",
	Body: `
import {Duplex} from 'stream';
import {Buffer} from 'buffer';
import {EventEmitter} from 'events';

const goAddrToNode = addr => {
	// todo: support ipv6 addresses, udp, ipc, etc
	let parts = addr.String().split(':');
	return {
		host: parts[0],
		port: parseInt(parts[1]),
		family: addr.Network(),
	};
};

export class Socket extends Duplex {
    constructor(options = {}) {
		super(options);
		this.options = options || {};
		this._connection = null;
		this._local = null;
		this._remote = null;
		this._connecting = false;
		this.on('ready', () => {
			this._connecting = false;
			this._local = goAddrToNode(this._connection.LocalAddr());
			this._remote = goAddrToNode(this._connection.RemoteAddr());
		});
    }

	_read(size = null) {
		if(!this._connection) {
			return;
		}
		let result = this._connection.Read(size);
		let wait = 1;
		let check = () => {
			if(result.Ready()) {
				let data = result.Value();
				if(data !== null && data.length) {
					this.push(data);
				} else {
					this.push(null);
				}
			} else {
				if(wait < 64) {
					wait *= 2;
				}
				setTimeout(check, wait);
			}
		};
		check();
	}

    _write(buffer, encoding, callback) {
		if(!this._connection) {
			callback(Error('not connected'));
			return;
		}
		let err = null;
		try {
			this._connection.Write(buffer);
		} catch(e) {
			err = e;
		} finally {
			callback(err);
		}
    }

    async connect(options, listener = null) {
		// todo: support ipc
		// todo: udp is defined in Node's dgram module
		if(listener !== null) {
			this.once('connect', listener);
		}
		let host = options.host || 'localhost';
		let port = options.port;
		if(!port) {
			throw new Error('ipc connections are unsupported');
		}
		console.log('dialing', host + ':' + port);
		this._connecting = true;
		this._connection = native.Dial('tcp', host + ':' + port);
		this.emit('connect');
		this.emit('ready');
    }

    setEncoding(encoding) {
		this.encoding = encoding;
    }

	_destroy(callback) {
		let err = null;
		try {
			this._connection.Close();
		} catch(e) {
			err = e;
			console.log('error destroying', err.toString());
		} finally {
			this._connection = null;
			if(callback) {
				callback(err);
			}
		}
	}

    // setTimeout(timeout, callback = null) {}
 	// setNoDelay(noDelay) {}
    // setKeepAlive(keepAlive) {}
    // address() {}
    // unref() {}
    // ref() {}
	// 
    // get bufferSize() {}
    // get bytesRead() {}
    // get bytesWritten() {}
    get connecting() {
		return this._connecting;
	}
    get localAddress() {
		if(!this._connection) {
			return null;
		}
		return this._local.host;
	}
    get localPort() {
		if(!this._connection) {
			return null;
		}
		return this._local.port;
	}
    get remoteAddress() {
		if(!this._connection) {
			return null;
		}
		return this._remote.host;
	}
    get remoteFamily() {
		if(!this._connection) {
			return null;
		}
		return this._remote.family;
	}
    get remotePort() {
		if(!this._connection) {
			return null;
		}
		return this._remote.port;
	}
}

export class Server extends EventEmitter {
    constructor(listener = null) {
		super();
		if(listener !== null) {
			this.on('connection', listener);
		}
		this._server = null;
    }

    listen(port, hostname, listener = null) {
		if(listener !== null) {
			this.on('connection', listener);
		}
		let addr = hostname + ':' + port;
		let accept = (conn) => {
			let socket = new Socket();
			socket._connection = conn;
			socket.on('end', () => {
				console.log('server ended');
				socket.destroy();
			});
			socket.emit('connect');
			this.emit('connection', socket);
			socket.emit('ready');
		};
		this._server = native.Listen(accept, 'tcp4', addr);
		this.emit('listening');
	}

	close(callback = null) {
		this._server.Close();
		this.emit('close');
		if(callback !== null) {
			callback();
		}
	}

    address() {
		return goAddrToNode(this._server.Addr());
	}

    getConnections(callback) {}

    ref() {}

    unref() {}

    get maxConnections() {}
    get connections() {}
    get listening() {}
}
// 
// export function createServer(options = null, connectionListener = null) {}
// 
// export function connect(options, connectionListener = null) {}
// 
// export function createConnection(options, connectionListener = null) {}
// 
// export function isIP(input) {}
// 
// export function isIPv4(input) {}
// 
// export function isIPv6(input) {}
`,
}

Net is a polyfill for the node net module.

View Source
var Stream = &vm.Module{
	Name: "stream",
	Main: "index.js",
	Path: "stream",
	Body: `// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

module.exports = Stream;

var EE = require('events').EventEmitter;
var inherits = require('inherits');

inherits(Stream, EE);
Stream.Readable = require('readable-stream/lib/_stream_readable.js');
Stream.Writable = require('readable-stream/lib/_stream_writable.js');
Stream.Duplex = require('readable-stream/lib/_stream_duplex.js');
Stream.Transform = require('readable-stream/lib/_stream_transform.js');
Stream.PassThrough = require('readable-stream/lib/_stream_passthrough.js');
Stream.finished = require('readable-stream/lib/internal/streams/end-of-Stream.js')
Stream.pipeline = require('readable-stream/lib/internal/streams/pipeline.js')

// Backwards-compat with node 0.4.x
Stream.Stream = Stream;



// old-style streams.  Note that the pipe method (the only relevant
// part of this class) is overridden in the Readable class.

function Stream() {
  EE.call(this);
}

Stream.prototype.pipe = function(dest, options) {
  var source = this;

  function ondata(chunk) {
    if (dest.writable) {
      if (false === dest.write(chunk) && source.pause) {
        source.pause();
      }
    }
  }

  source.on('data', ondata);

  function ondrain() {
    if (source.readable && source.resume) {
      source.resume();
    }
  }

  dest.on('drain', ondrain);

  // If the 'end' option is not supplied, dest.end() will be called when
  // source gets the 'end' or 'close' events.  Only dest.end() once.
  if (!dest._isStdio && (!options || options.end !== false)) {
    source.on('end', onend);
    source.on('close', onclose);
  }

  var didOnEnd = false;
  function onend() {
    if (didOnEnd) return;
    didOnEnd = true;

    dest.end();
  }


  function onclose() {
    if (didOnEnd) return;
    didOnEnd = true;

    if (typeof dest.destroy === 'function') dest.destroy();
  }

  // don't leave dangling pipes when there are errors.
  function onerror(er) {
    cleanup();
    if (EE.listenerCount(this, 'error') === 0) {
      throw er; // Unhandled Stream error in pipe.
    }
  }

  source.on('error', onerror);
  dest.on('error', onerror);

  // remove all the event listeners that were added.
  function cleanup() {
    source.removeListener('data', ondata);
    dest.removeListener('drain', ondrain);

    source.removeListener('end', onend);
    source.removeListener('close', onclose);

    source.removeListener('error', onerror);
    dest.removeListener('error', onerror);

    source.removeListener('end', cleanup);
    source.removeListener('close', cleanup);

    dest.removeListener('close', cleanup);
  }

  source.on('end', cleanup);
  source.on('close', cleanup);

  dest.on('close', cleanup);

  dest.emit('pipe', source);

  // Allow for unix-like usage: A.pipe(B).pipe(C)
  return dest;
};`,
}

Stream is based on stream-browserify and relies on readable-stream. See https://github.com/browserify/stream-browserify/blob/v3.0.0/index.js

Functions

func Initialize

func Initialize(m *plugin.Manager) (plugin.Plugin, error)

Types

type Process

type Process struct {
	// contains filtered or unexported fields
}

func NewProcess

func NewProcess(command string, args ...string) *Process

func (*Process) CloseInput

func (p *Process) CloseInput() error

func (*Process) Done

func (p *Process) Done() bool

func (*Process) Error

func (p *Process) Error() string

func (*Process) ExitCode

func (p *Process) ExitCode() int

func (*Process) Input

func (p *Process) Input(input string) error

func (*Process) Kill

func (p *Process) Kill() error

func (*Process) Output

func (p *Process) Output() string

func (*Process) PID

func (p *Process) PID() (int, error)

func (*Process) Result

func (p *Process) Result() (*os.ProcessState, error)

func (*Process) Run

func (p *Process) Run()

Run starts the process, closing standard input immediately.

Note that whatever input is already buffered (ie. through calls to Input) will still be written to the process's stdin.

func (*Process) Start

func (p *Process) Start()

Start starts the process, leaving stdin open for writing.

If the started process reads from stdin, it may not exit until CloseInput is called.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL