概要
Lambdaでジャンケンゲームを作ります。
http://lambda-janken.s3-website-ap-northeast-1.amazonaws.com [停止中]
※データが流れている部分を枠で表示しています
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
※グーチョキパーで結果を表示します
※素材:ごっこあそび - http://gokkoasobi.com/omen_jyanken.html
AWSのサービスをフル活用します。
「JavaScriptだけで出来るやん・・」というツッコミは置いておいて、以下のサービスを組み合わせて実装します。
Amazon Cognito
Amazon Kinesis
Amazon Lambda
Amazon SQS
Amazon S3
ブラウザで受けたリクエストをKinesis に流し込み、これを受けて発火したLambdaファンクションで、グー・チョキ・パーを表す乱数を生成し、SQSにメッセージとしてに結果をキューイングします。ブラウザはキューイングされたSQSを取得し、グー・チョキ・パーのイラストを表示して切り替えます。
※現時点でLambdaはプレビューのため、すべて us-east-1 リージョンを利用します。
Kinesis 設定
AWSマネージメントコンソールから適当な名前でストリームを作成します。
stream_name = LambdaJanken
ARN = arn:aws:kinesis:us-east-1:xxxxxxxxxx:stream/LambdaJanken
number of shard = 1
SQS 設定
AWSマネージメントコンソールから適当な名前でキューを作成します。
queue_name = LambdaJanken
URL = https://sqs.us-east-1.amazonaws.com/xxxxxxxxxx/LambdaJanken"
ARN = arn:aws:sqs:us-east-1: xxxxxxxxxx:LambdaJanken
Lambda 設定
index.jsを作成します。
var aws = require('aws-sdk');
var kinesis = new aws.Kinesis({region:'us-east-1'});
var sqs = new aws.SQS({region:'us-east-1'});
exports.handler = function(event, context) {
var rand = Math.floor( Math.random() * 3 );
var params = {
MessageBody: String(rand),
QueueUrl: 'https://sqs.us-east-1.amazonaws.com/xxxxxxxxxx/LambdaJanken',
DelaySeconds: 0,
};
sqs.sendMessage(params, function(err, data) {
if (err) {
console.log(err, err.stack);
}else{
console.log(data);
context.done();
}
});
}
index.jsをzip化して、index.zipを作成します。
AWS CLIからFunctionを作成、アップロードします。
aws lambda upload-function \
--region us-east-1 \
--function-name LambdaJanken \
--function-zip index.zip \
--runtime nodejs \
--role arn:aws:iam::xxxxxxxxxx:role/lambda_exec_role \
--handler index.handler \
--mode event \
--timeout 30
AWS CLIからイベントをアタッチします。
aws lambda add-event-source \
--region us-east-1 \
--function-name LambdaJanken \
--role arn:aws:iam::xxxxxxxxxx:stream:role/lambda_invoke_role \
--event-source arn:aws:kinesis:us-east-1:xxxxxxxxxx:stream/LambdaJanken \
--batch-size 1 \
--parameters InitialPositionInStream=LATEST
Cognito 設定
AWSマネージメントコンソールから適当な名前でプールを作成します。
identity_pool_name = LambdaJanken
identity_pool_id = us-east-1:cf2xxxx-1xxx-4xxx-9xxx-1856xxxxxxxx
Unauthenticated Identities is checked
IAM 設定
{
"Version": "2012-10-17",
"Statement": [{
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*"
],
"Effect": "Allow",
"Resource": [
"*"
]
}]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kinesis:*",
"Resource": "arn:aws:kinesis:us-east-1:xxxxxxxxxx:stream/LambdaJanken"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sqs:*"
],
"Effect": "Allow",
"Resource": "arn:aws:sqs:us-east-1:xxxxxxxxxx:LambdaJanken"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:cxxxxx-1xxx-4xxx-9xxx-1xxxxxxxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "unauthenticated"
}
}
}
]
}
HTML 作成
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lambda ジャンケン</title>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.28.min.js"></script>
<style type="text/css"><!--
.waku{ position: absolute; top: 180px; left: 95px; z-index: 1; }
.gu{ position: absolute; top: 20px; left: 180px; z-index: 1; display: none; }
.choki{ position: absolute; top: 20px; left: 180px; z-index: 1; display: none; }
.pa{ position: absolute; top: 20px; left: 180px; z-index: 1; display: none; }
textarea { margin-left: 50px; width: 850px; height: 300px; line-height: 1.5em; }
--></style>
</head>
<body>
<img src="LambdaJanken.png" />
<img src="LambdaJanken_waku.png" class="waku" id="waku" />
<img src="gu.png" class="gu" id="gu" />
<img src="choki.png" class="choki" id="choki" />
<img src="pa.png" class="pa" id="pa" />
<textarea cols="40" rows="7" id="tex"></textarea>
<p style="padding-left:50px">素材提供:ごっこあそび - http://gokkoasobi.com/omen_jyanken.html</p>
<script>
var janken;
var tex = document.getElementById('tex');
var waku = document.getElementById('waku');
//Cognito
var params = {
AccountId: "xxxxxxx",
RoleArn: "arn:aws:iam::xxxxxxx:role/Cognito_LambdaJankenUnauth_DefaultRole",
IdentityPoolId: "us-east-1:cxxxxxx-1xxx-4xxx-9xxx-1xxxxxxx"
};
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials(params);
AWS.config.credentials.get(function(err) {
if (!err) {
//Log
tex.value = tex.value + "===== Cognito authentication =====" + "\n"
tex.value = tex.value + "Cognito Identity Id: " + AWS.config.credentials.identityId + "\n";
//CSS
waku.style.left = "280px";
}
});
//Kinesis
var kinesis = new AWS.Kinesis();
var params1 = {
Data: 'Hello', /* required */
PartitionKey: 'partitionkey', /* required */
StreamName: 'LambdaJanken', /* required */
};
kinesis.putRecord(params1, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
}else{
//Log
tex.value = tex.value + "===== Kinesis put object =====" + "\n";
tex.value = tex.value + "SequenceNumber: " + data.SequenceNumber + "\n";
tex.value = tex.value + "ShardId: " + data.ShardId + "\n";
//Lambda
tex.value = tex.value + "===== Lambda invoke function =====" + "\n";
//CSS
waku.style.left = "465px";
//Log
tex.value = tex.value + "===== SQS send message =====" + "\n";
//SQS
var sqs = new AWS.SQS();
var params2 = {
QueueUrl: 'https://sqs.us-east-1.amazonaws.com/xxxxxxxx/LambdaJanken', /* required */
MaxNumberOfMessages: 1,
WaitTimeSeconds: 5
};
sqs.receiveMessage(params2, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}else{
janken = data.Messages[0].Body;
//CSS
waku.style.left = "650px";
//Log
tex.value = tex.value + "===== SQS retrieve message =====" + "\n";
tex.value = tex.value + "ReceiptHandle: " + data.Messages[0].ReceiptHandle + "\n";
tex.value = tex.value + "Body: " + data.Messages[0].Body + "\n";
var params3 = {
QueueUrl: 'https://sqs.us-east-1.amazonaws.com/xxxxxxxxxxx/LambdaJanken', /* required */
ReceiptHandle: data.Messages[0].ReceiptHandle /* required */
};
sqs.deleteMessage(params3, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
}else{
//Log
tex.value = tex.value + "===== SQS delete message =====" + "\n";
tex.value = tex.value + "RequestId: " + data.ResponseMetadata.RequestId + "\n";
//CSS
waku.style.display = "none";
//Display Janken
switch (Number(janken)){
case 0:
var ele = document.getElementById('gu');
ele.style.display = "block";
break;
case 1:
var ele = document.getElementById('choki');
ele.style.display = "block";
break;
case 2:
var ele = document.getElementById('pa');
ele.style.display = "block";
break;
}
}
});
}
});
}
});
</script>
</body>
</html>
|-index.html(本体)
|-LambdaJanken.png (背景)
|-LambdaJanken_waku.png (オレンジ枠)
|-gu.png(グー)
|-choki.png(チョキ)
|-pa.png(パー)
これらファイルをS3へアップロードして公開します。
免責
こちらは個人の意見で会社とは関係ありません。