Skip to content

Commit b111c37

Browse files
authored
Merge pull request #7 from amasses/support-all-proxy-runtimes
Updated support to cover Proxy-runtimes (python, ruby) not just python
2 parents 734e0a3 + 838767b commit b111c37

File tree

8 files changed

+81
-63
lines changed

8 files changed

+81
-63
lines changed

manual_test/handler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module.exports.hello = (event, context, callback) => {
44
const response = {
55
statusCode: 200,
66
body: JSON.stringify({
7-
message: 'Go Serverless v1.0! Your function executed successfully!',
7+
message: 'NodeJS Go Serverless v1.0! Your function executed successfully!',
88
input: event,
99
}),
1010
};

manual_test/handler.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
def hello(event, context):
3+
return {"statusCode": 200, "body": "{\"message\": \"hi there from python\"}"}

manual_test/handler.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require 'json'
2+
3+
def hello(event:, context:)
4+
begin
5+
# puts "Received Request (RUBY): #{event}"
6+
7+
{ statusCode: 200, body: JSON.generate("Ruby Go Serverless v1.0! Your function executed successfully! #{event['body']}") }
8+
rescue StandardError => e
9+
puts e.message
10+
puts e.backtrace.inspect
11+
{ statusCode: 400, body: JSON.generate("Bad request, please POST a request body!") }
12+
end
13+
end

manual_test/serverless.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
service: basic
1515

1616
plugins:
17-
- serverless-offline
17+
- serverless-offline-python
1818

1919
provider:
2020
name: aws
2121
runtime: nodejs4.3
22+
# runtime: ruby2.5
23+
# runtime: python2.7
2224
apiKeys:
2325
- token
2426
# you can overwrite defaults here

src/createAuthScheme.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ module.exports = function createAuthScheme(authFun, authorizerOptions, funName,
2222
identityHeader = identitySourceMatch[1].toLowerCase();
2323
}
2424

25-
// HACK: since handlerName is used to invoke python function locally,
25+
// HACK: since handlerName is used to invoke python/ruby (ie. a proxy runtime) function locally,
2626
// we have to pass the authFunName instead of funcName
27-
const funOptions = functionHelper.getFunctionOptions(authFun, utils.isPythonRuntime(serviceRuntime) ? authFunName : funName, servicePath, serviceRuntime);
27+
const funOptions = functionHelper.getFunctionOptions(authFun, utils.isProxyRuntime(serviceRuntime) ? authFunName : funName, servicePath, serviceRuntime);
2828

2929
// Create Auth Scheme
3030
return () => ({

src/functionHelper.js

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,60 +11,60 @@ const utils = require('./utils');
1111
const handlerCache = {};
1212
const messageCallbacks = {};
1313

14-
function runPythonHandler(funOptions, options) {
15-
var spawn = require("child_process").spawn;
16-
return function (event, context) {
17-
var args = ["invoke", "local", "-f", funOptions.funName]
18-
var stage = options.s || options.stage
19-
if (stage)
20-
args = args.concat(["-s", stage])
21-
22-
var process = spawn('sls', args,
23-
{ stdio: ['pipe', 'pipe', 'pipe'], shell: true, cwd: funOptions.servicePath });
24-
process.stdin.write(JSON.stringify(event) + "\n");
25-
process.stdin.end();
26-
let results = ''
27-
let hasDetectedJson = false;
28-
process.stdout.on('data', (data) => {
29-
let str = data.toString('utf8');
30-
if (hasDetectedJson) {
31-
// Assumes that all data after matching the start of the
32-
// JSON result is the rest of the context result.
33-
results = results + trimNewlines(str);
34-
} else {
35-
// Search for the start of the JSON result
36-
// https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
37-
const match = /{[\r\n]\s+"isBase64Encoded"|{[\r\n]\s+"statusCode"|{[\r\n]\s+"headers"|{[\r\n]\s+"body"|{[\r\n]\s+"principalId"/.exec(str);
38-
if (match && match.index > -1) {
39-
// The JSON result was in this chunk so slice it out
40-
hasDetectedJson = true;
41-
results = results + trimNewlines(str.slice(match.index));
42-
str = str.slice(0, match.index);
43-
}
44-
45-
if(str.length > 0) {
46-
// The data does not look like JSON and we have not
47-
// detected the start of JSON, so write the
48-
// output to the console instead.
49-
console.log('Python:', '\x1b[34m' + str + '\x1b[0m');
50-
}
51-
}
52-
});
53-
process.stderr.on('data', (data) => {
54-
context.fail(data);
55-
});
56-
process.on('close', (code) => {
57-
if (code == 0) {
58-
try {
59-
context.succeed(JSON.parse(results));
60-
} catch (ex) {
61-
context.fail(results);
62-
}
63-
} else {
64-
context.succeed(code, results);
65-
}
66-
});
67-
}
14+
function runProxyHandler(funOptions, options) {
15+
var spawn = require("child_process").spawn;
16+
return function (event, context) {
17+
var args = ["invoke", "local", "-f", funOptions.funName]
18+
var stage = options.s || options.stage
19+
if (stage)
20+
args = args.concat(["-s", stage])
21+
22+
var process = spawn('sls', args,
23+
{ stdio: ['pipe', 'pipe', 'pipe'], shell: true, cwd: funOptions.servicePath });
24+
process.stdin.write(JSON.stringify(event) + "\n");
25+
process.stdin.end();
26+
let results = ''
27+
let hasDetectedJson = false;
28+
process.stdout.on('data', (data) => {
29+
let str = data.toString('utf8');
30+
if (hasDetectedJson) {
31+
// Assumes that all data after matching the start of the
32+
// JSON result is the rest of the context result.
33+
results = results + trimNewlines(str);
34+
} else {
35+
// Search for the start of the JSON result
36+
// https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
37+
const match = /{[\r\n]?\s*"isBase64Encoded"|{[\r\n]?\s*"statusCode"|{[\r\n]?\s*"headers"|{[\r\n]?\s*"body"|{[\r\n]?\s*"principalId"/.exec(str);
38+
if (match && match.index > -1) {
39+
// The JSON result was in this chunk so slice it out
40+
hasDetectedJson = true;
41+
results = results + trimNewlines(str.slice(match.index));
42+
str = str.slice(0, match.index);
43+
}
44+
45+
if(str.length > 0) {
46+
// The data does not look like JSON and we have not
47+
// detected the start of JSON, so write the
48+
// output to the console instead.
49+
console.log('Proxy Handler could not detect JSON:', '\x1b[34m' + str + '\x1b[0m');
50+
}
51+
}
52+
});
53+
process.stderr.on('data', (data) => {
54+
context.fail(data);
55+
});
56+
process.on('close', (code) => {
57+
if (code == 0) {
58+
try {
59+
context.succeed(JSON.parse(results));
60+
} catch (ex) {
61+
context.fail(results);
62+
}
63+
} else {
64+
context.succeed(code, results);
65+
}
66+
});
67+
}
6868
}
6969

7070

@@ -159,10 +159,10 @@ module.exports = {
159159
if (!key.match('node_modules')) delete require.cache[key];
160160
}
161161
}
162-
let user_python = true
162+
163163
let handler = null;
164-
if (utils.isPythonRuntime(funOptions['serviceRuntime'])) {
165-
handler = runPythonHandler(funOptions, options)
164+
if (utils.isProxyRuntime(funOptions['serviceRuntime'])) {
165+
handler = runProxyHandler(funOptions, options)
166166
} else {
167167
debugLog(`Loading handler... (${funOptions.handlerPath})`);
168168
handler = require(funOptions.handlerPath)[funOptions.handlerName];

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class Offline {
324324
const apiKeys = this.service.provider.apiKeys;
325325
const protectedRoutes = [];
326326

327-
if (['nodejs', 'nodejs4.3', 'nodejs6.10', 'nodejs8.10', 'babel', 'python2.7', 'python3.6'].indexOf(serviceRuntime) === -1) {
327+
if (['nodejs', 'nodejs4.3', 'nodejs6.10', 'nodejs8.10', 'babel', 'python2.7', 'python3.6', 'ruby2.5'].indexOf(serviceRuntime) === -1) {
328328
this.printBlankLine();
329329
this.serverlessLog(`Warning: found unsupported runtime '${serviceRuntime}'`);
330330

src/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ module.exports = {
1717
// Detect the toString encoding from the request headers content-type
1818
// enhance if further content types need to be non utf8 encoded.
1919
detectEncoding: request => _.includes(request.headers['content-type'], 'multipart/form-data') ? 'binary' : 'utf8',
20-
isPythonRuntime: runtime => runtime.startsWith('python')
20+
isProxyRuntime: runtime => { return runtime.startsWith('python') || runtime.startsWith('ruby') }
2121
};

0 commit comments

Comments
 (0)