defmodule MyspaceIPFS do @moduledoc """ MyspaceIPFS.Api is where the main commands of the IPFS API reside. Alias this library and you can run the commands via Api.. ## Examples iex> alias MyspaceIPFS.API, as: Api iex> Api.get("Multihash_key") <<0, 19, 148, 0, ... >> """ import MyspaceIPFS.Api import MyspaceIPFS.Utils @experimental Application.get_env(:myspace_ipfs, :experimental) # Types @typedoc """ The path to the endpoint to be hit. For example, `/add` or `/cat`. It's called path because sometimes the MultiHash is not enough to identify the resource, and a path is needed, eg. /ipns/myspace.bahner.com """ @type path :: String.t() @typedoc """ The file system path to the file to be sent to the node. """ @type fspath :: String.t() @typedoc """ The name of the file or data to be sent to the node. """ @type name :: String.t() @typedoc """ The options to be sent to the node. These are dependent on the endpoint """ @type opts :: list @typedoc """ The structure of a normal error response from the node. """ @type error :: {:error, Tesla.Env.t()} | {:eserver, Tesla.Env.t()} | {:eclient, Tesla.Env.t()} | {:eaccess, Tesla.Env.t()} | {:emissing, Tesla.Env.t()} | {:enoallow, Tesla.Env.t()} @typedoc """ The structure of a normal response from the node. """ @type mapped :: {:ok, list} | {:error, Tesla.Env.t()} @typedoc """ The structure of a JSON response from the node. """ @type okresult :: {:ok, any} | {:error, Tesla.Env.t()} @typedoc """ The structure of a JSON response from the node. """ @type result :: any | {:error, Tesla.Env.t()} @doc """ Start the IPFS daemon. You should run this before any other command, but it's probably easier to do outside of the library. ## Options https://docs.ipfs.tech/reference/kubo/cli/#ipfs-daemon ``` [ "--init", # Initialize IPFS with default settings, if not already initialized "--migrate", # If answer yes to migration prompt "--init-config ", # Path to the configuration file to use "--init-profile ", # Apply profile settings to config "--routing ", # Override the routing system "--mount", # Mount IPFS to the filesystem (experimental) "--writable", # Enable writing objects (with POST, PUT, DELETE) "--mount-ipfs ", # Path to the mountpoint for IPFS (if using --mount) "--mount-ipns ", # Path to the mountpoint for IPNS (if using --mount) "--unrestricted-api", # Allow API access to unlisted hashes "--disable-transport-encryption", # Disable transport encryption (for debugging) "--enable-gc", # Enable automatic repo garbage collection "--enable-pubsub-experiment", # Enable experimental pubsub "--enable-namesys-pubsub", # Enable experimental namesys pubsub "--agent-version-suffix ", # Suffix to append to the AgentVersion string for id() ] ``` """ def daemon(start? \\ true, flag \\ [], opts \\ []) do {:ok, pid} = Task.start(fn -> System.cmd("ipfs", ["daemon"] ++ opts) end) if start? == false do pid |> shutdown(flag) else pid end end defp shutdown(pid, term) do Process.exit(pid, term) end @doc """ Shutdown the IPFS daemon. """ @spec shutdown :: result def shutdown, do: post_query("/shutdown") @doc """ Resolve the value of names to IPFS. ## Options https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-resolve ``` [ recursive: true, nocache: true, dht-record-count: 10, dht-timeout: 10 ] ``` """ @spec resolve(path, opts) :: result def resolve(path, opts \\ []), do: post_query("/resolve?arg=" <> path, opts) |> map_response_data() |> okify() @doc """ Add a file to IPFS. ## Options https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-add """ @spec add(fspath, opts) :: result def add(fspath, opts \\ []), do: post_file("/add", fspath, opts) |> map_response_data() |> okify() @doc """ Get a file or directory from IPFS. As it stands ipfs sends a text blob back, so we need to implement a way to get the file extracted and saved to disk. The default name is the CID or the basename of the IPNS or IPFS path. *NB! Unsafe (relative symlinks) will raise an error.* Compression is not implemented yet. ## Options https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-get ``` [ output: , # Optional, default: Name of the object. CID or path basename. archive: , # Optional, default: false compress: , # NOT IMPLEMENTED compression_level: # NOT IMPLEMENTED ] ``` """ @spec get(path, opts) :: result defdelegate get(path, opts \\ []), to: MyspaceIPFS.Get @doc """ Get the contents of a file from ipfs. Easy way to get the contents of a text file for instance. ## Options https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-cat ``` [ offset: , length: , progress: ] ``` """ @spec cat(path, opts) :: result def cat(path, opts \\ []), do: post_query("/cat?arg=" <> path, opts) |> okify() @doc """ List the files in an IPFS object. ## Options https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-ls ``` [ headers: , resolve-type: , stream: , size: , ] ``` ## Response ``` { Objects: [ { "Name": "string", "Hash": "string", "Size": 0, "Type": 0, "Links": [ { "Name": "string", "Hash": "string", "Size": 0, "Type": 0 } ] } ] } ``` """ @spec ls(path, opts) :: result def ls(path, opts \\ []), do: post_query("/ls?arg=" <> path, opts) |> Jason.decode!() |> okify() @doc """ Show the id of the IPFS node. https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-id Returns a map with the following keys: - ID: the id of the node. - PublicKey: the public key of the node. - Addresses: the addresses of the node. - AgentVersion: the version of the node. - ProtocolVersion: the protocol version of the node. - Protocols: the protocols of the node. """ @spec id :: result def id, do: post_query("/id") |> map_response_data() |> filter_empties() |> unlist() |> okify() @doc """ Ping a peer. ## Parameters - peer: the peer to ping. ## Options https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-ping ``` [ n|count: , ] ``` """ @spec ping(name, opts) :: result def ping(peer, opts \\ []), do: post_query("/ping?arg=" <> peer, opts) |> map_response_data() |> okify() if @experimental do @doc """ Mount an IPFS read-only mountpoint. ## Options https://docs.ipfs.tech/reference/kubo/rpc/#api-v0-mount ``` [ ipfs-path: , # default: /ipfs ipns-path: , # default: /ipns ] ``` """ @spec mount(opts) :: result def mount(opts \\ []) do post_query("/mount", opts) |> map_response_data() |> okify() end end end