やります。
今回こちらのアプリで件名の感じで、あれをこうしました。
ボールをゴールへドーン ios
ボールをゴールへドーン Android
ゲームはCocos2d-xで開発をしています。
ゲーム内で、ユーザー問題作成機能的なものを提供してそちらで使っています。
まずServerlessを使えるようにしないと話になりません。
Serverlessの導入はこちらを参考にしてみてはいかがでしょうか。
とことんサーバーレス①:Serverless Framework入門編
こちらも超参考にさせていただきました
Serverless Framework で DynamoDB を使う
Serverlessの導入ができたら、まずは単純なAPIを作成して、deployしてみましょう。
$ sls create --template aws-nodejs --name test
$ sls deploy -v
自分はnodejsを使うことにしましたが、pythonとかC#とか使えちゃうらしいですね。
最小の段階だと、lambdaが1個作られるだけなので、AWSの管理画面から確認する。
なんかできている。
あとはこれに付けたし付け足ししていこう。
まず、nodejsのパッケージを色々使うので、npmのセットアップをしたいと思う(意味わかってない)
$ npm init
(なんかいろいろでるので、いろいろする)
こんな感じで dependenciesを追加します。
意味?しるか。
$ npm install
とかやると、npmが関連ライブラリを調べてインストールしてくれます。
これはローカルに展開されるんですね。
最終的にServerlessでdeployしたときに、諸々の関連ファイルを全部zipで固めてアップしてくれる段取りになっているみたいです。
次にserverless.yamlを変更します。
ここに定義を書いていって、最終的にはCloudFormationとかいう機能を使うみたいですね。
それが、まとめたサーバー構成のセットアップ手順を定義する仕組みで、
簡単に構成を再構築することができるやつみたいな感じっていうかんじー?
....
provider:
name: aws
runtime: nodejs4.3
iamRoleStatements: # ロールを新たに追加します
- Effect: Allow
Action:
- dynamodb:DescribeTable
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:us-east-1:*:table/dev-test-*" #us-east-1リージョンの dev-test-なんたらってテーブル全部に権限あたえますよって感じ
functions:
hello:
handler: handler.hello
userCreate: #これがlambdaコマンドになる
handler: handler.userCreate #handler.js のどのメソッドを使うか
events: #lambdaを何経由で起動させるか
- http: # API Gatewayを使う
path: user # https://awsのどっか.../user というURLになる
method: post #意味わかるやろ
cors: true
userRead: #こいつは複数件よむやつ
handler: handler.userRead
events:
- http:
path: user
method: get
cors: true
userGet: #こいつは1件だけ読むやつ
handler: handler.userGet
events:
- http:
path: user/{id}
method: get
cors: true
resources: #必要なリソースを用意するよ!
Resources: #重要なので2回書きました
UserDbTable: #リソース識別名です。使われません
Type: 'AWS::DynamoDB::Table' #DynamoDB テーブルをつくるよ
DeletionPolicy: "Delete" #テーブルを容赦なく削除します。しない設定もある。調べろ
Properties: #細かい設定やで
AttributeDefinitions: #最低限必要となるカラム的なやつ
-
AttributeName: "id" #IDカラム
AttributeType: "S" #文字列型
-
AttributeName: "delfg" #削除フラグ、使わないけど使う
AttributeType: "N" #
-
AttributeName: "updt" #更新日時とかいれる、後にIndex使うためのカラム
AttributeType: "S" #
KeySchema: #主キー的なやつだよ
-
AttributeName: "id" #
KeyType: "HASH" #HASH形式にする 他何があったか忘れた
ProvisionedThroughput: #これがプロヴィジョニングのキャパシティだ!
ReadCapacityUnits: "1" #読み込みキャパ
WriteCapacityUnits: "1" #書込キャパ とりあえず1で後で管理画面から変えれる
GlobalSecondaryIndexes: #Index これがないと副次ソートできないの(TдT)
-
IndexName: "myUPDT" #なまえ
KeySchema:
-
AttributeName: "delfg" #これは固定値をいれるため
KeyType: "HASH" #
-
AttributeName: "updt" #並び替えをしたいカラム
KeyType: "RANGE" #
Projection: #投影するカラム(一緒に抽出したいカラム)
NonKeyAttributes:
- "id" #
- "username" #
ProjectionType: "INCLUDE"
ProvisionedThroughput:
ReadCapacityUnits: "1" #キャパだよー
WriteCapacityUnits: "1"
TableName: "dev-test-users" #作成されるDynamoDBテーブル名
こんな感じですかね。
適宜コメントで注釈いれてますが、詳しくはCloudFormationのヘルプに詳しく書いてあります。
Tableを増やしたいときは、YAMLの記述にのっとって、
Resourcesの後ろにバンバン追加していくんですね。
S3のBucketとかもつくれます。
ここまでで、AWSに、lambda APIGateway DynamoDBを作って、つなげるところまでやってくれます。
あとはhandler.jsの中に、処理を書くだけです。
'use strict';
const AWS = require('aws-sdk'),
dynamoDb = new AWS.DynamoDB.DocumentClient(),
uuid = require('uuid'),
moment = require('moment'),
userTableName = `dev-test-users`;
const createResponse = (statusCode, body) => (
{
statusCode,
headers: {
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify(body),
}
);
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
}),
};
callback(null, response);
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};
module.exports.userCreate = (event, context, callback) => {
const item = JSON.parse(event.body);
item.id = uuid.v1();
item.updt = moment().utc().toISOString();
item.delfg = 0;
const params = {
TableName: userTableName,
Item: item
};
dynamoDb.put(params, (err, data)=>{
if(err){
callback(null, createResponse(500, {Message: err.message}));
} else {
callback(null, createResponse(200, {id: item.id}));
}
});
};
module.exports.userRead = (event, context, callback) => {
let page = "";
let limit = 4;
let my_index = "myUPDT";
if(event.queryStringParameters != null)
{
if(event.queryStringParameters.page !== undefined ) {
page = event.queryStringParameters.page;
}
if(event.queryStringParameters.limit !== undefined ) {
limit = event.queryStringParameters.limit;
}
}
const params = {
TableName: userTableName,
IndexName: my_index,
KeyConditionExpression: "#key1 = :val1",
ExpressionAttributeNames: { "#key1": "delfg" },
ExpressionAttributeValues: {":val1": 0 },
ScanIndexForward: false,
Limit: limit
};
if(page != "" ) {
let js = JSON.parse(page);
params["ExclusiveStartKey"] = js;
}
dynamoDb.query(params, (err,data) =>{
if(err){
callback(null, createResponse(500, { message: err.message }));
} else {
callback(null, createResponse(200, data));
}
});
};
module.exports.userGet = (event, context, callback) => {
const id = event.pathParameters.id;
const params = {
TableName: userTableName,
Key: {
id: id
}
};
dynamoDb.get(params, (err,data) =>{
if(err){
callback(null, createResponse(500, { message: err.message }));
} else {
callback(null, createResponse(200, data));
}
});
};
たぶんこんな感じ。
これで、もっかい
$ sls deploy -v
ここにEndpointつくりましたよって結果がでてきます。
あとはこのAPIを使って通信すればOKです。
実際にAWS管理画面でみてみると
それぞれ作成されているのがわかります。
それでは、試しに、作成するjsonをなげてみます。
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"username":"takaoka"}' https://h86ribf3tj.execute-api.us-east-1.amazonaws.com/dev/user
これで、username=takaokaというデータをつくってくれるはずです。
dynamoDBでデータをみてみると、作られているのがわかります。
ここでは他のデータも投入した結果が表示されていますね。
ではデータ取得はどうでしょうか。
curl https://h86ribf3tj.execute-api.us-east-1.amazonaws.com/dev/user
とすると
{
"Items":[
{
"updt":"2017-01-25T15:35:43.408Z",
"username":"merukuma",
"id":"eef18bf0-e313-11e6-b508-c1acf2e4eaa5",
"delfg":0
},
{
"updt":"2017-01-25T15:35:16.039Z",
"username":"takaoka",
"id":"dea18570-e313-11e6-ba2a-9d6ebdcb394f",
"delfg":0
}
],
"Count":2,
"ScannedCount":2
}
このJSONが返ってきます。
個別取得のAPIは
curl https://h86ribf3tj.execute-api.us-east-1.amazonaws.com/dev/user/eef18bf0-e313-11e6-b508-c1acf2e4eaa5
発行されたIDを使います。
{
"Item":{
"updt":"2017-01-25T15:35:43.408Z",
"username":"merukuma",
"id":"eef18bf0-e313-11e6-b508-c1acf2e4eaa5",
"delfg":0
}
}
とれてますね。
あとは、アプリから、http通信を行ってJSONのやりとりをするだけです。
そのうち、各プラットフォームでのクライアント通信の処理もかきたいですーしょりしょりー
Cocos2d-xでの通信処理
#include "json11.hpp"
#include "network/HttpClient.h"
....
cocos2d::network::HttpRequest *req = new cocos2d::network::HttpRequest();
std::string query = "https://h86ribf3tj.execute-api.us-east-1.amazonaws.com/dev/user";
req->setUrl(query.c_str());
json11::Json::object obj;
obj["user_name"] = user_name;
std::string json_str = json11::Json(obj).dump();
req->setRequestType(cocos2d::network::HttpRequest::Type::POST);
std::string postdata = json_str;
req->setRequestData(postdata.c_str(), postdata.length());
req->setResponseCallback([=](cocos2d::network::HttpClient* sender, cocos2d::network::HttpResponse* respons){
if ( respons->isSucceed() && respons->getResponseCode() == 200 ) {
# いろいろがんばってください
}
}
cocos2d::network::HttpClient::getInstance()->send(req);
なんとなくわかるやろう。