AWS Lambda を利用して Nexus 6 を (σ´∀`)σゲッツ!!
Nexus 6 が欲しいのになかなか買えない!!!!!!
SIM カードが不要なので Google Play で買おうと思ってるのですが、いつ見ても
現在在庫切れです。しばらくしてからもう一度ご確認ください。
色や容量にはこだわらないのに、年末から折を見て確認しているのに、いつ見ても
現在在庫切れです。しばらくしてからもう一度ご確認ください。
(#`Д´)ノノ┻┻;:'、・゙
こうなってしまうと本当に在庫が復活するのか疑わしい物です。
どれ、ちょっと自動で在庫をチェックして、在庫が復活した際に通知を送りましょう。
Azure に tie-in してよいのであれば、すぐに作れます。
なぜなら Azure には Node.js をバックエンドに GUI からスケジューラを作成できるお手軽便利機能があるからです。
今回はそれではつまらないのと(Azure が優秀過ぎる)、Amazon SNS のトピックが便利(モバイルデバイス以外にもメールにも通知を行いたい)なため最近ホットな AWS Lambda を使ってみます。
ところが、AWS Lambda にはスケジューラ機能がありません。そのうち実装されると思いますが、とにかく今はないので、代替方法を探します。
皆さん、S3 を利用したり Lambda API で自分自身を呼び出したりとなんとか頑張ってループしているようです。
今回の例ですと、後者の Lambda API で 45 秒間隔で Nexus 6 のサイトをチェックし、在庫がある場合に通知を行う Lambda を作ってみましょう。
また、通知を連続で送ってしまわないよう、通知済みを記録するファイルを作成します。このファイルがある場合には、通知済みとして通知を行わず、ファイルが存在しない場合には通知を行うようにします。
var AWS = require('aws-sdk'); var HTTPS = require('https'); // http な場合は var HTTP = require('http'); とします exports.handler = function(event, context) { console.log('Starting nexus 6 stock checker...'); console.log(event); var lambda = new AWS.Lambda({ accessKeyId: 'XXXXXXXXXXXXXXXXXXX', // FIXME: AWS Lambda の IAM アクセスキー secretAccessKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', // FIXME: AWS Lambda の IAM シークレットキー region: 'us-east-1' // FIXME: Lambda のリージョン }); setTimeout(function() { var params = { FunctionName: 'checkNuxus6Stock', // Lambda 関数名 InvokeArgs: '{}' }; lambda.invokeAsync(params, function(err, data) { if (err) { console.log('Unexpected error encountered while invoking lambda function.'); console.log(err, err.stack); return; } else { console.log(data); } try { // get なのでキャッシュされないよう URL に _ パラメータ(名前は何でもいい、値が一意であれば)をくっつけておきます check('https://play.google.com/store/devices/details/Nexus_6_32_GB_%E3%83%80%E3%83%BC%E3%82%AF%E3%83%96%E3%83%AB%E3%83%BC?id=nexus_6_blue_32gb&_=' + new Date().getTime(), context); // 青/32GB check('https://play.google.com/store/devices/details/Nexus_6_64_GB_%E3%83%80%E3%83%BC%E3%82%AF%E3%83%96%E3%83%AB%E3%83%BC?id=nexus_6_blue_64gb&_=' + new Date().getTime(), context); // 青/64GB check('https://play.google.com/store/devices/details/Nexus_6_32_GB_%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89_%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88?id=nexus_6_white_32gb&_=' + new Date().getTime(), context); // 白/32GB check('https://play.google.com/store/devices/details/Nexus_6_64_GB_%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89_%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88?id=nexus_6_white_64gb&_=' + new Date().getTime(), context); // 白/64GB context.done(); } catch (e) { console.log(e); } }); }, 45000); // 45 秒後に自身を実行 function check(url, context) { HTTPS.get(url, function (res) { // http な場合は HTTP.get とします console.log(url + ' response:' + res.statusCode); if (res.statusCode < 200 || res.statusCode >= 300) { return; } var body = ''; res.on('data', function(chunk) { // レスポンスをドラゴンボールのようにかき集めます body += chunk; }); res.on('end', function() { // レスポンスから在庫がないときに存在する HTML コードの検索を行い、在庫状況をチェックします console.log(body); if (body != null && body.indexOf('We are out of inventory. Please check back soon.') == -1) { console.log('Notifying me...'); notifyMe(); } }); }).on('error', function(e){ console.log('error', e); }); } function notifyMe() { var s3 = new AWS.S3({ apiVersion: '2006-03-01' }); s3.getObject({ Bucket: 'XXXXXXXXXX', Key: 'nexus6_has_notified'}, function(err, data) { // FIXME: 通知状況を確認するためのバケットとキー(パス) if (err) { // ファイルが存在しない場合には未通知とみなし通知を行います console.log('Object not found.'); var sns = new AWS.SNS({ apiVersion: '2010-03-31', region: 'us-east-1' // FIXME: AWS SNS のリージョン }); var payload = { aps: { alert: 'Nexus 6 is now available!', sound: 'default', customProperty: 'We are Nexsus!' // デバイスに独自にデータを渡したい場合この辺に突っ込んどきます(iPhone の場合) } }; var message = { default: 'Nexus 6 is now available!', APNS: JSON.stringify(payload) // iPhone の場合(GCM, Baidu 等を用いて通知したい場合それぞれのプラットフォームに応じた形式の JSON を格納します) }; var params = { TopicArn: 'arn:aws:sns:us-east-1:XXXXXXXXXXX:XXXXXXX', // FIXME: AWS SNS の通知先トピックARN MessageStructure: 'json', Message: JSON.stringify(message) }; sns.publish(params, function(err, data) { if (err) { console.log('Unexpected error encountered while Notifying me.'); console.log(err); } }); s3.putObject({ // 通知済みであることを S3 に保存します Bucket: 'XXXXXXXXXX', // FIXME: 通知状況を保存するバケット Key: 'nexus6_has_notified', Body: new Buffer('1', 'binary'), // 今回の例だとファイルが「存在する/しない」のみの制御なので何が書いてあっても問題なし ContentType: 'application/octet-stream' }, function(err, res) { if (err) { console.log('Unexpected error encountered while putting object.'); console.error(err); } }); } else { console.log('Object found.'); } }); } };
Lambda 作成時の名前を「checkNuxus6Stock」、タイムアウトを「60」秒にして作成すれば OK です。