Skip to content

Commit

Permalink
i don't even know
Browse files Browse the repository at this point in the history
  • Loading branch information
mekaem committed Oct 4, 2024
1 parent 679b84a commit 2330b4f
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 269 deletions.
127 changes: 127 additions & 0 deletions lib/hexpds/car/process.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
defmodule Hexpds.Car.Writer.Process do
@moduledoc """
GenServer process responsible for managing the CAR stream.
"""

use GenServer

alias Hexpds.CID

@doc """
Starts the CAR writer GenServer.
## Options
- `:file_path` - The path to the CAR file to write to.
## Examples
iex> {:ok, pid} = Hexpds.Car.Writer.Process.start_link(file_path: "output.car")
"""
def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end

@doc """
Adds a block to the CAR stream.
## Parameters
- `cid`: The CID of the data block.
- `serialized_entries`: The binary data to write.
## Returns
- `:ok` on success.
- `{:error, reason}` on failure.
## Examples
iex> Hexpds.Car.Writer.Process.put(pid, cid, serialized_data)
:ok
"""
@spec put(pid(), CID.t(), binary()) :: :ok | {:error, term()}
def put(pid, %CID{} = cid, serialized_entries) when is_binary(serialized_entries) do
GenServer.call(pid, {:put, cid, serialized_entries})
end

@doc """
Finalizes the CAR stream
## Parameters
- `pid`: The PID of the CAR writer GenServer.
## Returns
- `:ok` on success.
- `{:error, reason}` on failure.
## Examples
iex> Hexpds.Car.Writer.Process.finalize(pid)
:ok
"""
@spec finalize(pid()) :: :ok | {:error, term()}
def finalize(pid) do
GenServer.call(pid, :finalize)
end

## Server Callbacks

@impl true
def init(opts) do
file_path = Keyword.fetch!(opts, :file_path)

case File.open(file_path, [:write, :binary]) do
{:ok, file} ->
{:ok, %{file: file}}

{:error, reason} ->
{:stop, {:cannot_open_file, reason}}
end
end

@impl true
def handle_call({:put, cid, serialized_entries}, _from, state) do
case write_block(state.file, cid, serialized_entries) do
:ok ->
{:reply, :ok, state}

{:error, reason} ->
{:reply, {:error, reason}, state}
end
end

def handle_call(:finalize, _from, state) do
case File.close(state.file) do
:ok ->
{:reply, :ok, state}

{:error, reason} ->
{:reply, {:error, reason}, state}
end
end

@impl true
def terminate(_reason, state) do
File.close(state.file)
:ok
end

## Helper Functions

defp write_block(file, %CID{} = cid, data) do
# TODO

cid_string = Hexpds.CID.to_string(cid)
data_length = byte_size(data)

write_data = "#{cid_string}\n#{data_length}\n#{data}"

case IO.binwrite(file, write_data) do
:ok -> :ok
{:error, reason} -> {:error, reason}
end
end
end
35 changes: 35 additions & 0 deletions lib/hexpds/car/writer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Hexpds.Car.Writer do
@moduledoc """
Module for writing data blocks to a CAR stream.
"""

alias Hexpds.CID

@doc """
Writes a block to the CAR stream.
## Parameters
- `car`: The CAR writer process or handle.
- `cid`: The CID of the data block.
- `serialized_entries`: The binary data to write.
## Returns
- `:ok` on success.
- `{:error, reason}` on failure.
## Examples
iex> Hexpds.Car.Writer.put(car_writer, cid, serialized_data)
:ok
"""
@spec put(car :: pid() | atom(), cid :: CID.t(), serialized_entries :: binary()) :: :ok | {:error, term()}
def put(car, %CID{} = cid, serialized_entries) when is_binary(serialized_entries) do
# TODO
GenServer.call(car, {:put, cid, serialized_entries})
rescue
e ->
{:error, "Failed to write to CAR stream: #{inspect(e)}"}
end
end
60 changes: 60 additions & 0 deletions lib/hexpds/cid.ex
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ defmodule Hexpds.CID do
do_encode(cid, encoding_id)
end

@spec encode!(Hexpds.CID.t()) :: binary()
@doc """
Encodes a CID as a Multibase encoded string.
Expand Down Expand Up @@ -364,6 +365,7 @@ defmodule Hexpds.CID do
do_encode_buffer(cid)
end

@spec encode_buffer!(Hexpds.CID.t()) :: binary()
@doc """
Encodes a CID as a raw buffer to be encoded with Multibase.
Expand Down Expand Up @@ -772,7 +774,65 @@ defmodule Hexpds.CID do
end
end

@doc """
Creates a new CID by hashing the given data using the specified hash algorithm and codec.
## Parameters
- `hash_algorithm`: The hash algorithm to use (e.g., `:sha2_256`).
- `data`: The binary data to hash.
- `codec`: The codec to use for the CID (e.g., `"dag-cbor"`).
## Returns
- `{:ok, CID.t()}` on success.
- `{:error, reason}` on failure.
"""
@spec create_cid(atom(), binary(), Multicodec.multi_codec()) :: {:ok, t()} | {:error, term()}
def create_cid(hash_algorithm, data, codec \\ @v0_codec) when is_atom(hash_algorithm) and is_binary(data) do
with {:ok, multihash} <- Multihash.encode(hash_algorithm, data),
{:ok, cid} <- cid(multihash, codec, @current_version) do
{:ok, cid}
else
{:error, reason} -> {:error, reason}
end
end

@doc """
Alias for `create_cid/3`.
"""
@spec new(atom(), binary()) :: {:ok, t()} | {:error, term()}
def new(hash_algorithm, data) do
create_cid(hash_algorithm, data)
end


defimpl String.Chars, for: CID do
def to_string(cid), do: CID.encode!(cid, :base32_lower)
end

@spec to_string(CID.t()) :: String.t()
def to_string(%CID{} = cid) do
encode!(cid, :base32_lower)
end

@doc """
Parses a CID string into a CID struct.
Returns `{:ok, CID.t()}` on success, or `{:error, reason}` on failure.
"""
@spec from_string(String.t()) :: {:ok, t()} | {:error, term()}
def from_string(cid_string) when is_binary(cid_string) do
decode_cid(cid_string)
end

@doc """
Parses a CID string into a CID struct.
Raises an exception if the CID string is invalid.
"""
@spec from_string!(String.t()) :: t()
def from_string!(cid_string) do
decode_cid!(cid_string)
end
end
Loading

0 comments on commit 2330b4f

Please sign in to comment.