From a862bf94250b335ebee6d0c255602898403a7528 Mon Sep 17 00:00:00 2001 From: KarolK99 Date: Fri, 10 Nov 2023 17:20:11 +0100 Subject: [PATCH 1/3] Add API for s3 bucket --- lib/jellyfish/component/hls.ex | 13 +++++++++++-- lib/jellyfish/room.ex | 8 +++++++- test/jellyfish/room_test.exs | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/jellyfish/component/hls.ex b/lib/jellyfish/component/hls.ex index 00110b3..855832c 100644 --- a/lib/jellyfish/component/hls.ex +++ b/lib/jellyfish/component/hls.ex @@ -8,18 +8,27 @@ defmodule Jellyfish.Component.HLS do @behaviour Jellyfish.Component.Deserializer + @type credentials :: %{ + access_key_id: String.t(), + secret_access_key: String.t(), + region: String.t(), + bucket: String.t() + } + @enforce_keys [] defstruct @enforce_keys ++ [ low_latency: false, persistent: false, - target_window_duration: nil + target_window_duration: nil, + s3: nil ] @type t :: %__MODULE__{ low_latency: boolean(), persistent: boolean(), - target_window_duration: pos_integer() | nil + target_window_duration: pos_integer() | nil, + s3: credentials() | nil } @impl true diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index e153d5f..826296e 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -205,7 +205,7 @@ defmodule Jellyfish.Room do "type" => Component.string_from_options(component), "options" => Map.from_struct(component) - |> Map.new(fn {k, v} -> {snake_case_to_camel_case(k), v} end) + |> map_snake_case_to_camel_case() } ), {:ok, data} <- Map.fetch(body, "data"), @@ -253,6 +253,12 @@ defmodule Jellyfish.Room do end end + defp map_snake_case_to_camel_case(%{} = map), + do: + Map.new(map, fn {k, v} -> {snake_case_to_camel_case(k), map_snake_case_to_camel_case(v)} end) + + defp map_snake_case_to_camel_case(value), do: value + defp snake_case_to_camel_case(atom) do [first | rest] = Atom.to_string(atom) |> String.split("_") rest = rest |> Enum.map(&String.capitalize/1) diff --git a/test/jellyfish/room_test.exs b/test/jellyfish/room_test.exs index a7eae78..4cd35ac 100644 --- a/test/jellyfish/room_test.exs +++ b/test/jellyfish/room_test.exs @@ -14,6 +14,13 @@ defmodule Jellyfish.RoomTest do target_window_duration: nil } + @s3 %{ + access_key_id: "access_key_id", + secret_access_key: "secret_access_key", + region: "region", + bucket: "bucket" + } + @rtsp_component_opts %Component.RTSP{ source_uri: "rtsp://ef36c6dff23ecc5bbe311cc880d95dc8.se:2137/does/not/matter" } @@ -156,6 +163,13 @@ defmodule Jellyfish.RoomTest do assert %Component{type: Component.HLS, metadata: @hls_metadata} = component end + test "when request is valid with s3 credentials", %{client: client, room_id: room_id} do + assert {:ok, component} = + Room.add_component(client, room_id, %{@hls_component_opts | s3: @s3}) + + assert %Component{type: Component.HLS, metadata: @hls_metadata} = component + end + test "when request is invalid", %{client: client} do assert_raise FunctionClauseError, fn -> Room.add_component(client, @room_id, %InvalidComponentOpts{}) From 5efc138a9c0c4660f0073bd983444688b548c338 Mon Sep 17 00:00:00 2001 From: KarolK99 Date: Tue, 14 Nov 2023 18:06:39 +0100 Subject: [PATCH 2/3] Requested changes --- lib/jellyfish/exception.ex | 14 ++++++++++++++ lib/jellyfish/room.ex | 16 +++++++++++++++- lib/jellyfish/utils.ex | 3 ++- test/jellyfish/room_test.exs | 18 ++++++++++++++++-- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/lib/jellyfish/exception.ex b/lib/jellyfish/exception.ex index d9c6c54..e1dba59 100644 --- a/lib/jellyfish/exception.ex +++ b/lib/jellyfish/exception.ex @@ -28,4 +28,18 @@ defmodule Jellyfish.Exception do %__MODULE__{message: msg} end end + + defmodule OptionsError do + defexception [:message] + + @impl true + def exception(_opts) do + msg = """ + Passed component options that doesn't match function spec. + Look closely on `Jellyfish.Room.add_component/3` spec. + """ + + %__MODULE__{message: msg} + end + end end diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index 826296e..eaac004 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -31,9 +31,12 @@ defmodule Jellyfish.Room do """ alias Tesla.Env + alias Jellyfish.Component.{HLS, RTSP} alias Jellyfish.{Client, Component, Peer, Utils} alias Jellyfish.Exception.StructureError + @s3_kyes [:access_key_id, :secret_access_key, :region, :bucket] + @enforce_keys [ :id, :config, @@ -197,7 +200,8 @@ defmodule Jellyfish.Room do def add_component(client, room_id, component) do component = if is_atom(component), do: struct!(component), else: component - with {:ok, %Env{status: 201, body: body}} <- + with :ok <- validate_component(component), + {:ok, %Env{status: 201, body: body}} <- Tesla.post( client.http_client, "/room/#{room_id}/component", @@ -253,6 +257,16 @@ defmodule Jellyfish.Room do end end + defp validate_component(%RTSP{}), do: :ok + defp validate_component(%HLS{s3: nil}), do: :ok + defp validate_component(%HLS{s3: %{} = s3}), do: validate_s3_credentials(s3) + defp validate_component(_component), do: {:error, :component_validation} + + defp validate_s3_credentials(credentials) do + keys = Map.keys(credentials) + if @s3_kyes -- keys == [] and keys -- @s3_kyes, do: :ok, else: {:error, :component_validation} + end + defp map_snake_case_to_camel_case(%{} = map), do: Map.new(map, fn {k, v} -> {snake_case_to_camel_case(k), map_snake_case_to_camel_case(v)} end) diff --git a/lib/jellyfish/utils.ex b/lib/jellyfish/utils.ex index ef6d7bf..ca4401b 100644 --- a/lib/jellyfish/utils.ex +++ b/lib/jellyfish/utils.ex @@ -2,7 +2,7 @@ defmodule Jellyfish.Utils do @moduledoc false alias Jellyfish.Client - alias Jellyfish.Exception.{ProtocolPrefixError, StructureError} + alias Jellyfish.Exception.{OptionsError, ProtocolPrefixError, StructureError} alias Tesla.Env @protocol_prefixes ["http://", "https://", "ws://", "wss://"] @@ -36,5 +36,6 @@ defmodule Jellyfish.Utils do do: {:error, "Request failed: #{error}"} def handle_response_error({:ok, %Env{body: _body}}), do: raise(StructureError) + def handle_response_error({:error, :component_validation}), do: raise(OptionsError) def handle_response_error({:error, reason}), do: {:error, reason} end diff --git a/test/jellyfish/room_test.exs b/test/jellyfish/room_test.exs index 4cd35ac..695b435 100644 --- a/test/jellyfish/room_test.exs +++ b/test/jellyfish/room_test.exs @@ -1,6 +1,7 @@ defmodule Jellyfish.RoomTest do use ExUnit.Case doctest Jellyfish.Room + alias Jellyfish.Exception.OptionsError alias Jellyfish.{Client, Component, Peer, Room} @server_api_token "development" @@ -170,12 +171,25 @@ defmodule Jellyfish.RoomTest do assert %Component{type: Component.HLS, metadata: @hls_metadata} = component end + test "when request is invalid - wrong s3 credentials", %{client: client, room_id: room_id} do + assert_raise OptionsError, fn -> + Room.add_component(client, room_id, %{ + @hls_component_opts + | s3: Map.delete(@s3, :bucket) + }) + end + + assert_raise OptionsError, fn -> + Room.add_component(client, room_id, %{@hls_component_opts | s3: []}) + end + end + test "when request is invalid", %{client: client} do - assert_raise FunctionClauseError, fn -> + assert_raise OptionsError, fn -> Room.add_component(client, @room_id, %InvalidComponentOpts{}) end - assert_raise FunctionClauseError, fn -> + assert_raise OptionsError, fn -> Room.add_component(client, @room_id, InvalidComponentOpts) end end From 226b49008485c83e018736c70e4f7e80f05311d9 Mon Sep 17 00:00:00 2001 From: KarolK99 Date: Wed, 15 Nov 2023 11:53:52 +0100 Subject: [PATCH 3/3] Requested changes --- lib/jellyfish/room.ex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/jellyfish/room.ex b/lib/jellyfish/room.ex index eaac004..a1c52b8 100644 --- a/lib/jellyfish/room.ex +++ b/lib/jellyfish/room.ex @@ -35,7 +35,7 @@ defmodule Jellyfish.Room do alias Jellyfish.{Client, Component, Peer, Utils} alias Jellyfish.Exception.StructureError - @s3_kyes [:access_key_id, :secret_access_key, :region, :bucket] + @s3_keys [:access_key_id, :secret_access_key, :region, :bucket] @enforce_keys [ :id, @@ -264,7 +264,10 @@ defmodule Jellyfish.Room do defp validate_s3_credentials(credentials) do keys = Map.keys(credentials) - if @s3_kyes -- keys == [] and keys -- @s3_kyes, do: :ok, else: {:error, :component_validation} + + if @s3_keys -- keys == [] and keys -- @s3_keys == [], + do: :ok, + else: {:error, :component_validation} end defp map_snake_case_to_camel_case(%{} = map),