とっしぃのTech Memo

PHPとかサーバとか他色々言語のメモ的な。あとはたまにガジェットとか。

JavascriptのAWS SDKをAngular2/4で使ったらめっちゃエラー出た件

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/lib/http_response.d.ts (1,25): Cannot find module 'stream'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/lib/http_response.d.ts (14,18): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/lib/request.d.ts (1,25): Cannot find module 'stream'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/lib/request.d.ts (132,45): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/acm.d.ts (108,37): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/acm.d.ts (110,38): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/acm.d.ts (344,32): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/apigateway.d.ts (1031,23): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/clouddirectory.d.ts (973,38): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/cloudsearchdomain.d.ts (41,23): Cannot find name 'Buffer'.

~~~

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/rekognition.d.ts (561,27): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/s3.d.ts (746,22): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/s3.d.ts (1050,42): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/s3.d.ts (3213,32): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/ses.d.ts (1127,32): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/sns.d.ts (275,24): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/sqs.d.ts (192,24): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/support.d.ts (336,22): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/waf.d.ts (372,39): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/clients/wafregional.d.ts (416,39): Cannot find name 'Buffer'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/lib/config.d.ts (1,34): Cannot find module 'http'.

ERROR in {PROJECT_DIR}/node_modules/aws-sdk/lib/config.d.ts (2,35): Cannot find module 'https'.
webpack: Failed to compile.

Why?

結論から言うと確かな原因は分かりませんでした(´・ω・`)

ただ、下記StackOverflowのコメント

stackoverflow.com

npm install --save-dev @type/aws-sdk

してみたところ動きはしたので、恐らくライブラリそのものが原因ではあろうと思います。

でも↑のコメントだと、aws/aws-sdkはES2015に対応してないとかなんとかあるんですけど、 どっちかというとTypeScriptな気がするんですよねぇ・・・。 気がするだけですけど。

ほんとのところ知ってる人がいたら教えてください。

AWSのRoute53とSES、SNS、S3でSSL証明書のメールを受け取るまで

また社内でそこそこの頻度でありそう&大体その時には忘れてる系の事案(エントリタイトルの通り)があったのでメモ。

前提

  • 以前からドメイン取ってるサービスがあって、ドメインはそこで一元管理
  • サービスそのものはAWSで開発、本番運用予定
  • DNSAWSのRoute53を利用

という状態で、SSL証明書取るためのadmin@hogehogeとか受け取りたい

のです。

よくあるドメインレジストラの機能が使えない

んです。

お名前.comとかだと「メール転送サービス」とかありますよね。
こっちでMXレコードとか設定したりメールサーバ用意しなくても、指定したメールアドレスへのメールを届けてくれるやつ。

Route53はシンプルで良いサービスだと思いますが、シンプルなだけにそんな便利な機能はないです。

SESを使ってメールを受信する

なのでAWSのメールサービス、SESを利用します。

とは言っても、SESは基本メール送信のためのサービスで、受信はおまけみたいなもんなのであんまりいい感じにはしてくれません。

ドメインを登録する

f:id:tossy_yukky:20170522114334p:plain
からの
f:id:tossy_yukky:20170522114357p:plain
ですが、メールの受信がしたいだけの場合、

Generate DKIM Settings

のチェックは入れなくて大丈夫です。
DKIMはメール送信時のオプションです。

あとは大体言われるがままで大丈夫だと思います。
大丈夫じゃなかったとしても責任は負いませんが。

「Email Receiving」→Rule Setsで受信ルールを作る

f:id:tossy_yukky:20170522113657p:plain

  • 受信するメールアドレスを指定

f:id:tossy_yukky:20170522113608p:plain

  • 受信した時のアクションを指定

f:id:tossy_yukky:20170522113500p:plain

    • SNSとか
    • S3にファイルとして保存とか
    • Lambdaに渡すとか

大体いつもSNSでメール送信させる&S3にバックアップとしてファイル保存、て感じです。

SNSに渡して、SNSでメール送信させるような

場合、EncodingはBase64にしておかないとあとでハゲます。

SNS

は、Protocolは何でもいいですが、メール受信したい場合ならEmailかEmail-Jsonを選ばないとメール来ません。
当たり前ですが。

受信したメールがわけわからんぞ

base64エンコードされてますからね。デコードしないとダメですよね。

,\"content\":\"〜〜〜〜〜\"}",

って部分を探して、そこを一回デコードすることでメールを全てテキストで取り出すことができます。
そのなかで、メールボディも更にbase64エンコードされているため、文面を日本語で読みたい場合はもう一回デコードしないといけません。

ということで

少々めんどいですが、SSL証明書取る時くらいのメール受信ならまぁなんとか我慢できる範囲でしょうかね。
これが毎日のメールだったら吐きます。

以上、「AWSのRoute53とSES、SNS、S3でSSL証明書のメールを受け取るまで」でした。

AWS Route53でRate for operation ChangeResourceRecordSets exceeded

業務でAWSのRoute53を使ってるんですが、このレコードセットを変更しようとした際に出た下記のエラー

Rate for operation ChangeResourceRecordSets exceeded

f:id:tossy_yukky:20170314184014p:plain

何度Save Record Setボタン押しても出てきちゃって何がまずいねんと思ってたんですが、
まぁやっぱりStack Overflow先生ですよね。
stackoverflow.com

ココ見ろよと。
https://status.aws.amazon.com/


思いっきり出てますね。

Amazon Route 53    Slow propagation times

f:id:tossy_yukky:20170314183855p:plain
これはNorth Americaリージョンの画面ですが、案の定他のリージョンも同じように出てました。

つまりこれはもう待つしかないってことですね。

追記
ちなみに載っていた情報をgoogle翻訳先生に見てもらったらこんな感じ。

Mar 14, 1:50 AM PDT Record changes are slowly propagating, while we work through the backlog of pending changes that have accumulated. We still expect full recovery to take several more hours. We are continuing to throttle ChangeResourceRecordSets API calls. Queries to existing DNS records remain unaffected.
蓄積された保留中の変更のバックログを調べながら、記録の変化はゆっくりと伝播しています。まだ完全回復にはさらに数時間かかることが予想されます。私たちは、ChangeResourceRecordSets APIコールを抑制し続けています。既存のDNSレコードへのクエリは影響を受けません。

PDTなのでJSTだと 3/14 17:50 ですね。

Laravel5.2でパスワードリセットのメールをテキストで送りたい

なんでデフォルトがHTMLなんや。

でもテキストで送れないとなるとトークン自分で作ったりその認証したりめんどいので なんとかソースコード追って設定(+override)でどうにかしたい。

まずはRouting

Laravelは5.2からartisanコマンドにmake:authが出来て、ルーティングやらなんやらを一気にやってくれるようになったみたいですね。 5.1以前をやったことないので前は知らないけど(´・ω・`)

とりあえずphp artisan make:authを打ってみて、ルーティングを見てみる。

Route::post('password/email', 'Auth\PasswordController@sendResetLinkEmail');

PasswordControllerのsendResetLinkEmailメソッドでメールを発行しているらしい。

じゃあそのメソッド見れば解決やん。

・・・

ない(´・ω・`)

そんなメソッド書いてない(´・ω・`)

ということでPasswordControllerの上の方を見てみると

    use ResetsPasswords;

という記述が。

Laravelはこういったtrait機能をふんだんに使った書き方がされているみたい。

んでそのtraitは

use Illuminate\Foundation\Auth\ResetsPasswords;

とのことなのでそちらを見てみるとありましたねsendResetLinkEmail

    /**
     * Send a reset link to the given user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function sendResetLinkEmail(Request $request)
    {
        $this->validate($request, ['email' => 'required|email']);

        $broker = $this->getBroker();

        $response = Password::broker($broker)->sendResetLink(
            $request->only('email'), $this->resetEmailBuilder()
        );

        switch ($response) {
            case Password::RESET_LINK_SENT:
                return $this->getSendResetLinkEmailSuccessResponse($response);

            case Password::INVALID_USER:
            default:
                return $this->getSendResetLinkEmailFailureResponse($response);
        }
    }

この中でメールを送っているらしき部分は

        $response = Password::broker($broker)->sendResetLink(
            $request->only('email'), $this->resetEmailBuilder()
        );

なので、今度はそこをvendor/laravelの中で探すと vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.php にそれっぽいのを発見。

    /**
     * Send the password reset link via e-mail.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @param  string  $token
     * @param  \Closure|null  $callback
     * @return int
     */
    public function emailResetLink(CanResetPasswordContract $user, $token, Closure $callback = null)
    {
        // We will use the reminder view that was given to the broker to display the
        // password reminder e-mail. We'll pass a "token" variable into the views
        // so that it may be displayed for an user to click for password reset.
        $view = $this->emailView;

        return $this->mailer->send($view, compact('token', 'user'), function ($m) use ($user, $token, $callback) {
            $m->to($user->getEmailForPasswordReset());

            if (! is_null($callback)) {
                call_user_func($callback, $m, $user, $token);
            }
        });
    }

見事にsendしてる。

んでここの$view、その前を見ると$this->emailViewを、テキストメールの送り方である['text' => 'view_name']にできればおっけー。

その$this->emailViewはどうやらコンストラクタで設定されているようなので、PasswordBrokerをnewしてるところを探せばいけるんじゃないかね。

するとnewしてるのはvendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.phpと判明。

その中のresolveメソッドでnewしてた。

    /**
     * Resolve the given broker.
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\PasswordBroker
     *
     * @throws \InvalidArgumentException
     */
    protected function resolve($name)
    {
        $config = $this->getConfig($name);

        if (is_null($config)) {
            throw new InvalidArgumentException("Password resetter [{$name}] is not defined.");
        }

        // The password broker uses a token repository to validate tokens and send user
        // password e-mails, as well as validating that password reset process as an
        // aggregate service of sorts providing a convenient interface for resets.
        return new PasswordBroker(
            $this->createTokenRepository($config),
            $this->app['auth']->createUserProvider($config['provider']),
            $this->app['mailer'],
            $config['email']
        );
    }

どうやら$config['email']がそれっぽい。

んで$this->getConfig($name);はというと

    /**
     * Get the password broker configuration.
     *
     * @param  string  $name
     * @return array
     */
    protected function getConfig($name)
    {
        return $this->app['config']["auth.passwords.{$name}"];
    }

これっすねー。

Laravelのconfigファイルは、configディレクトリ以下にファイルを置くだけで使えるので、 この記述からはconfig/auth.phpファイルのpasswords['email']を見ている、と。

ということで、上記を['text' => 'auth.emails.password']に変えてみたら見事にテキストメールで送られました。

ふぅ(´・ω・`)

ES6でReact使ってたらsetStateがundefinedとか怒られた件

急に寒くなってきたこの頃、いかがお過ごしでしょうか。

鼻水やらくしゃみやら頭痛やら止まらなくて調べたら「寒暖差アレルギー」なんじゃないかと思い始めました。

とっしぃです。

Uncaught TypeError: Cannot read property 'setState' of undefined

ところで、業務に関係ありそうでなさそうな適当なツールChromeのextensionで作ってみようと思い、 どうせ外に出すわけでもないツールだし以前から興味のあったReactで書いていたわけです。

更にどうせならES6で書かない理由もないということで、

var CommentBox = React.createClass({
...

ではなく

class CommentBox extends React.Component {
...

って感じ。

でもそこで

class CommentBox extends React.Component {
    
    constructor(props) {
        super(props);
        let data = localStorage.getItem('data_key');
        this.state = {
            data: data
        }
    }

    changeData(e) {
        this.setState({data: e.target.value});
    }

    save(e) {
        e.preventDefault();
        localStorage.setItem('data_key', this.state.data);
        return false;
    }

    render() {
        <form>
            <Input type="text" value={this.state.data} onChange={this.changeData} label="DATA" />
            <button onClick={this.save}>SAVE</button>
        </form>
    }
}

的に書いてみたところ、developer toolのコンソールに

Uncaught TypeError: Cannot read property 'setState' of undefined

とか出てるじゃないですか。

色んなチュートリアル見ながらその通りやったのに(´・ω・`)

調べてみると

qiita.com

facebook.github.io

どうやら

var CommentBox = React.createClass({

で書いた場合はthisが勝手にbindされるけど、ES6で

class CommentBox extends React.Component {

って書いた場合はthisがbindされないとのこと。

なのでコンストラクタで明示的に

class CommentBox extends React.Component {
    constructor(props) {
        super(props);
        let data = localStorage.getItem('data_key');
        this.state = {
            data: data
        }

        this.changeData = this.changeData.bind(this);
        this.save = this.save.bind(this);
    }

とbindしてあげないといけないらしい。

まとめ

Reactもbabelもちょこちょこバージョン上がってるので npm install して落ちてきたバージョンが新し目だったらちゃんとリリースノート(の翻訳でもいいので)を見といた方がいいですね。 ReactなんてrenderメソッドがReactクラスじゃなくてReactDOMクラスのメソッドになってたし。

AWS EC2にt2.nanoインスタンスができた

おはようございます。 とっしぃです。

朝メールを見たらAWSからのお知らせメールで、EC2にt2.nanoインスタンスができたとのこと。

Introducing t2.nano: the Smallest, Lowest Cost Amazon EC2 Instance

スペック見た感じだとGoogleGoogle Conpute Engine f1-microインスタンスと同じくらいですかね。

メモリ vCPU 料金
EC2 t2.nano 512MB 1 4.75 USD/月(0.0065 USD/時間)
GCE f1-micro 0.6GB 1 5.00 USD/月(0.007 USD/時間(平均)

GCEの場合は月の稼働時間で若干変わるみたいなので平均値で。

今までは、適当に作って捨ててっていう遊びではf1-microで十分なのでGCEでやってたんですが t2.nanoができるとこれでもいいかもしれないですね。

ちょっとこっちでもやってみようかと思います。

PHP7を軽くいじってみる

とっしぃです。

もうすぐ2015年も終わってしまうということで駆け込み投稿です。

リリースされましたねPHP7。

PHP: News Archive - 2015

ということでちょっとばかり触ってみようと思います。

まずはインストール

なにはなくともインストールしないことには始まりません。

とりあえずいつも使っているさくらのVPSでやってみます。

yumにはあるのかな?

ありますね。さすがremi。仕事が速い。

blog.remirepo.net

適当に書いてある通りに入れてみます。

$ sudo yum-config-manager --enable remi-php70
$ sudo yum update php\*
$ sudo yum install php70

でもこのままやるとデフォルトでremi-php70リポジトリが有効になっちゃうので、 嫌な人はこっちの記事のやり方の方がいいかも。

blog.remirepo.net

$ sudo yum --enablerepo=remi update remi-release
$ sudo yum --enablerepo=remi-php70 update php\*

これで入ったと思うのでバージョン確認。

$ php -v
PHP 7.0.0 (cli) (built: Dec  5 2015 07:17:51) ( NTS )
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologies

おっけー☆

Let's try

一番の目玉は速度改善ではあるんですが、とりあえずは新しい文法というか記法ですかね。

ちなみにPHP7で追加・変更された文法・記法的なものは下記が詳しいですね。

d.hatena.ne.jp

このうち簡単に試せそうですぐに取り入れられそう、かつ有効性が高そうなものだと - スカラ型のタイプヒンティング - 関数・メソッドの戻り値についてのタイプヒンティング - ??(Null Coalesce)演算子 とかですかね。

引数のスカラ型タイプヒンティングはまぁ普段書いてる関数・メソッド定義に少々加えるだけなので ほんとにすぐに使えますね。

戻り値のタイプヒンティングも。

??(Null Coalesce)演算子は、今まで

$a = isset($b['index']) ? $b['index'] : '';

とか書いてたのが

$a = $b['index'] ?? '';

って書けるのはでかいですよね。

なんで同じ値を2回も書かなきゃならんのかと常々思ってましたし。

あとは無名関数とかはだんだん流行りの(?)関数型への道を進み始めてるって感じでしょうか。

$func = function($a) {
    return $a * 2;
}

とか

(function() {
    echo 'hoge';
})();

とか、一歩間違うとjavascriptかと思っちゃいますよね。

感想

まぁPHP7の恩恵のメインは速度だと思うので、とりあえずはWordpressとかCakePHP、Laravel辺りで実感するとして、 実際にある程度の規模のサイト、プログラムを書く時にはこれらの書き味的なものがじわじわと実感できそうな気がします。

業務でしばらく5.1とか使ってた後に、違うプロジェクトで5.4系とか使ったらarray()が[]で書けて無性に嬉しかったりそういうやつですねw

あとはそのうちASTで色々やってくれるツールとかもガンガン出てくると思うしその辺も期待ですかね。

以上です。