40
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Lambdaでジャンケンゲームを作ろう

Last updated at Posted at 2014-11-26

概要

Lambdaでジャンケンゲームを作ります。
http://lambda-janken.s3-website-ap-northeast-1.amazonaws.com [停止中]

Screen Shot 2014-11-26 at 5.52.41 PM.png
※データが流れている部分を枠で表示しています
 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
Screen Shot 2014-11-26 at 5.52.49 PM.png
※グーチョキパーで結果を表示します
※素材:ごっこあそび - 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マネージメントコンソールから適当な名前でストリームを作成します。

setting
stream_name = LambdaJanken
ARN = arn:aws:kinesis:us-east-1:xxxxxxxxxx:stream/LambdaJanken
number of shard = 1

SQS 設定

AWSマネージメントコンソールから適当な名前でキューを作成します。

setting
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を作成します。

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を作成、アップロードします。

upload-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からイベントをアタッチします。

add-event-source
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マネージメントコンソールから適当な名前でプールを作成します。

setting
identity_pool_name = LambdaJanken
identity_pool_id = us-east-1:cf2xxxx-1xxx-4xxx-9xxx-1856xxxxxxxx
Unauthenticated Identities is checked

IAM 設定

Cognito_LambdaJankenUnauth_DefaultRole
{
    "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"
    }
  ]
}
Entities-cognito-identity.amazonaws.com
{
  "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 作成

index.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へアップロードして公開します。

免責
こちらは個人の意見で会社とは関係ありません。

40
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?