Skip to content

Instantly share code, notes, and snippets.

@kevinkoltz
Created April 17, 2019 15:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevinkoltz/9d642ddd8a017376bf14b348f814a73c to your computer and use it in GitHub Desktop.
Save kevinkoltz/9d642ddd8a017376bf14b348f814a73c to your computer and use it in GitHub Desktop.
defmodule SeleniumServer do
@moduledoc """
Runs Selenium Server from a process.
Can be supervised from the application, for example:
# Define workers and child supervisors to be supervised
children = [
...other children
# Start selenium server process for Hound
supervisor(SeleniumServer, [])
]
"""
use GenServer
require Logger
@executable "selenium-server"
@args ""
@impl
def init(state \\ %{}) do
send(self(), :start)
{:ok, state}
end
def start_link() do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
@impl true
def handle_info(:start, state) do
start()
{:noreply, state}
end
defp start do
shutdown_existing_selenium_server()
path = System.find_executable(@executable)
port =
Port.open({:spawn_executable, path}, [
:stderr_to_stdout,
:binary,
:exit_status
])
{:os_pid, os_pid} = Port.info(port, :os_pid)
System.at_exit(fn _exit_status ->
swallow_cmd("kill -9 #{os_pid}")
end)
stream_output(port)
end
defp shutdown_existing_selenium_server() do
swallow_cmd("kill -9 $(lsof -ti tcp:4444)")
end
defp stream_output(port) do
receive do
{^port, {:data, data}} ->
log_selenium_output(data)
stream_output(port)
{^port, {:exit_status, 0}} ->
log("Command success")
{^port, {:exit_status, status}} ->
log("Command error, status #{status}", :error)
end
end
# Sends standard output and standard error to /dev/null,
# preventing it from being printed to the screen.
defp swallow_cmd(cmd) do
"#{cmd} > /dev/null 2>&1"
|> to_char_list
|> :os.cmd()
end
defp log_selenium_output(data) do
data
|> String.split("\n")
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))
|> Enum.map(fn message ->
[
~r/^[0-9]{4}-[0-9]{2}-[0-9]{2}\s+/,
~r/^[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}\s+/,
~r/^INFO\s+/,
~r/.*INFO::main:\s+/
]
|> Enum.reduce(message, fn regex, acc ->
Regex.replace(regex, acc, "")
end)
end)
|> Enum.each(&log/1)
end
defp log(message, level \\ :info) do
Logger.log(level, "[SeleniumServer] " <> String.trim(message))
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment