Elixirでの画像のやり取りはPhoenixやLiveViewのHTTPで送受信する記事が多く、例えばGenServerなどの他の通信方法でできるんかよく分からなかったのでやってみました。GenServerで。
環境
このような環境で確認しました。
❯ sw_vers
ProductName: macOS
ProductVersion: 13.5
BuildVersion: 22G74
❯ asdf current
elixir 1.14.5-otp-25
erlang 25.2.2
画像送受信の流れ
テストってことで、画像フォーマットチェックやファイル名指定して送受信などは考慮していません。
- プロジェクトの配下のディレクトリに画像ファイルを設置
-
./data/IMG_9999.jpg
を設置
-
- ローカルで起動しているGenServerのプロセスに
GenServer.cast()
- GenServerでは、受信した画像ファイルを
./data/receive/1.jpg
として保存
プロジェクト作成
ImageTransceiver
というプロジェクトを作成してモジュールを作っていきます。
❯ mix new image_transceiver
❯ cd image_transceiver
送受信のプログラム作成
lib
ディレクトリの下に、送信用のモジュールと受信用のモジュールを作成します。
- 送信用:lib/send.ex
- 受信用:lib/reciev_server.ex
送信用:lib/send.ex
ファイルを読み込み、GenServer.castするプログラムとしています。
defmodule ImageTransceiver.Send do
def to(to_pid, image_path) do
{:ok, image_file} = File.read(image_path)
GenServer.cast(to_pid, {:send, image_file})
end
end
受信用:lib/reciev_server.ex
handle_castで受信した画像を 1.jpg
として保存するプログラムとしています。
長くなるので必要最低限の関数のみ記載してます。
defmodule ImageTransceiver.RecieveServer do
use GenServer
def start_link([my_pname]) do
state = []
GenServer.start_link(__MODULE__, state, name: my_pname)
end
@impl true
def handle_cast({:send, image_file}, state) do
File.write!("./data/receive/1.jpg", image_file)
{:noreply, state}
end
@impl true
def init(state) do
{:ok, state}
end
end
いよいよやってみた
まずは受信ディレクトリに移動して、何もファイルがないことを確認。
❯ cd data/receive
❯ ls -l
total 0
プロジェクトフォルダ直下で、iexを実行し、サーバープロセスを起動して、画像ファイルを送信。
❯ iex -S mix
iex> ImageTransceiver.RecieveServer.start_link([:recieve_server])
{:ok, #PID<0.223.0>}
iex> ImageTransceiver.Send.to(:recieve_server, "./data/IMG_9999.jpg")
:ok
受信ディレクトリでファイルができていることを確認。
❯ ls -l
total 3560
-rw-r--r-- 1 kazuma staff 1820267 8 4 15:06 1.jpg
まとめ
はじめは、画像エンコードしなきゃーとかやっぱりBase64かねーとか思ってたんですが、特に考慮せずに画像を送受信することができました。いや、ホントは考慮しないといけないことはまだまだあるんでしょうけど。
今回はローカルでの確認となったのでファイルコピーになっちゃいましたけど、サーバープロセスをリモートで稼働していると、リモートのノードに画像ファイルコピーやり放題!ってなるので何かに使えるかもです