LoginSignup
40
37

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