firebase-adminでAlexaスキルからRealtime Databaseを更新する

#Realtime Database側
こんな感じにしておく。
スキルが起動するとOn。キャンセルするとOffにする。

Root
　-launch : on/off
　
#実装
```index.js
'use strict';

const Alexa = require('ask-sdk-core');
const admin = require('firebase-admin');
const serviceAccount = require('秘密鍵jsonのパス');

admin.initializeApp( {
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "データベースのURL" 
} );

const db = admin.database();
const ref = db.ref(); //ハマりポイント１

const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  async handle(handlerInput) {
    await ref.update({
      "launch" : "on"
    },  (error)=>{
      if(error) {
        console.log("書き込み失敗");
        console.log(error);
      }else{
        console.log("書き込み成功");        
      }
    });

    const speechText = '起動したよ';

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(speechText)
      .getResponse();
  },
};

const CancelAndStopIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
        || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
  },
  async handle(handlerInput) {
    await ref.update({
      "launch" : "off"
    },  (error)=>{
      if(error) {
        console.log("書き込み失敗");
        console.log(error);
      }else{
        console.log("書き込み成功");        
      }
    });

    const speechText = 'さようなら!';

    return handlerInput.responseBuilder
      .speak(speechText)
      .getResponse();
  },
};

let skill; //ハマりポイント２
exports.handler = async (event, context) =>{
  console.log(skill);
  if(!skill){
    skill = Alexa.SkillBuilders.custom()
          .addRequestHandlers(
            LaunchRequestHandler,
            HelpIntentHandler,
            CancelAndStopIntentHandler,
            SessionEndedRequestHandler,
            LightRequestHandler)
          .addErrorHandlers(ErrorHandler)
          .create();

  }
  return skill.invoke(event); 
}

```

#（ハマるとしたら多分私ぐらいだが）ハマりポイント解説
##Realtime Databaseのルート指定方法
```index.js
const ref = db.ref(); 
```
色々な方のソースを参考にさせていただきましたが、どれもルートの下にちゃんと構造作られてて、ルート直下の要素を更新するサンプルが見つけられませんでした。
ちゃんと公式サイトに載ってました。この書き方でルートを指定できました。

[firebaseのリファレンス（ルート指定方法）](https://firebase.google.com/docs/reference/node/firebase.database.Reference?hl=ja)

##handlerの実装方法
ここの部分ですが・・・

```index.js
let skill; //ハマりポイント２
exports.handler = async (event, context) =>{
  console.log(skill);
  if(!skill){
    skill = Alexa.SkillBuilders.custom()
          .addRequestHandlers(
            LaunchRequestHandler,
            HelpIntentHandler,
            CancelAndStopIntentHandler,
            SessionEndedRequestHandler,
            LightRequestHandler)
          .addErrorHandlers(ErrorHandler)
          .create();

  }
  return skill.invoke(event); 
}
```

こんな風にも書くこともできます。

```index.js
const skillBuilder = Alexa.SkillBuilders.custom(); 

exports.handler = skillBuilder
   .addRequestHandlers(
     LaunchRequestHandler,
     HelpIntentHandler,
     CancelAndStopIntentHandler,
     SessionEndedRequestHandler,
     LightRequestHandler)
   .addErrorHandlers(ErrorHandler)
   .lambda();

```
一応公式でも「また、ASK SDK v2 for Node.jsで提供されるlambdaビルダー関数を使って、Skillのインスタンスを呼び出して応答を返すLambdaハンドラー関数を簡単に作成することもできます。」と説明されてます。
[ASK SDK for Node.jsの公式ガイド](https://ask-sdk-for-nodejs.readthedocs.io/ja/latest/Developing-Your-First-Skill.html)

###ですが、動きが違いました。

後者の書き方だとRealtime Databaseのセッションが残ってしまい（？）、Lambdaでタイムアウトが発生して、結果的に「スキルからの応答に問題があります」とエラーが返ってきてしまいました。
（Realtime Databaseへの更新はうまくいきます）

今のところ理由は定かではありませんが、とりあえず前者のcreate()でハンドラ作る方法を推奨します。
#動きの違いが気になって試したこと
##goOfflineでRealtime Databaseとの接続を切れるらしい
###lambdaで試した
```index.js
    await ref.update({
      "launch" : "on"
    },  (error)=>{
      if(error) {
        console.log("書き込み失敗");
        console.log(error);
      }else{
        console.log("書き込み成功");        
      }
    });

    db.goOffline(); //←これを追記

 
```
結果：タイムアウトは変わらず。ダメでした。
###ローカルで試したけど・・・
```local.js
'use strict';

//省略

const db = admin.database();
const ref = db.ref();

const dbupdate = async () => {
  await ref.update({"launch" : "on"});
  db.goOffline();
};

dbupdate();
```
結果：こいつもダメでした。

間違いなどあったら訂正しますので是非ご指摘ください。

#追記
12/4 タイトルが日本語的にあれだったので直しました
12/6 ソース汚くて恥ずかしいのでスリム化しました
12/6 試したこと色々追記しました。田中みそさん、にしぞのさんの[ディスカッション](https://twitter.com/wowsawa/status/1069632446650474496)も貴重。