node_compat

package
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: Mar 6, 2022 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.

Source Files

  • child_process.go
  • crypto.go
  • event_emitter.go
  • exec.go
  • http.go
  • net.go
  • plugin.go
  • stream.go

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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