Unity WebGL x IoT ~スマートロックをつくったよ~ WebHook編

# はじめに
　とある事情があり、スマートロックほしい。スマートロック超便利。作ろう。となったので作ったのですが。色々な罠を踏み抜いたのでそれを書いていきます。なお、大量に罠を踏み抜いた理由は以下のような変な構成にしたからです。<font color="gray">(この構成にした理由は、上からの「早く作りなさい」という圧力と、私のスキル)</font>
![image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338159/5344ff27-a7bb-6818-67b4-58a8af3e3d83.jpeg)

 さて、三回目の今回はWebHook編です。

## WebGLでネットワークを使う
　前回の、UnityのWebGLではネットワークが使えないというままだと救いがないのでUnity WebGLでネットワークを使う方法を紹介してきます。

### UnityのNetWork
　WebGLでは`WWW`クラスと`UnityWebRequest`クラスが使えます。今は`WWW`は使わないほうがいいとされています。使い方は以下のもののようです。
[kanのメモ帳 : UnityWebRequestの使い方【Unity】](http://kan-kikuchi.hatenablog.com/entry/UnityWebRequest)
　私が作っているときは上のような便利なページを見つけられなかったので以下のようにJSで書きました。サンプル数は圧倒的にJSのほうが多いです。

### JSでNetWork
　UnityでJSを使うには.jslibにJSの関数を書いて、C#から呼び出します。公式ページの説明は[こちら](https://docs.unity3d.com/ja/current/Manual/webgl-interactingwithbrowserscripting.html)です。
　URLにpostすることを元に解説していきます。

```js:post.jslib

mergeInto(LibraryManager.library, {
    //ここに関数を書く
})

```

　基本はこの形です。
　次に、関数を宣言していきます。

```js:post.jslib

mergeInto(LibraryManager.library, {

    post1: function (url, msg1, msg2) {
        //中身
    },  //複数の関数を書くときは間にコロンを忘れずに

    post2: function (url, msg1, msg2){
        //同じく
    }   //最後のところにはコロンはないよ
}

```

　このように書くと、ダブルコロンの前が関数名となり、かっこの中はC#と同じように引数となります。型名を書かないのがJSです。
　このように書いた関数を、C#(Unity)から使うには以下のようにします。

```csharp
public static class Hoge{

    [DllImport("__Internal")]
    private static extern void post1(string url, string msg1, string msg2);

    [DllImport("__Internal")]
    private static extern void post2(string url, string msg1, string msg2);

}
```

　`[DllImport("__Internal")]`の後に.jslibで書いた関数と同じ名前、同じ引数の数の関数を宣言すると、使えるようになります。

#### JSONでURLにPost

　ではJSON形式でURLにPostする関数を作ります。

```js

    post1(url, msg1, msg2){
        var j_url = Pointer_stringify(url);
        var j_msg1 = Pointer_stringify(msg1);
        var j_msg2 = Pointer_stringify(msg2);
    }

```

　string型は、そのままJSに渡せないので、`Pointer_stringify()`関数を使ってJSのstringにします。
　それでは完成させます。

```js
    post1: function(url, msg1, msg2){

    var j_url = Pointer_stringify(url);
    var j_msg1 = Pointer_stringify(msg1);
    var j_msg2 = Pointer_stringify(msg2);
    
    //これはJSONで送ってるよと伝える
    var headers = new Headers({
      'Content-Type': 'application/json',
    });

    //中身のJSONにする配列製作
    var bodys = {
      "msg1": j_msg1,
      "msg2": j_msg2,  //JSでJSON(というか配列)を作るときは最後の後のコロンを忘れずに
    };

    //これでURLにPOSTしている
    fetch(j_url,{
      method : 'POST',
      headers : headers,
      body : JSON.stringify(bodys)
    });
  },
```

#### URLエンコードでURLにPost

　次に、URLエンコードでURLにPostします。

```js
    var bodys = 'msg1=' + encodeURIComponent(j_msg1) + '&msg2=' + encodeURIComponent(j_msg2);
```

　`変数名=encodeURIComponent(中身)`としてやることで、bodyをURLエンコードできます。変数をいくつも送るときは、間を`&`でつなぎます。その他はJSONの時とほぼ変わりません。
　完成版は以下です。

```js
    post2: function(url, msg1, msg2){

    var j_url = Pointer_stringify(url);
    var j_msg1 = Pointer_stringify(msg1);
    var j_msg2 = Pointer_stringify(msg2);

    //JSONじゃなくてURLエンコードなのに注意
    var headers = new Headers( {
        'Content-Type': 'application/x-www-form-urlencoded',
      }
    );

    var bodys = 'msg1=' + encodeURIComponent(j_msg1) + '&msg2=' + encodeURIComponent(j_msg2);

    fetch(j_gas,{
      method : 'POST',
      body : bodys,
      headers : headers
      }
    );

  }
```

## Beebotteに情報を送る

　以上のことを踏まえて、どのような壁に当たってどのような罠にはまって最終的にどのように実現したのか書いていきます。

### Beebotte SDK の罠

　BeeBotteには、C#用のSDKもあり、こりゃ楽だと思っていました。**Editor上では**。しかし、このSDKも例にもれず.NETの`Networking`を使っていましたので、当然ブラウザ上では動きませんでした。
　何とか原因を見つけ出し、SDKにあった.NETの`Networking`を全てUnityのものに置き換えたところ、次の罠が待って今した。(なお、SDK自体は使いやすかったです。)

### http-request-headerの罠
　
　UnityのWebReqestに置き換えたものをブラウザ上で実行したところ、`http requestのdateは変更することはできません`みたいなエラーが出ました。（詳細なエラーメッセージ覚えていなくてすいません。）
　色々調べたところ、どうやらchromeではセキュリティー的にいくつかのhttp-request-headerの値は変更できないみたいです。ということで全く別の道を探す必要が出てきました。

### 公式に載っていた別のやり方（失敗）

- beebotteの公式にクライアント側のJSでPublishできるものがあったが、サーバーを経由するもので、サーバーレスの今回は断念。
- MQTTで送信するJSはあったが、node.jsのもので、MQTTからMQTTは送れないので断念。

### なんとかbeebotteへ送れた

　必死に公式のドキュメントを見ていると、cURLの物ってそのままPostではないか？うまく書き直したら行けるのでは？と思い、これが大当たり。何とかなりました。以下がcURL。

```shell

curl -i -H "Content-Type: application/json" \
  -H "X-Auth-Token: YOUR_CHANNEL_TOKEN" \
  -X POST -d '{"data":"Hello World"}' \
  http://api.beebotte.com/v1/data/publish/private-(チャンネル名)/(トピック名)

```

　そして、以下がJSに直したもの。

```js

    var j_url = "http://api.beebotte.com/v1/data/publish/private-(チャンネル名)/(トピック名)";
    var j_token = "YOUR_CHANNEL_TOKEN";
    
    var bodys = {
        "data" : "Hello World",
    };

    const headers = new Headers( { 
        "Content-type" : "application/json",
        "X-Auth-Token": j_token, 
        }
    );
    fetch(j_url, {
            method : 'POST',
            body : JSON.stringify(bodys),
            headers: headers
        }

```

## LineBotに情報を送る

　多人数で鍵の管理をする予定だったので、開けたり、閉めたりする時に通知があると便利だと思い作りました。
　LineBotに関しては皆さんよくやられているようで、たくさん参考資料があってやりやすかったです。また、公式のドキュメントは豊富でした。(ただし肝心のところがないのはお約束)

### LineBotの罠1

　Webhookがあったので直接Postしようとしましたが、CORSによってはじかれました。よって、GASを経由して送るという方針に転換しました。ただ、一つ罠あったんですけど。

### GASの罠

　bodyをLineで使うJSON形式でPostしましたが、これがいけませんでした。GASへはJSON形式でPostできないようです。（なぜかCORSエラーが返ってきて謎だった。）そのため、`x-www-form-urlencoded`でPostしました。


### LineBotの罠2

　運用に入ってから気づいたことなのですが、異様に早くメッセージの上限に達しました。なぜかと理由を探ったところ、グループでは、一発言につき人数分の発言をしたこととなるようです。~~（おかげで数日しか持たないbotとなった）~~

## SlackBotに情報を送る

　こちらはLine以上に資料があり、Webhookのインテグレーションもすんなりと行き、ほぼ問題なくできました。一点を除いては。

### SlackBotの罠

　こちらもJSONのPostができませんでした。しかし、こちらは少々特殊で、`http-request-header`の`Content-Type`を`application/x-www-form-urlencoded`するだけですんなり通りました。<font color=gray>なんでやねん。body、JSONや。</font>

# The next is...

　なんとか他のサービスにつなげることができたのでここは以上です。次は[ラズパイ編](https://qiita.com/kumaS-kumachan/items/d6407d7c9c62f90af9b7)です。

# シリーズ一覧

* [NCMB編](https://qiita.com/kumaS-kumachan/items/bd4df506f01f5014b154)
* [Unity WebGL編](https://qiita.com/kumaS-kumachan/items/8be3bf4e3bad31f5cb12)
* WebHook編　←いまここ
* [ラズパイ編](https://qiita.com/kumaS-kumachan/items/d6407d7c9c62f90af9b7)