Created
May 9, 2019 19:44
-
-
Save fcmendoza/835ff97e682a69503757f11191c68e4b to your computer and use it in GitHub Desktop.
Go Go Power Rangers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// See comments for examples. |
Push to Kinesis
package main
import (
"encoding/json"
"flag"
"fmt"
"math/rand"
"os"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/kinesis"
)
type testItem struct {
StatusTime string
Groups []string
DonationAmount float64
}
func main() {
donationPtr := flag.Float64("donation-amount", 0, "a float64")
groupPtr := flag.String("groups", "", "a string")
flag.Parse()
groupsEmpty := make([]string, 0)
groups := strings.Split(*groupPtr, ",")
fmt.Println("groups:", groups)
fmt.Println("donation amount:", *donationPtr)
if *groupPtr != "" {
start(donationPtr, groups)
} else {
start(donationPtr, groupsEmpty)
}
}
func start(donationAmount *float64, groups []string) {
name := flag.String("name", "Shadowfax", "Unicorn Name")
stream := flag.String("stream", "hackathon-donations-datastream", "Stream Name")
flag.Parse()
sess := session.Must(
session.NewSessionWithOptions(
session.Options{
SharedConfigState: session.SharedConfigEnable,
},
),
)
submitData(kinesis.New(sess), name, stream, donationAmount, groups)
}
func submitData(client *kinesis.Kinesis, name, stream *string, donationAmount *float64, groups []string) {
rand.Seed(time.Now().UnixNano())
status, _ := json.Marshal(
&testItem{
StatusTime: time.Now().Format("2006-01-02 15:04:05.000"),
Groups: groups,
DonationAmount: *donationAmount,
},
)
putRecordInput := &kinesis.PutRecordInput{
Data: append([]byte(status), "\n"...),
PartitionKey: name,
StreamName: stream,
}
if _, err := client.PutRecord(putRecordInput); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Print(".")
}
You need to have your AWS keys in ~/.aws
or set environment keys; for example:
# These keys are invalid in case you're wondering if they work
export AWS_REGION=us-east-2
export AWS_ACCESS_KEY_ID=ASIAZ2AROKC7R6FMSNN5
export AWS_SECRET_ACCESS_KEY=B952zZmzi0/aNmXiKPQ8vaMQ9iAkReZMmZtLlWqd
export AWS_SESSION_TOKEN=FQoGZXIvYXdzEMH//////////wEaDIaAtn7RO5T7O9klzSKyAjOsHvMKi8ex0R5azJ+E+3r11DT/ReK1mPVR4SbBXt4CZSpzs7+/ajzD84MidDyYOaF+GuvTDNQnX89DhCTHqpl10VFlrVqYgeplozJbwC2AR5hy/njZa2637PQb4DmKm02eDx5nC/tJ0Fi8FBPFaD78tC2X0lJUsCTsck5S0FaDhxRClf/wZ0x2xIBL+nfHqWvd9oZTgnYv2du/3QpWH4V/afrsdBX6QTvuxfr8pcSlRzl2nMn7mEvBu+uoVMbzO3hCaqMiWNl4bM7qmjGKQfS47SguL+eBX7P55G+9XEJFJZdop8V0ISfFeRR/8NJjYoyXnxaGXHvgIVHM2PUqsvRKZjOfuZpVL6L3OnYnrnrs6RsGrTLbZWNAY0ce6rSJIFkChRV5y+kZ6K2nmhuWjNwRWCjO3InoBQ==
Then you can run it passing in arguments:
go build push.go
./push -donation-amount=5 -groups=fsfp,frth
Lambda in Nodejs
const AWS = require('aws-sdk');
var dbClient = new AWS.DynamoDB.DocumentClient();
require('./patch.js'); // apply the patch
var apigwManagementApi = new AWS.ApiGatewayManagementApi({
apiVersion: '2018-11-29',
endpoint: '2dbxbx3s5j.execute-api.us-east-2.amazonaws.com' + '/' + 'test'
});
exports.handler = function(event, context) {
//console.log(event);
//console.log(JSON.stringify(event, null, 2));
if (event.Records) { // event is Kinesis
event.Records.forEach(function(record) {
// Kinesis data is base64 encoded so decode here
var payload = new Buffer(record.kinesis.data, 'base64').toString('ascii');
console.log('Decoded payload:', payload);
var data = JSON.parse(payload);
var groups = data.Groups || [];
var expressions = [];
for (var g of groups) {
expressions.push(`votes.${g}.vote_count = votes.${g}.vote_count + :v`);
}
expressions.push("total_donation_amount = total_donation_amount + :d");
var update_expression = "set " + expressions.join(", "); // e.g.: "set votes.fsfp.vote_count = votes.fsfp.vote_count + :v, votes.pow.vote_count = votes.pow.vote_count + :v"
console.log(update_expression);
var update_params = {
TableName : 'hackathon-donations-api-totals',
Key:{
"TotalsID": 2
},
UpdateExpression: update_expression,
ReturnValues:"UPDATED_NEW"
};
update_params.ExpressionAttributeValues = groups.length == 0 // can't update vote counts if no groups were provided
? { ":d":data.DonationAmount ? data.DonationAmount : 0 }
: {
":v":1,
":d":data.DonationAmount ? data.DonationAmount : 0
};
console.log("Updating the item...");
dbClient.update(update_params, function(err, data) {
if (err) {
console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("UpdateItem succeeded:", JSON.stringify(data, null, 2));
}
});
//
// TODO: Another lambda should take care of processing a dyanmo stream (everytime counts are updated) and push to the API Gateway
//
var table_params = {
TableName: 'hackathon-donations-api-totals',
Key: {
"TotalsID": 2
}
};
dbClient.get(table_params, function(err, data) {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
} else {
// GetItem succeeded
var resp = data.Item;
delete resp.TotalsID;
//console.log(JSON.stringify(resp));
post_to_clients(resp);
}
});
});
}
if (event.requestContext) { // event is API Gateway
console.log("not supported for now");
}
//var groups = ["fsfp", "pow"];
};
function post_to_clients(jsondata) {
console.log('Posting data:', JSON.stringify(jsondata));
var table_params = {
TableName: 'hackathon-donations-api-connections',
Item: {
'ConnectionID' : {N: '001'}
}
};
dbClient.scan(table_params, function (err, data) {
if (err)
console.log('error when scanning db.');
else {
//console.log('Connections found.');
for (var i = 0; i < data.Items.length; i++) {
var connectionId = data.Items[i].ConnectionID;
console.log("Connection found:", connectionId);
var params = {
ConnectionId: connectionId,
Data: JSON.stringify(jsondata)
};
apigwManagementApi.postToConnection(params, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log("Message sent to", params.ConnectionId); // successful response
});
}
}
});
}
Patch.js
require('aws-sdk/lib/node_loader');
var AWS = require('aws-sdk/lib/core');
var Service = AWS.Service;
var apiLoader = AWS.apiLoader;
apiLoader.services['apigatewaymanagementapi'] = {};
AWS.ApiGatewayManagementApi = Service.defineService('apigatewaymanagementapi', ['2018-11-29']);
Object.defineProperty(apiLoader.services['apigatewaymanagementapi'], '2018-11-29', {
get: function get() {
var model = {
"metadata": {
"apiVersion": "2018-11-29",
"endpointPrefix": "execute-api",
"signingName": "execute-api",
"serviceFullName": "AmazonApiGatewayManagementApi",
"serviceId": "ApiGatewayManagementApi",
"protocol": "rest-json",
"jsonVersion": "1.1",
"uid": "apigatewaymanagementapi-2018-11-29",
"signatureVersion": "v4"
},
"operations": {
"PostToConnection": {
"http": {
"requestUri": "/@connections/{connectionId}",
"responseCode": 200
},
"input": {
"type": "structure",
"members": {
"Data": {
"type": "blob"
},
"ConnectionId": {
"location": "uri",
"locationName": "connectionId"
}
},
"required": [
"ConnectionId",
"Data"
],
"payload": "Data"
}
}
},
"shapes": {}
}
model.paginators = {
"pagination": {}
}
return model;
},
enumerable: true,
configurable: true
});
module.exports = AWS.ApiGatewayManagementApi;
Understanding functions
// C# version
string doSomething(string ctx, int timeout) {
return ctx + timeout.ToString();
}
// Go version
func doSomething(ctx string, timeout int) string {
return ctx + strconv.Itoa(timeout)
}
Pointers
Super basic
name := "Jon"
fmt.Println("\nValue of *name* is", name)
fmt.Println("Memory value of *name* is", &name)
ptr := &name
fmt.Println("Pointer to *name* address is", ptr)
Value of *name* is Jon
Memory value of *name* is 0xc0000381d0
Pointer to *name* address is 0xc0000381d0
Basic
func main() {
name := "Jon"
fmt.Println("\nValue of *name* is", name)
fmt.Println("Memory value of *name* is", &name)
ptr := &name
fmt.Println("Pointer (ptr) to *name* address is", ptr)
var pun = &name
fmt.Println("Pointer (pun) to *name* address is", pun)
var poi *string = &name // the type *string is optional here
fmt.Println("Pointer (poi) to *name* address is", poi)
someByRef(&name)
}
func someByRef(some *string) {
fmt.Println("Value of *some* is", some, "and its value is", *some)
}
Value of *name* is Jon
Memory value of *name* is 0xc0000381d0
Pointer (ptr) to *name* address is 0xc0000381d0
Pointer (pun) to *name* address is 0xc0000381d0
Pointer (poi) to *name* address is 0xc0000381d0
Value of *some* is 0xc0000381d0 and its value is Jon
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Functions in structs
Output:
Implicit implementation
I think
DasError
implementserror
implicitly by virtue of having anError
method as part of it:and because we're defining the
oops
function to returnerror
we can safely return aDasError
type here:References