Packages
baobab
0.13.1
0.35.1
0.35.0
0.34.0
0.31.0
0.30.0
0.21.2
0.21.1
0.21.0
0.20.0
0.19.2
0.19.1
0.19.0
0.18.1
0.18.0
0.17.1
0.17.0
0.16.8
0.16.7
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.2
0.15.1
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.0
Bamboo append-only logs
Current section
Files
Jump to
Current section
Files
lib/baobab/interchange.ex
defmodule Baobab.Interchange do
@moduledoc """
Functions related to the interchange of Bamboo data with
other Bamboo sources
"""
@doc """
Import and store a list of log entries from their binary format.
"""
@spec import_binaries([binary]) :: [%Baobab.Entry{} | {:error, String.t()}]
def import_binaries(binaries, options \\ [])
def import_binaries(binary, options) when is_binary(binary),
do: import_binaries([binary], options)
def import_binaries(binaries, options) when is_list(binaries) do
import_listed_binaries(binaries, options |> Baobab.optvals([:replace, :clump_id]), [])
end
def import_binaries(_, _), do: [{:error, "Import requires a list of binaries"}]
defp import_listed_binaries([], _, acc), do: acc
defp import_listed_binaries([binary | rest], {overwrite, clump_id} = opts, acc) do
result =
binary
|> Baobab.Entry.from_binaries(true, clump_id)
|> Enum.map(fn e -> Baobab.Entry.store(e, clump_id, overwrite) end)
import_listed_binaries(rest, opts, acc ++ result)
end
@doc """
Import a bamboo store
At present this only handles an exported directory as produced by `export_store/1`
"""
def import_store(path) do
# Right now we just mirror the export assuming everything
# is "in its place". Eventually we should have some switches
# to allow partial imports.. and from other sources
top = path |> Path.expand()
case Path.wildcard(Path.join([top, "identities/*.keyfile.json"])) do
[] -> notours()
ids -> import_store_identities(ids)
end
case Path.wildcard(Path.join([top, "content/*/*.bamboo.log"])) do
[] -> notours()
logs -> import_store_logs(logs)
end
end
defp import_store_identities([]), do: :ok
defp import_store_identities([json_file | rest]) do
case json_file |> File.read!() |> Jason.decode!() do
# This is surprisingly liberal given our stance on current importing
%{"identity" => id, "secret_key" => sk, "public_key" => pk} ->
case Baobab.create_identity(id, sk) do
^pk -> :ok
_ -> notours()
end
_ ->
notours()
end
import_store_identities(rest)
end
defp import_store_logs([]), do: :ok
defp import_store_logs([bamboo_file | rest]) do
# The logs themselves contain all of the info for their structure
# except for the `clump_id` so we'll need that
cid = clump_from_path(bamboo_file)
bamboo_file
|> File.read!()
|> then(fn contents -> import_binaries([contents], replace: false, clump_id: cid) end)
import_store_logs(rest)
end
@doc """
Export full store contents to the provided directory
Produces:
- JSON keyfiles for each identity
- Per clump directories containing a file for each author, `log_id` pair
"""
def export_store(path) do
where = Path.expand(path)
id_path = Path.join([where, "identities"])
:ok = File.mkdir_p(id_path)
:ok = File.chmod(id_path, 0o700)
export_store_identities(Baobab.identities(), id_path)
bb_path = Path.join(where, "content")
:ok = File.mkdir_p(bb_path)
:ok = File.chmod(bb_path, 0o700)
export_store_clumps(Baobab.clumps(), bb_path)
where
end
defp export_store_identities([], _), do: :ok
defp export_store_identities([{i, pk} | rest], path) do
file = Path.join(path, i <> ".keyfile.json")
{:ok, json} =
%{
"source" => "baobab",
"key_encoding" => "base62",
"key_type" => "ed25519",
"identity" => i,
"public_key" => pk,
"secret_key" => Baobab.identity_key(i, :secret) |> BaseX.Base62.encode()
}
|> Jason.encode()
:ok = File.write(file, json)
:ok = File.chmod(file, 0o600)
export_store_identities(rest, path)
end
defp export_store_clumps([], _), do: :ok
defp export_store_clumps([cid | rest], path) do
export_store_clump(cid, path)
export_store_clumps(rest, path)
end
defp export_store_clump(cid, path) do
dir = Path.join(path, cid)
:ok = File.mkdir_p(dir)
export_store_logs(Baobab.stored_info(cid), cid, dir)
end
defp export_store_logs([], _, _), do: :ol
defp export_store_logs([{a, l, _} | rest], cid, dir) do
file = Path.join([dir, a <> "_" <> Integer.to_string(l) <> ".bamboo.log"])
log = Baobab.full_log(a, log_id: l, clump_id: cid, format: :binary) |> Enum.join("")
:ok = File.write(file, log)
:ok = File.chmod(file, 0o700)
export_store_logs(rest, cid, dir)
end
@doc false
def clump_from_path(path) do
[_, clump | _] = path |> Path.split() |> Enum.reverse()
clump
end
defp notours(), do: raise("Not a Baobab export structure")
end