memorandums

日々の生活で問題解決したこと、知ってよかったことなどを自分が思い出すために記録しています。

GASクリッカー・アプデ

昨年の授業用にGAS(Google App Script)+ Fusion Tableで簡易的なクリッカーアプリを作りました。

memorandums.hatenablog.com

が。

Fusion Tableが今年いっぱいで終了する。。。ということで、書き換えなきゃなぁ。。。と。

gsuiteupdates-ja.googleblog.com

せっかくなのでRailsで作り直そうとも思ったのですが、データの集計とか考えるとGoogle SpreadSheetで扱える利点は大きいので。そのままGASでいきたいな。。。と。

ググるとFirebaseが使えるようですが、それこそGoogle SpreadSheetとの連携部分も作らなければならないのは嫌だな。。。と。

Google SpreadSheetのワークシートをDBとして利用できることは知っていましたが。。。さすがに遅いだろうなとFusion Tableを使ってきました。

とりあえず試しにGoogle SpreadSheetをDB化してみることにしてみました。

すると、なんかそれなりに動いちゃいました。データを挿入するコードは以下のような感じです(★先に書きますが、これは実はダメコードですので気をつけてください)。とりあえずロックはかけるようにしました。FusionTableではその必要はなかったんですけどね。。。

function insert(id, no, ans, timestamp){
  if (isWritable(no)) {
    var lock = LockService.getScriptLock();
    if (lock.tryLock(30000)) {
      var spreadsheet = SpreadsheetApp.openById('★idをいれます★');
      var sheet = spreadsheet.getSheetByName('data');
      var r = sheet.getLastRow() + 1; //空の場合は0が返ってくるので1足している
      var v = [[r, no, ans, timestamp]];
      sheet.getRange(r, 1, 1, 4).setValues(v);
      lock.releaseLock();
    }
    return 1;
  } else {
    return 0; //時間外のため送信不可
  }
}

とりあえず、一通り完成させたあと、複数人で同時に書き込んでも動作するだろうか。。。とテストをしようとしたのですが、これが経験値がなかったので実現方法を探すのに苦労しました。日頃、Web開発している人ならすぐ思いつくのでしょうね。。。

クリッカーのUIは以下のような感じです。学籍番号を入力してもらい、選択肢を選択して送信ボタンを押してもらいます。複数人で同時に送信するテストをするには、とりあえず送信ボタンを押さなければなりません。

f:id:ke_takahashi:20190319173821p:plain

で、この辺はGUIテストのツールがあるだろうと。。。ぐぐってchromeless、cypressを試しました。いずれもダメ。。。スクリプトの書き方をいろいろと試行錯誤しましたがダメ。Chrome拡張を使って操作を記録してスクリプトを生成してみましたがこれもダメ。原因は薄々気づいていたのですが、上記のUIを出力するhtmlをGASで作成しているのですが、このhtmlがユニコード化?されるんですね。。。以下のような感じ。なのでDOMの解析ができず目的の要素にたどり着けない。。。当然といえば当然なんです。

f:id:ke_takahashi:20190319174514p:plain

ユーザに送信ボタンを押させることは無理とわかりました。調べたいのはGASからGoogle SpreadSheetに挿入するスクリプトを同時に実行したときの動作なので、上記のUIを初期表示したときにこのスクリプトを起動するように書き換えました。

そして、とりあえずHTTPリクエストを送ればいいと思い、wgetcurlを使ってgetしてみたのですがダメ。。。この辺の仕組みはよくわかりませんが、Ajax通信するときに成功・失敗の処理をしないと単にGASのスクリプトをキックできない。。。そんな感じのように思います。つまるところ、コマンドラインからのアクセスでは難しく、ブラウザでしっかりアクセスしてあげなければいけない。。。ようでした。

最後の手として、ChromeでGASのページを数十個タブを開いて同時に更新する手を試してみました。複数のタブを同時に更新するには以下のChrome拡張がありました。

chrome.google.com

これで何とかテストできました。実行するとダメ。。。30個タブを開いて同時更新すると20個くらいしかGoogle SpreadSheetには追加されません。

上記のinsert関数の読み出し回数を調べようとしたのですが、GASのログ関数であるLogger.logはHTTPリクエスト1回分の履歴しか保存できないようで回数がわかりません。こう書いても何を言っているのかわからないですよね。。。たぶん。とりあえず私的メモなのでご容赦を。

直接的な原因がわからないまま、とりあえずGoogle SpreadSheetにデータを挿入する方法を変えてみることにしました。Excelマクロではよく使う手だったのですが、最終行を取得してその次の行に新しいデータを追加するようにしていたのですがどうもこれがうまくいかなかったようです。で、appendRowという便利メソッドを使うことで自動的に最終行に追加できるようになりました。

function insert(id, no, ans, timestamp){
  if (isWritable(no)) {
    var lock = LockService.getScriptLock();
    if (lock.tryLock(30000)) {
      var spreadsheet = SpreadsheetApp.openById('★idをいれます★');
      var sheet = spreadsheet.getSheetByName('data');
      sheet.appendRow([id, no, ans, timestamp]);
      lock.releaseLock();
    }
    return 1;
  } else {
    return 0; //時間外のため送信不可
  }
}

受講生はだいたい50名くらいなので、これでもうまくいくと思われます。あとは本番で試すしかないですね。。。