1
0
Fork 0
arcology-elixir/link_routers.org

5.7 KiB

Arcology Link Routers

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 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 Arcology.Sitemap
  • domain_to_site and build_site_key in 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 Arcology configuration for this to work in production, anyways…

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

"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.

defmodule Arcology.LinkRouter.Local do
  require Logger

  <<normalize_urls>>

  def url_for_arcology_key(key) do
    "/#{key}.html"
  end
end

Normalizing HTML URLs

The arcology should route all internal URLs, rewriting any which are not exposed via ARCOLOGY_KEY to the 404 page. the URLs which are roam: prefixed are dangling links in my 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.

@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)

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 org-roam and 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 Arcology.Roam.Link from this page variable to get to a Arcology.Roam.Keyword.

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