Elixirでチャットサーバを作ってみた

動機

Elixirを使ってスクレイピングとか、そんなことをやっていたのですが、ふとあんまりElixirらしい使い方では無いなと思いました。 それで、ElixirらしいといえばOTPなんかを使ったサーバサイドプログラミングだと思っているので、そんな感じのことをすればElixirのなんたるかが見えてくるのではないかと思ったので、軽めにチャットサーバなんかを作ってみようと思いました。

目的

  • チャットサーバの作成
  • チャンネル機能の実装
  • 各種チャットの情報を取得するコマンドの実装
  • OTPの学習(最初はホントに名前くらいしか知らなかった)注: 今回全く使いこなせてません。

OTP(Behavior)

とりあえずわかったこと

Behaviorとは、振る舞いという意味で、ここでは、サーバの振る舞いという意味。この振る舞いというのは、サーバを構築する上でよくでてくる実装をサーバのBehaviorとしていて、その振る舞いをテンプレート化しようっていうやつがらしい。なので、やってることは、簡単で細かいフレームワーク群を用意しているみたいな感じだった。

GenServer Behavior

  • Erlang VM上でプロセス間通信を行う際に行う処理のBehaviorの一つ
  • コールバック何かを使って、プロセス間通信の処理を隠蔽している

Supervisor Behavior

  • Supervisorが監視しているプロセスがクラッシュした場合、指定した戦略に基づいてプロセスを再起動する。
  • Supervisor Treeといった形で、プロセスをSuperviseして、更にそれをSuperviseして、Tree状にして管理するらしい

できていない点

  1. Behaviorを使って、他のVM上のプログラムとの通信を行うこと。
  2. クライアント/サーバシステムとして設計したが、クライアントとサーバを物理的に別のプログラムにした(同じVM上じゃなくした)ためGenServerのようなBehaviorで通信を行うことができなかった。
  3. プロセス化したクライアントアクセプタがうまく機能しなかったうえ、Superviseもうまく行かなった。

改善のアイディア

  • とりあえず、設計をもっとElixir(Erlang)に合わせて考える。
    • すごいErlangゆかいに学ぼう!を読め
  • Supervisor Treeの設計も念頭において設計をする
    • まず、Supervisorを使いこなせ
  • サンプルを見ているとサーバとクライアントを同じVM上に実装していたので、真似する。

    • どうやって、サーバとクライアントを物理的に離して接続してるのか全く想像がつかない
    • ElixirのNodeという機能を使うことで実現できるみたいです。Nodeについては、これから勉強します。
  • Elixirむずくね?

というわけで、チャットシステムの概要

f:id:naxatoko:20170721231808p:plain こんな感じで、サーバとクライアントを分けてます。 Processとかいうよくわかんない部分がありますが、実は、Reciverの部分に取り込まれており、実は、明確には分割されていません。 当初はchannelシステムなしで行こうと考えていたのでstate lessなシステムになると思っていたのですが、途中でchannelシステムを追加したため、思ったよりも状態が複雑になってしまい、そのへんがグダグダになってしまっいました。

システムの流れ

  1. クライアントから何らかのeventが送信される
  2. サーバがそのイベントを受信し、それに対応した処理を行う
  3. その結果、クライアントへ送信する必要があれば、eventを送信する
  4. クライアントは、eventを受け取ったらそれに応じた処理を行う

機能の解説

発言する以外の機能を用いる際は、:hogehogeといったようにすると、存在する機能の場合、hogehoge機能に対する処理が実行されます。

  1. channel機能

    • :channel_list
      • 現在サーバが管理しているチャンネル一覧を表示する
    • :now_channel
      • 現在、クライアントが所属しているチャンネルを表示する
    • :user_list
      • 現在所属しているチャンネルのユーザ一覧を表示する
    • :move arg1
      • arg1で指定したチャンネルに所属チャンネルを移動する
    • :create arg1
      • arg1で指定した名前のチャンネルを作成する
    • :delete arg1
      • arg1で指定した名前のチャンネルを削除する
  2. whisper機能

    • :whisper arg1 arg2
      • arg1で指定したユーザに対してarg2をメッセージとして送信
  3. say機能

    • arg1
      • 先頭にコマンドを指定しないで、入力すると、現在所属しているチャンネルにarg1を発言する

反省

  • Nodeの存在を知らなかったばっかりに、クライアントとのコネクションを:gen_tcpで持ってきてた。
    • Nodeの勉強します
  • Behaivior,OTPについて取っ掛かりをしっかりつかめたので、発展させていきたい
  • Supervisoruで管理できるプロセスは、基本的に何らかのBehaiviorに則ったプロセスのみなので、注意したい
  • すごいE本を読む

Source

Nodeの仕組みを知らなかったため、サーバとクライアントのソースが別れている;;