Music streaming on ATProto!

feat(appview): add `at://` URI struct

ovyerus.com d7daf070 041496e1

verified
Changed files
+65 -1
apps
backend
lib
comet
+4 -1
.gitignore
··· 26 26 vite.config.ts.timestamp-* 27 27 28 28 # Nix 29 - result 29 + result 30 + 31 + # Dumps 32 + erl_crash.dump
+61
apps/backend/lib/comet/aturi.ex
··· 1 + defmodule Comet.AtURI do 2 + use TypedStruct 3 + 4 + @did "did:(?:plc|web):[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]" 5 + @handle "(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?" 6 + @nsid "[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)" 7 + 8 + @authority "(?<authority>(?:#{@did})|(?:#{@handle}))" 9 + @collection "(?<collection>#{@nsid})" 10 + @rkey "(?<rkey>[a-zA-Z0-9.-_:~]{1,512})" 11 + 12 + @re ~r"^at://#{@authority}(?:/#{@collection}(?:/#{@rkey})?)?$" 13 + 14 + typedstruct do 15 + field :authority, String.t(), enforce: true 16 + field :collection, String.t() | nil 17 + field :rkey, String.t() | nil 18 + end 19 + 20 + @spec new(String.t()) :: {:ok, t()} | :error 21 + def new(string) when is_binary(string) do 22 + case Regex.named_captures(@re, string) do 23 + %{} = captures -> {:ok, from_named_captures(captures)} 24 + nil -> :error 25 + end 26 + end 27 + 28 + @spec new!(String.t()) :: t() 29 + def new!(string) when is_binary(string) do 30 + case new(string) do 31 + {:ok, uri} -> uri 32 + :error -> raise ArgumentError, message: "Malformed at:// URI" 33 + end 34 + end 35 + 36 + @spec match?(String.t()) :: boolean() 37 + def match?(string), do: Regex.match?(@re, string) 38 + 39 + @spec to_string(t()) :: String.t() 40 + def to_string(%__MODULE__{} = uri) do 41 + "at://#{uri.authority}/#{uri.collection}/#{uri.rkey}" 42 + |> String.trim_trailing("/") 43 + end 44 + 45 + defp from_named_captures(%{"authority" => authority, "collection" => "", "rkey" => ""}), 46 + do: %__MODULE__{authority: authority} 47 + 48 + defp from_named_captures(%{"authority" => authority, "collection" => collection, "rkey" => ""}), 49 + do: %__MODULE__{authority: authority, collection: collection} 50 + 51 + defp from_named_captures(%{ 52 + "authority" => authority, 53 + "collection" => collection, 54 + "rkey" => rkey 55 + }), 56 + do: %__MODULE__{authority: authority, collection: collection, rkey: rkey} 57 + end 58 + 59 + defimpl String.Chars, for: Comet.AtURI do 60 + def to_string(%Comet.AtURI{} = uri), do: Comet.AtURI.to_string(uri) 61 + end