動機
MQTTを使用して、Lambdaからブラウザを更新する方法〜aws-iot-device-sdk(aws-iot-sdk-browser-bundle.js)を使用する場合〜 の例を自分でも試してみようと…の続き。
今見ると、純粋 JS 実装の aws-iot-device-sdk とネイティブライブラリで一部書き直された aws-iot-device-sdk-v2 とがあるが、ブラウザで使うのにネイティブは却下。 aws-iot-device-sdk だけかと思って npm trends 調べたら、人気なのは Amplify らしい…。ドキュメントがいまいち不親切で、やりたいことをどうやれば実現できるかよくわからなくて敬遠していたが、人間、長いものに巻かれるのも大事だ。
経過
- Cognito の Identity Pool (IDプール) を用意して Enable access to unauthenticated identities (認証されていない ID に対してアクセスを有効にする) のチェックを on にする
- 未認証ユーザに割り当てる IAM Role は
iot:Connect
,iot:Receive
,iot:Subscribe
の最低限のポリシーだけを付与する
この辺は くだんの記事 と同じ。で、未認証ユーザに subscribe させるのって、 amplify でどうやって書くんだ?ドキュメントの例は signin して認証済みユーザとして subscribe するものばかりで、案の定わけわからん。
こういうときは、ソースを見るしかない。 GitHub から clone してきてローカルでいろいろ探索してみる。どうやら、
- Auth の config に region と identityPoolId だけ与えて放置すれば、 PubSub で必要になったときに暗黙に @aws-amplify/core の
Credentials._setCredentialsForGuest()
が呼ばれて、 guest 用の credentials ( accessKeyId, secretAccessKey, sessionToken を持つ未認証ユーザ向けの一時 credentials ) が勝手に用意されるらしい - Amplify をまるごと import しなくても、 PubSub にも
addPluggable()
があるので、 AWSIoTProvider はそこで設定すればよい - subscribe したときの
next
イベントには、 publish されてきた payload だけではなく provider の情報も一緒に入ってくるので、選り分けないといけない
ということが見えてきた。 いや、そりゃ OSS だから自分でソース見りゃいいってのはそうなんですが、もう少しどこかに書いておいてくれても…。
結果
import Auth from '@aws-amplify/auth';
import PubSub from '@aws-amplify/pubsub';
import { AWSIoTProvider } from '@aws-amplify/pubsub/lib/Providers';
const AWS_REGION = 'ap-northeast-1';
const IDENTITY_POOL_ID = 'ap-northeast-1:XXXXXXXXXXXXXXXXXXXXXX';
const ENDPOINT = 'yyyyyyyyyyy.iot.ap-northeast-1.amazonaws.com';
const TOPIC = 'hoge';
const subscribeJob = async () => {
Auth.configure({
region: AWS_REGION,
identityPoolId: IDENTITY_POOL_ID,
});
PubSub.configure();
PubSub.addPluggable(new AWSIoTProvider({
aws_pubsub_region: AWS_REGION,
aws_pubsub_endpoint: `wss://${ENDPOINT}/mqtt`,
}));
const onMessage = ({ provider, value }) => {
console.log('> ' + JSON.stringify(value));
};
const onError = (err) => {
console.error(err);
};
const onClose = () => {
console.log('Closed');
}
PubSub.subscribe(TOPIC).subscribe({
next: onMessage,
error: onError,
close: onClose,
});
console.log('subscribe success');
};
export default subscribeJob;
あとはこの関数をどこか初期化にふさわしい場所で呼び出す ( React なら App.js で useEffect()
するとか) だけ。 AWS IoT のコンソールでテスト publish すると、ブラウザのコンソールに publish したメッセージが表示される。めでたしめでたし。
確かに、 aws-iot-device-sdk よりも amplify のほうがコードは簡単になっている。が、このとっつきにくさは何なんだろう…。