remove elixir code
This commit is contained in:
parent
884c9f736d
commit
f8269c8aec
18 changed files with 119 additions and 711 deletions
117
.gitignore
vendored
117
.gitignore
vendored
|
@ -10,30 +10,111 @@ thumbs.db
|
||||||
/priv/yarn-debug.log*
|
/priv/yarn-debug.log*
|
||||||
/priv/yarn-error.log*
|
/priv/yarn-error.log*
|
||||||
|
|
||||||
# The directory Mix will write compiled artifacts to.
|
# Byte-compiled / optimized / DLL files
|
||||||
/_build/
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
# If you run "mix test --cover", coverage assets end up here.
|
# C extensions
|
||||||
/cover/
|
*.so
|
||||||
|
|
||||||
# The directory Mix downloads your dependencies sources to.
|
# Distribution / packaging
|
||||||
/deps/
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
# Where 3rd-party dependencies like ExDoc output generated docs.
|
# PyInstaller
|
||||||
/doc/
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
# Installer logs
|
||||||
/.fetch
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
# Unit test / coverage reports
|
||||||
erl_crash.dump
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
# Also ignore archive artifacts (built via "mix archive.build").
|
# Translations
|
||||||
*.ez
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
# Ignore package tarball (built via "mix hex.build").
|
|
||||||
elstat-*.tar
|
|
||||||
|
|
||||||
*.db
|
*.db
|
||||||
config/config.exs
|
config.py
|
||||||
|
|
||||||
|
|
20
config.example.py
Normal file
20
config.example.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
PORT = 8069
|
||||||
|
|
||||||
|
SERVICES = {
|
||||||
|
'elixire': {
|
||||||
|
'description': "elixi.re's backend",
|
||||||
|
'adapter': 'elixire',
|
||||||
|
'adapter_args': {
|
||||||
|
'base_url': 'https://elixi.re'
|
||||||
|
},
|
||||||
|
'poll': 10
|
||||||
|
},
|
||||||
|
'dabian': {
|
||||||
|
'description': 'elixi.re main server',
|
||||||
|
'adapter': 'ping',
|
||||||
|
'adapter_args': {
|
||||||
|
'address': '192.168.1.1'
|
||||||
|
},
|
||||||
|
'poll': 15
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
use Mix.Config
|
|
||||||
|
|
||||||
config :elstat,
|
|
||||||
# where will elstat (backend and frontend)
|
|
||||||
# be served
|
|
||||||
port: 8069,
|
|
||||||
|
|
||||||
# which services will be managed by elstat?
|
|
||||||
# this follows a service spec
|
|
||||||
# the example here is for elixire
|
|
||||||
services: [
|
|
||||||
%{
|
|
||||||
id: :elixire,
|
|
||||||
description: "elixi.re",
|
|
||||||
adapter: Elstat.Adapter.Elixire,
|
|
||||||
adapter_opts: %{
|
|
||||||
base_url: "https://elixi.re",
|
|
||||||
},
|
|
||||||
# every 10 seconds
|
|
||||||
poll: 10,
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
id: :genserver,
|
|
||||||
description: "genserver, elixire main server",
|
|
||||||
adapter: Elstat.Adapter.Ping,
|
|
||||||
adapter_opts: %{
|
|
||||||
address: "192.168.1.1",
|
|
||||||
},
|
|
||||||
poll: 15,
|
|
||||||
},
|
|
||||||
]
|
|
|
@ -1,27 +0,0 @@
|
||||||
use Mix.Config
|
|
||||||
|
|
||||||
config :elstat,
|
|
||||||
port: 8069,
|
|
||||||
|
|
||||||
# which services will be managed by elstat?
|
|
||||||
# this follows a service spec
|
|
||||||
# the example here is for elixire
|
|
||||||
services: %{
|
|
||||||
elixire: %{
|
|
||||||
description: "the backend of elixi.re",
|
|
||||||
adapter: Elstat.Adapter.Elixire,
|
|
||||||
adapter_opts: %{
|
|
||||||
base_url: "https://elixi.re",
|
|
||||||
},
|
|
||||||
# every 10 seconds
|
|
||||||
poll: 10,
|
|
||||||
},
|
|
||||||
genserver: %{
|
|
||||||
description: "genserver, elixire main server",
|
|
||||||
adapter: Elstat.Adapter.Ping,
|
|
||||||
adapter_opts: %{
|
|
||||||
address: "192.168.1.1",
|
|
||||||
},
|
|
||||||
poll: 15,
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
defmodule Elstat.Adapter do
|
|
||||||
@type adapter_check_res :: {:ok, any()} | {:error, any()}
|
|
||||||
|
|
||||||
@type adp_args :: Map.t
|
|
||||||
|
|
||||||
@callback check(adp_args) :: adapter_check_res
|
|
||||||
end
|
|
|
@ -1,39 +0,0 @@
|
||||||
defmodule Elstat.Adapter.Elixire do
|
|
||||||
@behaviour Elstat.Adapter
|
|
||||||
|
|
||||||
def adapter_spec do
|
|
||||||
%{
|
|
||||||
db_columns: [:timestamp, :status, :latency]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def check(args) do
|
|
||||||
addr = args.base_url
|
|
||||||
|
|
||||||
req_start = :erlang.monotonic_time(:millisecond)
|
|
||||||
status = HTTPoison.get("#{addr}/api/hello")
|
|
||||||
req_end = :erlang.monotonic_time(:millisecond)
|
|
||||||
|
|
||||||
delta = req_end - req_start
|
|
||||||
|
|
||||||
case status do
|
|
||||||
{:ok, resp} ->
|
|
||||||
{:ok, {:map, %{
|
|
||||||
status: resp.status_code == 200,
|
|
||||||
latency: delta
|
|
||||||
}}}
|
|
||||||
{:error, reason} ->
|
|
||||||
{:ok, {:map, %{
|
|
||||||
status: false,
|
|
||||||
|
|
||||||
# use drops to 0 as failure on conn
|
|
||||||
latency: 0
|
|
||||||
}}}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def transform_val({:map, %{status: status, latency: latency}}) do
|
|
||||||
[status, latency]
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,20 +0,0 @@
|
||||||
defmodule Elstat.Adapter.Ping do
|
|
||||||
@behaviour Elstat.Adapter
|
|
||||||
|
|
||||||
def adapter_spec do
|
|
||||||
%{
|
|
||||||
db_columns: [:timestamp, :status]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def check(args) do
|
|
||||||
{cmd_output, _} = System.cmd("ping", ["-c", "1", args.address])
|
|
||||||
alive? = not Regex.match?(~r/100(\.0)?% packet loss/, cmd_output)
|
|
||||||
{:ok, {:bool, alive?}}
|
|
||||||
end
|
|
||||||
|
|
||||||
def transform_val({:bool, alive?}) do
|
|
||||||
[alive?]
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
33
lib/api.ex
33
lib/api.ex
|
@ -1,33 +0,0 @@
|
||||||
defmodule Elstat.API.CurrentStatus do
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def init(req0, state) do
|
|
||||||
data = Elstat.Manager.get_current_state()
|
|
||||||
|
|
||||||
req = :cowboy_req.reply(200,
|
|
||||||
%{"content-type" => "text/json", "Access-Control-Allow-Origin" => "*"},
|
|
||||||
Poison.encode!(data),
|
|
||||||
req0
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, req, state}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defmodule Elstat.API.Status do
|
|
||||||
def init(req0, state) do
|
|
||||||
status = Elstat.Manager.get_current_state()
|
|
||||||
graph = Elstat.Manager.get_graph_state()
|
|
||||||
|
|
||||||
req = :cowboy_req.reply(200,
|
|
||||||
%{"content-type" => "text/json", "Access-Control-Allow-Origin" => "*"},
|
|
||||||
Poison.encode!(%{
|
|
||||||
status: status,
|
|
||||||
graph: graph,
|
|
||||||
}),
|
|
||||||
req0
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, req, state}
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,41 +0,0 @@
|
||||||
defmodule Elstat.Cowboy.DefaultHandler do
|
|
||||||
def init(req0, state) do
|
|
||||||
|
|
||||||
# TODO: find a way to send a html file
|
|
||||||
# instead of hewwo owo
|
|
||||||
req = :cowboy_req.reply(200,
|
|
||||||
%{"content-type" => "text/plain"},
|
|
||||||
"hewwo",
|
|
||||||
req0
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, req, state}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
defmodule Elstat.Cowboy do
|
|
||||||
def start_link do
|
|
||||||
dispatch_config = build_dispatch_config()
|
|
||||||
|
|
||||||
port = Application.fetch_env!(:elstat, :port)
|
|
||||||
|
|
||||||
{:ok, _} = :cowboy.start_clear(
|
|
||||||
:elstat,
|
|
||||||
[{:port, port}],
|
|
||||||
%{env: %{dispatch: dispatch_config}}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_dispatch_config do
|
|
||||||
:cowboy_router.compile([
|
|
||||||
{:_, [
|
|
||||||
{"/hewwo", Elstat.Cowboy.DefaultHandler, []},
|
|
||||||
{"/api/current_status", Elstat.API.CurrentStatus, []},
|
|
||||||
{"/api/status", Elstat.API.Status, []},
|
|
||||||
{"/", :cowboy_static, {:priv_file, :elstat, "frontend/build/index.html"}},
|
|
||||||
{"/[...]", :cowboy_static, {:priv_dir, :elstat, "frontend/build"}},
|
|
||||||
]}
|
|
||||||
])
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,15 +0,0 @@
|
||||||
defmodule Elstat do
|
|
||||||
use Application
|
|
||||||
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def start(_type, _args) do
|
|
||||||
Logger.info "starting app"
|
|
||||||
Supervisor.start_link(
|
|
||||||
[
|
|
||||||
Elstat.Supervisor
|
|
||||||
],
|
|
||||||
strategy: :one_for_one
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
244
lib/manager.ex
244
lib/manager.ex
|
@ -1,244 +0,0 @@
|
||||||
defmodule Elstat.Error.Service do
|
|
||||||
defexception message: "default message"
|
|
||||||
end
|
|
||||||
|
|
||||||
defmodule Elstat.ServiceWorker do
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def start_link(service) do
|
|
||||||
Logger.info "spawning worker for #{inspect service.id}"
|
|
||||||
|
|
||||||
worker_pid = spawn(fn ->
|
|
||||||
worker_func(service)
|
|
||||||
end)
|
|
||||||
|
|
||||||
{:ok, worker_pid}
|
|
||||||
end
|
|
||||||
|
|
||||||
def worker_func(service) do
|
|
||||||
adapter = service.adapter
|
|
||||||
|
|
||||||
result = adapter.check(service.adapter_opts)
|
|
||||||
Logger.info "result from #{inspect adapter} #{inspect service.id}: #{inspect result}"
|
|
||||||
|
|
||||||
man_pid = :global.whereis_name Elstat.Manager
|
|
||||||
send man_pid, {:service_info, {service.id, result}}
|
|
||||||
|
|
||||||
Process.sleep(service.poll * 1000)
|
|
||||||
worker_func(service)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defmodule Elstat.Manager do
|
|
||||||
@moduledoc """
|
|
||||||
Elstat's service manager.
|
|
||||||
"""
|
|
||||||
use GenServer
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def start_link(opts) do
|
|
||||||
GenServer.start_link(__MODULE__, :ok, [name: {:global, Elstat.Manager}] ++ opts)
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_services() do
|
|
||||||
services = Application.fetch_env!(:elstat, :services)
|
|
||||||
|
|
||||||
workers = services
|
|
||||||
|> Map.keys
|
|
||||||
|> Enum.map(fn service_id ->
|
|
||||||
service = Map.put(services[service_id], :id, service_id)
|
|
||||||
|
|
||||||
# each service worker will enter an infinite loop
|
|
||||||
# polling the service (via an adapter) and giving
|
|
||||||
# information back to the manager, so it can
|
|
||||||
# process and show those via its API.
|
|
||||||
%{
|
|
||||||
id: service_id,
|
|
||||||
start: {Elstat.ServiceWorker, :start_link, [service]}
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
|
|
||||||
# spawn the managere alongside service workers
|
|
||||||
[ Elstat.Manager | workers]
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_current_state() do
|
|
||||||
man_pid = :global.whereis_name Elstat.Manager
|
|
||||||
GenServer.call(man_pid, {:get_current})
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_graph_state() do
|
|
||||||
man_pid = :global.whereis_name Elstat.Manager
|
|
||||||
GenServer.call(man_pid, {:get_graph})
|
|
||||||
end
|
|
||||||
|
|
||||||
# server callbacks
|
|
||||||
|
|
||||||
def get_columns_def do
|
|
||||||
%{
|
|
||||||
timestamp: "timestamp bigint",
|
|
||||||
status: "status bool",
|
|
||||||
latency: "latency bigint",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_columns_name do
|
|
||||||
%{
|
|
||||||
timestamp: "timestamp",
|
|
||||||
status: "status",
|
|
||||||
latency: "latency",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def init(:ok) do
|
|
||||||
services = Application.fetch_env!(:elstat, :services)
|
|
||||||
|
|
||||||
Sqlitex.with_db('elstat.db', fn(db) ->
|
|
||||||
services
|
|
||||||
|> Map.keys
|
|
||||||
|> Enum.each(fn service_id ->
|
|
||||||
service = services[service_id]
|
|
||||||
adapter = service.adapter
|
|
||||||
|
|
||||||
spec = adapter.adapter_spec
|
|
||||||
|
|
||||||
columns = get_columns_def()
|
|
||||||
|
|
||||||
column_res = spec.db_columns
|
|
||||||
|> Enum.map(fn column ->
|
|
||||||
columns[column]
|
|
||||||
end)
|
|
||||||
|> Enum.join(",\n")
|
|
||||||
|
|
||||||
query = """
|
|
||||||
CREATE TABLE IF NOT EXISTS #{Atom.to_string service_id} (
|
|
||||||
#{column_res}
|
|
||||||
);
|
|
||||||
"""
|
|
||||||
|
|
||||||
Logger.debug "query for #{inspect service_id}: #{query}"
|
|
||||||
|
|
||||||
case Sqlitex.query(db, query) do
|
|
||||||
{:ok, _} ->
|
|
||||||
Logger.info "created table for #{inspect service_id}"
|
|
||||||
{:error, _err} ->
|
|
||||||
Logger.error "error making table for #{inspect service_id}"
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
{:ok, %{
|
|
||||||
services: services,
|
|
||||||
serv_state: %{},
|
|
||||||
}}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_call({:get_current}, _from, state) do
|
|
||||||
reply = state.serv_state
|
|
||||||
|> Map.keys
|
|
||||||
|> Enum.map(fn key ->
|
|
||||||
data = state.serv_state[key]
|
|
||||||
desc = state.services[key].description
|
|
||||||
|
|
||||||
case data do
|
|
||||||
{:map, data_map} ->
|
|
||||||
{key, Map.put(data_map, :description, desc)}
|
|
||||||
{:bool, data_bool} ->
|
|
||||||
{key, %{
|
|
||||||
status: data_bool,
|
|
||||||
description: desc,
|
|
||||||
}}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|> Map.new
|
|
||||||
|
|
||||||
{:reply, reply, state}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_call({:get_graph}, _from, state) do
|
|
||||||
graph_reply = state.serv_state
|
|
||||||
|> Map.keys
|
|
||||||
|> Enum.map(fn key ->
|
|
||||||
spec = state.services[key].adapter.adapter_spec
|
|
||||||
|
|
||||||
if Enum.member?(spec.db_columns, :latency) do
|
|
||||||
{:ok, result} = Sqlitex.with_db('elstat.db', fn db ->
|
|
||||||
query = """
|
|
||||||
SELECT timestamp, latency FROM #{Atom.to_string key}
|
|
||||||
ORDER BY timestamp DESC
|
|
||||||
LIMIT 50
|
|
||||||
"""
|
|
||||||
|
|
||||||
Logger.debug "query for latency: #{query}"
|
|
||||||
|
|
||||||
Sqlitex.query(db, query)
|
|
||||||
end)
|
|
||||||
|
|
||||||
act = result
|
|
||||||
|> Enum.map(fn field ->
|
|
||||||
[Keyword.get(field, :timestamp), Keyword.get(field, :latency)]
|
|
||||||
end)
|
|
||||||
|
|
||||||
{key, act}
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|> Enum.filter(fn d -> d != nil end)
|
|
||||||
|> Map.new
|
|
||||||
|
|
||||||
Logger.debug "graph reply: #{inspect graph_reply}"
|
|
||||||
|
|
||||||
{:reply, graph_reply, state}
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_insert_query(service_id, state) do
|
|
||||||
services = state.services
|
|
||||||
service = services[service_id]
|
|
||||||
spec = service.adapter.adapter_spec
|
|
||||||
|
|
||||||
columns_str = spec.db_columns
|
|
||||||
|> Enum.map(fn atom ->
|
|
||||||
Atom.to_string atom
|
|
||||||
end)
|
|
||||||
|> Enum.join(",")
|
|
||||||
|
|
||||||
query_args_str = 1..Enum.count(spec.db_columns)
|
|
||||||
|> Enum.map(fn num ->
|
|
||||||
"$#{num}"
|
|
||||||
end)
|
|
||||||
|> Enum.join(",")
|
|
||||||
|
|
||||||
"""
|
|
||||||
INSERT INTO #{Atom.to_string service_id} (#{columns_str})
|
|
||||||
VALUES (#{query_args_str})
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_info({:service_info, {sid, sdata}}, state) do
|
|
||||||
case sdata do
|
|
||||||
{:ok, actual_data} ->
|
|
||||||
new_serv_state = Map.put(state.serv_state, sid, actual_data)
|
|
||||||
|
|
||||||
query = build_insert_query(sid, state)
|
|
||||||
|
|
||||||
adapter = state.services[sid].adapter
|
|
||||||
adp_args = adapter.transform_val(actual_data)
|
|
||||||
|
|
||||||
timestamp = :erlang.system_time(:millisecond)
|
|
||||||
|
|
||||||
Logger.debug "query: #{query}, timestamp: #{timestamp}, adp args: #{inspect adp_args}"
|
|
||||||
|
|
||||||
Sqlitex.with_db('elstat.db', fn(db) ->
|
|
||||||
res = Sqlitex.query(db, query, bind: [timestamp | adp_args])
|
|
||||||
IO.puts "#{inspect res}"
|
|
||||||
end)
|
|
||||||
|
|
||||||
{:noreply, %{state | serv_state: new_serv_state}}
|
|
||||||
{:error, err} ->
|
|
||||||
Logger.warn "error on #{inspect sid}: #{inspect err}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,30 +0,0 @@
|
||||||
defmodule Elstat.Supervisor do
|
|
||||||
use Supervisor
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def start_link(opts) do
|
|
||||||
Supervisor.start_link(__MODULE__, :ok, opts)
|
|
||||||
end
|
|
||||||
|
|
||||||
def init(:ok) do
|
|
||||||
Logger.info "starting sup"
|
|
||||||
|
|
||||||
base_children = [
|
|
||||||
%{
|
|
||||||
id: Elstat.Cowboy,
|
|
||||||
start: {Elstat.Cowboy, :start_link, []},
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
id: Sqlitex.Server,
|
|
||||||
start: {Sqlitex.Server, :start_link, ['elstat.db', [name: Sqlitex.Server]]}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
service_children = Elstat.Manager.build_services()
|
|
||||||
|
|
||||||
children = service_children ++ base_children
|
|
||||||
Logger.debug "final children #{inspect children}"
|
|
||||||
Supervisor.init(children, strategy: :one_for_one)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
32
mix.exs
32
mix.exs
|
@ -1,32 +0,0 @@
|
||||||
defmodule Elstat.MixProject do
|
|
||||||
use Mix.Project
|
|
||||||
|
|
||||||
def project do
|
|
||||||
[
|
|
||||||
app: :elstat,
|
|
||||||
version: "0.1.0",
|
|
||||||
elixir: "~> 1.6",
|
|
||||||
start_permanent: Mix.env() == :prod,
|
|
||||||
deps: deps()
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run "mix help compile.app" to learn about applications.
|
|
||||||
def application do
|
|
||||||
[
|
|
||||||
mod: {Elstat, []},
|
|
||||||
extra_applications: [:logger]
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run "mix help deps" to learn about dependencies.
|
|
||||||
defp deps do
|
|
||||||
[
|
|
||||||
{:httpoison, "~> 1.1.1"},
|
|
||||||
{:poison, "~> 3.1"},
|
|
||||||
{:sqlitex, "~> 1.4.2"},
|
|
||||||
{:cowboy, "~> 2.4.0"},
|
|
||||||
{:distillery, "~> 1.5", runtime: false}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
19
mix.lock
19
mix.lock
|
@ -1,19 +0,0 @@
|
||||||
%{
|
|
||||||
"certifi": {:hex, :certifi, "2.3.1", "d0f424232390bf47d82da8478022301c561cf6445b5b5fb6a84d49a9e76d2639", [:rebar3], [{:parse_trans, "3.2.0", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
|
|
||||||
"cowboy": {:hex, :cowboy, "2.4.0", "f1b72fabe9c8a5fc64ac5ac85fb65474d64733d1df52a26fad5d4ba3d9f70a9f", [:rebar3], [{:cowlib, "~> 2.3.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.5.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
|
|
||||||
"cowlib": {:hex, :cowlib, "2.3.0", "bbd58ef537904e4f7c1dd62e6aa8bc831c8183ce4efa9bd1150164fe15be4caa", [:rebar3], [], "hexpm"},
|
|
||||||
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"},
|
|
||||||
"distillery": {:hex, :distillery, "1.5.2", "eec18b2d37b55b0bcb670cf2bcf64228ed38ce8b046bb30a9b636a6f5a4c0080", [:mix], [], "hexpm"},
|
|
||||||
"esqlite": {:hex, :esqlite, "0.2.4", "3a8a352c190afe2d6b828b252a6fbff65b5cc1124647f38b15bdab3bf6fd4b3e", [:rebar3], [], "hexpm"},
|
|
||||||
"hackney": {:hex, :hackney, "1.12.1", "8bf2d0e11e722e533903fe126e14d6e7e94d9b7983ced595b75f532e04b7fdc7", [:rebar3], [{:certifi, "2.3.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
|
|
||||||
"httpoison": {:hex, :httpoison, "1.1.1", "96ed7ab79f78a31081bb523eefec205fd2900a02cda6dbc2300e7a1226219566", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
|
|
||||||
"idna": {:hex, :idna, "5.1.1", "cbc3b2fa1645113267cc59c760bafa64b2ea0334635ef06dbac8801e42f7279c", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
|
|
||||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
|
|
||||||
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"},
|
|
||||||
"parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"},
|
|
||||||
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
|
|
||||||
"ranch": {:hex, :ranch, "1.5.0", "f04166f456790fee2ac1aa05a02745cc75783c2bfb26d39faf6aefc9a3d3a58a", [:rebar3], [], "hexpm"},
|
|
||||||
"sqlitex": {:hex, :sqlitex, "1.4.2", "b18f2b53cefbc9cca0bd17d51386f9caa7cf341144cb314e5cd9fd2a1f9b0845", [:mix], [{:decimal, "~> 1.1", [hex: :decimal, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.4", [hex: :esqlite, repo: "hexpm", optional: false]}], "hexpm"},
|
|
||||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
|
|
||||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"},
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
# Import all plugins from `rel/plugins`
|
|
||||||
# They can then be used by adding `plugin MyPlugin` to
|
|
||||||
# either an environment, or release definition, where
|
|
||||||
# `MyPlugin` is the name of the plugin module.
|
|
||||||
Path.join(["rel", "plugins", "*.exs"])
|
|
||||||
|> Path.wildcard()
|
|
||||||
|> Enum.map(&Code.eval_file(&1))
|
|
||||||
|
|
||||||
use Mix.Releases.Config,
|
|
||||||
# This sets the default release built by `mix release`
|
|
||||||
default_release: :default,
|
|
||||||
# This sets the default environment used by `mix release`
|
|
||||||
default_environment: Mix.env()
|
|
||||||
|
|
||||||
# For a full list of config options for both releases
|
|
||||||
# and environments, visit https://hexdocs.pm/distillery/configuration.html
|
|
||||||
|
|
||||||
|
|
||||||
# You may define one or more environments in this file,
|
|
||||||
# an environment's settings will override those of a release
|
|
||||||
# when building in that environment, this combination of release
|
|
||||||
# and environment configuration is called a profile
|
|
||||||
|
|
||||||
environment :dev do
|
|
||||||
# If you are running Phoenix, you should make sure that
|
|
||||||
# server: true is set and the code reloader is disabled,
|
|
||||||
# even in dev mode.
|
|
||||||
# It is recommended that you build with MIX_ENV=prod and pass
|
|
||||||
# the --env flag to Distillery explicitly if you want to use
|
|
||||||
# dev mode.
|
|
||||||
set dev_mode: true
|
|
||||||
set include_erts: false
|
|
||||||
set cookie: :"fn5>S.FMYz7!Ri/U.Svz5hXw,kKO=S,2kvDr;~8I!ufa<SB`awK,KX)iC&mv~`At"
|
|
||||||
end
|
|
||||||
|
|
||||||
environment :prod do
|
|
||||||
set include_erts: true
|
|
||||||
set include_src: false
|
|
||||||
set cookie: :"1>bm2160O|df!iH=}h2j6tAG4X8L(v/}S<8oS>!UZ!oI0@`si;=lmA1Wf=Ns=^?d"
|
|
||||||
end
|
|
||||||
|
|
||||||
# You may define one or more releases in this file.
|
|
||||||
# If you have not set a default release, or selected one
|
|
||||||
# when running `mix release`, the first release in the file
|
|
||||||
# will be used by default
|
|
||||||
|
|
||||||
release :elstat do
|
|
||||||
set version: current_version(:elstat)
|
|
||||||
set applications: [
|
|
||||||
:runtime_tools
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Access-Control-Allow-Origin" content="*">
|
|
||||||
<style>
|
|
||||||
body { background-color: #ddd; }
|
|
||||||
p {
|
|
||||||
text-align: center;
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 13pt;
|
|
||||||
}
|
|
||||||
#pretty-box {
|
|
||||||
padding-left: 5px;
|
|
||||||
max-width: 500px;
|
|
||||||
max-height: 250px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto;
|
|
||||||
background-color: #eee;
|
|
||||||
border-radius: 15px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
// https://stackoverflow.com/a/4033310
|
|
||||||
function httpGetAsync(theUrl, callback)
|
|
||||||
{
|
|
||||||
var xmlHttp = new XMLHttpRequest();
|
|
||||||
xmlHttp.onreadystatechange = function() {
|
|
||||||
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
|
|
||||||
callback(xmlHttp.responseText);
|
|
||||||
}
|
|
||||||
xmlHttp.open("GET", theUrl, true); // true for asynchronous
|
|
||||||
xmlHttp.send(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function genText(data) {
|
|
||||||
base = `${data.description}`;
|
|
||||||
base += ` [${data.status ? "online" : "offline"}]`;
|
|
||||||
|
|
||||||
if('latency' in data) {
|
|
||||||
base += ` - latency: ${data.latency} ms`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
function curStatHandler(text) {
|
|
||||||
let box = document.getElementById('pretty-box');
|
|
||||||
let payload = JSON.parse(text);
|
|
||||||
|
|
||||||
for(const service in payload) {
|
|
||||||
let data = payload[service];
|
|
||||||
|
|
||||||
let elementId = `${service}-description`;
|
|
||||||
let existingElement = document.getElementById(elementId);
|
|
||||||
|
|
||||||
if (existingElement === null) {
|
|
||||||
let element = document.createElement('p');
|
|
||||||
|
|
||||||
element.id = elementId;
|
|
||||||
element.innerText = genText(data);
|
|
||||||
box.appendChild(element);
|
|
||||||
} else {
|
|
||||||
existingElement.innerText = genText(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchStatus () {
|
|
||||||
httpGetAsync("http://127.0.0.1:8069/api/current_status", curStatHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = function () {
|
|
||||||
fetchStatus();
|
|
||||||
setInterval(() => {
|
|
||||||
fetchStatus();
|
|
||||||
}, 3000)
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="pretty-box">
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
|
@ -1,8 +0,0 @@
|
||||||
defmodule ElstatTest do
|
|
||||||
use ExUnit.Case
|
|
||||||
doctest Elstat
|
|
||||||
|
|
||||||
test "greets the world" do
|
|
||||||
assert Elstat.hello() == :world
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1 +0,0 @@
|
||||||
ExUnit.start()
|
|
Loading…
Reference in a new issue