defmodule MishkaInstaller do
alias MishkaInstaller.PluginState
@spec plugin_activity(String.t(), PluginState.t(), String.t(), String.t()) ::
:ignore | {:error, any} | {:ok, pid} | {:ok, pid, any}
def plugin_activity(action, %PluginState{} = plugin, priority, status \\ "info") do
MishkaInstaller.Activity.create_activity_by_start_child(
activity_required_map("plugin", "other", action, priority, status),
Map.drop(Map.from_struct(plugin), [:parent_pid, :extension])
)
end
@spec dependency_activity(map, String.t(), String.t()) :: nil
def dependency_activity(state, priority, status \\ "error") do
MishkaInstaller.Activity.create_activity_by_start_child(
activity_required_map("dependency", "compiling", "compiling", priority, status),
Map.merge(state, %{
state:
Enum.map(state.state, fn item ->
case item do
{:error, :do_deps_compile, app, operation: operation, output: output}
when is_struct(output) ->
%{operation: operation, output: Map.from_struct(output), status: status, app: app}
{:error, :do_deps_compile, app, operation: operation, output: output} ->
%{operation: operation, output: Kernel.inspect(output), status: status, app: app}
value ->
value
end
end)
})
)
nil
end
@spec update_activity(map, String.t(), String.t()) :: nil
def update_activity(state, priority, status \\ "error") do
MishkaInstaller.Activity.create_activity_by_start_child(
activity_required_map("dependency", "updating", "updating", priority, status),
state
)
nil
end
def ip(user_ip),
do: (is_bitstring(user_ip) && user_ip) || Enum.join(Tuple.to_list(user_ip), ".")
def get_config(item, section \\ :basic) do
case Application.fetch_env(:mishka_installer, section) do
:error -> nil
{:ok, list} -> Keyword.fetch!(list, item)
end
rescue
_e -> nil
end
def repo() do
env_db = "#{System.get_env("INSTALLER_DB")}" |> String.replace("Elixir.", "")
case MishkaInstaller.get_config(:repo) do
nil ->
if Mix.env() == :test,
do: Ecto.Integration.TestRepo,
else:
if(env_db != "",
do: String.to_atom("Elixir.#{env_db}"),
else: ensure_compiled(nil)
)
value ->
value
end
end
def gettext() do
case MishkaInstaller.get_config(:gettext) do
nil -> MishkaInstaller.Gettext
value -> value
end
rescue
_ -> MishkaInstaller.Gettext
end
def ensure_compiled(module) do
case Code.ensure_compiled(module) do
{:module, _} ->
module
{:error, _} ->
raise "This module does not exist or is not configured if it is related to Ecto. Please read the documentation at GitHub. \n Output: #{inspect(module)}."
end
end
# Ref: https://elixirforum.com/t/how-to-start-oban-out-of-application-ex/48417/6
# Ref: https://elixirforum.com/t/cant-start-oban-as-cron-every-minute/48459/5
@spec start_oban_in_runtime(nil | list()) ::
:ignore | {:error, any} | {:ok, pid} | {:ok, pid, any}
def start_oban_in_runtime(opts \\ MishkaInstaller.get_config(:oban_config)) do
oban_opts = [
repo: MishkaInstaller.repo(),
queues: [compile_events: [limit: 1], update_events: [limit: 1]],
plugins: [
Oban.Plugins.Pruner,
{Oban.Plugins.Cron,
crontab: [
{"*/5 * * * *", MishkaInstaller.DepUpdateJob}
]}
]
]
DynamicSupervisor.start_child(
MishkaInstaller.RunTimeObanSupervisor,
{Oban, opts || oban_opts}
)
end
defp activity_required_map(type, section, action, priority, status) do
%{
type: type,
section: section,
section_id: nil,
action: action,
priority: priority,
status: status,
user_id: nil
}
end
def checksum(file_path) do
File.stream!(file_path, [], 2048)
|> Enum.reduce(:crypto.hash_init(:sha256), fn line, acc -> :crypto.hash_update(acc, line) end)
|> :crypto.hash_final()
|> Base.encode16()
|> String.downcase()
end
def trim_url(url) do
String.trim(
if(String.ends_with?(url, "/"), do: String.replace_trailing(url, "/", ""), else: url)
)
end
end