165 lines
3.8 KiB
JavaScript
165 lines
3.8 KiB
JavaScript
|
const path = require('path');
|
||
|
const dotenv = require('dotenv');
|
||
|
const cwd = process.cwd();
|
||
|
['.common.env', '.dev.env', '.env'].forEach((filename) => {
|
||
|
dotenv.config({path: path.join(cwd, filename)});
|
||
|
});
|
||
|
|
||
|
const {fork} = require('child_process');
|
||
|
|
||
|
const chalk = require('chalk');
|
||
|
|
||
|
const {servicesList} = require('@truss/core');
|
||
|
|
||
|
const services = servicesList();
|
||
|
|
||
|
const longestServiceNameLength = services.reduce((l, r) => {
|
||
|
return (r.length > l.length) ? r : l;
|
||
|
}, '').length;
|
||
|
|
||
|
let color = 1;
|
||
|
const colors = [
|
||
|
'redBright', 'greenBright', 'yellowBright', 'blueBright', 'magentaBright',
|
||
|
'cyanBright', 'whiteBright', 'red', 'green', 'yellow', 'blue', 'magenta',
|
||
|
'cyan', 'white', 'gray',
|
||
|
];
|
||
|
|
||
|
const children = [];
|
||
|
const childrenOfService = {};
|
||
|
|
||
|
const bundleServices = (process.env.BUNDLE_SERVICES || '').split(',');
|
||
|
const serviceCounts = bundleServices.reduce((l, r) => {
|
||
|
const [service, count = 1] = r.split(':');
|
||
|
if (service in l) { l[service] = count; }
|
||
|
return l;
|
||
|
}, services.reduce((l, r) => {
|
||
|
l[r] = 1;
|
||
|
return l;
|
||
|
}, {}));
|
||
|
|
||
|
services.forEach((service) => {
|
||
|
for (let i = 0; i < serviceCounts[service]; ++i) {
|
||
|
forkService(service);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function forkService(service) {
|
||
|
|
||
|
const servicePath = path.join(cwd, 'dist', 'production', service);
|
||
|
// const servicePath = path.join(cwd, 'services', service);
|
||
|
|
||
|
let index;
|
||
|
const colorizer = chalk[colors[color++]];
|
||
|
const dresser = (line) => {
|
||
|
const prefix = colorizer(`${(index + '').padStart(2, '0')} » ${
|
||
|
service.padEnd(longestServiceNameLength)
|
||
|
} |`);
|
||
|
console.error(`${prefix} ${line}`);
|
||
|
};
|
||
|
const logger = (message) => {
|
||
|
message.split('\n').forEach(dresser);
|
||
|
};
|
||
|
|
||
|
const child = fork(servicePath, [], {
|
||
|
env: Object.assign({
|
||
|
SOURCE_PATH: servicePath,
|
||
|
}, process.env),
|
||
|
execArgv: [],
|
||
|
stdio: 'pipe',
|
||
|
});
|
||
|
|
||
|
const forwardStream = (data) => {
|
||
|
logger(data.toString('utf8').replace(/\n$/, ''));
|
||
|
};
|
||
|
child.stdout.on('data', forwardStream);
|
||
|
child.stderr.on('data', forwardStream);
|
||
|
|
||
|
childrenOfService[service] = childrenOfService[service] || [];
|
||
|
childrenOfService[service].push(child);
|
||
|
|
||
|
index = children.length;
|
||
|
logger(`forking...`);
|
||
|
children.push(child);
|
||
|
|
||
|
const createChildActions = (child) => {
|
||
|
const actions = createActions(child);
|
||
|
return (action) => {
|
||
|
actions[action.type](action);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
child.on('message', createChildActions(child));
|
||
|
}
|
||
|
|
||
|
function createActions (child) {
|
||
|
|
||
|
return {
|
||
|
|
||
|
listening: () => (child.listening = true),
|
||
|
|
||
|
connect: ({payload: {clientId, service}}) => {
|
||
|
|
||
|
const candidate = randomService(service);
|
||
|
if (candidate) {
|
||
|
|
||
|
candidate.send({
|
||
|
type: 'connection_from',
|
||
|
payload: {
|
||
|
clientId,
|
||
|
from: children.indexOf(child),
|
||
|
},
|
||
|
});
|
||
|
|
||
|
child.send({
|
||
|
type: 'connection_to',
|
||
|
payload: {
|
||
|
clientId,
|
||
|
to: children.indexOf(candidate),
|
||
|
},
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
child.send({
|
||
|
type: 'connection_error',
|
||
|
payload: {
|
||
|
clientId,
|
||
|
},
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
client_send: ({payload}) => {
|
||
|
children[payload.to].send({
|
||
|
type: 'server_recv',
|
||
|
payload: {
|
||
|
clientId: payload.clientId,
|
||
|
data: payload.data,
|
||
|
},
|
||
|
});
|
||
|
},
|
||
|
|
||
|
server_send: ({payload}) => {
|
||
|
children[payload.to].send({
|
||
|
type: 'client_recv',
|
||
|
payload: {
|
||
|
clientId: payload.clientId,
|
||
|
data: payload.data,
|
||
|
},
|
||
|
});
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function randomService(service) {
|
||
|
|
||
|
const candidates = [...childrenOfService[service]];
|
||
|
while (candidates.length > 0) {
|
||
|
const index = Math.floor(Math.random() * candidates.length);
|
||
|
const [candidate] = candidates.splice(index, 1);
|
||
|
if (candidate.listening) {
|
||
|
return candidate;
|
||
|
}
|
||
|
}
|
||
|
}
|