server service
import http from 'http';
import Busboy from 'busboy';
import { createHash } from 'crypto';
export default {
create(){
return this;
},
start(apps = [{ name: 'main', host: '127.0.0.1', port: 3000 }]){
apps.forEach(({ name, host, port }) => {
const isTest = process.env.NODE_ENV == 'test';
http.createServer(async (request, response) => {
try {
const params = await this.extractParams(request);
if(!params._headers['x-app']) params._headers['x-app'] = name;
const [ status, headers, body ] = await this.fetch(params);
const etag = this.createHash(body);
if(params._headers['if-none-match'] == etag){
response.statusCode = 304;
response.end();
return;
}
headers.etag = etag;
response.statusCode = status;
Object.keys(headers).forEach(
(name) => response.setHeader(name, headers[name])
)
body.forEach(chunk => response.write(chunk));
response.end();
} catch (e){
response.statusCode = 500;
response.setHeader('content-type', 'text/plain');
response.end((e.stack || e).toString());
}
if(!isTest) console.log(`${request.method}: ${request.url} (${response.statusCode})`);
}).listen(port, host, () => {
if(!isTest) console.log(`Blognami running "${name}" app at "http://${host}:${port}/"`)
});
});
},
async extractParams(request){
const { method, url, headers } = request;
const _url = new URL(url, 'http://127.0.0.1');
const urlParams = {};
_url.searchParams.forEach((value, key) => {
urlParams[key] = value;
});
const body = method.match(/^POST|PUT|PATCH$/) ? await this.parseBody(request) : {};
return {
...urlParams,
...body,
_method: method,
_url,
_headers: headers
};
},
parseBody(request){
return new Promise((resolve) => {
const out = {};
const busboy = new Busboy({ headers: request.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimeType) {
const chunks = [];
file.on('data', chunk => {
chunks.push(Buffer.from(chunk));
});
file.on('end', () => {
out[fieldname] = {
filename,
encoding,
mimeType,
data: Buffer.concat(chunks)
};
});
});
busboy.on('field', (fieldname, value) => {
out[fieldname] = value
});
busboy.on('finish', () => resolve(out));
request.pipe(busboy);
});
},
createHash(data){
return createHash('sha1').update(JSON.stringify(data)).digest('base64');
}
};