Create archives in worker to lessen load time

Also use new response helpers to set content type later when Raxx doesn't
crash from it
This commit is contained in:
Mikko Ahlroth 2018-11-24 23:10:08 +02:00
parent 8ca9ff1690
commit e7ff21ace3
6 changed files with 70 additions and 12 deletions

View file

@ -28,6 +28,9 @@ defmodule Mebe2.Engine.DB do
# Table for storing menu data
@menu_table :mebe2_menu
# Table for storing archives
@archives_table :mebe2_archives
@spec init() :: :ok
def init() do
# Only create tables if they don't exist already
@ -38,6 +41,7 @@ defmodule Mebe2.Engine.DB do
:ets.new(@single_post_table, [:named_table, :set, :protected, read_concurrency: true])
:ets.new(@tag_table, [:named_table, :ordered_set, :protected, read_concurrency: true])
:ets.new(@menu_table, [:named_table, :ordered_set, :protected, read_concurrency: true])
:ets.new(@archives_table, [:named_table, :set, :protected, read_concurrency: true])
end
:ok
@ -50,6 +54,7 @@ defmodule Mebe2.Engine.DB do
:ets.delete_all_objects(@post_table)
:ets.delete_all_objects(@single_post_table)
:ets.delete_all_objects(@tag_table)
:ets.delete_all_objects(@archives_table)
:ok
end
@ -107,6 +112,15 @@ defmodule Mebe2.Engine.DB do
:ets.insert(@tag_table, tag_posts)
end
@doc """
Insert archive data into the archive table.
"""
@spec insert_archives([{integer, integer}], :months) :: true
@spec insert_archives(%{optional(String.t()) => integer}, :tags) :: true
def insert_archives(data, type) when is_atom(type) do
:ets.insert(@archives_table, {type, data})
end
@spec get_menu() :: [Models.MenuItem.t()]
def get_menu() do
case :ets.match(@menu_table, :"$1") do
@ -185,6 +199,19 @@ defmodule Mebe2.Engine.DB do
end)
end
@doc """
Get data from archives with the given type.
"""
@spec get_archives(:months) :: [{integer, integer}]
@spec get_archives(:tags) :: %{optional(String.t()) => integer}
def get_archives(type) do
case :ets.match_object(@archives_table, {type, :"$1"}) do
[{_, data}] -> data
_ when type == :months -> []
_ when type == :tags -> %{}
end
end
@spec get_page(String.t()) :: Models.Page.t() | nil
def get_page(slug) do
case :ets.match_object(@page_table, {slug, :"$1"}) do

View file

@ -11,6 +11,7 @@ defmodule Mebe2.Engine.Worker do
GenServer.start_link(__MODULE__, :ok, opts)
end
@spec init(:ok) :: {:ok, nil}
def init(:ok) do
load_db()
{:ok, nil}
@ -21,17 +22,21 @@ defmodule Mebe2.Engine.Worker do
{:reply, :ok, nil}
end
@spec refresh_db() :: :ok
def refresh_db() do
Logger.info("Destroying database…")
DB.destroy()
:ok = DB.destroy()
Logger.info("Reloading database…")
load_db()
:ok = load_db()
Logger.info("Update done!")
:ok
end
@doc """
Initialize the database by crawling the configured path and parsing data to the DB.
"""
@spec load_db() :: :ok
def load_db() do
data_path = Mebe2.get_conf(:data_path)
@ -71,6 +76,11 @@ defmodule Mebe2.Engine.Worker do
DB.insert_count(:month, month, Enum.count(months[month]))
end)
DB.get_all_months() |> DB.insert_archives(:months)
DB.get_all_tags() |> DB.insert_archives(:tags)
Logger.info("Posts loaded.")
:ok
end
end

View file

@ -28,10 +28,10 @@ defmodule Mebe2.Web.Middleware.Archives do
"""
@spec put_archives() :: :ok
def put_archives() do
months = Mebe2.Engine.DB.get_all_months()
months = Mebe2.Engine.DB.get_archives(:months)
Process.put(@month_archives_key, months)
tags = Mebe2.Engine.DB.get_all_tags()
tags = Mebe2.Engine.DB.get_archives(:tags)
Process.put(@tag_archives_key, tags)
:ok
end

View file

@ -1,14 +1,15 @@
defmodule Mebe2.Web.Routes.Page do
use Raxx.SimpleServer
alias Mebe2.Engine.{DB, Models}
alias Mebe2.Web.Routes.Utils
@impl Raxx.SimpleServer
def handle_request(%Raxx.Request{path: [slug]} = _req, _state) do
with {:page, %Models.Page{} = page} <- {:page, DB.get_page(slug)} do
response(200)
Utils.html_response(200)
|> Mebe2.Web.Views.Page.render(page)
else
_ -> Mebe2.Web.Routes.Utils.render_404()
_ -> Utils.render_404()
end
end
end

View file

@ -1,6 +1,7 @@
defmodule Mebe2.Web.Routes.Post do
use Raxx.SimpleServer
alias Mebe2.Engine.{DB, Models}
alias Mebe2.Web.Routes.Utils
@impl Raxx.SimpleServer
def handle_request(%Raxx.Request{path: [y_str, m_str, d_str, slug]} = _req, _state) do
@ -8,10 +9,10 @@ defmodule Mebe2.Web.Routes.Post do
{:month, {month, ""}} <- {:month, Integer.parse(m_str)},
{:day, {day, ""}} <- {:day, Integer.parse(d_str)},
{:post, %Models.Post{} = post} <- {:post, DB.get_post(year, month, day, slug)} do
response(200)
Utils.html_response(200)
|> Mebe2.Web.Views.SinglePost.render(post)
else
_ -> Mebe2.Web.Routes.Utils.render_404()
_ -> Utils.render_404()
end
end
end

View file

@ -46,9 +46,9 @@ defmodule Mebe2.Web.Routes.Utils do
) :: Raxx.Response.t()
def render_posts(page \\ "1", post_getter, renderer) do
with n when is_integer(n) <- parse_page_number(page),
{first, limit} = Mebe2.Web.Routes.Utils.get_post_range(n),
{first, limit} = get_post_range(n),
{[_ | _] = posts, total} <- post_getter.(first, limit) do
Raxx.response(200) |> renderer.(posts, total, n)
html_response(200) |> renderer.(posts, total, n)
else
_ -> render_404()
end
@ -67,7 +67,7 @@ defmodule Mebe2.Web.Routes.Utils do
{first, limit} = get_post_range(1, Mebe2.get_conf(:posts_in_feed))
{posts, _} = post_getter.(first, limit)
Raxx.response(200)
rss_response(200)
|> Mebe2.Web.Views.Feeds.PostList.render(posts)
else
_ -> render_404()
@ -79,7 +79,26 @@ defmodule Mebe2.Web.Routes.Utils do
"""
@spec render_404() :: Raxx.Response.t()
def render_404() do
Raxx.response(404)
html_response(404)
|> Mebe2.Web.Views.NotFound.render()
end
@doc """
Get an HTML response with the proper content type.
"""
@spec html_response(integer) :: Raxx.Response.t()
def html_response(code) when is_integer(code) do
Raxx.response(code)
# TODO: Fix these when Raxx doesn't crash on setting content type when using views
# |> Raxx.set_header("content-type", "text/html; charset=utf-8")
end
@doc """
Get an RSS response with the proper content type.
"""
@spec rss_response(integer) :: Raxx.Response.t()
def rss_response(code) when is_integer(code) do
Raxx.response(code)
# |> Raxx.set_header("content-type", "application/xml+rss; charset=utf-8")
end
end