blogですかい

仕事、プライベートで学んだことなどを発信し、その内容がたとえ少数でも誰かの役に立ったらなら、それはとっても嬉しいなって

Amazon S3 でマルチドメイン名対応のWebサイトを作りたい人生だった

S3とは

AWSの提供するクラウドストレージで、ファイルの保管場所としても使えるし、静的コンテンツのWebサーバとしても使用できるというステキなサービス。

画像や動画などの静的コンテンツをS3から配信しているWebサービスは多い。HTMLも静的なものだけであれば、S3のみで運用が可能。

やりたかったこと

S3にバケットを作って、そのエンドポイントを*.example.comのCNAMEにセットする

以下略
と、任意のサブドメイン名でアクセスできるWebサイトを作りたかった。

でも、S3ではできなかった

S3では、Webホスティング独自ドメインを使用する場合、バケット名はFQDNと同一にしなければならない。
よって、ひとつのバケットで複数のドメイン名に対応することはできない。

  • aaa.example.com というバケット
  • bbb.example.com というバケット
  • ccc.example.com というバケット
  • 以下略
    と、大量のバケットを作り、それぞれのCNAMEレコードを設定し、それぞれのバケットの中身を管理しなければならない。 当然、そんなことはできないのでS3ですることは諦めた。

IaaSやVPSなら簡単にできる

春イベント戦績 その1(とケッコンカッコカリ)

E-1

参加者(レベル・索敵値は攻略完了時のもの)

艦名 レベル 索敵 主な役割
鳥海 98 55 旗艦・眼鏡
摩耶 76 50 対空・火力
北上 78 35 対潜・開幕
大井 66 31 対潜・開幕
木曾 55 36 対潜
金剛 76 51 火力
伊勢 77 48 対潜・火力
赤城 46 78 索敵値・航空
加賀 75 89 索敵値・航空
隼鷹 24 44 対潜・航空
五月雨 57 - 支援
雪風 49 - 支援

出撃回数 : 8
敵主力到達回数 : 6
撤退回数 : 2 (操作ミス1, 隼鷹大破)
使用バケツ数 : 7

E-2

参加者(レベル・索敵値は攻略完了時のもの)

艦名 レベル 索敵 主な役割
鳥海 100 61 旗艦・眼鏡
摩耶 77 51 対空・火力
北上 78 35 開幕・夜戦
大井 67 32 開幕・夜戦
木曾 55 36 火力
金剛 76 51 火力
伊勢 77 48 火力・航空
山城 59 48 火力・航空
赤城 48 78 索敵・開幕
加賀 75 89 索敵・開幕
隼鷹 25 44 支援
飛鷹 14 41 支援
五月雨 57 - 支援
雪風 49 - 支援

出撃回数 : 10
敵主力到達回数 : 6
撤退回数 : 2 (操作ミス, 赤城大破)
使用バケツ数 : 16

編成は 重/重/戦/航戦/雷/航 とすることが多かった。
雷巡や空母が旗艦をかばうことが無いよう、基本的に単縦陣。

操作ミスについて

なんか、以前のUIと比べて撤退ボタンが押しやすくなった気がする。
間違えて大破進軍するというミスは起こさなかったが、起こり得ると思うので、戦果やドロップ画面の操作には注意したい。

弾着観測について

弾着観測のカットインや連撃をするための必要条件としてまず制空権をとるか航空優勢にする必要がある。
しかし、まともに戦えるレベルの空母が加賀・赤城しかいないという現状・・・なんとかしたい。

千歳甲(39)や千代田甲(36)を航改にすべきなのは分かっているが、踏み切れないでいる。
ちなみに、水母は弾着観測のカットインや連撃が出来ないっぽい(要検証)

ケッコンカッコカリ

E-2攻略の途中で、ようやくケッコンカッコカリできた。

動画は、手続きの方法が分からず右往左往している様子。(ケッコンカッコカリ自体の映像はカット)

HowToKekkonKakkoKari from Yoshihiro Ohsuka on Vimeo.

AzureのWebサイトでIDN TLDは使えないっぽい

前回の続き

msdnのフォーラムで質問を投げたところ、REST APIを使用すれば登録できるという解答をいただいた。

REST APIを直接使う方法がわからなかったので(証明書周り)、コマンドラインツールを使用したところ、設定はできた。

しかし、設定したFQDNにWebアクセスしてみると404になる。

$ azure site list
info:    Executing command site list
+ Getting locations
+ Getting sites
data:    Name                         Slot  Status   Location    Mode      URL
data:    ---------------------------  ----  -------  ----------  --------  ------------------------------------------------------------------------------------------------------------
data:    hoge-nanimokamo-minna              Running  Japan East  Shared  hoge-nanimokamo-minna.azurewebsites.net,hoge.xn--u8j1cd6gb.xn--q9jyb4c
info:    site list command OK

$ curl -I http://hoge.xn--u8j1cd6gb.xn--q9jyb4c
HTTP/1.1 404 Site Not Found
Content-Length: 66773
Content-Type: text/html
Server: Microsoft-IIS/8.0
Date: Wed, 02 Apr 2014 11:20:25 GMT

PaaSなWebサーバの日本語TLD対応状況

「.みんな」のドメインをいくつか取得したので、何か簡単なサービスをAzureのWebサイトで作ろうと思ったら、「.みんな」のドメインが設定できなかったので、他のPaaSはどうなのか調べてみた。

EngineYard

OK

Heroku

OK

Sqale

OK

Webサイト(Windows Azure)

NG

バリデーションがかかり、登録できない。

f:id:oh-sky:20140322181251p:plain

SSLを有効にして、専用のIPアドレスをバインドすれば、もしかしたらできるかもしれない。(それでもAzureのコントロールパネル上ではできないだろうけど)

canvasで編集した画像をAWS SDK for JavaScript in the Browserを使ってS3にアップロードする

アップロード用ユーザの作り方は「S3 IAM policy」で検索

バケットの設定は「S3 Bucket policy」で検索

単にローカルファイルをアップロードしたいだけなら

AWSの公式サンプルを参考にすれば簡単に実装できます。
http://aws.amazon.com/jp/developers/getting-started/browser/

canvasで作成した画像をS3にアップロードするには

ここから本題
S3へファイルをアップロードする際には、putObject()というメソッドを使用します。

putObject()に与えるハッシュのBodyというキーの値は、input[type=file]か、ファイルのバイナリ列を渡さなければなりません。

ところがcanvasから画像のバイナリ列を取り出す手段は(たぶん)無く、toDataURL()でBase64エンコードされた文字列を取り出し、バイナリにデコードする必要があります。

dataURLをバイナリに変換するライブラリをGithubで見つけましたので、それを使用しました。 https://github.com/rgeraldporter/canvas-polyfill-DataURLtoBlob/blob/master/dataURLtoBlob.js

以下のようなコードを書きました。(canvasの操作をする処理等は省略しております)

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script type="text/javascript" src="https://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.js"></script>
    <script type=“text/javascript” src=“https://rawgithub.com/rgeraldporter/canvas-polyfill-DataURLtoBlob/master/dataURLtoBlob.js”></script>
</head>
<body>
<div>
    <canvas id="TheCanvas"></canvas>
    <button id="TheButton">upload</button>
</div>
<script type="text/javascript">
var bucketName = 'YourBucketName';
var regionName = 'ap-northeast-1';
AWS.config.update({
    accessKeyId: 'YourAccessKeyId',
    secretAccessKey: 'YourSecretAccessKey',
});
var bucket = new AWS.S3({
    params: {
        Bucket: bucketName,
        Region: regionName,
    },
});
$(function () {
    $('#TheButton').on('click', function () {
        var canvas = $(‘#TheCanvas’);
        var dataURL = canvas[0].toDataURL(‘image/jpeg’);
        var binaryData = dataURLtoBlob(dataURL);
        bucket.putObject(
            {
                'ACL': 'public-read',
                'Key': ‘YourUploadingObjectKey’,
                'ContentType': 'image/jpeg',
                'Body': binaryData,
            },
            function (error, data) {
                if (error === null) {
                } else {
                }
            }
        );
    });
});
</script>
</body>
</html>

注意

  • 性質上、アクセスキーを隠すことができないので、publicなアプリケーションには使用しないこと

気になること

  • putObject()のコールバック関数に渡されるdataにこれといって何も入っておらず、使い道がない

はてな認証API使ってみた

はてな認証APIとは

http://auth.hatena.ne.jp/

はてな認証APIははてなアカウントによる認証システムをサードパーティアプリケーションに搭載するための Web API です。はてな認証APIを使うと、サードパーティアプリケーションのアカウント管理をはてなに任せることができます。

使用例

アクセスしてきたユーザのはてブRSSを表示するPHPのアプリ

動作例

思ったこと

GPUとか使ってグルグル回したら、わりと簡単に秘密鍵を特定できそうな気がする。
まぁ、取得できる情報は少ないし、コールバック先は固定なので、悪用はできそうにないけども。

CakePHP2でModelのアソシエーションをまとめて外す方法

全て外したいだけなら

$this->Model->recursive = -1;

一旦全て外して、アソシエーションを設定し直したいなら

たくさんのアソシエーションが設定してある。 この場所では1個だけJOINすれば事足りるのだけれど、不要なものを全てunbindModel()するのが面倒。そんな時に

例えば、コントローラの中で

$this->Model->belongsTo = array();
$this->Model->hasMany = array();
$this->Model->hasOne = array();
$this->Model->hasAndBelongsToMany = array();

あるいは、AppModelクラスに次のようなメソッドを定義する

// app/Model/AppModel.php
class AppModel extends Model {
    public function unbindAllAssociation() {
        $this->belongsTo = array();
        $this->hasMany = array();
        $this->hasOne = array();
        $this->hasAndBelongsToMany = array();
    }
}

上の例は少々乱暴な気がしますので

// app/Model/AppModel.php
class AppModel extends Model {
    public function unbindAllAssociations($reset = true) {
        foreach ($this->_associations as $associationName) {
            foreach ($this->{$associationName} as $modelKey => $modelValue) {
                $modelName = is_numeric($modelKey) ? $modelValue : $modelKey;
                $this->unbindModel(array($associationName => array($modelName)), $reset);
            }
        }
    }
}

全てのアソシエーションを外してからModel::bindModel()で必要なモデルを結合すれば良い。

ここまでするなら別のModelを書いたほうが良い気もするけれど