Migrate entrypoint-http.js to TypeScript. Source is now HttpNodeInstanceEntryPoint.ts.

This commit is contained in:
SteveSandersonMS
2016-07-01 11:49:22 +01:00
parent 393e156b47
commit 260a0d6bcb
7 changed files with 388 additions and 190 deletions

View File

@@ -1,47 +1,103 @@
(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive, // Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module. // but simplifies things for the consumer of this module.
var http = require('http'); var http = __webpack_require__(2);
var path = require('path'); var path = __webpack_require__(3);
var parsedArgs = parseArgs(process.argv); var ArgsUtil_1 = __webpack_require__(4);
var requestedPortOrZero = parsedArgs.port || 0; // 0 means 'let the OS decide' var AutoQuit_1 = __webpack_require__(5);
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
// reference to Node's runtime 'require' function.
var dynamicRequire = eval('require');
var parsedArgs = ArgsUtil_1.parseArgs(process.argv);
if (parsedArgs.watch) { if (parsedArgs.watch) {
autoQuitOnFileChange(process.cwd(), parsedArgs.watch.split(',')); AutoQuit_1.autoQuitOnFileChange(process.cwd(), parsedArgs.watch.split(','));
} }
var server = http.createServer(function (req, res) { var server = http.createServer(function (req, res) {
readRequestBodyAsJson(req, function (bodyJson) { readRequestBodyAsJson(req, function (bodyJson) {
var resolvedPath = path.resolve(process.cwd(), bodyJson.moduleName); var resolvedPath = path.resolve(process.cwd(), bodyJson.moduleName);
var invokedModule = require(resolvedPath); var invokedModule = dynamicRequire(resolvedPath);
var func = bodyJson.exportedFunctionName ? invokedModule[bodyJson.exportedFunctionName] : invokedModule; var func = bodyJson.exportedFunctionName ? invokedModule[bodyJson.exportedFunctionName] : invokedModule;
if (!func) { if (!func) {
throw new Error('The module "' + resolvedPath + '" has no export named "' + bodyJson.exportedFunctionName + '"'); throw new Error('The module "' + resolvedPath + '" has no export named "' + bodyJson.exportedFunctionName + '"');
} }
var hasSentResult = false; var hasSentResult = false;
var callback = function (errorValue, successValue) { var callback = function (errorValue, successValue) {
if (!hasSentResult) { if (!hasSentResult) {
hasSentResult = true; hasSentResult = true;
if (errorValue) { if (errorValue) {
res.statusCode = 500; res.statusCode = 500;
if (errorValue.stack) { if (errorValue.stack) {
res.end(errorValue.stack); res.end(errorValue.stack);
} else { }
else {
res.end(errorValue.toString()); res.end(errorValue.toString());
} }
} else if (typeof successValue !== 'string') { }
else if (typeof successValue !== 'string') {
// Arbitrary object/number/etc - JSON-serialize it // Arbitrary object/number/etc - JSON-serialize it
res.setHeader('Content-Type', 'application/json'); res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(successValue)); res.end(JSON.stringify(successValue));
} else { }
else {
// String - can bypass JSON-serialization altogether // String - can bypass JSON-serialization altogether
res.setHeader('Content-Type', 'text/plain'); res.setHeader('Content-Type', 'text/plain');
res.end(successValue); res.end(successValue);
} }
} }
}; };
// Support streamed responses // Support streamed responses
Object.defineProperty(callback, 'stream', { Object.defineProperty(callback, 'stream', {
enumerable: true, enumerable: true,
@@ -50,27 +106,24 @@ var server = http.createServer(function(req, res) {
hasSentResult = true; hasSentResult = true;
res.setHeader('Content-Type', 'application/octet-stream'); res.setHeader('Content-Type', 'application/octet-stream');
} }
return res; return res;
} }
}); });
try { try {
func.apply(null, [callback].concat(bodyJson.args)); func.apply(null, [callback].concat(bodyJson.args));
} catch (synchronousException) { }
catch (synchronousException) {
callback(synchronousException, null); callback(synchronousException, null);
} }
}); });
}); });
var requestedPortOrZero = parsedArgs.port || 0; // 0 means 'let the OS decide'
server.listen(requestedPortOrZero, 'localhost', function () { server.listen(requestedPortOrZero, 'localhost', function () {
// Signal to HttpNodeHost which port it should make its HTTP connections on // Signal to HttpNodeHost which port it should make its HTTP connections on
console.log('[Microsoft.AspNetCore.NodeServices.HttpNodeHost:Listening on port ' + server.address().port + '\]'); console.log('[Microsoft.AspNetCore.NodeServices.HttpNodeHost:Listening on port ' + server.address().port + '\]');
// Signal to the NodeServices base class that we're ready to accept invocations // Signal to the NodeServices base class that we're ready to accept invocations
console.log('[Microsoft.AspNetCore.NodeServices:Listening]'); console.log('[Microsoft.AspNetCore.NodeServices:Listening]');
}); });
function readRequestBodyAsJson(request, callback) { function readRequestBodyAsJson(request, callback) {
var requestBodyAsString = ''; var requestBodyAsString = '';
request request
@@ -78,20 +131,24 @@ function readRequestBodyAsJson(request, callback) {
.on('end', function () { callback(JSON.parse(requestBodyAsString)); }); .on('end', function () { callback(JSON.parse(requestBodyAsString)); });
} }
function autoQuitOnFileChange(rootDir, extensions) {
// Note: This will only work on Windows/OS X, because the 'recursive' option isn't supported on Linux.
// Consider using a different watch mechanism (though ideally without forcing further NPM dependencies).
var fs = require('fs');
var path = require('path');
fs.watch(rootDir, { persistent: false, recursive: true }, function(event, filename) {
var ext = path.extname(filename);
if (extensions.indexOf(ext) >= 0) {
console.log('Restarting due to file change: ' + filename);
process.exit(0);
}
});
}
/***/ },
/* 2 */
/***/ function(module, exports) {
module.exports = require("http");
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = require("path");
/***/ },
/* 4 */
/***/ function(module, exports) {
"use strict";
function parseArgs(args) { function parseArgs(args) {
// Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external // Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
// dependencies (such as an args-parsing library) to this file. // dependencies (such as an args-parsing library) to this file.
@@ -102,11 +159,43 @@ function parseArgs(args) {
var argName = arg.substring(2); var argName = arg.substring(2);
result[argName] = undefined; result[argName] = undefined;
currentKey = argName; currentKey = argName;
} else if (currentKey) { }
else if (currentKey) {
result[currentKey] = arg; result[currentKey] = arg;
currentKey = null; currentKey = null;
} }
}); });
return result; return result;
} }
exports.parseArgs = parseArgs;
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
var fs = __webpack_require__(6);
var path = __webpack_require__(3);
function autoQuitOnFileChange(rootDir, extensions) {
// Note: This will only work on Windows/OS X, because the 'recursive' option isn't supported on Linux.
// Consider using a different watch mechanism (though ideally without forcing further NPM dependencies).
fs.watch(rootDir, { persistent: false, recursive: true }, function (event, filename) {
var ext = path.extname(filename);
if (extensions.indexOf(ext) >= 0) {
console.log('Restarting due to file change: ' + filename);
process.exit(0);
}
});
}
exports.autoQuitOnFileChange = autoQuitOnFileChange;
/***/ },
/* 6 */
/***/ function(module, exports) {
module.exports = require("fs");
/***/ }
/******/ ])));

View File

@@ -44,27 +44,89 @@
/* 0 */ /* 0 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1); module.exports = __webpack_require__(7);
/***/ }, /***/ },
/* 1 */ /* 1 */,
/* 2 */,
/* 3 */
/***/ function(module, exports) {
module.exports = require("path");
/***/ },
/* 4 */
/***/ function(module, exports) {
"use strict";
function parseArgs(args) {
// Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
// dependencies (such as an args-parsing library) to this file.
var result = {};
var currentKey = null;
args.forEach(function (arg) {
if (arg.indexOf('--') === 0) {
var argName = arg.substring(2);
result[argName] = undefined;
currentKey = argName;
}
else if (currentKey) {
result[currentKey] = arg;
currentKey = null;
}
});
return result;
}
exports.parseArgs = parseArgs;
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
var fs = __webpack_require__(6);
var path = __webpack_require__(3);
function autoQuitOnFileChange(rootDir, extensions) {
// Note: This will only work on Windows/OS X, because the 'recursive' option isn't supported on Linux.
// Consider using a different watch mechanism (though ideally without forcing further NPM dependencies).
fs.watch(rootDir, { persistent: false, recursive: true }, function (event, filename) {
var ext = path.extname(filename);
if (extensions.indexOf(ext) >= 0) {
console.log('Restarting due to file change: ' + filename);
process.exit(0);
}
});
}
exports.autoQuitOnFileChange = autoQuitOnFileChange;
/***/ },
/* 6 */
/***/ function(module, exports) {
module.exports = require("fs");
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
"use strict"; "use strict";
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive, // Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module. // but simplifies things for the consumer of this module.
var fs = __webpack_require__(2); var net = __webpack_require__(8);
var net = __webpack_require__(3); var path = __webpack_require__(3);
var path = __webpack_require__(4); var readline = __webpack_require__(9);
var readline = __webpack_require__(5); var ArgsUtil_1 = __webpack_require__(4);
var virtualConnectionServer = __webpack_require__(6); var AutoQuit_1 = __webpack_require__(5);
var virtualConnectionServer = __webpack_require__(10);
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct // Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
// reference to Node's runtime 'require' function. // reference to Node's runtime 'require' function.
var dynamicRequire = eval('require'); var dynamicRequire = eval('require');
var parsedArgs = parseArgs(process.argv); var parsedArgs = ArgsUtil_1.parseArgs(process.argv);
if (parsedArgs.watch) { if (parsedArgs.watch) {
autoQuitOnFileChange(process.cwd(), parsedArgs.watch.split(',')); AutoQuit_1.autoQuitOnFileChange(process.cwd(), parsedArgs.watch.split(','));
} }
// Signal to the .NET side when we're ready to accept invocations // Signal to the .NET side when we're ready to accept invocations
var server = net.createServer().on('listening', function () { var server = net.createServer().on('listening', function () {
@@ -116,68 +178,27 @@
var useWindowsNamedPipes = /^win/.test(process.platform); var useWindowsNamedPipes = /^win/.test(process.platform);
var listenAddress = (useWindowsNamedPipes ? '\\\\.\\pipe\\' : '/tmp/') + parsedArgs.pipename; var listenAddress = (useWindowsNamedPipes ? '\\\\.\\pipe\\' : '/tmp/') + parsedArgs.pipename;
server.listen(listenAddress); server.listen(listenAddress);
function autoQuitOnFileChange(rootDir, extensions) {
// Note: This will only work on Windows/OS X, because the 'recursive' option isn't supported on Linux.
// Consider using a different watch mechanism (though ideally without forcing further NPM dependencies).
fs.watch(rootDir, { persistent: false, recursive: true }, function (event, filename) {
var ext = path.extname(filename);
if (extensions.indexOf(ext) >= 0) {
console.log('Restarting due to file change: ' + filename);
process.exit(0);
}
});
}
function parseArgs(args) {
// Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
// dependencies (such as an args-parsing library) to this file.
var result = {};
var currentKey = null;
args.forEach(function (arg) {
if (arg.indexOf('--') === 0) {
var argName = arg.substring(2);
result[argName] = undefined;
currentKey = argName;
}
else if (currentKey) {
result[currentKey] = arg;
currentKey = null;
}
});
return result;
}
/***/ }, /***/ },
/* 2 */ /* 8 */
/***/ function(module, exports) {
module.exports = require("fs");
/***/ },
/* 3 */
/***/ function(module, exports) { /***/ function(module, exports) {
module.exports = require("net"); module.exports = require("net");
/***/ }, /***/ },
/* 4 */ /* 9 */
/***/ function(module, exports) {
module.exports = require("path");
/***/ },
/* 5 */
/***/ function(module, exports) { /***/ function(module, exports) {
module.exports = require("readline"); module.exports = require("readline");
/***/ }, /***/ },
/* 6 */ /* 10 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
"use strict"; "use strict";
var events_1 = __webpack_require__(7); var events_1 = __webpack_require__(11);
var VirtualConnection_1 = __webpack_require__(8); var VirtualConnection_1 = __webpack_require__(12);
// Keep this in sync with the equivalent constant in the .NET code. Both sides split up their transmissions into frames with this max length, // Keep this in sync with the equivalent constant in the .NET code. Both sides split up their transmissions into frames with this max length,
// and both will reject longer frames. // and both will reject longer frames.
var MaxFrameBodyLength = 16 * 1024; var MaxFrameBodyLength = 16 * 1024;
@@ -358,13 +379,13 @@
/***/ }, /***/ },
/* 7 */ /* 11 */
/***/ function(module, exports) { /***/ function(module, exports) {
module.exports = require("events"); module.exports = require("events");
/***/ }, /***/ },
/* 8 */ /* 12 */
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
"use strict"; "use strict";
@@ -373,7 +394,7 @@
function __() { this.constructor = d; } function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}; };
var stream_1 = __webpack_require__(9); var stream_1 = __webpack_require__(13);
/** /**
* Represents a virtual connection. Multiple virtual connections may be multiplexed over a single physical socket connection. * Represents a virtual connection. Multiple virtual connections may be multiplexed over a single physical socket connection.
*/ */
@@ -414,7 +435,7 @@
/***/ }, /***/ },
/* 9 */ /* 13 */
/***/ function(module, exports) { /***/ function(module, exports) {
module.exports = require("stream"); module.exports = require("stream");

View File

@@ -0,0 +1,85 @@
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module.
import * as http from 'http';
import * as path from 'path';
import { parseArgs } from './Util/ArgsUtil';
import { autoQuitOnFileChange } from './Util/AutoQuit';
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
// reference to Node's runtime 'require' function.
const dynamicRequire: (name: string) => any = eval('require');
const parsedArgs = parseArgs(process.argv);
if (parsedArgs.watch) {
autoQuitOnFileChange(process.cwd(), parsedArgs.watch.split(','));
}
const server = http.createServer((req, res) => {
readRequestBodyAsJson(req, bodyJson => {
const resolvedPath = path.resolve(process.cwd(), bodyJson.moduleName);
const invokedModule = dynamicRequire(resolvedPath);
const func = bodyJson.exportedFunctionName ? invokedModule[bodyJson.exportedFunctionName] : invokedModule;
if (!func) {
throw new Error('The module "' + resolvedPath + '" has no export named "' + bodyJson.exportedFunctionName + '"');
}
let hasSentResult = false;
const callback = (errorValue, successValue) => {
if (!hasSentResult) {
hasSentResult = true;
if (errorValue) {
res.statusCode = 500;
if (errorValue.stack) {
res.end(errorValue.stack);
} else {
res.end(errorValue.toString());
}
} else if (typeof successValue !== 'string') {
// Arbitrary object/number/etc - JSON-serialize it
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(successValue));
} else {
// String - can bypass JSON-serialization altogether
res.setHeader('Content-Type', 'text/plain');
res.end(successValue);
}
}
};
// Support streamed responses
Object.defineProperty(callback, 'stream', {
enumerable: true,
get: function() {
if (!hasSentResult) {
hasSentResult = true;
res.setHeader('Content-Type', 'application/octet-stream');
}
return res;
}
});
try {
func.apply(null, [callback].concat(bodyJson.args));
} catch (synchronousException) {
callback(synchronousException, null);
}
});
});
const requestedPortOrZero = parsedArgs.port || 0; // 0 means 'let the OS decide'
server.listen(requestedPortOrZero, 'localhost', function () {
// Signal to HttpNodeHost which port it should make its HTTP connections on
console.log('[Microsoft.AspNetCore.NodeServices.HttpNodeHost:Listening on port ' + server.address().port + '\]');
// Signal to the NodeServices base class that we're ready to accept invocations
console.log('[Microsoft.AspNetCore.NodeServices:Listening]');
});
function readRequestBodyAsJson(request, callback) {
let requestBodyAsString = '';
request
.on('data', chunk => { requestBodyAsString += chunk; })
.on('end', () => { callback(JSON.parse(requestBodyAsString)); });
}

View File

@@ -1,10 +1,11 @@
// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive, // Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
// but simplifies things for the consumer of this module. // but simplifies things for the consumer of this module.
import * as fs from 'fs';
import * as net from 'net'; import * as net from 'net';
import * as path from 'path'; import * as path from 'path';
import * as readline from 'readline'; import * as readline from 'readline';
import { Duplex } from 'stream'; import { Duplex } from 'stream';
import { parseArgs } from './Util/ArgsUtil';
import { autoQuitOnFileChange } from './Util/AutoQuit';
import * as virtualConnectionServer from './VirtualConnections/VirtualConnectionServer'; import * as virtualConnectionServer from './VirtualConnections/VirtualConnectionServer';
// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct // Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
@@ -71,37 +72,6 @@ const useWindowsNamedPipes = /^win/.test(process.platform);
const listenAddress = (useWindowsNamedPipes ? '\\\\.\\pipe\\' : '/tmp/') + parsedArgs.pipename; const listenAddress = (useWindowsNamedPipes ? '\\\\.\\pipe\\' : '/tmp/') + parsedArgs.pipename;
server.listen(listenAddress); server.listen(listenAddress);
function autoQuitOnFileChange(rootDir: string, extensions: string[]) {
// Note: This will only work on Windows/OS X, because the 'recursive' option isn't supported on Linux.
// Consider using a different watch mechanism (though ideally without forcing further NPM dependencies).
fs.watch(rootDir, { persistent: false, recursive: true } as any, (event, filename) => {
var ext = path.extname(filename);
if (extensions.indexOf(ext) >= 0) {
console.log('Restarting due to file change: ' + filename);
process.exit(0);
}
});
}
function parseArgs(args: string[]): any {
// Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
// dependencies (such as an args-parsing library) to this file.
const result = {};
let currentKey = null;
args.forEach(arg => {
if (arg.indexOf('--') === 0) {
const argName = arg.substring(2);
result[argName] = undefined;
currentKey = argName;
} else if (currentKey) {
result[currentKey] = arg;
currentKey = null;
}
});
return result;
}
interface RpcInvocation { interface RpcInvocation {
moduleName: string; moduleName: string;
exportedFunctionName: string; exportedFunctionName: string;

View File

@@ -0,0 +1,18 @@
export function parseArgs(args: string[]): any {
// Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
// dependencies (such as an args-parsing library) to this file.
const result = {};
let currentKey = null;
args.forEach(arg => {
if (arg.indexOf('--') === 0) {
const argName = arg.substring(2);
result[argName] = undefined;
currentKey = argName;
} else if (currentKey) {
result[currentKey] = arg;
currentKey = null;
}
});
return result;
}

View File

@@ -0,0 +1,14 @@
import * as fs from 'fs';
import * as path from 'path';
export function autoQuitOnFileChange(rootDir: string, extensions: string[]) {
// Note: This will only work on Windows/OS X, because the 'recursive' option isn't supported on Linux.
// Consider using a different watch mechanism (though ideally without forcing further NPM dependencies).
fs.watch(rootDir, { persistent: false, recursive: true } as any, (event, filename) => {
var ext = path.extname(filename);
if (extensions.indexOf(ext) >= 0) {
console.log('Restarting due to file change: ' + filename);
process.exit(0);
}
});
}

View File

@@ -10,6 +10,7 @@ module.exports = {
] ]
}, },
entry: { entry: {
'entrypoint-http': ['./TypeScript/HttpNodeInstanceEntryPoint'],
'entrypoint-socket': ['./TypeScript/SocketNodeInstanceEntryPoint'], 'entrypoint-socket': ['./TypeScript/SocketNodeInstanceEntryPoint'],
}, },
output: { output: {