├── README.md ├── benchmark └── full.js └── src ├── server.js └── parser.js /README.md: -------------------------------------------------------------------------------- 1 | ### Event Loop Demo 2 | 3 | Run over and download N|Solid at 4 | [downloads.nodesource.com/](https://downloads.nodesource.com/) then read 5 | up on how to make the most of it with 6 | [this excellent blog post](https://nodesource.com/blog/getting-started-with-nsolid-at-the-command-line) 7 | by Patrick Mueller. 8 | 9 | Start the server by running: 10 | ``` 11 | $ nsolid src/server.js 12 | ``` 13 | 14 | The included benchmark will nail the server. To change the number of 15 | simultaneous connections edit the `CONNECTIONS` variable at the top of the 16 | file. Run with: 17 | 18 | ``` 19 | $ nsolid benchmark/full.js 20 | ``` 21 | 22 | This example includes data about modules and their authors from npm. The server 23 | is a very simple REST-ish service that can give you some limited information. 24 | Such as, the flattened recursive dependencies for a given modules. 25 | 26 | After starting the server try the following example: 27 | ``` 28 | $ curl 'http://localhost:8007/module/fulldeps/express' 29 | ``` 30 | You should see all the dependencies that will be installed by installing 31 | express. 32 | -------------------------------------------------------------------------------- /benchmark/full.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | 6 | const CONNECTIONS = 10; 7 | const USERNAME_PATH = __dirname + '/../data/maintainers_usernames.json'; 8 | const usernames = JSON.parse(fs.readFileSync(USERNAME_PATH)); 9 | var req_completed = 0; 10 | 11 | 12 | setInterval(function() { 13 | console.log('Requests completed:', req_completed / 5, '/sec'); 14 | req_completed = 0; 15 | }, 5000); 16 | 17 | 18 | function randomUser() { 19 | return usernames[((Math.random() * 1e7) % usernames.length) >>> 0]; 20 | } 21 | 22 | 23 | function startRequest() { 24 | http.request('http://localhost:8007/user/modules/' + randomUser(), (res) => { 25 | res.on('data', function(chunk) { 26 | req_completed++; 27 | iteratePackages(JSON.parse(chunk.toString())); 28 | }); 29 | }).end(); 30 | } 31 | 32 | 33 | function iteratePackages(list) { 34 | if (!list || list.length === 0) 35 | return startRequest(); 36 | 37 | const item = list.pop(); 38 | http.request('http://localhost:8007/module/fulldeps/' + item, (res) => { 39 | res.on('data', function() { 40 | req_completed++; 41 | iteratePackages(list); 42 | }); 43 | }).end(); 44 | } 45 | 46 | 47 | for (var i = 0; i < CONNECTIONS; i++) 48 | startRequest(); 49 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const PORT = 8007; 4 | 5 | const parser = require('./parser'); 6 | const http = require('http'); 7 | const url = require('url'); 8 | 9 | 10 | const server = http.createServer().listen(PORT); 11 | const routes = []; 12 | 13 | 14 | server.on('request', function(req, res) { 15 | const ret = simpleRoute(url.parse(req.url).path); 16 | setTimeout(function() { 17 | res.end(JSON.stringify(ret) + '\n'); 18 | // Artificial latency for retrieving data from remote location. Play around 19 | // with it to see how much latency can affect response time. 20 | }, (Math.random() * 100) >>> 0); 21 | }); 22 | 23 | 24 | // Return detailed user information from username 25 | addRoute(/^\/user\/name\/.+/, function(path) { 26 | return parser.userDetails(path.substr(11)); 27 | }); 28 | 29 | 30 | // Return all modules maintained by given username 31 | addRoute(/^\/user\/modules\/.+/, function(path) { 32 | return parser.moduleAuthor(path.substr(14)); 33 | }); 34 | 35 | 36 | // Return first level deps for module 37 | addRoute(/^\/module\/simpledeps\/.+/, function(path) { 38 | return parser.singleDep(path.substr(19)); 39 | }); 40 | 41 | 42 | // Return a flattened list of recursive dependency lookup 43 | addRoute(/^\/module\/fulldeps\/.+/, function(path) { 44 | return parser.fullDeps(path.substr(17)); 45 | }); 46 | 47 | 48 | // Simple routing logic for incoming requests. 49 | 50 | function simpleRoute(path) { 51 | for (var i = 0; i < routes.length / 2; i++) { 52 | if (routes[i * 2].test(path)) 53 | return routes[i * 2 + 1](path); 54 | } 55 | return null; 56 | } 57 | 58 | 59 | function addRoute(reg, fn) { 60 | routes.push(reg, fn); 61 | } 62 | -------------------------------------------------------------------------------- /src/parser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const DATA_PATH = __dirname + '/../data'; 4 | const DEPENCENCY_FILE = DATA_PATH + '/dependency_list.json'; 5 | const MODULE_MAINTAINERS_FILE = DATA_PATH + '/module_maintainers.json'; 6 | 7 | const fs = require('fs'); 8 | 9 | exports.singleDep = singleDep; 10 | exports.fullDeps = fullDeps; 11 | exports.moduleAuthor = moduleAuthor; 12 | 13 | var deps_obj; 14 | var mods_obj; 15 | 16 | 17 | // Refresh JSON data at intervals to see if it's been updated 18 | (function refreshData() { 19 | deps_obj = JSON.parse(fs.readFileSync(DEPENCENCY_FILE).toString()); 20 | mods_obj = JSON.parse(fs.readFileSync(MODULE_MAINTAINERS_FILE).toString()); 21 | setTimeout(refreshData, 5000); 22 | }()); 23 | 24 | 25 | // iterate through mods_obj and create a reverse lookup of modules and their 26 | // maintainers. 27 | 28 | 29 | // Return first layer of deps for given module 30 | function singleDep(name) { 31 | if (!deps_obj[name]) 32 | return null; 33 | return deps_obj[name]; 34 | } 35 | 36 | 37 | // Return all depencencies as a flattened list for given module 38 | function fullDeps(name) { 39 | if (!Array.isArray(deps_obj[name])) 40 | return null; 41 | 42 | const deps = []; 43 | deps_obj[name].forEach((item) => recurse(item, deps)); 44 | 45 | return deps; 46 | } 47 | 48 | 49 | function recurse(name, deps) { 50 | if (deps.indexOf(name) > -1) 51 | return; 52 | deps.push(name); 53 | if (!Array.isArray(deps_obj[name])) 54 | return; 55 | deps_obj[name].forEach((item) => recurse(item, deps)); 56 | } 57 | 58 | 59 | // Return all modules maintained by the given user 60 | function moduleAuthor(name) { 61 | if (!mods_obj[name]) 62 | return null; 63 | return mods_obj[name]; 64 | } 65 | --------------------------------------------------------------------------------