Current section

Files

Jump to
librarian lib SSH SCP fetch.ex
Raw

lib/SSH/SCP/fetch.ex

defmodule SSH.SCP.Fetch do
@moduledoc """
implements the data transactions involved in streaming SCP file transfer
*from* the destination server.
Concretely, the following functions are implemented:
- `init/2`, for `c:SSH.ModuleApi.init/2`
- `on_stdout/2`, for `c:SSH.ModuleApi.on_stdout/2`
- `on_stderr/2`, for `c:SSH.ModuleApi.on_stderr/2`
"""
require Logger
@behaviour SSH.ModuleApi
@impl true
@doc "initializes the fetching procedure for SCP"
@spec init(SSH.Stream.t, any) :: {:ok, SSH.Stream.t} | {:error, String.t}
def init(stream, _) do
# in order to kick off the SCP routine, we need to send an ready message,
# which is simply a "0" byte over the standard out.
SSH.Stream.send_data(stream, <<0>>)
{:ok, stream}
end
@impl true
@doc "responds to information returned on the `stderr` stream by the `scp -f` command"
@spec on_stdout(binary, SSH.Stream.t) :: {[], SSH.Stream.t}
def on_stdout("C0" <> <<_perms :: binary-size(3)>> <> _rest, stream) do
SSH.Stream.send_data(stream, <<0>>)
{[], stream}
end
def on_stdout(value, stream) do
# store all inbound values into the stream.
SSH.Stream.send_data(stream, <<0>>)
{[value], stream}
end
@impl true
@doc "responds to information returned on the `stdout` stream by the `scp -f` command"
@spec on_stderr(binary, SSH.Stream.t) :: {[term], SSH.Stream.t}
def on_stderr(string, stream), do: {[stderr: string], stream}
@impl true
@doc "handles the remote `scp` agent not calling back"
@spec on_timeout(SSH.Stream.t) :: {[], SSH.Stream.t}
def on_timeout(stream) do
SSH.Stream.send_data(stream, <<0>>)
{[], stream}
end
@doc false
def reducer(value, :ok) when is_binary(value) do
# TODO: don't use string.trim for this because String module expects
# unicode data.
{:ok, String.trim(value, <<0>>)}
end
def reducer(value, {:ok, previous}) when is_binary(value) do
# TODO: don't use string.trim for this because String module expects
# unicode data.
{:ok, previous <> String.trim(value, <<0>>)}
end
end