scf-service-stack
Version:
A set for developing a cloud function
152 lines (143 loc) • 4.8 kB
JavaScript
const http = require('http'),
https = require('https'),
express = require('express');
const bodyParser = require('body-parser');
const parse = (rawBody) => {
const params = rawBody.split('&');
const body = {};
for (let i = 0; i < params.length; i++) {
const str = params[i].split('=');
body[str[0]] = str[1];
}
return body;
};
class SCFSimulator {
setEnv(env) {
for (let key in env) {
process.env[key] = env[key];
}
}
getDecoratedRequest(req, rawBody) {
const getPathAndParameters = (url) => {
let pathEndIndex = url.indexOf('?');
pathEndIndex = pathEndIndex > -1 ? pathEndIndex : url.length;
return {
path: url.substring(0, pathEndIndex),
parameters:
pathEndIndex === url.length
? {}
: parse(url.substring(pathEndIndex + 1))
};
};
const request = {};
const queryObject = getPathAndParameters(req.url);
request.headers = req.headers;
request.path = queryObject.path;
request.httpMethod = req.method;
request.requestContext = {
requestId: 'mock-request-' + new Date().getTime(),
envId: this.envConfig.context.envId,
appId: this.envConfig.context.appId,
uin: this.envConfig.context.uin
};
request.queryStringParameters = queryObject.parameters;
if (typeof rawBody === 'object') {
request.body = JSON.stringify(rawBody);
} else {
request.body = rawBody;
}
if (req.headers) {
req.headers[`x-forwarded-proto`] = req.headers[`x-client-proto`] =
this.envConfig.protocol === 'https' ? 'https' : 'http';
req.headers[`x-client-proto-ver`] = `HTTP/${req.httpVersion}`;
req.headers[`x-real-ip`] = req.headers[`x-forwarded-for`] =
req.connection.remoteAddress;
}
req.headers[`isBase64Encoded`] = false;
return request;
}
resolve(req, res, body) {
this.entrance(this.getDecoratedRequest(req, body), {})
.then((response) => {
res.send(response);
})
.catch((e) => {
console.error(e.stack);
res.status(500).send('Something broke!');
});
}
constructor(envConfig) {
// TODO deploy different scfs
this.envConfig = envConfig;
this.setEnv(envConfig.functionEnvVariables);
}
deploy(entrance, httpsOptions) {
this.entrance = entrance;
const app = express();
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
app.use(bodyParser.json({limit: '50mb'}));
const self = this;
app.use((req, res, next) => {
self
.entrance(this.getDecoratedRequest(req, req.body), {})
.then((response) => {
if (typeof response === 'string' || typeof response === 'number') {
res
.status(200)
.set({
'Content-Length': Buffer.byteLength(response + ''),
'Content-Type': 'text/plain'
})
.end(response);
} else if (typeof response === 'object') {
if (response.statusCode) {
response.headers = Object.assign(
response.headers,
response.multiValueHeaders || {}
);
if (typeof response.body === 'object') {
res
.status(response.statusCode)
.set(response.headers)
.send(response.body);
} else {
let body;
if (response.isBase64Encoded) {
body = new Buffer(response.body, 'base64');
} else {
body = response.body;
}
res.status(response.statusCode).set(response.headers).end(body);
}
} else {
res
.status(200)
.set({
'Content-Length': Buffer.byteLength(JSON.stringify(response)),
'Content-Type': 'application/json'
})
.end(JSON.stringify(response));
}
}
})
.catch((e) => {
console.error(e.stack);
res.status(500).send(e.message);
});
});
let server;
if (this.envConfig.protocol === 'https') {
server = https.createServer(httpsOptions, app);
} else {
server = http.createServer(app);
}
server.listen(this.envConfig.port || 3001);
console.log(
`the mock service has been setup at ${
this.envConfig.protocol === 'https' ? 'https' : 'http'
}://localhost:${this.envConfig.port || 3001}`
);
return server;
}
}
module.exports = SCFSimulator;