pinterest / riffed

Provides idiomatic Elixir bindings for Apache Thrift
Apache License 2.0
308 stars 37 forks source link

Use Riffed to serialize/deserialize messages #26

Closed darkofabijan closed 8 years ago

darkofabijan commented 8 years ago

Hello,

Thanks for making our lives easier with Riffed! :) It's really nice to work with it.

In some parts of our service we would like to just serialize models and transport them to other parts of the system over RabbitMQ. Ruby and Elixir will talk to each other over RabbitMQ. For Ruby side we are covered with https://wiki.apache.org/thrift/ThriftUsageRuby. Is there something as easy to use on the Riffed side?

Thanks, Darko

scohen commented 8 years ago

What you're going to need to use is the memory transport to serialize the thrift models.

Imagine you have a struct defined in the service module and it's called SerialStruct. You have a list of the elixir SerialStructs as serial_struct_list You'd do something like this:

@spec to_binary([%Service.SerialStruct{}...]) :: binary
def to_binary(serial_struct_list) do
    with({:ok, tf} <- :thrift_memory_buffer.new_transport_factory(),
         {:ok, pf} <- :thrift_binary_protocol.new_protocol_factory(tf, []),
         {:ok, binary_protocol} <- pf.()) do

     proto = serial_struct_list
      |> Enum.map(&Service.to_erlang(&1, {:struct, {:service, :SerialStruct}})
      |> Enum.reduce(binary_protocol,
        fn(thrift_struct, protocol) ->
          {proto, :ok} = :thrift_protocol.write(protocol, {struct_info, thrift_struct})
          proto
        end)

      {_, data} = :thrift_protocol.flush_transport(proto)
      :erlang.iolist_to_binary(data)
end
isaacsanders commented 8 years ago

How does one deserialize a thrift message with this library?

scohen commented 8 years ago

@isaacsanders You do something like this: In the example, record_binary is the result of reading a file via File.read! or something

The struct_definition is a description of the struct in the erlang format, often like {struct, {struct_module, StructName}}

For example, if I have a User struct defined in a file called models.thrift, the struct definition would be: {:struct, {:models, :User}}.

  def to_thrift(record_binary, struct_definition) do
    try do

      with({:ok, memory_buffer_transport} <- :thrift_memory_buffer.new(record_binary),
           {:ok, binary_protocol} <- :thrift_binary_protocol.new(memory_buffer_transport),
           {_, {:ok, record}} <- :thrift_protocol.read(binary_protocol, struct_definition)) do

        {:ok, Models.to_elixir(record, struct_definition)}
      end

    rescue _ ->
        {:error, :cant_decode}
    end
  end