From 1663a5e21f71fc7c2e1304c148a07a3ec53ff342 Mon Sep 17 00:00:00 2001 From: Vanja Bucic Date: Wed, 5 Dec 2018 12:55:18 -0500 Subject: [PATCH 1/5] initial commit of http client generator --- example/config/config.exs | 6 + .../generated/divide_by_zero_error.ex | 41 +- .../lib/calculator/generated/http/client.ex | 201 ++++++ example/lib/calculator/generated/service.ex | 648 +++++------------- .../calculator/generated/service/handler.ex | 18 +- example/lib/calculator/generated/vector.ex | 140 ++-- .../generated/vector_product_result.ex | 74 +- .../generated/vector_product_type.ex | 21 +- example/mix.exs | 3 +- lib/mix/tasks/thrift.httpclient.generate.ex | 264 +++++++ mix.lock | 1 + 11 files changed, 728 insertions(+), 689 deletions(-) create mode 100644 example/lib/calculator/generated/http/client.ex create mode 100644 lib/mix/tasks/thrift.httpclient.generate.ex diff --git a/example/config/config.exs b/example/config/config.exs index 098ae2f0..0a8baad3 100644 --- a/example/config/config.exs +++ b/example/config/config.exs @@ -2,3 +2,9 @@ use Mix.Config config :calculator, port: 9090 + +config :calculator, Calculator.Generated.HTTP.Client, + endpoint: "http://localhost:8080/TCalculatorServlet/Calculator" + +config :calculator, CommonDataStream.Generated.HTTP.Client, + endpoint: "http://192.168.100.168:8080/CommonDataInjectionStreamer/CommonTagServletBin" diff --git a/example/lib/calculator/generated/divide_by_zero_error.ex b/example/lib/calculator/generated/divide_by_zero_error.ex index d3487b53..a5f2cd6b 100644 --- a/example/lib/calculator/generated/divide_by_zero_error.ex +++ b/example/lib/calculator/generated/divide_by_zero_error.ex @@ -1,64 +1,45 @@ defmodule(Calculator.Generated.DivideByZeroError) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift exception calculator.DivideByZeroError" _ = "1: string message" defexception(message: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %Calculator.Generated.DivideByZeroError{}) end - defp(deserialize(<<0, rest::binary>>, %Calculator.Generated.DivideByZeroError{} = acc)) do {acc, rest} end - - defp( - deserialize( - <<11, 1::16-signed, string_size::32-signed, value::binary-size(string_size), - rest::binary>>, - acc - ) - ) do + defp(deserialize(<<11, 1::16-signed, string_size::32-signed, value::binary-size(string_size), rest::binary>>, acc)) do deserialize(rest, %{acc | message: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%Calculator.Generated.DivideByZeroError{message: message})) do - [ - case(message) do - nil -> - <<>> - - _ -> - [<<11, 1::16-signed, byte_size(message)::32-signed>> | message] - end - | <<0>> - ] + [case(message) do + nil -> + <<>> + _ -> + [<<11, 1::16-signed, byte_size(message)::32-signed>> | message] + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end -end +end \ No newline at end of file diff --git a/example/lib/calculator/generated/http/client.ex b/example/lib/calculator/generated/http/client.ex new file mode 100644 index 00000000..fec5aaea --- /dev/null +++ b/example/lib/calculator/generated/http/client.ex @@ -0,0 +1,201 @@ +defmodule(Calculator.Generated.HTTP.Client) do + require(Logger) + @default_headers Accept: "application/x-thrift", "Content-Type": "application/x-thrift" + @http_client_options hackney: [pool: :default] + @service_endpoint Application.get_env( + Mix.Project.config()[:app], + Calculator.Generated.HTTP.Client, + %{} + )[:endpoint] + def(post_thrift(serialized_binary)) do + if(@service_endpoint == nil) do + Logger.error( + "service endpoint not defined for #{Macro.to_string(__MODULE__)}!! Please add it to config file!" + ) + end + + case( + HTTPoison.post(@service_endpoint, serialized_binary, @default_headers, @http_client_options) + ) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + {:ok, body} + + {:ok, %HTTPoison.Response{status_code: code, body: body}} -> + {:service_err, code, body} + + {:error, %HTTPoison.Error{reason: reason}} -> + {:http_err, inspect(reason)} + end + end +end + +defmodule(Calculator.Generated.HTTP.Service) do + alias(Calculator.Generated.Service) + alias(Calculator.Generated.HTTP) + alias(Thrift.Protocol.Binary) + + ( + @doc "left: i64\n\nright: i64" + def(add(left, right)) do + args = %Service.AddArgs{left: left, right: right} + serialized_args = Service.AddArgs.BinaryProtocol.serialize(args) + tcall = Binary.serialize(:message_begin, {:call, 0, "add"}) + payload = [tcall | serialized_args] |> IO.iodata_to_binary() + + with( + {:ok, body} <- HTTP.Client.post_thrift(payload), + {:ok, {:reply, _, _, ser_resp}} <- Binary.deserialize(:message_begin, body), + {response, _} <- Service.AddResponse.deserialize(ser_resp) + ) do + response + else + {:service_err, code, body} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "service error [#{code}] #{body}" + ) + + {:http_err, err_str} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "http error: #{err_str}" + ) + + {:ok, {:exception, _, _, ser_ex}} -> + Binary.deserialize(:application_exception, ser_ex) + end + end + ) + + ( + @doc "left: i64\n\nright: i64" + def(divide(left, right)) do + args = %Service.DivideArgs{left: left, right: right} + serialized_args = Service.DivideArgs.BinaryProtocol.serialize(args) + tcall = Binary.serialize(:message_begin, {:call, 0, "divide"}) + payload = [tcall | serialized_args] |> IO.iodata_to_binary() + + with( + {:ok, body} <- HTTP.Client.post_thrift(payload), + {:ok, {:reply, _, _, ser_resp}} <- Binary.deserialize(:message_begin, body), + {response, _} <- Service.DivideResponse.deserialize(ser_resp) + ) do + response + else + {:service_err, code, body} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "service error [#{code}] #{body}" + ) + + {:http_err, err_str} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "http error: #{err_str}" + ) + + {:ok, {:exception, _, _, ser_ex}} -> + Binary.deserialize(:application_exception, ser_ex) + end + end + ) + + ( + @doc "left: i64\n\nright: i64" + def(multiply(left, right)) do + args = %Service.MultiplyArgs{left: left, right: right} + serialized_args = Service.MultiplyArgs.BinaryProtocol.serialize(args) + tcall = Binary.serialize(:message_begin, {:call, 0, "multiply"}) + payload = [tcall | serialized_args] |> IO.iodata_to_binary() + + with( + {:ok, body} <- HTTP.Client.post_thrift(payload), + {:ok, {:reply, _, _, ser_resp}} <- Binary.deserialize(:message_begin, body), + {response, _} <- Service.MultiplyResponse.deserialize(ser_resp) + ) do + response + else + {:service_err, code, body} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "service error [#{code}] #{body}" + ) + + {:http_err, err_str} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "http error: #{err_str}" + ) + + {:ok, {:exception, _, _, ser_ex}} -> + Binary.deserialize(:application_exception, ser_ex) + end + end + ) + + ( + @doc "left: i64\n\nright: i64" + def(subtract(left, right)) do + args = %Service.SubtractArgs{left: left, right: right} + serialized_args = Service.SubtractArgs.BinaryProtocol.serialize(args) + tcall = Binary.serialize(:message_begin, {:call, 0, "subtract"}) + payload = [tcall | serialized_args] |> IO.iodata_to_binary() + + with( + {:ok, body} <- HTTP.Client.post_thrift(payload), + {:ok, {:reply, _, _, ser_resp}} <- Binary.deserialize(:message_begin, body), + {response, _} <- Service.SubtractResponse.deserialize(ser_resp) + ) do + response + else + {:service_err, code, body} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "service error [#{code}] #{body}" + ) + + {:http_err, err_str} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "http error: #{err_str}" + ) + + {:ok, {:exception, _, _, ser_ex}} -> + Binary.deserialize(:application_exception, ser_ex) + end + end + ) + + ( + @doc "left: `Calculator.Generated.Vector`\n\nright: `Calculator.Generated.Vector`\n\ntype: `Calculator.Generated.VectorProductType`" + def(vector_product(left, right, type)) do + args = %Service.VectorProductArgs{left: left, right: right, type: type} + serialized_args = Service.VectorProductArgs.BinaryProtocol.serialize(args) + tcall = Binary.serialize(:message_begin, {:call, 0, "vectorProduct"}) + payload = [tcall | serialized_args] |> IO.iodata_to_binary() + + with( + {:ok, body} <- HTTP.Client.post_thrift(payload), + {:ok, {:reply, _, _, ser_resp}} <- Binary.deserialize(:message_begin, body), + {response, _} <- Service.VectorProductResponse.deserialize(ser_resp) + ) do + response + else + {:service_err, code, body} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "service error [#{code}] #{body}" + ) + + {:http_err, err_str} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "http error: #{err_str}" + ) + + {:ok, {:exception, _, _, ser_ex}} -> + Binary.deserialize(:application_exception, ser_ex) + end + end + ) +end diff --git a/example/lib/calculator/generated/service.ex b/example/lib/calculator/generated/service.ex index 4c036ea4..ce5f28fe 100644 --- a/example/lib/calculator/generated/service.ex +++ b/example/lib/calculator/generated/service.ex @@ -1,1055 +1,739 @@ defmodule(Calculator.Generated.Service) do - @moduledoc false + @moduledoc(false) defmodule(AddArgs) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.AddArgs" _ = "1: i64 left" _ = "2: i64 right" defstruct(left: nil, right: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %AddArgs{}) end - defp(deserialize(<<0, rest::binary>>, %AddArgs{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 1::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | left: value}) end - defp(deserialize(<<10, 2::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | right: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%AddArgs{left: left, right: right})) do - [ - case(left) do - nil -> - <<>> - - _ -> - <<10, 1::16-signed, left::64-signed>> - end, - case(right) do - nil -> - <<>> - - _ -> - <<10, 2::16-signed, right::64-signed>> - end - | <<0>> - ] + [case(left) do + nil -> + <<>> + _ -> + <<10, 1::16-signed, left::64-signed>> + end, case(right) do + nil -> + <<>> + _ -> + <<10, 2::16-signed, right::64-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(DivideArgs) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.DivideArgs" _ = "1: i64 left" _ = "2: i64 right" defstruct(left: nil, right: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %DivideArgs{}) end - defp(deserialize(<<0, rest::binary>>, %DivideArgs{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 1::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | left: value}) end - defp(deserialize(<<10, 2::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | right: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%DivideArgs{left: left, right: right})) do - [ - case(left) do - nil -> - <<>> - - _ -> - <<10, 1::16-signed, left::64-signed>> - end, - case(right) do - nil -> - <<>> - - _ -> - <<10, 2::16-signed, right::64-signed>> - end - | <<0>> - ] + [case(left) do + nil -> + <<>> + _ -> + <<10, 1::16-signed, left::64-signed>> + end, case(right) do + nil -> + <<>> + _ -> + <<10, 2::16-signed, right::64-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(MultiplyArgs) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.MultiplyArgs" _ = "1: i64 left" _ = "2: i64 right" defstruct(left: nil, right: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %MultiplyArgs{}) end - defp(deserialize(<<0, rest::binary>>, %MultiplyArgs{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 1::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | left: value}) end - defp(deserialize(<<10, 2::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | right: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%MultiplyArgs{left: left, right: right})) do - [ - case(left) do - nil -> - <<>> - - _ -> - <<10, 1::16-signed, left::64-signed>> - end, - case(right) do - nil -> - <<>> - - _ -> - <<10, 2::16-signed, right::64-signed>> - end - | <<0>> - ] + [case(left) do + nil -> + <<>> + _ -> + <<10, 1::16-signed, left::64-signed>> + end, case(right) do + nil -> + <<>> + _ -> + <<10, 2::16-signed, right::64-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(SubtractArgs) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.SubtractArgs" _ = "1: i64 left" _ = "2: i64 right" defstruct(left: nil, right: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %SubtractArgs{}) end - defp(deserialize(<<0, rest::binary>>, %SubtractArgs{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 1::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | left: value}) end - defp(deserialize(<<10, 2::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | right: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%SubtractArgs{left: left, right: right})) do - [ - case(left) do - nil -> - <<>> - - _ -> - <<10, 1::16-signed, left::64-signed>> - end, - case(right) do - nil -> - <<>> - - _ -> - <<10, 2::16-signed, right::64-signed>> - end - | <<0>> - ] + [case(left) do + nil -> + <<>> + _ -> + <<10, 1::16-signed, left::64-signed>> + end, case(right) do + nil -> + <<>> + _ -> + <<10, 2::16-signed, right::64-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(VectorProductArgs) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.VectorProductArgs" _ = "1: calculator.Vector left" _ = "2: calculator.Vector right" _ = "3: calculator.VectorProductType type" defstruct(left: nil, right: nil, type: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %VectorProductArgs{}) end - defp(deserialize(<<0, rest::binary>>, %VectorProductArgs{} = acc)) do {acc, rest} end - defp(deserialize(<<12, 1::16-signed, rest::binary>>, acc)) do case(Elixir.Calculator.Generated.Vector.BinaryProtocol.deserialize(rest)) do {value, rest} -> deserialize(rest, %{acc | left: value}) - :error -> :error end end - defp(deserialize(<<12, 2::16-signed, rest::binary>>, acc)) do case(Elixir.Calculator.Generated.Vector.BinaryProtocol.deserialize(rest)) do {value, rest} -> deserialize(rest, %{acc | right: value}) - :error -> :error end end - defp(deserialize(<<8, 3::16-signed, value::32-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | type: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%VectorProductArgs{left: left, right: right, type: type})) do - [ - case(left) do - nil -> - <<>> - - _ -> - [<<12, 1::16-signed>> | Calculator.Generated.Vector.serialize(left)] - end, - case(right) do - nil -> - <<>> - - _ -> - [<<12, 2::16-signed>> | Calculator.Generated.Vector.serialize(right)] - end, - case(type) do - nil -> - <<>> - - _ -> - <<8, 3::16-signed, type::32-signed>> - end - | <<0>> - ] + [case(left) do + nil -> + <<>> + _ -> + [<<12, 1::16-signed>> | Calculator.Generated.Vector.serialize(left)] + end, case(right) do + nil -> + <<>> + _ -> + [<<12, 2::16-signed>> | Calculator.Generated.Vector.serialize(right)] + end, case(type) do + nil -> + <<>> + _ -> + <<8, 3::16-signed, type::32-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(AddResponse) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.AddResponse" _ = "0: i64 success" defstruct(success: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %AddResponse{}) end - defp(deserialize(<<0, rest::binary>>, %AddResponse{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 0::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | success: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%AddResponse{success: success})) do - [ - case(success) do - nil -> - <<>> - - _ -> - <<10, 0::16-signed, success::64-signed>> - end - | <<0>> - ] + [case(success) do + nil -> + <<>> + _ -> + <<10, 0::16-signed, success::64-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(DivideResponse) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.DivideResponse" _ = "0: i64 success" _ = "1: calculator.DivideByZeroError e" defstruct(success: nil, e: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %DivideResponse{}) end - defp(deserialize(<<0, rest::binary>>, %DivideResponse{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 0::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | success: value}) end - defp(deserialize(<<12, 1::16-signed, rest::binary>>, acc)) do case(Elixir.Calculator.Generated.DivideByZeroError.BinaryProtocol.deserialize(rest)) do {value, rest} -> deserialize(rest, %{acc | e: value}) - :error -> :error end end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%DivideResponse{success: success, e: e})) do - [ - case(success) do - nil -> - <<>> - - _ -> - <<10, 0::16-signed, success::64-signed>> - end, - case(e) do - nil -> - <<>> - - _ -> - [<<12, 1::16-signed>> | Calculator.Generated.DivideByZeroError.serialize(e)] - end - | <<0>> - ] + [case(success) do + nil -> + <<>> + _ -> + <<10, 0::16-signed, success::64-signed>> + end, case(e) do + nil -> + <<>> + _ -> + [<<12, 1::16-signed>> | Calculator.Generated.DivideByZeroError.serialize(e)] + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(MultiplyResponse) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.MultiplyResponse" _ = "0: i64 success" defstruct(success: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %MultiplyResponse{}) end - defp(deserialize(<<0, rest::binary>>, %MultiplyResponse{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 0::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | success: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%MultiplyResponse{success: success})) do - [ - case(success) do - nil -> - <<>> - - _ -> - <<10, 0::16-signed, success::64-signed>> - end - | <<0>> - ] + [case(success) do + nil -> + <<>> + _ -> + <<10, 0::16-signed, success::64-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(SubtractResponse) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.SubtractResponse" _ = "0: i64 success" defstruct(success: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %SubtractResponse{}) end - defp(deserialize(<<0, rest::binary>>, %SubtractResponse{} = acc)) do {acc, rest} end - defp(deserialize(<<10, 0::16-signed, value::64-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | success: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%SubtractResponse{success: success})) do - [ - case(success) do - nil -> - <<>> - - _ -> - <<10, 0::16-signed, success::64-signed>> - end - | <<0>> - ] + [case(success) do + nil -> + <<>> + _ -> + <<10, 0::16-signed, success::64-signed>> + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(VectorProductResponse) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct Elixir.VectorProductResponse" _ = "0: calculator.VectorProductResult success" defstruct(success: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %VectorProductResponse{}) end - defp(deserialize(<<0, rest::binary>>, %VectorProductResponse{} = acc)) do {acc, rest} end - defp(deserialize(<<12, 0::16-signed, rest::binary>>, acc)) do case(Elixir.Calculator.Generated.VectorProductResult.BinaryProtocol.deserialize(rest)) do {value, rest} -> deserialize(rest, %{acc | success: value}) - :error -> :error end end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%VectorProductResponse{success: success})) do - [ - case(success) do - nil -> - <<>> - - _ -> - [<<12, 0::16-signed>> | Calculator.Generated.VectorProductResult.serialize(success)] - end - | <<0>> - ] + [case(success) do + nil -> + <<>> + _ -> + [<<12, 0::16-signed>> | Calculator.Generated.VectorProductResult.serialize(success)] + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end end - defmodule(Binary.Framed.Client) do - @moduledoc false + @moduledoc(false) alias(Thrift.Binary.Framed.Client, as: ClientImpl) defdelegate(close(conn), to: ClientImpl) defdelegate(connect(conn, opts), to: ClientImpl) defdelegate(start_link(host, port, opts \\ []), to: ClientImpl) - def(unquote(:add)(client, left, right, rpc_opts \\ [])) do args = %AddArgs{left: left, right: right} serialized_args = AddArgs.BinaryProtocol.serialize(args) ClientImpl.call(client, "add", serialized_args, AddResponse.BinaryProtocol, rpc_opts) end - def(unquote(:add!)(client, left, right, rpc_opts \\ [])) do case(unquote(:add)(client, left, right, rpc_opts)) do {:ok, rsp} -> rsp - {:error, {:exception, ex}} -> raise(ex) - {:error, reason} -> raise(Thrift.ConnectionError, reason: reason) end end - def(unquote(:divide)(client, left, right, rpc_opts \\ [])) do args = %DivideArgs{left: left, right: right} serialized_args = DivideArgs.BinaryProtocol.serialize(args) ClientImpl.call(client, "divide", serialized_args, DivideResponse.BinaryProtocol, rpc_opts) end - def(unquote(:divide!)(client, left, right, rpc_opts \\ [])) do case(unquote(:divide)(client, left, right, rpc_opts)) do {:ok, rsp} -> rsp - {:error, {:exception, ex}} -> raise(ex) - {:error, reason} -> raise(Thrift.ConnectionError, reason: reason) end end - def(unquote(:multiply)(client, left, right, rpc_opts \\ [])) do args = %MultiplyArgs{left: left, right: right} serialized_args = MultiplyArgs.BinaryProtocol.serialize(args) - - ClientImpl.call( - client, - "multiply", - serialized_args, - MultiplyResponse.BinaryProtocol, - rpc_opts - ) - end - + ClientImpl.call(client, "multiply", serialized_args, MultiplyResponse.BinaryProtocol, rpc_opts) + end def(unquote(:multiply!)(client, left, right, rpc_opts \\ [])) do case(unquote(:multiply)(client, left, right, rpc_opts)) do {:ok, rsp} -> rsp - {:error, {:exception, ex}} -> raise(ex) - {:error, reason} -> raise(Thrift.ConnectionError, reason: reason) end end - def(unquote(:subtract)(client, left, right, rpc_opts \\ [])) do args = %SubtractArgs{left: left, right: right} serialized_args = SubtractArgs.BinaryProtocol.serialize(args) - - ClientImpl.call( - client, - "subtract", - serialized_args, - SubtractResponse.BinaryProtocol, - rpc_opts - ) - end - + ClientImpl.call(client, "subtract", serialized_args, SubtractResponse.BinaryProtocol, rpc_opts) + end def(unquote(:subtract!)(client, left, right, rpc_opts \\ [])) do case(unquote(:subtract)(client, left, right, rpc_opts)) do {:ok, rsp} -> rsp - {:error, {:exception, ex}} -> raise(ex) - {:error, reason} -> raise(Thrift.ConnectionError, reason: reason) end end - def(unquote(:vector_product)(client, left, right, type, rpc_opts \\ [])) do args = %VectorProductArgs{left: left, right: right, type: type} serialized_args = VectorProductArgs.BinaryProtocol.serialize(args) - - ClientImpl.call( - client, - "vectorProduct", - serialized_args, - VectorProductResponse.BinaryProtocol, - rpc_opts - ) - end - + ClientImpl.call(client, "vectorProduct", serialized_args, VectorProductResponse.BinaryProtocol, rpc_opts) + end def(unquote(:vector_product!)(client, left, right, type, rpc_opts \\ [])) do case(unquote(:vector_product)(client, left, right, type, rpc_opts)) do {:ok, rsp} -> rsp - {:error, {:exception, ex}} -> raise(ex) - {:error, reason} -> raise(Thrift.ConnectionError, reason: reason) end end end - defmodule(Binary.Framed.Server) do - @moduledoc false + @moduledoc(false) require(Logger) alias(Thrift.Binary.Framed.Server, as: ServerImpl) defdelegate(stop(name), to: ServerImpl) - def(start_link(handler_module, port, opts \\ [])) do ServerImpl.start_link(__MODULE__, port, handler_module, opts) end - def(handle_thrift("add", binary_data, handler_module)) do case(Elixir.Calculator.Generated.Service.AddArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.AddArgs{left: left, right: right}, ""} -> - try do + try() do rsp = handler_module.add(left, right) - ( response = %Calculator.Generated.Service.AddResponse{success: rsp} - - {:reply, - Elixir.Calculator.Generated.Service.AddResponse.BinaryProtocol.serialize(response)} + {:reply, Elixir.Calculator.Generated.Service.AddResponse.BinaryProtocol.serialize(response)} ) rescue [] catch kind, reason -> formatted_exception = Exception.format(kind, reason, System.stacktrace()) - - Logger.error( - "Exception not defined in thrift spec was thrown: #{formatted_exception}" - ) - - error = - Thrift.TApplicationException.exception( - type: :internal_error, - message: "Server error: #{formatted_exception}" - ) - + Logger.error("Exception not defined in thrift spec was thrown: #{formatted_exception}") + error = Thrift.TApplicationException.exception(type: :internal_error, message: "Server error: #{formatted_exception}") {:server_error, error} end - {_, extra} -> - raise(Thrift.TApplicationException, - type: :protocol_error, - message: "Could not decode #{inspect(extra)}" - ) + raise(Thrift.TApplicationException, type: :protocol_error, message: "Could not decode #{inspect(extra)}") end end - def(handle_thrift("divide", binary_data, handler_module)) do - case( - Elixir.Calculator.Generated.Service.DivideArgs.BinaryProtocol.deserialize(binary_data) - ) do + case(Elixir.Calculator.Generated.Service.DivideArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.DivideArgs{left: left, right: right}, ""} -> - try do + try() do rsp = handler_module.divide(left, right) - ( response = %Calculator.Generated.Service.DivideResponse{success: rsp} - - {:reply, - Elixir.Calculator.Generated.Service.DivideResponse.BinaryProtocol.serialize( - response - )} + {:reply, Elixir.Calculator.Generated.Service.DivideResponse.BinaryProtocol.serialize(response)} ) rescue e in Calculator.Generated.DivideByZeroError -> response = %Calculator.Generated.Service.DivideResponse{e: e} - - {:reply, - Elixir.Calculator.Generated.Service.DivideResponse.BinaryProtocol.serialize( - response - )} + {:reply, Elixir.Calculator.Generated.Service.DivideResponse.BinaryProtocol.serialize(response)} catch kind, reason -> formatted_exception = Exception.format(kind, reason, System.stacktrace()) - - Logger.error( - "Exception not defined in thrift spec was thrown: #{formatted_exception}" - ) - - error = - Thrift.TApplicationException.exception( - type: :internal_error, - message: "Server error: #{formatted_exception}" - ) - + Logger.error("Exception not defined in thrift spec was thrown: #{formatted_exception}") + error = Thrift.TApplicationException.exception(type: :internal_error, message: "Server error: #{formatted_exception}") {:server_error, error} end - {_, extra} -> - raise(Thrift.TApplicationException, - type: :protocol_error, - message: "Could not decode #{inspect(extra)}" - ) + raise(Thrift.TApplicationException, type: :protocol_error, message: "Could not decode #{inspect(extra)}") end end - def(handle_thrift("multiply", binary_data, handler_module)) do - case( - Elixir.Calculator.Generated.Service.MultiplyArgs.BinaryProtocol.deserialize(binary_data) - ) do + case(Elixir.Calculator.Generated.Service.MultiplyArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.MultiplyArgs{left: left, right: right}, ""} -> - try do + try() do rsp = handler_module.multiply(left, right) - ( response = %Calculator.Generated.Service.MultiplyResponse{success: rsp} - - {:reply, - Elixir.Calculator.Generated.Service.MultiplyResponse.BinaryProtocol.serialize( - response - )} + {:reply, Elixir.Calculator.Generated.Service.MultiplyResponse.BinaryProtocol.serialize(response)} ) rescue [] catch kind, reason -> formatted_exception = Exception.format(kind, reason, System.stacktrace()) - - Logger.error( - "Exception not defined in thrift spec was thrown: #{formatted_exception}" - ) - - error = - Thrift.TApplicationException.exception( - type: :internal_error, - message: "Server error: #{formatted_exception}" - ) - + Logger.error("Exception not defined in thrift spec was thrown: #{formatted_exception}") + error = Thrift.TApplicationException.exception(type: :internal_error, message: "Server error: #{formatted_exception}") {:server_error, error} end - {_, extra} -> - raise(Thrift.TApplicationException, - type: :protocol_error, - message: "Could not decode #{inspect(extra)}" - ) + raise(Thrift.TApplicationException, type: :protocol_error, message: "Could not decode #{inspect(extra)}") end end - def(handle_thrift("subtract", binary_data, handler_module)) do - case( - Elixir.Calculator.Generated.Service.SubtractArgs.BinaryProtocol.deserialize(binary_data) - ) do + case(Elixir.Calculator.Generated.Service.SubtractArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.SubtractArgs{left: left, right: right}, ""} -> - try do + try() do rsp = handler_module.subtract(left, right) - ( response = %Calculator.Generated.Service.SubtractResponse{success: rsp} - - {:reply, - Elixir.Calculator.Generated.Service.SubtractResponse.BinaryProtocol.serialize( - response - )} + {:reply, Elixir.Calculator.Generated.Service.SubtractResponse.BinaryProtocol.serialize(response)} ) rescue [] catch kind, reason -> formatted_exception = Exception.format(kind, reason, System.stacktrace()) - - Logger.error( - "Exception not defined in thrift spec was thrown: #{formatted_exception}" - ) - - error = - Thrift.TApplicationException.exception( - type: :internal_error, - message: "Server error: #{formatted_exception}" - ) - + Logger.error("Exception not defined in thrift spec was thrown: #{formatted_exception}") + error = Thrift.TApplicationException.exception(type: :internal_error, message: "Server error: #{formatted_exception}") {:server_error, error} end - {_, extra} -> - raise(Thrift.TApplicationException, - type: :protocol_error, - message: "Could not decode #{inspect(extra)}" - ) + raise(Thrift.TApplicationException, type: :protocol_error, message: "Could not decode #{inspect(extra)}") end end - def(handle_thrift("vectorProduct", binary_data, handler_module)) do - case( - Elixir.Calculator.Generated.Service.VectorProductArgs.BinaryProtocol.deserialize( - binary_data - ) - ) do - {%Calculator.Generated.Service.VectorProductArgs{left: left, right: right, type: type}, - ""} -> - try do + case(Elixir.Calculator.Generated.Service.VectorProductArgs.BinaryProtocol.deserialize(binary_data)) do + {%Calculator.Generated.Service.VectorProductArgs{left: left, right: right, type: type}, ""} -> + try() do rsp = handler_module.vector_product(left, right, type) - ( response = %Calculator.Generated.Service.VectorProductResponse{success: rsp} - - {:reply, - Elixir.Calculator.Generated.Service.VectorProductResponse.BinaryProtocol.serialize( - response - )} + {:reply, Elixir.Calculator.Generated.Service.VectorProductResponse.BinaryProtocol.serialize(response)} ) rescue [] catch kind, reason -> formatted_exception = Exception.format(kind, reason, System.stacktrace()) - - Logger.error( - "Exception not defined in thrift spec was thrown: #{formatted_exception}" - ) - - error = - Thrift.TApplicationException.exception( - type: :internal_error, - message: "Server error: #{formatted_exception}" - ) - + Logger.error("Exception not defined in thrift spec was thrown: #{formatted_exception}") + error = Thrift.TApplicationException.exception(type: :internal_error, message: "Server error: #{formatted_exception}") {:server_error, error} end - {_, extra} -> - raise(Thrift.TApplicationException, - type: :protocol_error, - message: "Could not decode #{inspect(extra)}" - ) + raise(Thrift.TApplicationException, type: :protocol_error, message: "Could not decode #{inspect(extra)}") end end end -end +end \ No newline at end of file diff --git a/example/lib/calculator/generated/service/handler.ex b/example/lib/calculator/generated/service/handler.ex index a558c3eb..64e46719 100644 --- a/example/lib/calculator/generated/service/handler.ex +++ b/example/lib/calculator/generated/service/handler.ex @@ -1,14 +1,10 @@ defmodule(Calculator.Generated.Service.Handler) do - @moduledoc false + @moduledoc(false) ( - @callback add(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64() - @callback divide(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64() - @callback multiply(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64() - @callback subtract(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64() - @callback vector_product( - left :: %Calculator.Generated.Vector{}, - right :: %Calculator.Generated.Vector{}, - type :: non_neg_integer - ) :: %Calculator.Generated.VectorProductResult{} + @callback(add(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64()) + @callback(divide(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64()) + @callback(multiply(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64()) + @callback(subtract(left :: Thrift.i64(), right :: Thrift.i64()) :: Thrift.i64()) + @callback(vector_product(left :: %Calculator.Generated.Vector{}, right :: %Calculator.Generated.Vector{}, type :: non_neg_integer) :: %Calculator.Generated.VectorProductResult{}) ) -end +end \ No newline at end of file diff --git a/example/lib/calculator/generated/vector.ex b/example/lib/calculator/generated/vector.ex index d0b95380..583a7fb3 100644 --- a/example/lib/calculator/generated/vector.ex +++ b/example/lib/calculator/generated/vector.ex @@ -1,163 +1,117 @@ defmodule(Calculator.Generated.Vector) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift struct calculator.Vector" _ = "1: double x" _ = "2: double y" _ = "3: double z" defstruct(x: 0.0, y: 0.0, z: 0.0) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %Calculator.Generated.Vector{}) end - defp(deserialize(<<0, rest::binary>>, %Calculator.Generated.Vector{} = acc)) do {acc, rest} end - defp(deserialize(<<4, 1::16-signed, 0::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | x: :inf}) end - defp(deserialize(<<4, 1::16-signed, 1::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | x: :"-inf"}) end - defp(deserialize(<<4, 1::16-signed, sign::1, 2047::11, frac::52, rest::binary>>, acc)) do deserialize(rest, %{acc | x: %Thrift.NaN{sign: sign, fraction: frac}}) end - defp(deserialize(<<4, 1::16-signed, value::float-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | x: value}) end - defp(deserialize(<<4, 2::16-signed, 0::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | y: :inf}) end - defp(deserialize(<<4, 2::16-signed, 1::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | y: :"-inf"}) end - defp(deserialize(<<4, 2::16-signed, sign::1, 2047::11, frac::52, rest::binary>>, acc)) do deserialize(rest, %{acc | y: %Thrift.NaN{sign: sign, fraction: frac}}) end - defp(deserialize(<<4, 2::16-signed, value::float-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | y: value}) end - defp(deserialize(<<4, 3::16-signed, 0::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | z: :inf}) end - defp(deserialize(<<4, 3::16-signed, 1::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | z: :"-inf"}) end - defp(deserialize(<<4, 3::16-signed, sign::1, 2047::11, frac::52, rest::binary>>, acc)) do deserialize(rest, %{acc | z: %Thrift.NaN{sign: sign, fraction: frac}}) end - defp(deserialize(<<4, 3::16-signed, value::float-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | z: value}) end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%Calculator.Generated.Vector{x: x, y: y, z: z})) do - [ - case(x) do - nil -> - <<>> - - _ -> - [ - <<4, 1::16-signed>> - | case(x) do - :inf -> - <<0::1, 2047::11, 0::52>> - - :"-inf" -> - <<1::1, 2047::11, 0::52>> - - %Thrift.NaN{sign: sign, fraction: frac} -> - <> - - _ -> - <> - end - ] - end, - case(y) do - nil -> - <<>> - - _ -> - [ - <<4, 2::16-signed>> - | case(y) do - :inf -> - <<0::1, 2047::11, 0::52>> - - :"-inf" -> - <<1::1, 2047::11, 0::52>> - - %Thrift.NaN{sign: sign, fraction: frac} -> - <> - - _ -> - <> - end - ] - end, - case(z) do - nil -> - <<>> - - _ -> - [ - <<4, 3::16-signed>> - | case(z) do - :inf -> - <<0::1, 2047::11, 0::52>> - - :"-inf" -> - <<1::1, 2047::11, 0::52>> - - %Thrift.NaN{sign: sign, fraction: frac} -> - <> - - _ -> - <> - end - ] - end - | <<0>> - ] + [case(x) do + nil -> + <<>> + _ -> + [<<4, 1::16-signed>> | case(x) do + :inf -> + <<0::1, 2047::11, 0::52>> + :"-inf" -> + <<1::1, 2047::11, 0::52>> + %Thrift.NaN{sign: sign, fraction: frac} -> + <> + _ -> + <> + end] + end, case(y) do + nil -> + <<>> + _ -> + [<<4, 2::16-signed>> | case(y) do + :inf -> + <<0::1, 2047::11, 0::52>> + :"-inf" -> + <<1::1, 2047::11, 0::52>> + %Thrift.NaN{sign: sign, fraction: frac} -> + <> + _ -> + <> + end] + end, case(z) do + nil -> + <<>> + _ -> + [<<4, 3::16-signed>> | case(z) do + :inf -> + <<0::1, 2047::11, 0::52>> + :"-inf" -> + <<1::1, 2047::11, 0::52>> + %Thrift.NaN{sign: sign, fraction: frac} -> + <> + _ -> + <> + end] + end | <<0>>] end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end -end +end \ No newline at end of file diff --git a/example/lib/calculator/generated/vector_product_result.ex b/example/lib/calculator/generated/vector_product_result.ex index 2558239e..8c0315f8 100644 --- a/example/lib/calculator/generated/vector_product_result.ex +++ b/example/lib/calculator/generated/vector_product_result.ex @@ -1,114 +1,82 @@ defmodule(Calculator.Generated.VectorProductResult) do - @moduledoc false + @moduledoc(false) _ = "Auto-generated Thrift union calculator.VectorProductResult" _ = "1: double scalar" _ = "2: calculator.Vector vector" defstruct(scalar: nil, vector: nil) - @type t :: %__MODULE__{} + @type(t :: %__MODULE__{}) def(new) do %__MODULE__{} end - defmodule(BinaryProtocol) do - @moduledoc false + @moduledoc(false) def(deserialize(binary)) do deserialize(binary, %Calculator.Generated.VectorProductResult{}) end - defp(deserialize(<<0, rest::binary>>, %Calculator.Generated.VectorProductResult{} = acc)) do {acc, rest} end - defp(deserialize(<<4, 1::16-signed, 0::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | scalar: :inf}) end - defp(deserialize(<<4, 1::16-signed, 1::1, 2047::11, 0::52, rest::binary>>, acc)) do deserialize(rest, %{acc | scalar: :"-inf"}) end - defp(deserialize(<<4, 1::16-signed, sign::1, 2047::11, frac::52, rest::binary>>, acc)) do deserialize(rest, %{acc | scalar: %Thrift.NaN{sign: sign, fraction: frac}}) end - defp(deserialize(<<4, 1::16-signed, value::float-signed, rest::binary>>, acc)) do deserialize(rest, %{acc | scalar: value}) end - defp(deserialize(<<12, 2::16-signed, rest::binary>>, acc)) do case(Elixir.Calculator.Generated.Vector.BinaryProtocol.deserialize(rest)) do {value, rest} -> deserialize(rest, %{acc | vector: value}) - :error -> :error end end - defp(deserialize(<>, acc)) do rest |> Thrift.Protocol.Binary.skip_field(field_type) |> deserialize(acc) end - defp(deserialize(_, _)) do :error end - def(serialize(%Calculator.Generated.VectorProductResult{scalar: nil, vector: nil})) do <<0>> end - def(serialize(%Calculator.Generated.VectorProductResult{scalar: scalar, vector: nil})) do - [ - <<4, 1::16-signed>>, - case(scalar) do - :inf -> - <<0::1, 2047::11, 0::52>> - - :"-inf" -> - <<1::1, 2047::11, 0::52>> - - %Thrift.NaN{sign: sign, fraction: frac} -> - <> - - _ -> - <> - end - | <<0>> - ] + [<<4, 1::16-signed>>, case(scalar) do + :inf -> + <<0::1, 2047::11, 0::52>> + :"-inf" -> + <<1::1, 2047::11, 0::52>> + %Thrift.NaN{sign: sign, fraction: frac} -> + <> + _ -> + <> + end | <<0>>] end - def(serialize(%Calculator.Generated.VectorProductResult{scalar: nil, vector: vector})) do [<<12, 2::16-signed>>, Calculator.Generated.Vector.serialize(vector) | <<0>>] end - def(serialize(%Calculator.Generated.VectorProductResult{} = value)) do - set_fields = - value - |> Map.from_struct() - |> Enum.flat_map(fn - {_, nil} -> - [] - - {key, _} -> - [key] - end) - - raise(%Thrift.Union.TooManyFieldsSetError{ - message: "Thrift union has more than one field set", - set_fields: set_fields - }) + set_fields = value |> Map.from_struct() |> Enum.flat_map(fn + {_, nil} -> + [] + {key, _} -> + [key] + end) + raise(%Thrift.Union.TooManyFieldsSetError{message: "Thrift union has more than one field set", set_fields: set_fields}) end end - def(serialize(struct)) do BinaryProtocol.serialize(struct) end - def(serialize(struct, :binary)) do BinaryProtocol.serialize(struct) end - def(deserialize(binary)) do BinaryProtocol.deserialize(binary) end -end +end \ No newline at end of file diff --git a/example/lib/calculator/generated/vector_product_type.ex b/example/lib/calculator/generated/vector_product_type.ex index 085287a0..55fa88ef 100644 --- a/example/lib/calculator/generated/vector_product_type.ex +++ b/example/lib/calculator/generated/vector_product_type.ex @@ -1,76 +1,59 @@ defmodule(Calculator.Generated.VectorProductType) do - @moduledoc false + @moduledoc(false) defmacro(unquote(:dot_product)()) do 1 end - defmacro(unquote(:cross_product)()) do 2 end - def(value_to_name(1)) do {:ok, :dot_product} end - def(value_to_name(2)) do {:ok, :cross_product} end - def(value_to_name(v)) do {:error, {:invalid_enum_value, v}} end - def(name_to_value(:dot_product)) do {:ok, 1} end - def(name_to_value(:cross_product)) do {:ok, 2} end - def(name_to_value(k)) do {:error, {:invalid_enum_name, k}} end - def(value_to_name!(value)) do {:ok, name} = value_to_name(value) name end - def(name_to_value!(name)) do {:ok, value} = name_to_value(name) value end - def(meta(:names)) do [:dot_product, :cross_product] end - def(meta(:values)) do [1, 2] end - def(member?(1)) do true end - def(member?(2)) do true end - def(member?(_)) do false end - def(name?(:dot_product)) do true end - def(name?(:cross_product)) do true end - def(name?(_)) do false end -end +end \ No newline at end of file diff --git a/example/mix.exs b/example/mix.exs index afd72472..116cb793 100644 --- a/example/mix.exs +++ b/example/mix.exs @@ -31,7 +31,8 @@ defmodule Calculator.MixProject do [ # Note: you will want to replace the next line to get elixir-thrift from either # Hex or GitHub in your own project. - {:thrift, path: ".."} + {:thrift, path: ".."}, + {:httpoison, "~> 0.13"} ] end end diff --git a/lib/mix/tasks/thrift.httpclient.generate.ex b/lib/mix/tasks/thrift.httpclient.generate.ex new file mode 100644 index 00000000..70678753 --- /dev/null +++ b/lib/mix/tasks/thrift.httpclient.generate.ex @@ -0,0 +1,264 @@ +defmodule Mix.Tasks.Thrift.HttpClient.Generate do + use Mix.Task + require Logger + + @shortdoc "Generates Elixir source files for client HTTP thrift service" + + @moduledoc """ + Generates Elixir HTTP thrift client for a given service + + To generate a client: + + mix thrift.http_client.generate thrift/calculator.thrift + + It assumes that you have already generated the thrift support files with + + mix compile.thrift thrift/calculator.thrift + + Each service requires an endpoint to be configured in your config file + + config :calculator, Calculator.Generated.HTTP.Client, + endpoint: "http://localhost:8080/TCalculatorServlet/Calculator" + + """ + + @default_namespace "Thrift.Generated" + + # ---------------------------------------------------------------------------- + def run(args) do + Logger.info("Compiling HTTP Thrift Service ...") + + {opts, files} = + OptionParser.parse!( + args, + switches: [out: :string], + aliases: [] + ) + + output_path = opts[:out] || "lib" + + for file <- files do + file + |> Thrift.Parser.parse_file() + |> Map.get(:schemas) + |> Enum.each(fn {_, schema} -> + namespace = get_namespace(schema) + dest_dir = get_destination_dir(namespace, output_path) + + modules = + Enum.map(schema.services, fn {service_name, service_spec} -> + gen_module(namespace, service_name, service_spec) + end) + + code = + quote do + unquote(gen_http_helper(namespace)) + unquote_splicing(modules) + end + + File.mkdir("#{dest_dir}/http") + output_file = "#{dest_dir}/http/client.ex" + + File.write!(output_file, Macro.to_string(code)) + System.cmd("mix", ["format", output_file]) + end) + end + + :ok + end + + # ---------------------------------------------------------------------------- + def get_namespace(schema) do + schema.namespaces + |> Map.get(:elixir, %Thrift.AST.Namespace{ + line: -1, + scope: :elixir, + value: @default_namespace + }) + |> Map.get(:value) + end + + # ---------------------------------------------------------------------------- + def get_destination_dir(namespace, output_path) do + schema_dir = + namespace + |> String.split(".") + |> Enum.map(&Macro.underscore/1) + |> Path.join() + + "#{output_path}/#{schema_dir}" + end + + # ---------------------------------------------------------------------------- + def gen_http_helper(namespace) do + module_name = Module.concat([namespace, HTTP, Client]) + + Logger.info(""" + Generating HTTP Client for #{namespace} + NOTE: + Make sure to update your config files with + config :your_app, #{Macro.to_string(module_name)}, + endpoint: "http://x.x.y.y:8080/some_endpoint" + """) + + quote do + defmodule unquote(module_name) do + require Logger + + @default_headers [ + Accept: "application/x-thrift", + "Content-Type": "application/x-thrift" + ] + @http_client_options [hackney: [pool: :default]] + @service_endpoint Application.get_env( + Mix.Project.config()[:app], + unquote(module_name), + %{} + )[:endpoint] + + def post_thrift(serialized_binary) do + if @service_endpoint == nil do + Logger.error( + "service endpoint not defined for #{Macro.to_string(__MODULE__)}!! Please add it to config file!" + ) + end + + case HTTPoison.post( + @service_endpoint, + serialized_binary, + @default_headers, + @http_client_options + ) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + {:ok, body} + + {:ok, %HTTPoison.Response{status_code: code, body: body}} -> + {:service_err, code, body} + + {:error, %HTTPoison.Error{reason: reason}} -> + {:http_err, inspect(reason)} + end + end + end + end + end + + # ---------------------------------------------------------------------------- + def gen_module(namespace, service_name, service_spec) do + module_name = Module.concat([namespace, HTTP, service_name]) + + functions = + service_spec.functions + |> Enum.map(&gen_function(&1, namespace, service_name)) + + quote do + defmodule unquote(module_name) do + alias unquote(Module.concat(namespace, service_name)) + alias unquote(Module.concat([namespace, HTTP])) + alias Thrift.Protocol.Binary + + unquote_splicing(functions) + end + end + end + + # ---------------------------------------------------------------------------- + def gen_function({_name, %Thrift.AST.Function{} = function}, namespace, service_name) do + args_module = module_name(function, service_name, :args) + + args_binary_module = Module.concat(args_module, :BinaryProtocol) + + response_module = module_name(function, service_name, :response) + + function_name = to_snake_case(function.name) + + vars = Enum.map(function.params, &Macro.var(&1.name, nil)) + + assignments = + function.params + |> Enum.zip(vars) + |> Enum.map(fn {param, var} -> + quote do + {unquote(param.name), unquote(var)} + end + end) + + doc = + function.params + |> Enum.map(fn %Thrift.AST.Field{name: name, type: type} -> + "#{name}: #{param_type(namespace, type)}" + end) + |> Enum.join("\n\n") + + quote do + @doc unquote(doc) + + def(unquote(function_name)(unquote_splicing(vars))) do + args = %unquote(args_module){unquote_splicing(assignments)} + serialized_args = unquote(args_binary_module).serialize(args) + + tcall = + Binary.serialize( + :message_begin, + {:call, 0, unquote(Atom.to_string(function.name))} + ) + + payload = [tcall | serialized_args] |> IO.iodata_to_binary() + + with {:ok, body} <- HTTP.Client.post_thrift(payload), + {:ok, {:reply, _, _, ser_resp}} <- Binary.deserialize(:message_begin, body), + {response, _} <- unquote(response_module).deserialize(ser_resp) do + response + else + {:service_err, code, body} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "service error [#{code}] #{body}" + ) + + {:http_err, err_str} -> + Thrift.TApplicationException.exception( + type: :missing_result, + message: "http error: #{err_str}" + ) + + {:ok, {:exception, _, _, ser_ex}} -> + Binary.deserialize(:application_exception, ser_ex) + end + end + end + end + + # ---------------------------------------------------------------------------- + # ---------------------------------------------------------------------------- + def module_name(%Thrift.AST.Function{} = function, service_name, suffix) do + struct_name = + "#{function.name}_#{suffix}" + |> Macro.camelize() + + Module.concat(Elixir, "#{service_name}.#{struct_name}" |> String.to_atom()) + end + + def to_snake_case(name) do + name + |> Atom.to_string() + |> Macro.underscore() + |> String.to_atom() + end + + # Type helpers for func doc generation -------------------------------------- + def param_type(namespace, %Thrift.AST.TypeRef{referenced_type: type}) do + type = Module.concat(namespace, type) |> Macro.to_string() + "`#{type}`" + end + + # list of + def param_type(namespace, {:list, %Thrift.AST.TypeRef{referenced_type: type}}) do + type = Module.concat(namespace, type) |> Macro.to_string() + "[`#{type}`]" + end + + def param_type(_namespace, simple_type) do + simple_type + end +end diff --git a/mix.lock b/mix.lock index 20f1c00d..7eabcc00 100644 --- a/mix.lock +++ b/mix.lock @@ -9,6 +9,7 @@ "excoveralls": {:hex, :excoveralls, "0.10.3", "b090a3fbcb3cfa136f0427d038c92a9051f840953ec11b40ee74d9d4eac04d1e", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"}, "hackney": {:hex, :hackney, "1.13.0", "24edc8cd2b28e1c652593833862435c80661834f6c9344e84b6a2255e7aeef03", [:rebar3], [{:certifi, "2.3.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.2", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "httpoison": {:hex, :httpoison, "0.13.0", "bfaf44d9f133a6599886720f3937a7699466d23bb0cd7a88b6ba011f53c6f562", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "5.1.2", "e21cb58a09f0228a9e0b95eaa1217f1bcfc31a1aaa6e1fdf2f53a33f7dbd9494", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"}, From acfeb76005e2161200e822bb29b6689375bf839f Mon Sep 17 00:00:00 2001 From: Vanja Bucic Date: Wed, 5 Dec 2018 13:10:07 -0500 Subject: [PATCH 2/5] doc update --- lib/mix/tasks/thrift.httpclient.generate.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mix/tasks/thrift.httpclient.generate.ex b/lib/mix/tasks/thrift.httpclient.generate.ex index 70678753..5d29447a 100644 --- a/lib/mix/tasks/thrift.httpclient.generate.ex +++ b/lib/mix/tasks/thrift.httpclient.generate.ex @@ -13,7 +13,7 @@ defmodule Mix.Tasks.Thrift.HttpClient.Generate do It assumes that you have already generated the thrift support files with - mix compile.thrift thrift/calculator.thrift + mix compile.thrift Each service requires an endpoint to be configured in your config file From d0e8ff96713180dfa27bedf7eeff36c6482cc2f7 Mon Sep 17 00:00:00 2001 From: Vanja Bucic Date: Wed, 5 Dec 2018 14:02:16 -0500 Subject: [PATCH 3/5] remove other config --- example/config/config.exs | 3 --- 1 file changed, 3 deletions(-) diff --git a/example/config/config.exs b/example/config/config.exs index 0a8baad3..5e4f10dd 100644 --- a/example/config/config.exs +++ b/example/config/config.exs @@ -5,6 +5,3 @@ config :calculator, config :calculator, Calculator.Generated.HTTP.Client, endpoint: "http://localhost:8080/TCalculatorServlet/Calculator" - -config :calculator, CommonDataStream.Generated.HTTP.Client, - endpoint: "http://192.168.100.168:8080/CommonDataInjectionStreamer/CommonTagServletBin" From c3660136b4155294ad6852886a833e2ee2f116e7 Mon Sep 17 00:00:00 2001 From: Vanja Bucic Date: Wed, 3 Apr 2019 12:11:50 -0400 Subject: [PATCH 4/5] added compile.thrift.all task --- .../lib/calculator/generated/http/client.ex | 1 + example/lib/calculator/generated/service.ex | 10 +- lib/mix/tasks/compile.thrift.all.ex | 25 +++++ lib/mix/tasks/thrift.generate.ex | 104 ------------------ lib/mix/tasks/thrift.httpclient.generate.ex | 24 ++-- mix.lock | 1 + 6 files changed, 45 insertions(+), 120 deletions(-) create mode 100644 lib/mix/tasks/compile.thrift.all.ex delete mode 100644 lib/mix/tasks/thrift.generate.ex diff --git a/example/lib/calculator/generated/http/client.ex b/example/lib/calculator/generated/http/client.ex index fec5aaea..a074a2e8 100644 --- a/example/lib/calculator/generated/http/client.ex +++ b/example/lib/calculator/generated/http/client.ex @@ -30,6 +30,7 @@ defmodule(Calculator.Generated.HTTP.Client) do end defmodule(Calculator.Generated.HTTP.Service) do + @behaviour Calculator.Generated.Service.Handler alias(Calculator.Generated.Service) alias(Calculator.Generated.HTTP) alias(Thrift.Protocol.Binary) diff --git a/example/lib/calculator/generated/service.ex b/example/lib/calculator/generated/service.ex index ce5f28fe..2a954a92 100644 --- a/example/lib/calculator/generated/service.ex +++ b/example/lib/calculator/generated/service.ex @@ -626,7 +626,7 @@ defmodule(Calculator.Generated.Service) do def(handle_thrift("add", binary_data, handler_module)) do case(Elixir.Calculator.Generated.Service.AddArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.AddArgs{left: left, right: right}, ""} -> - try() do + try do rsp = handler_module.add(left, right) ( response = %Calculator.Generated.Service.AddResponse{success: rsp} @@ -648,7 +648,7 @@ defmodule(Calculator.Generated.Service) do def(handle_thrift("divide", binary_data, handler_module)) do case(Elixir.Calculator.Generated.Service.DivideArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.DivideArgs{left: left, right: right}, ""} -> - try() do + try do rsp = handler_module.divide(left, right) ( response = %Calculator.Generated.Service.DivideResponse{success: rsp} @@ -672,7 +672,7 @@ defmodule(Calculator.Generated.Service) do def(handle_thrift("multiply", binary_data, handler_module)) do case(Elixir.Calculator.Generated.Service.MultiplyArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.MultiplyArgs{left: left, right: right}, ""} -> - try() do + try do rsp = handler_module.multiply(left, right) ( response = %Calculator.Generated.Service.MultiplyResponse{success: rsp} @@ -694,7 +694,7 @@ defmodule(Calculator.Generated.Service) do def(handle_thrift("subtract", binary_data, handler_module)) do case(Elixir.Calculator.Generated.Service.SubtractArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.SubtractArgs{left: left, right: right}, ""} -> - try() do + try do rsp = handler_module.subtract(left, right) ( response = %Calculator.Generated.Service.SubtractResponse{success: rsp} @@ -716,7 +716,7 @@ defmodule(Calculator.Generated.Service) do def(handle_thrift("vectorProduct", binary_data, handler_module)) do case(Elixir.Calculator.Generated.Service.VectorProductArgs.BinaryProtocol.deserialize(binary_data)) do {%Calculator.Generated.Service.VectorProductArgs{left: left, right: right, type: type}, ""} -> - try() do + try do rsp = handler_module.vector_product(left, right, type) ( response = %Calculator.Generated.Service.VectorProductResponse{success: rsp} diff --git a/lib/mix/tasks/compile.thrift.all.ex b/lib/mix/tasks/compile.thrift.all.ex new file mode 100644 index 00000000..c4663847 --- /dev/null +++ b/lib/mix/tasks/compile.thrift.all.ex @@ -0,0 +1,25 @@ +defmodule Mix.Tasks.Compile.Thrift.All do + use Mix.Task + require Logger + + @impl Mix.Task + @spec run(OptionParser.argv()) :: :ok + def run(command_line_args) do + {opts, _, _} = OptionParser.parse(command_line_args, switches: [verbose: :boolean]) + + verbose = Keyword.get(opts, :verbose, false) + + input_files = + Keyword.get(Mix.Project.config(), :thrift, []) + |> Keyword.get(:files, []) + + for file <- input_files do + if(verbose, do: Logger.info("Compiling thrift file: #{file}")) + Mix.Tasks.Compile.Thrift.run([file]) + if(verbose, do: Logger.info("Generating thrift HTTP client for file: #{file}")) + Mix.Tasks.Thrift.HttpClient.Generate.run([file]) + end + + :ok + end +end diff --git a/lib/mix/tasks/thrift.generate.ex b/lib/mix/tasks/thrift.generate.ex deleted file mode 100644 index b3d20305..00000000 --- a/lib/mix/tasks/thrift.generate.ex +++ /dev/null @@ -1,104 +0,0 @@ -defmodule Mix.Tasks.Thrift.Generate do - use Mix.Task - - @shortdoc "Generates Elixir source files from Thrift IDL files" - - @moduledoc """ - Generate Elixir source files from Thrift IDL files (`.thrift`). - - A list of files should be given after the task name in order to select - the specific Thrift IDL files to parse: - - mix thrift.generate file1.thrift file2.thrift - - ## Command line options - - * `-I dir` / `--include dir` - add a directory to the list of - directory paths in which to search for included files, overriding - the `:include_paths` configuration value. This option can be repeated - in order to add multiple directories to the search list. - * `--namespace namespace` - set the default namespace for generated - modules, overriding the `:namespace` configuration value - * `-o dir` / `--out dir` - set the output directory, overriding the - `:output_path` configuration value - * `-v` / `--verbose` - enable verbose task logging - - ## Configuration - - * `:include_paths` - list of additional directory paths in which to - search for included files. Defaults to `[]`. - * `:namespace` - default namespace for generated modules, which will - be used when Thrift files don't specify their own `elixir` namespace. - * `:output_path` - output directory into which the generated Elixir - source files will be generated. Defaults to `"lib"`. - - ``` - # example mix.exs - defmodule MyProject.Mixfile do - # ... - - def project do - [ - # other settings... - thrift: [ - include_paths: ["./extra_thrift"], - output_path: "lib/generated" - ] - ] - end - end - ``` - """ - - @spec run(OptionParser.argv()) :: :ok - def run(args) do - {opts, files} = - OptionParser.parse!( - args, - switches: [include: :keep, namespace: :string, out: :string, verbose: :boolean], - aliases: [I: :include, o: :out, v: :verbose] - ) - - config = Keyword.get(Mix.Project.config(), :thrift, []) - output_path = opts[:out] || Keyword.get(config, :output_path, "lib") - namespace = opts[:namespace] || Keyword.get(config, :namespace) - - include_paths = - (opts[:include] && Keyword.get_values(opts, :include)) || - Keyword.get(config, :include_paths, []) - - parser_opts = - Keyword.new() - |> Keyword.put(:include_paths, include_paths) - |> Keyword.put(:namespace, namespace) - - unless Enum.empty?(files) do - File.mkdir_p!(output_path) - Enum.each(files, &generate!(&1, output_path, parser_opts, opts)) - end - end - - defp parse!(thrift_file, opts) do - Thrift.Parser.parse_file_group!(thrift_file, opts) - rescue - e -> Mix.raise("#{thrift_file}: #{Exception.message(e)}") - end - - defp generate!(thrift_file, output_path, parser_opts, opts) do - Mix.shell().info("Parsing #{thrift_file}") - - generated_files = - thrift_file - |> parse!(parser_opts) - |> Thrift.Generator.generate!(output_path) - - if opts[:verbose] do - generated_files - |> Enum.uniq() - |> Enum.sort() - |> Enum.each(fn file -> - Mix.shell().info("Wrote #{Path.join(output_path, file)}") - end) - end - end -end diff --git a/lib/mix/tasks/thrift.httpclient.generate.ex b/lib/mix/tasks/thrift.httpclient.generate.ex index 5d29447a..9de74a8b 100644 --- a/lib/mix/tasks/thrift.httpclient.generate.ex +++ b/lib/mix/tasks/thrift.httpclient.generate.ex @@ -26,8 +26,6 @@ defmodule Mix.Tasks.Thrift.HttpClient.Generate do # ---------------------------------------------------------------------------- def run(args) do - Logger.info("Compiling HTTP Thrift Service ...") - {opts, files} = OptionParser.parse!( args, @@ -38,8 +36,7 @@ defmodule Mix.Tasks.Thrift.HttpClient.Generate do output_path = opts[:out] || "lib" for file <- files do - file - |> Thrift.Parser.parse_file() + Thrift.Parser.parse_file_group!(file) |> Map.get(:schemas) |> Enum.each(fn {_, schema} -> namespace = get_namespace(schema) @@ -93,13 +90,16 @@ defmodule Mix.Tasks.Thrift.HttpClient.Generate do def gen_http_helper(namespace) do module_name = Module.concat([namespace, HTTP, Client]) - Logger.info(""" - Generating HTTP Client for #{namespace} - NOTE: - Make sure to update your config files with - config :your_app, #{Macro.to_string(module_name)}, - endpoint: "http://x.x.y.y:8080/some_endpoint" - """) + Logger.info( + """ + Generating HTTP Client for #{namespace} + NOTE: + Make sure to update your config files with + config :your_app, #{Macro.to_string(module_name)}, + endpoint: "http://x.x.y.y:8080/some_endpoint" + """ + |> String.trim() + ) quote do defmodule unquote(module_name) do @@ -146,6 +146,7 @@ defmodule Mix.Tasks.Thrift.HttpClient.Generate do # ---------------------------------------------------------------------------- def gen_module(namespace, service_name, service_spec) do module_name = Module.concat([namespace, HTTP, service_name]) + interface_name = Module.concat([namespace, service_name, Handler]) functions = service_spec.functions @@ -153,6 +154,7 @@ defmodule Mix.Tasks.Thrift.HttpClient.Generate do quote do defmodule unquote(module_name) do + @behaviour unquote(interface_name) alias unquote(Module.concat(namespace, service_name)) alias unquote(Module.concat([namespace, HTTP])) alias Thrift.Protocol.Binary diff --git a/mix.lock b/mix.lock index d513e200..40bd2cfb 100644 --- a/mix.lock +++ b/mix.lock @@ -8,6 +8,7 @@ "ex_doc": {:hex, :ex_doc, "0.20.0", "47ef7d09d990fa4a4373c96c4bdff846836f011e88dd7695d31f54ec035ff38e", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "excoveralls": {:hex, :excoveralls, "0.10.6", "e2b9718c9d8e3ef90bc22278c3f76c850a9f9116faf4ebe9678063310742edc2", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "httpoison": {:hex, :httpoison, "0.13.0", "bfaf44d9f133a6599886720f3937a7699466d23bb0cd7a88b6ba011f53c6f562", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, From 391c74da4eb884d9726d0e9de8f98f80a73e5ac7 Mon Sep 17 00:00:00 2001 From: Vanja Bucic Date: Wed, 3 Apr 2019 12:17:53 -0400 Subject: [PATCH 5/5] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 4847b981..1138c6da 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# Added: Autogenerated HTTP Client +see `example/lib/calculator/generated/http/client.ex` + +___ + # Elixir Thrift [![Hex Version](https://img.shields.io/hexpm/v/thrift.svg)](https://hex.pm/packages/thrift)