Phoenix websocketとNeosVRを繋ぐ

# はじめに
今回は[こちら](https://qiita.com/sand/items/886ace4dcdff5953e673)のクライアント部分をNeosVRに置き換えて
phoenix websocketをサーバーをデプロイしNeosVR内と通信をしていきます
やることとしては以下になります

Phoenix

- phoenix project作成
- websocketを有効化
- joinと、イベントを１つ作成
- デプロイ

NeosVR

- devtool -> new object -> 3d model > box
- box -> second -> open inspector -> add component -> network -> websocket client
- LogixToolTip -> box inspector -> websocket client grab -> box secondary 
- websocket connect logix
- websocket join logix
- websocket push event logix


# Phoenix
### プロジェクト作成
今回DBは使わないので、 --no-ectoを付けても問題ありません

```bash
phx.new neos
```

### Websocket
次にwebsocketを有効にします

```lib/neos_web/channels/user_socket.ex
defmodule NeosWeb.UserSocket do
  use Phoenix.Socket

  ## Channels
  channel "room:*", NeosWeb.RoomChannel
...
end
```

次にroom:*に対応するroom_channelモジュールを作成します
中身はjoin関数と、event5イベントになります
event5は以下の２つ関数を定義しています
payloadが{"error" => true}のときにエラーメッセージを返す関数
pongというメッセージを返す関数

```lib/neos_web/channels/room_channel.ex
defmodule NeosWeb.RoomChannel do
  use Phoenix.Channel
  require Logger

  def join(topic, _payload, socket) do
    Logger.info("*** topic = #{topic}")
    {:ok, socket}
  end

  def handle_in("event5", %{"error" => true}, socket) do
    {
      :reply,
      {:error,
        %{reason: "error flag for event5 request is true"}
      },
      socket
    }
  end

  def handle_in("event5", _payload, socket) do
    {:reply, {:ok, %{event: "pong"}}, socket}
  end
end

```

websocket部分はこれで完了なので、次はgigalixirにデプロイするための設定をしていきます

### Gigalixir
以下のコマンドでappを作成してURLを取得します

```
gigalixir create
```

your.gigalixir.com の箇所を上記で作成されたappのアドレスに書き換えてください

```config/prod.exs
config :neos, NeosWeb.Endpoint,
  url: [host: "your.gigalixir.com", port: 443],
  cache_static_manifest: "priv/static/cache_manifest.json"

```

sslを有効化しましょう

```config/prod.secret.exs
config :neos, Neos.Repo,
  ssl: true, # これ
  url: database_url,
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")

```

elixir,erlang,nodejs,npmのバージョンを指定しましょう

```elixir_buildpack.config
elixir_version=1.11.3
erlang_version=23.2.5
```

```phoenix_static_buildpack.config
node_version=12.14.0
npm_version=6.14.3
```

gigagixirのapp -> configurationのタブで
mix phx.gen.secret　secretで生成した値を
SECRET_KEY_BASEをキーにして保存してください

これで準備が終わりましたので以下のコマンドでデプロイしましょう

```
git push gigalixir main 
```

phoenix側はこれで終了になります


# NeosVR

### websocket clientをつけるオブジェクト作成
これを参考に作っていきましょう
https://www.youtube.com/watch?v=q9dqSebqlW4

### WebSocketClient
DevToolTipを装備してboxモデルを作成します
次にboxのインスペクターを出して add componentでWebSocketClientを追加します
clientを追加したらLogixToolTipに持ち替えて、WebSocketClientをグラブして
boxにレーザーを当てた状態でセカンダリーを押してスロットを表示させます

### WebSocket Connect Logix
connectionを貼るLogixはこんな感じで、BoxのinspectorのURLに直接入れても構いません
![connect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/cbf10949-c3ed-c122-2842-71771f6dd092.png)
左側の上から２番目をWebSocketClientスロットにつなげてください
input Stringにはyour.gigalixir.appをデプロイしたアプリのアドレスに置き換えてください

```
ws://your.gigalixir.app/socket/websocket?token=undefined&vsn=2.0.0
```

### WebSocket Join Logix
これでコネクションが貼れたので、次は特定のroomにjoinする処理を組んでいきます
![join.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/2ac78eae-4791-ef02-07cb-0b209ff599d9.png)
senderとreceiverの左側をWebSocketClientのスロットにつないでください
senderのinput Stringには以下を入力してください

```
["3","3","room:3","phx_join",{}]
```
各パラメータは
0と１番目の３は調査不足のためわかりませんが、
2 ルームと番号
3 joinイベントを発火させる
4 payload トークンとかを渡せます
となっています

成功すればreceiverのoutput stringの箇所にレスポンスが書き込まれます

### WebSocket Push Event Logix
次はイベントの発火になります
LogixはJoinと同じでinput stringだけが違います
![push_event.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/97321cdd-7ef7-f756-feb8-2f7f297e0184.png)
senderとreceiverの左側をWebSocketClientのスロットにつないでください
senderのinput Stringには以下を入力してください

```
["3","3","room:3","event5",{}]
```
2 roomと番号
3 発火させるイベント
4 payload {"error" => true}と入れるとエラーメッセージが返ってくる

これでsenderのパルスを発火させると phoenixのevent5が実行されて

```
{:ok, {event: "pong"}}
```
というレスポンスがreceiveのoutput stringの箇所に書き込まれます

# 最後に
これでPhoenix WebsocketとNeosVRを繋ぐことができました
phoenix側でbroadcastを実行すれば同一のroomにつないでいるオブジェクトに同じメッセージを送信したり、
現在同一のroomにあるオブジェクトの一覧を取得できたりと夢が広がりますね！

本記事は以上になりますありがとうございました!


# 参考
https://www.youtube.com/watch?v=q9dqSebqlW4
https://qiita.com/piacerex/items/4d8b23d99434d5a841ca
https://qiita.com/sand/items/886ace4dcdff5953e673
https://qiita.com/pojiro/items/efc72557fb00b56a977a
https://qiita.com/torifukukaiou/items/d2d0e9f56ffe3bb8eda1