index.js 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. 'use strict';
  2. const execa = require('execa');
  3. const macos = () => execa.stdout('netstat', ['-anv', '-p', 'tcp'])
  4. .then(data => Promise.all([data, execa.stdout('netstat', ['-anv', '-p', 'udp'])]))
  5. .then(data => data.join('\n'));
  6. const linux = () => execa.stdout('ss', ['-tunlp']);
  7. const win32 = () => execa.stdout('netstat', ['-ano']);
  8. const getListFn = process.platform === 'darwin' ? macos : process.platform === 'linux' ? linux : win32;
  9. const cols = process.platform === 'darwin' ? [3, 8] : process.platform === 'linux' ? [4, 6] : [1, 4];
  10. const isProtocol = x => /^\s*(tcp|udp)/i.test(x);
  11. const parsePid = input => {
  12. if (typeof input !== 'string') {
  13. return null;
  14. }
  15. const match = input.match(/(?:^|",|",pid=)(\d+)/);
  16. return match ? parseInt(match[1], 10) : null;
  17. };
  18. const getPort = (input, list) => {
  19. const regex = new RegExp(`[.:]${input}$`);
  20. const port = list.find(x => regex.test(x[cols[0]]));
  21. if (!port) {
  22. throw new Error(`Couldn't find a process with port \`${input}\``);
  23. }
  24. return parsePid(port[cols[1]]);
  25. };
  26. const getList = () => getListFn().then(list => list
  27. .split('\n')
  28. .reduce((result, x) => {
  29. if (isProtocol(x)) {
  30. result.push(x.match(/\S+/g) || []);
  31. }
  32. return result;
  33. }, [])
  34. );
  35. module.exports = input => {
  36. if (typeof input !== 'number') {
  37. return Promise.reject(new TypeError(`Expected a number, got ${typeof input}`));
  38. }
  39. return getList().then(list => getPort(input, list));
  40. };
  41. module.exports.all = input => {
  42. if (!Array.isArray(input)) {
  43. return Promise.reject(new TypeError(`Expected an array, got ${typeof input}`));
  44. }
  45. return getList()
  46. .then(list => Promise.all(input.map(x => [x, getPort(x, list)])))
  47. .then(list => new Map(list));
  48. };
  49. module.exports.list = () => getList().then(list => {
  50. const ret = new Map();
  51. for (const x of list) {
  52. const match = x[cols[0]].match(/[^]*[.:](\d+)$/);
  53. if (match) {
  54. ret.set(parseInt(match[1], 10), parsePid(x[cols[1]]));
  55. }
  56. }
  57. return ret;
  58. });