Skip to content

Instantly share code, notes, and snippets.

@peerreynders
Created December 18, 2018 21:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peerreynders/cbefdef71ce85fa0017d8d3262a9e1cd to your computer and use it in GitHub Desktop.
Save peerreynders/cbefdef71ce85fa0017d8d3262a9e1cd to your computer and use it in GitHub Desktop.
Elixir port using named pipe with forwarding script
defmodule FromPipe do
#
# Use a helper script "from_pipe_forward" to communicate
# contents from the named pipe to the port
#
@pipe_name "/tmp/testpipe"
@from_pipe_forward "./from_pipe_forward"
@from_pipe_clean "./from_pipe_clean"
# * terminate potential zombie OS process
# * trash potential left over named pipe
#
def clean() do
script_path = Path.expand(@from_pipe_forward)
path = Path.expand(@from_pipe_clean)
System.cmd(path, [script_path, @pipe_name])
end
# Signal forwarding OS process to clean up and terminate
#
def sig_int(os_pid) do
System.cmd("kill", ["-INT", Integer.to_string(os_pid)])
:ok
end
# Start the forwarding OS process script.
# Monitor in case process terminates
#
def start do
path = Path.expand(@from_pipe_forward)
args = [@pipe_name]
port = Port.open({:spawn_executable, path}, [:binary, :in, args: args])
ref = Port.monitor(port)
{port, ref}
end
# Demonitor and Close and close port
# Signal OS process to terminate
#
def stop({port, ref}) do
Port.demonitor(ref, [:flush])
info = Port.info(port, :os_pid)
Port.close(port)
# interrupt script reading from named pipe
case info do
{:os_pid, os_pid} ->
sig_int(os_pid)
_ ->
:ok
end
end
# Data Processing Loop
#
def loop({port, ref} = args) do
receive do
{^port, {:data, "quit\n"}} ->
stop(args)
{^port, {:data, data}} ->
IO.puts("port data: #{data}")
loop(args)
{:DOWN, ^ref, :port, ^port, _reason} ->
# script was terminated
:ok
msg ->
IO.puts("other: #{inspect(msg)}")
loop(args)
end
end
# Start "listening""
#
def run() do
clean()
loop(start())
end
end
#!/bin/bash
# file: from_pipe_clean script_path pipe_name
# kill script if running
pkill -KILL -f "$1 $2"
# remove pipe if present
if [[ -p $2 ]]; then
rm -f $2
fi
#!/bin/bash
# file: from_pipe_forward pipe_name
# cascade traps to prevent double cleanup
pipe=$1
trap cleanup EXIT
trap 'exit 127' HUP INT QUIT ABRT
cleanup() {
rm -f $pipe
exit 0
}
if [[ ! -p $pipe ]]; then
mkfifo $pipe
fi
set -e
while read line <$pipe; do
echo $line 2> /dev/null
done 2> /dev/null
1$ iex
Erlang/OTP 21 [erts-10.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> c("from_pipe.ex")
[FromPipe]
iex(2)> FromPipe.run()
port data: hello

port data: world

port data: 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ

:ok
iex(3)>
2$ echo hello >/tmp/testpipe
2$ echo world >/tmp/testpipe
2$ echo 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ >/tmp/testpipe
2$ echo quit >/tmp/testpipe
2$ 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment