David Reiss | ea2cba8 | 2009-03-30 21:35:00 +0000 | [diff] [blame] | 1 | %% |
| 2 | %% Licensed to the Apache Software Foundation (ASF) under one |
| 3 | %% or more contributor license agreements. See the NOTICE file |
| 4 | %% distributed with this work for additional information |
| 5 | %% regarding copyright ownership. The ASF licenses this file |
| 6 | %% to you under the Apache License, Version 2.0 (the |
| 7 | %% "License"); you may not use this file except in compliance |
| 8 | %% with the License. You may obtain a copy of the License at |
| 9 | %% |
| 10 | %% http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | %% |
| 12 | %% Unless required by applicable law or agreed to in writing, |
| 13 | %% software distributed under the License is distributed on an |
| 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | %% KIND, either express or implied. See the License for the |
| 16 | %% specific language governing permissions and limitations |
| 17 | %% under the License. |
| 18 | %% |
| 19 | |
David Reiss | ac54955 | 2008-06-10 22:56:59 +0000 | [diff] [blame] | 20 | -module(thrift_transport). |
| 21 | |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 22 | %% constructors |
| 23 | -export([new/1, new/2]). |
| 24 | %% transport callbacks |
| 25 | -export([read/2, read_exact/2, write/2, flush/1, close/1]). |
David Reiss | ac54955 | 2008-06-10 22:56:59 +0000 | [diff] [blame] | 26 | |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 27 | -record(t_transport, { |
| 28 | module :: module(), |
| 29 | state :: term() |
| 30 | }). |
| 31 | -type t_transport() :: #t_transport{}. |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 32 | -export_type([t_transport/0]). |
| 33 | |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 34 | %%%========================================================================= |
| 35 | %%% API |
| 36 | %%%========================================================================= |
| 37 | -type state() :: term(). |
| 38 | -export_type([state/0]). |
| 39 | -type reason() :: term(). |
| 40 | -export_type([reason/0]). |
David Reiss | ac54955 | 2008-06-10 22:56:59 +0000 | [diff] [blame] | 41 | |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 42 | -callback write(state(), iolist() | binary()) -> {state(), ok | {error, reason()}}. |
| 43 | -callback read(state(), non_neg_integer()) -> {state(), {ok, binary()} | {error, reason()}}. |
| 44 | -callback flush(state()) -> {state(), ok | {error, reason()}}. |
| 45 | -callback close(state()) -> {state(), ok | {error, reason()}}. |
David Reiss | ac54955 | 2008-06-10 22:56:59 +0000 | [diff] [blame] | 46 | |
David Reiss | 9b170eb | 2010-08-30 22:05:44 +0000 | [diff] [blame] | 47 | -ifdef(transport_wrapper_module). |
| 48 | -define(debug_wrap(Transport), |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 49 | case Transport#t_transport.module of |
| 50 | ?transport_wrapper_module -> |
| 51 | Transport; |
| 52 | _Else -> |
| 53 | {ok, Result} = ?transport_wrapper_module:new(Transport), |
| 54 | Result |
| 55 | end |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 56 | ). |
David Reiss | 9b170eb | 2010-08-30 22:05:44 +0000 | [diff] [blame] | 57 | -else. |
| 58 | -define(debug_wrap(Transport), Transport). |
| 59 | -endif. |
| 60 | |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 61 | -type wrappable() :: |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 62 | binary() |
| 63 | | list() |
| 64 | | {membuffer, binary() | list()} |
| 65 | | {membuffer, binary() | list(), list()} |
| 66 | | {tcp, port()} |
| 67 | | {tcp, port(), list()} |
| 68 | | {file, file:io_device()} |
| 69 | | {file, file:io_device(), list()} |
| 70 | | {file, file:filename()} |
| 71 | | {file, file:filename(), list()}. |
David Reiss | ac54955 | 2008-06-10 22:56:59 +0000 | [diff] [blame] | 72 | |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 73 | -spec new(wrappable()) -> {ok, #t_transport{}}. |
David Reiss | 90b4083 | 2008-06-10 22:58:52 +0000 | [diff] [blame] | 74 | |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 75 | new({membuffer, Membuffer}) -> |
| 76 | new({membuffer, Membuffer, []}); |
| 77 | new({membuffer, Membuffer, Opts}) when is_binary(Membuffer); is_list(Membuffer) -> |
| 78 | thrift_membuffer_transport:new(Membuffer, Opts); |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 79 | new({tcp, Socket}) when is_port(Socket) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 80 | new({tcp, Socket, []}); |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 81 | new({tcp, Socket, Opts}) when is_port(Socket) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 82 | thrift_socket_transport:new(Socket, Opts); |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 83 | new({file, Filename}) when is_list(Filename); is_binary(Filename) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 84 | new({file, Filename, []}); |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 85 | new({file, Filename, Opts}) when is_list(Filename); is_binary(Filename) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 86 | {ok, File} = file:open(Filename, [raw, binary]), |
| 87 | new({file, File, Opts}); |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 88 | new({file, File, Opts}) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 89 | thrift_file_transport:new(File, Opts). |
David Reiss | c11734e | 2008-06-11 00:59:48 +0000 | [diff] [blame] | 90 | |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 91 | -spec new(Module :: module(), State :: any()) -> {ok, t_transport()}. |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 92 | |
| 93 | new(Module, State) when is_atom(Module) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 94 | {ok, ?debug_wrap(#t_transport{module = Module, state = State})}. |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 95 | |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 96 | read(Transport = #t_transport{module = Module}, Len) when |
| 97 | is_integer(Len), Len >= 0 |
| 98 | -> |
| 99 | {NewState, Result} = Module:read(Transport#t_transport.state, Len), |
| 100 | {Transport#t_transport{state = NewState}, Result}. |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 101 | |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 102 | read_exact(Transport = #t_transport{module = Module}, Len) when |
| 103 | is_integer(Len), Len >= 0 |
| 104 | -> |
| 105 | case lists:keyfind(read_exact, 1, Module:module_info(exports)) of |
| 106 | {read_exact, 2} -> |
| 107 | {NewState, Result} = Module:read_exact(Transport#t_transport.state, Len), |
| 108 | {Transport#t_transport{state = NewState}, Result}; |
| 109 | _ -> |
| 110 | read(Transport, Len) |
| 111 | end. |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 112 | |
| 113 | write(Transport = #t_transport{module = Module}, Data) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 114 | {NewState, Result} = Module:write(Transport#t_transport.state, Data), |
| 115 | {Transport#t_transport{state = NewState}, Result}. |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 116 | |
| 117 | flush(Transport = #t_transport{module = Module}) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 118 | {NewState, Result} = Module:flush(Transport#t_transport.state), |
| 119 | {Transport#t_transport{state = NewState}, Result}. |
alisdair sullivan | a559f8d | 2014-11-17 20:28:35 -0800 | [diff] [blame] | 120 | |
| 121 | close(Transport = #t_transport{module = Module}) -> |
Sergei Elin | 4576409 | 2022-09-23 23:21:31 +0300 | [diff] [blame^] | 122 | {NewState, Result} = Module:close(Transport#t_transport.state), |
| 123 | {Transport#t_transport{state = NewState}, Result}. |