From e54047667a21ce444cd15d929626d670ebd48467 Mon Sep 17 00:00:00 2001 From: Jadenn Hillier Date: Thu, 22 Apr 2021 11:32:25 -0600 Subject: [PATCH 1/4] Correct a race condition when zbar is invoked before the previous file is finished processing --- lib/zbar.ex | 16 ++++++++++++---- mix.exs | 5 +++-- mix.lock | 17 +++++++++-------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/zbar.ex b/lib/zbar.ex index 1f8296e..4897db3 100644 --- a/lib/zbar.ex +++ b/lib/zbar.ex @@ -35,7 +35,8 @@ defmodule Zbar do | {:error, :timeout} | {:error, binary()} defp do_scan(jpeg_data, timeout) do - File.open!(temp_file(), [:write, :binary], & IO.binwrite(&1, jpeg_data)) + temp_file = temp_file() + File.open!(temp_file, [:write, :binary], &IO.binwrite(&1, jpeg_data)) {:spawn_executable, to_charlist(zbar_binary())} |> Port.open([ @@ -62,7 +63,10 @@ defmodule Zbar do end @spec temp_file() :: binary() - defp temp_file, do: Path.join(System.tmp_dir!(), "zbar_image.jpg") + defp temp_file do + file = Nanoid.generate() <> ".jpg" + Path.join(System.tmp_dir!(), file) + end @spec zbar_binary() :: binary() defp zbar_binary, do: Path.join(:code.priv_dir(:zbar), "zbar_scanner") @@ -76,13 +80,17 @@ defmodule Zbar do {^port, {:data, "Premature end of JPEG file\n"}} -> # Handles an error condition described in https://github.com/elixir-vision/zbar-elixir/issues/1 collect_output(port, timeout, buffer) + {^port, {:data, data}} -> collect_output(port, timeout, buffer <> to_string(data)) + {^port, {:exit_status, 0}} -> {:ok, buffer} + {^port, {:exit_status, _}} -> {:error, buffer} - after timeout -> + after + timeout -> Port.close(port) {:error, :timeout} end @@ -138,7 +146,7 @@ defmodule Zbar do defp parse_points(string) do string |> String.split(";") - |> Enum.map(& parse_point/1) + |> Enum.map(&parse_point/1) end @spec parse_point(binary()) :: Zbar.Symbol.point() diff --git a/mix.exs b/mix.exs index d5fc08b..5ed0789 100644 --- a/mix.exs +++ b/mix.exs @@ -11,8 +11,8 @@ defmodule Zbar.Mixfile do make_clean: ["clean"], compilers: [:elixir_make | Mix.compilers()], build_embedded: true, - start_permanent: Mix.env == :prod, - compilers: [:elixir_make] ++ Mix.compilers, + start_permanent: Mix.env() == :prod, + compilers: [:elixir_make] ++ Mix.compilers(), package: package(), deps: deps(), dialyzer: [plt_add_apps: [:mix]], @@ -29,6 +29,7 @@ defmodule Zbar.Mixfile do {:elixir_make, "~> 0.6", runtime: false}, {:dialyxir, "~> 1.0.0-rc.6", only: :dev, runtime: false}, {:ex_doc, "~> 0.21", only: :dev, runtime: false}, + {:nanoid, "~> 2.0.5", runtime: false} ] end diff --git a/mix.lock b/mix.lock index 66ad172..b53bbb7 100644 --- a/mix.lock +++ b/mix.lock @@ -1,10 +1,11 @@ %{ - "dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"}, - "earmark": {:hex, :earmark, "1.3.5", "0db71c8290b5bc81cb0101a2a507a76dca659513984d683119ee722828b424f6", [:mix], [], "hexpm"}, - "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"}, - "erlex": {:hex, :erlex, "0.2.4", "23791959df45fe8f01f388c6f7eb733cc361668cbeedd801bf491c55a029917b", [:mix], [], "hexpm"}, - "ex_doc": {:hex, :ex_doc, "0.21.1", "5ac36660846967cd869255f4426467a11672fec3d8db602c429425ce5b613b90", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"}, + "dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "49496d63267bc1a4614ffd5f67c45d9fc3ea62701a6797975bc98bc156d2763f"}, + "earmark": {:hex, :earmark, "1.3.5", "0db71c8290b5bc81cb0101a2a507a76dca659513984d683119ee722828b424f6", [:mix], [], "hexpm", "762b999fd414fb41e297944228aa1de2cd4a3876a07f968c8b11d1e9a2190d07"}, + "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"}, + "erlex": {:hex, :erlex, "0.2.4", "23791959df45fe8f01f388c6f7eb733cc361668cbeedd801bf491c55a029917b", [:mix], [], "hexpm", "4a12ebc7cd8f24f2d0fce93d279fa34eb5068e0e885bb841d558c4d83c52c439"}, + "ex_doc": {:hex, :ex_doc, "0.21.1", "5ac36660846967cd869255f4426467a11672fec3d8db602c429425ce5b613b90", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "93d2fee94d2f88abf507628378371ea5fab08ed03fa59a6daa3d4469d9159ddd"}, + "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, + "nanoid": {:hex, :nanoid, "2.0.5", "1d2948d8967ef2d948a58c3fef02385040bd9823fc6394bd604b8d98e5516b22", [:mix], [], "hexpm", "956e8876321104da72aa48770539ff26b36b744cd26753ec8e7a8a37e53d5f58"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"}, } From 51e16d115bbae466579ad8a51ffa62615d85646b Mon Sep 17 00:00:00 2001 From: Jadenn Hillier Date: Thu, 22 Apr 2021 11:32:59 -0600 Subject: [PATCH 2/4] Cleanup our mess when we're finished --- lib/zbar.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/zbar.ex b/lib/zbar.ex index 4897db3..319b6e8 100644 --- a/lib/zbar.ex +++ b/lib/zbar.ex @@ -55,9 +55,11 @@ defmodule Zbar do |> String.split("\n", trim: true) |> Enum.map(&parse_symbol/1) + File.rm(temp_file) {:ok, symbols} {:error, reason} -> + File.rm(temp_file) {:error, reason} end end From 73c0434d28195623f024635e29e2d7ce40e84b1a Mon Sep 17 00:00:00 2001 From: Jadenn Hillier Date: Thu, 22 Apr 2021 11:34:24 -0600 Subject: [PATCH 3/4] Prevent invalid or corrupt JPEG data from raising and causing a commotion --- lib/zbar.ex | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/zbar.ex b/lib/zbar.ex index 319b6e8..cae249d 100644 --- a/lib/zbar.ex +++ b/lib/zbar.ex @@ -20,9 +20,9 @@ defmodule Zbar do * `{:error, binary()}` if there was an error in the scanning process """ @spec scan(binary(), pos_integer()) :: - {:ok, list(Zbar.Symbol.t())} - | {:error, :timeout} - | {:error, binary()} + {:ok, list(Zbar.Symbol.t())} + | {:error, :timeout} + | {:error, binary()} def scan(jpeg_data, timeout \\ 5000) do # We run this in a `Task` so that `collect_output` can use `receive` # without interfering with the caller's mailbox. @@ -31,16 +31,16 @@ defmodule Zbar do end @spec do_scan(binary(), pos_integer()) :: - {:ok, [Zbar.Symbol.t()]} - | {:error, :timeout} - | {:error, binary()} + {:ok, [Zbar.Symbol.t()]} + | {:error, :timeout} + | {:error, binary()} defp do_scan(jpeg_data, timeout) do temp_file = temp_file() File.open!(temp_file, [:write, :binary], &IO.binwrite(&1, jpeg_data)) {:spawn_executable, to_charlist(zbar_binary())} |> Port.open([ - {:args, [temp_file()]}, + {:args, [temp_file]}, :binary, :stream, :exit_status, @@ -74,9 +74,9 @@ defmodule Zbar do defp zbar_binary, do: Path.join(:code.priv_dir(:zbar), "zbar_scanner") @spec collect_output(port(), pos_integer(), binary()) :: - {:ok, binary()} - | {:error, :timeout} - | {:error, binary()} + {:ok, binary()} + | {:error, :timeout} + | {:error, binary()} defp collect_output(port, timeout, buffer \\ "") do receive do {^port, {:data, "Premature end of JPEG file\n"}} -> @@ -113,19 +113,27 @@ defmodule Zbar do string |> String.split(" ") |> Enum.reduce(%Symbol{}, fn item, acc -> - [key, value] = String.split(item, ":", parts: 2) - case key do - "type" -> - %Symbol{acc | type: parse_type(value)} + case String.split(item, ":", parts: 2) do + [key, value] -> + case key do + "type" -> + %Symbol{acc | type: parse_type(value)} - "quality" -> - %Symbol{acc | quality: String.to_integer(value)} + "quality" -> + %Symbol{acc | quality: String.to_integer(value)} - "points" -> - %Symbol{acc | points: parse_points(value)} + "points" -> + %Symbol{acc | points: parse_points(value)} - "data" -> - %Symbol{acc | data: Base.decode64!(value)} + "data" -> + %Symbol{acc | data: Base.decode64!(value)} + + _ -> + acc + end + + _ -> + acc end end) end From bd1da08538318742e75afc7ba00630baab4c6bb1 Mon Sep 17 00:00:00 2001 From: Jadenn Hillier Date: Sun, 20 Aug 2023 14:17:39 -0600 Subject: [PATCH 4/4] Update nanoid and dialyzer --- config/config.exs | 1 - mix.exs | 6 +++--- mix.lock | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) delete mode 100644 config/config.exs diff --git a/config/config.exs b/config/config.exs deleted file mode 100644 index d2d855e..0000000 --- a/config/config.exs +++ /dev/null @@ -1 +0,0 @@ -use Mix.Config diff --git a/mix.exs b/mix.exs index 5ed0789..b487a39 100644 --- a/mix.exs +++ b/mix.exs @@ -15,7 +15,7 @@ defmodule Zbar.Mixfile do compilers: [:elixir_make] ++ Mix.compilers(), package: package(), deps: deps(), - dialyzer: [plt_add_apps: [:mix]], + dialyzer: [plt_add_apps: [:mix, :nanoid]], docs: docs() ] end @@ -27,9 +27,9 @@ defmodule Zbar.Mixfile do defp deps do [ {:elixir_make, "~> 0.6", runtime: false}, - {:dialyxir, "~> 1.0.0-rc.6", only: :dev, runtime: false}, + {:dialyxir, "~> 1.3", only: :dev, runtime: false}, {:ex_doc, "~> 0.21", only: :dev, runtime: false}, - {:nanoid, "~> 2.0.5", runtime: false} + {:nanoid, "~> 2.0", runtime: false} ] end diff --git a/mix.lock b/mix.lock index b53bbb7..e94da14 100644 --- a/mix.lock +++ b/mix.lock @@ -1,11 +1,13 @@ %{ - "dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "49496d63267bc1a4614ffd5f67c45d9fc3ea62701a6797975bc98bc156d2763f"}, + "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"}, "earmark": {:hex, :earmark, "1.3.5", "0db71c8290b5bc81cb0101a2a507a76dca659513984d683119ee722828b424f6", [:mix], [], "hexpm", "762b999fd414fb41e297944228aa1de2cd4a3876a07f968c8b11d1e9a2190d07"}, - "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"}, - "erlex": {:hex, :erlex, "0.2.4", "23791959df45fe8f01f388c6f7eb733cc361668cbeedd801bf491c55a029917b", [:mix], [], "hexpm", "4a12ebc7cd8f24f2d0fce93d279fa34eb5068e0e885bb841d558c4d83c52c439"}, - "ex_doc": {:hex, :ex_doc, "0.21.1", "5ac36660846967cd869255f4426467a11672fec3d8db602c429425ce5b613b90", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "93d2fee94d2f88abf507628378371ea5fab08ed03fa59a6daa3d4469d9159ddd"}, - "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, - "nanoid": {:hex, :nanoid, "2.0.5", "1d2948d8967ef2d948a58c3fef02385040bd9823fc6394bd604b8d98e5516b22", [:mix], [], "hexpm", "956e8876321104da72aa48770539ff26b36b744cd26753ec8e7a8a37e53d5f58"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, + "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "ex_doc": {:hex, :ex_doc, "0.30.5", "aa6da96a5c23389d7dc7c381eba862710e108cee9cfdc629b7ec021313900e9e", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "88a1e115dcb91cefeef7e22df4a6ebbe4634fbf98b38adcbc25c9607d6d9d8e6"}, + "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, + "nanoid": {:hex, :nanoid, "2.1.0", "d192a5bf1d774258bc49762b480fca0e3128178fa6d35a464af2a738526607fd", [:mix], [], "hexpm", "ebc7a342d02d213534a7f93a091d569b9fea7f26fcd3a638dc655060fc1f76ac"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, }