Skip to content

Instantly share code, notes, and snippets.

/instructions.md Secret

Created January 8, 2018 21:47
Show Gist options
  • Save anonymous/fcff2bfdd3ddd8a7862eeac4299b68ae to your computer and use it in GitHub Desktop.
Save anonymous/fcff2bfdd3ddd8a7862eeac4299b68ae to your computer and use it in GitHub Desktop.
Moreland Ave traffic single-datapoint site with Amazon Lambda, for NICAR
  1. Log in to your Amazon AWS account. What we're doing should be totally free, so you can use your personal account. We'll tell you how to disable the function when we're done, but it should likely be free forever (or maybe like a penny if you use it a TON).
  2. Go to create a new Lambda function here: https://console.aws.amazon.com/lambda/home?region=us-east-1#/create
  3. Fill in the form:
    • Name: whatever you want, maybe "NICAR18: serverless single-datapoint site"
    • Runtime:
    • Role: "Create new role from template(s)"
    • Role name: whatever you want, maybe "nicar18-serverless-site-role"
    • Policy templates: Basic Lambda Permissions or Basic Edge Lambda Permissions (This gives our Lambda just enough permissions to run, but not to do anything else.)
  4. Click "Create Function"
  5. You should get a little weird tree diagram, with the name for your Lambda up top, with a right-branching line (for outputs) going to Amazon Cloudwatch Logs and a left-branching line (for inputs) going to a blank list.
  6. To the left of that tree diagram, under "Add Triggers" hit "API Gateway". Configuring this will let us create our little ugly website.
  7. Scroll down to see Configure Triggers. This is where we're configuring the API Gateway, a.k.a. the piece of Amazon software that triggers our Lambda function when someone visits the URL and displays the Lambda function's output.
    • You can set the API Name to whatever you want.
    • You can leave the Deployment Stage as 'prod'.
    • Set Security to "Open". We're not going to tell anyone about the secret URL this generates and it's not like there are the crown jewels in here anyways. :)
    • Click Add (in the bottom right) when you're done, to save our API Gateway trigger.
  8. Click the orange Save button in the top right to save the whole thing.
  9. Now that we've set up all the plumbing, we have to actually write the function. Luckily for you, I already wrote it. In that tree diagram, click the top element, with the name of your Lambda function. Paste the code below in there. Then hit the top-right orange Save button again.
  10. Okay, now go back to that tree diagram and back to the API Gateway thing. Scroll down and you'll see an ugly URL called to "Invoke URL". Click it. You should see your page.
function jeremys_gross_xml_parser(xml){
var split_features = xml.split("</speeds_feature>")
var output = {"N": null, "S": null}
split_features.forEach(function(feature){
if(feature.indexOf("<route>SR 42/Moreland Ave</route>") >= 0 && feature.indexOf("<dir>N</dir>") >= 0){
var key = "N"
}else if(feature.indexOf("<route>SR 42/Moreland Ave</route>") >= 0 && feature.indexOf("<dir>S</dir>") >= 0){
var key = "S"
}else{
return
}
output[key] = parseInt(feature.split("<mph>")[1].split("</mph>")[0])
})
return output;
}
exports.handler = function(event, context){
var http = require('http');
var options = {
host: 'ga511maps0.iteriscdn.com',
port: 80,
path: '/mapserv/511ga-traffic/?LAYERS=all&QUERY_LAYERS=all&STYLES=&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&BBOX=-9390143.427899%2C3996082.6502%2C-9388160.842479%2C3998652.845275&FEATURE_COUNT=10&HEIGHT=538&WIDTH=415&FORMAT=image%2Fpng&INFO_FORMAT=application%2Fvnd.ogc.gml&SRS=EPSG%3A900913&X=96&Y=200'
};
http.get(options, function(resp){
resp.setEncoding("utf8");
let body = "";
resp.on("data", data => {
body += data;
});
resp.on('end', function(){
var output = jeremys_gross_xml_parser(body);
if (output["N"] > 30 && output["S"] > 30){
context.done(null, {statusCode: 200, headers: {"Content-Type": "text/html"}, body: "<html><head><title>How's Moreland Ave Traffic?</title></head></body><h1>Moreland Ave traffic is fine</h1></body></html>"})
}else if(output["N"] > 20 && output["S"] > 20){
context.done(null, {statusCode: 200, headers: {"Content-Type": "text/html"}, body: "<html><head><title>How's Moreland Ave Traffic?</title></head></body><h1>Moreland Ave traffic is kinda slow</h1></body></html>"})
}else{
context.done(null, {statusCode: 200, headers: {"Content-Type": "text/html"}, body: "<html><head><title>How's Moreland Ave Traffic?</title></head></body><h1>You'd be better off walking on Moreland Ave.</h1></body></html>"})
}
});
}).on("error", function(e){
console.log("Got error: " + e.message);
context.done("Got error: " + e.message, null)
});
}
if (require.main === module) {
exports.handler(null, {done: function(err, output){console.log("would return", output)} })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment