Packages
vix
0.31.1
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.1
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.1
0.2.0
retired
0.1.0
NIF based bindings for libvips
Current section
Files
Jump to
Current section
Files
lib/vix/target_pipe.ex
defmodule Vix.TargetPipe do
use GenServer
require Logger
alias Vix.Nif
alias __MODULE__
@moduledoc false
defstruct [:fd, :pending, :task_result, :task_pid]
defmodule Pending do
@moduledoc false
defstruct size: nil, client_pid: nil
end
@default_buffer_size 65_535
def new(vips_image, suffix) do
GenServer.start_link(__MODULE__, %{image: vips_image, suffix: suffix})
end
def read(process, max_size \\ @default_buffer_size)
when is_integer(max_size) and max_size > 0 do
GenServer.call(process, {:read, max_size}, :infinity)
end
def stop(pid) do
GenServer.stop(pid)
end
# Server
def init(%{image: image, suffix: suffix}) do
Process.flag(:trap_exit, true)
{:ok, nil, {:continue, %{image: image, suffix: suffix}}}
end
def handle_continue(%{image: image, suffix: suffix}, _) do
case Nif.nif_target_new() do
{:ok, {fd, target}} ->
pid = start_task(image, target, suffix)
{:noreply, %TargetPipe{fd: fd, task_pid: pid, pending: %Pending{}}}
{:error, reason} ->
{:stop, reason, nil}
end
end
def handle_call({:read, size}, from, %TargetPipe{pending: %Pending{client_pid: nil}} = state) do
do_read(%TargetPipe{state | pending: %Pending{size: size, client_pid: from}})
end
def handle_call({:read, _size}, _from, state) do
{:reply, {:error, :pending_read}, state}
end
def handle_info({:select, _read_resource, _ref, :ready_input}, state) do
do_read(state)
end
def handle_info({:EXIT, from, result}, %{task_pid: from} = state) do
do_read(%TargetPipe{state | task_result: result, task_pid: nil})
end
defmacrop eof, do: {:ok, <<>>}
defmacrop eagain, do: {:error, :eagain}
defp do_read(%TargetPipe{task_result: {:error, _reason} = error} = state) do
reply_action(state, error)
end
defp do_read(%TargetPipe{pending: %{size: size}} = state) do
case Nif.nif_read(state.fd, size) do
eof() ->
reply_action(state, :eof)
{:ok, binary} ->
reply_action(state, {:ok, binary})
eagain() ->
noreply_action(state)
{:error, errno} ->
reply_action(state, {:error, errno})
end
end
defp reply_action(%TargetPipe{pending: pending} = state, ret) do
if pending.client_pid do
:ok = GenServer.reply(pending.client_pid, ret)
end
{:noreply, %TargetPipe{state | pending: %Pending{}}}
end
defp noreply_action(state) do
{:noreply, state}
end
defp start_task(image, target, suffix) do
spawn_link(fn ->
result = Nif.nif_image_to_target(image, target, suffix)
Process.exit(self(), result)
end)
end
end