init
This commit is contained in:
commit
68abaaded2
|
@ -0,0 +1,4 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
|
@ -0,0 +1,29 @@
|
|||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where third-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
gh2ntfy-*.tar
|
||||
|
||||
# Temporary files, for example, from tests.
|
||||
/tmp/
|
||||
|
||||
# Silly lockfiles
|
||||
mix.lock
|
|
@ -0,0 +1,9 @@
|
|||
# Gh2ntfy
|
||||
|
||||
A service to forward github notifications to ntfy
|
||||
|
||||
## Setup
|
||||
|
||||
- Build a release by running `MIX_ENV=prod mix release`
|
||||
- Check `runtime.exs` for configuration
|
||||
- Start as usual
|
|
@ -0,0 +1,3 @@
|
|||
import Config
|
||||
config :gh2ntfy, topic: System.get_env("GH2NTFY_TOPIC")
|
||||
config :gh2ntfy, token: System.get_env("GH2NTFY_GITHUB_TOKEN")
|
|
@ -0,0 +1,16 @@
|
|||
defmodule Gh2ntfy.Application do
|
||||
use Application
|
||||
|
||||
def start(_type, _args) do
|
||||
children = [
|
||||
{Finch, name: Gh2ntfy.Finch},
|
||||
{Gh2ntfy.Ntfyer, Application.fetch_env!(:gh2ntfy, :topic)},
|
||||
{Gh2ntfy.GhPoll, Application.fetch_env!(:gh2ntfy, :token)},
|
||||
Gh2ntfy.LastPoll
|
||||
]
|
||||
|
||||
opts = [strategy: :one_for_one, name: Gh2ntfy.Supervisor]
|
||||
|
||||
{:ok, _} = Supervisor.start_link(children, opts)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,87 @@
|
|||
defmodule Gh2ntfy.GhPoll do
|
||||
alias Gh2ntfy.LastPoll
|
||||
require Logger
|
||||
|
||||
use GenServer
|
||||
|
||||
def start_link(token) when is_binary(token) do
|
||||
GenServer.start_link(__MODULE__, token, name: __MODULE__)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(token) do
|
||||
Process.send(self(), :poll, [])
|
||||
{:ok, token}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(:poll, token) do
|
||||
schedule()
|
||||
|
||||
Logger.info("polling notifications")
|
||||
|
||||
result =
|
||||
Finch.build(
|
||||
:get,
|
||||
"https://api.github.com/notifications?since=#{LastPoll.get_as_iso8601()}",
|
||||
[
|
||||
{"Authorization", "Bearer " <> token},
|
||||
{"Time-Zone", "Etc/UTC"}
|
||||
]
|
||||
)
|
||||
|> Finch.request(Gh2ntfy.Finch)
|
||||
|
||||
case result do
|
||||
{:ok, %{body: body}} ->
|
||||
case Poison.decode(body) do
|
||||
{:ok, res} ->
|
||||
Gh2ntfy.LastPoll.set_now()
|
||||
process_response(res)
|
||||
|
||||
{:error, e} ->
|
||||
Logger.error("invalid json from github: " <> Exception.format(:error, e))
|
||||
end
|
||||
|
||||
{:error, e} ->
|
||||
Logger.error("requesting info: " <> Exception.format(:error, e))
|
||||
end
|
||||
|
||||
{:noreply, token}
|
||||
end
|
||||
|
||||
defp process_response(res) do
|
||||
Enum.each(res, fn notif ->
|
||||
case notif do
|
||||
%{
|
||||
"repository" => %{"full_name" => title},
|
||||
"subject" => %{"title" => body, "latest_comment_url" => cmt_url},
|
||||
"reason" => reason
|
||||
} ->
|
||||
url_headers =
|
||||
try do
|
||||
[{"Click", get_issuecomment_url(cmt_url)}]
|
||||
rescue
|
||||
e ->
|
||||
Logger.warn("fetching issuecomment URL: " <> Exception.format(:error, e))
|
||||
[]
|
||||
end
|
||||
|
||||
Gh2ntfy.Ntfyer.send_notif("GitHub: " <> title, "#{reason}\n#{body}", url_headers)
|
||||
|
||||
_ ->
|
||||
Logger.warn("invalid data from github")
|
||||
nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp schedule do
|
||||
Process.send_after(self(), :poll, :timer.minutes(30))
|
||||
end
|
||||
|
||||
defp get_issuecomment_url(api_url) do
|
||||
{:ok, %{body: body}} = Finch.build(:get, api_url) |> Finch.request(Gh2ntfy.Finch)
|
||||
%{"html_url" => url} = Poison.decode!(body)
|
||||
url
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
defmodule Gh2ntfy.LastPoll do
|
||||
use Agent
|
||||
|
||||
def child_spec([]) do
|
||||
%{
|
||||
id: __MODULE__,
|
||||
start: {__MODULE__, :start_link, []}
|
||||
}
|
||||
end
|
||||
|
||||
def start_link do
|
||||
Agent.start_link(fn -> ~U[2000-01-01 00:00:00Z] end, name: __MODULE__)
|
||||
end
|
||||
|
||||
def get_as_iso8601 do
|
||||
Agent.get(__MODULE__, &DateTime.to_iso8601/1)
|
||||
end
|
||||
|
||||
def set_now do
|
||||
Agent.update(__MODULE__, fn _ -> DateTime.now!("Etc/UTC") end)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
defmodule Gh2ntfy.Ntfyer do
|
||||
require Logger
|
||||
|
||||
use GenServer
|
||||
|
||||
def start_link(topic) when is_binary(topic) do
|
||||
GenServer.start_link(__MODULE__, topic, name: __MODULE__)
|
||||
end
|
||||
|
||||
def send_notif(title, body, headers \\ []) do
|
||||
GenServer.cast(__MODULE__, {:send_notif, title, body, headers})
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(topic), do: {:ok, topic}
|
||||
|
||||
@impl true
|
||||
def handle_cast({:send_notif, title, body, headers}, topic) do
|
||||
Logger.info("sending notification with title '#{title}'")
|
||||
# TODO: allow other ntfy instances
|
||||
Finch.build(
|
||||
:post,
|
||||
"https://ntfy.sh/" <> topic,
|
||||
[
|
||||
{"Title", title}
|
||||
] ++ headers,
|
||||
body
|
||||
)
|
||||
|> Finch.request(Gh2ntfy.Finch)
|
||||
|
||||
{:noreply, topic}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
defmodule Gh2ntfy.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :gh2ntfy,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.14",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps()
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger],
|
||||
mod: {Gh2ntfy.Application, []}
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
{:finch, "~> 0.14.0"},
|
||||
{:poison, "~> 5.0"}
|
||||
]
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue