Open14

VimでElixirする

こまもか🦊こまもか🦊

LSPはMasonを使ってる場合、MasonInstall elixir-lsした後にlsが格納されているディレクトリを指定する

Linux(WSL)の場合は以下の通り。

if server == "elixirls" then
	require("lspconfig").elixirls.setup({
		-- Unix
		cmd = { "/home/coma/.local/share/nvim/mason/bin/elixir-ls" },
	})
end

以下参照元のGist(手前味噌)
https://gist.github.com/Comamoca/487ed2bf9470e55ca8e1481288a241b5

こまもか🦊こまもか🦊

Gistにも書いてあるけど、これだけだとハイライトが効かないので別途ハイライト用のプラグインを入れる必要がある

こまもか🦊こまもか🦊

これだけだと記事にするにはボリュームが少ないので、なんか適当な物を作ってボリュームを増やしたい

通信系の処理が得意[1]なのでWebsocketを使った簡単なチャットアプリを書いてみたい。この手の処理はElixir製のフレームワークPhoenixで書くのが良いらしいんだけど、フルスタックなフレームワークはどうも苦手なのでマイクロな感じで書いていきたい

脚注
  1. Erlang自体が通信系の処理を書くために作られているらしい ↩︎

こまもか🦊こまもか🦊

とりあえずインストールも環境構築も完了したので、早速ゴリッゴリに書いていきたいのだけれど実行方法が分からん。調べた感じ色々あるらしい。
https://qiita.com/pojiro/items/8955f78cfeb2e959c983

Goとかを書いているので、go run .みたいな感じで実行できるとありがたいのだけれど、それっぽいmix runを実行してもなぜか実行されない。

こまもか🦊こまもか🦊

Elixirには.ex.exsという二通りの形式があるらしく、

  • exはコンパイルするファイル
  • exsはインタプリタで実行可能なファイル(コンパイルが不要。設定ファイルとして使われてる場合が多い)

という違いがあるらしい。mix run/lib配下に.exファイルがある場合はコンパイルしかされない...という解釈で良いのだろうか

こまもか🦊こまもか🦊

escriptというものを使うと良い感じに実行できるらしい。

https://elixirschool.com/ja/lessons/intermediate/escripts#始めに-0

まずmix newで生成されるlib/配下のexファイルにあるdefmodule内にmain関数を作成する。この時引数でコマンドライン引数を受け取れるようにしなければいけないらしい。よく分かんなかったので以下の通りに実装してみた。_を使うと入力を切り捨てる事ができる。これは慣例的なのでわかりやすい。

# defmodule内に実装する
def main(_args // []) do
  IO.puts("Hi Elixir!")
end

次に mix.exsを編集する。差分は以下の通り

defmodule ElixirWebsocket.MixProject do
  use Mix.Project

  def project do
    [
      app: :elixir_websocket,
      version: "0.1.0",
      elixir: "~> 1.14",
      start_permanent: Mix.env() == :prod,
      # ElixirWebsocketはプロジェクトmain関数を追加したモジュールの名前
+     escript: [main_module: ElixirWebsocket],
      deps: deps()
    ]
  end
end

以下実行したコマンド

mix escript.build
# 配下に実行ファイルが生成される
./elixir_websocket
# main関数内の処理が実行される
こまもか🦊こまもか🦊

これでまぁまぁ実行しやすくなったけど、もっとシュッと実行する方法は無いのかな...色々調べてみるか

こまもか🦊こまもか🦊

ElixirでWebSocketサーバーを書く方法がPhoenix以外にほとんど見当たらなかったので、クライアントだけ書いてみる

WebSocketの受信先はMisskeyでやってみる[1]
https://misskey.io

WebSocketを実装しているライブラリで良さそうなのがあったので、これで実装してみる。
Hex:
https://hex.pm/packages/websockex

GitHub:
https://github.com/Azolo/websockex

脚注
  1. よく勘違いされがちだけどこのインスタンスはMisskey公式ではない。ただ開発者がアカウントを登録してるのと、安定していることもありユーザー数が世界で一番多かったりする ↩︎

こまもか🦊こまもか🦊

とりあえずMisskeyのストリームAPIにアクセスするために、投稿するようのJsonを書いている。

  def jsn do
    payload: %{
      type:  "connect",
      body: %{
        channel: "main", #ここでエラーが発生する
        id: "foobar",
      },
    }

このようにしてJsonに当たるMapの表現ができる。再帰的にMapを定義する場合は、そのMapにも%をつけないと構文エラーになるらしい。これでかなりハマったので注意

こまもか🦊こまもか🦊

WebSocketはハードルが高かったので、まずは適当なエントリポイントを叩くことにする。

Misskey APIを参考に、自分のアカウント情報を取得してみる。

https://twitter.com/Comamoca_/status/1627305753697746947?s=20

できた。リプにもソースコード貼ってるけどこっちにも。

    endpoint = "https://#{host}/api/i"

    body = %{
      i: token
    }

    resp =
      HTTPoison.post!(endpoint, Jason.encode!(body), %{
        "Content-Type" => "application/json"
      })

    json = Jason.decode!(resp.body)

    IO.puts("#{json["name"]}@#{json["username"]}")
    IO.puts(json["description"])