1
0
Fork 0
arcology-elixir/link_routers.org

125 lines
5.7 KiB
Org Mode

#+TITLE: Arcology Link Routers
#+ROAM_TAGS: Arcology
#+ROAM_ALIAS: Arcology.LinkRouter.Local Arcology.LinkRouter
#+ARCOLOGY_KEY: arcology/links
Routing differs between local development and production deployment, and may diverge further in the future. Consider this page, with the =ARCOLOGY_KEY= value =arcology/links=. In *each environment* this value should map one-to-one with a URL. In local development, the domain will be =localhost= and the path will be =/arcology/links=. In production, the domain will be (probably) =arcology.garden= and the path will be =/links=, and I will have multiple domains in the same Garden "namespace", a single [[file:../cce/org-roam.org][org-roam]] directory.
The router has to perform these tasks:
- rewrite an HTML url from the org-mode file to the =ARCOLOGY_KEY=.
- =add_site_colors= and =url_for_arcology_key= in [[file:arcology_sitemap.org][Arcology.Sitemap]]
- domain_to_site and build_site_key in [[file:arcology_web.org][ArcologyWeb.Router]]
Some of these are actually going to be the same in both environments, but it seems really smart to have all the mapping between Sites be in one module in another file is the right idea. Handful of modules. Base, Prod, Dev, swapped in based on the Config? it's actually probably just stuff *in config* yikes.
* Shared Functions in the =Arcology.KeyMaps= module map in to and out of "site keys" and domains.
It contains code that's used in other places but is related to domain-to-site mapping. Eventually sites could be an implementation of a struct which implements a protocol that these functions call against. I'm going to need to do a bunch of stuff in the [[file:phoenix.org][Arcology configuration]] for this to work in production, anyways...
#+begin_src elixir :tangle lib/arcology/key_maps.ex
defmodule Arcology.KeyMaps do
def domain_to_site_map do
%{
"arcology.garden" => %{site: "garden"},
"lionsrear.com" => %{site: "lionsrear"},
"cce.arcology.garden" => %{site: "cce"},
"doc.arcology.garden" => %{site: "doc"},
"localhost" => %{site: "local", local_wiki: true},
}
end
def site_colors_map do
%{
"cce" => "#707231",
"arcology" => "#82796C",
"lionsrear" => "#7e5c41",
"garden" => "#CC6960",
"doc" => "#67b4f8",
}
end
def domain_to_site(host), do: Map.get(domain_to_site_map(), host, %{site: "unknown"})
def site_key_to_color(site_key), do: Map.get(site_colors_map(), site_key, "#FFFFFF")
end
#+end_src
* "local" router
The local router allows for routing under a single domain, probably =localhost= for development purposes. This router lets you pass as the URL path an =ARCOLOGY_KEY= value, and needs to generate HTML links that work the same way.
#+begin_src elixir :tangle lib/arcology/link_router/local.ex :noweb yes
defmodule Arcology.LinkRouter.Local do
require Logger
<<normalize_urls>>
def url_for_arcology_key(key) do
"/#{key}.html"
end
end
#+end_src
** Normalizing HTML URLs
The arcology should route all internal URLs, rewriting any which are not exposed via =ARCOLOGY_KEY= to the [[file:404.org][404 page]]. the URLs which are =roam:= prefixed are dangling links in my [[file:../knowledge_base.org][Knowledge Base]], they otherwise would be rewritten to a real page and those are turned in to a broken link. I'd like to include some statistics for these at some point so I can have some awareness of the pages people are interested in, but that's not important right now.
#+begin_src elixir :noweb-ref normalize_urls
@doc "Rewrite the HTML anchors in the passed binary from org links to local-routing HTML links"
def normalize_urls(input_html) when is_binary(input_html) do
intermediate = Regex.replace(
~r/<a href="([0-9a-zA-Z_\- \/]+.org)">/,
input_html,
&normalize_org_url(&1, &2)
)
Regex.replace(
~r/<a href="(roam:[0-9a-zA-Z_\- \/,.!?]+)">roam:/,
intermediate,
&normalize_roam_url(&1, &2)
)
end
defp normalize_roam_url(_match, page) do
~s(<a href="/arcology/404.html" class="dead-link">)
end
defp normalize_org_url(_match, page) do
# arc_dir = Application.get_env(:arcology, :env)[:arcology_directory]
key = Arcology.Roam.Keyword.from_file(page|>IO.inspect, "ARCOLOGY_KEY")
cond do
key == nil ->
Logger.warn("could not load key for #{page}")
~s(<a href="/arcology/404.html" class="dead-link">)
true ->
~s(<a href="/#{key}.html">)
end
end
@doc "This is for tests, ignore the man behind the curtain"
def test_normalize(page), do: normalize_org_url(nil, page)
#+end_src
=normalize_url/2= is called by the =Regex.replace= in =normalize_urls/1=, the second argument is all we care about, it comes out of the capture in the expression, and is the string of the relative file-name in all likelihood; this is not really consistent and it *is* something that I need to resolve in my [[file:../cce/org-roam.org][org-roam]] and [[file:../org-mode.org][org-mode]] configurations. This is going to have a lot of data-validity issues, and I kind-of wish that it was easier to quickly get an [[file:arcology_roam.org][Arcology.Roam.Link]] from this =page= variable to get to a [[file:arcology_roam.org][Arcology.Roam.Keyword]].
#+begin_src elixir :tangle test/arcology/page_test.exs
defmodule ArcologyPageTestRewriteLocal do
use ExUnit.Case
setup do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Arcology.Repo)
end
test 'valid link with valid key' do
assert Arcology.LinkRouter.Local.test_normalize("arcology_page.org") == ~s(<a href="/arcology/page.html">)
assert Arcology.LinkRouter.Local.test_normalize("link_routers.org") == ~s(<a href="/arcology/links.html">)
end
test 'URLs not in the arcology-db get a dead-link class' do
assert Arcology.LinkRouter.Local.test_normalize("Private.org") =~ "dead-link"
end
end
#+end_src