From: David Reiss Date: Tue, 10 Jun 2008 22:56:59 +0000 (+0000) Subject: Initial commit of alternative erlang lib X-Git-Tag: 0.2.0~770 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=ac549554f425cf2b28ff391c6fefeaa0fe703a32;p=common%2Fthrift.git Initial commit of alternative erlang lib git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@666374 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/lib/alterl/COPYING b/lib/alterl/COPYING new file mode 100644 index 00000000..039f21e3 --- /dev/null +++ b/lib/alterl/COPYING @@ -0,0 +1,24 @@ +Thrift Software License +Copyright (c) 2006- Facebook, Inc. + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/lib/alterl/LICENSE b/lib/alterl/LICENSE new file mode 100644 index 00000000..039f21e3 --- /dev/null +++ b/lib/alterl/LICENSE @@ -0,0 +1,24 @@ +Thrift Software License +Copyright (c) 2006- Facebook, Inc. + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/lib/alterl/Makefile b/lib/alterl/Makefile new file mode 100644 index 00000000..0f2c8a82 --- /dev/null +++ b/lib/alterl/Makefile @@ -0,0 +1,7 @@ +MODULES = \ + src + +all clean docs: + for dir in $(MODULES); do \ + (cd $$dir; ${MAKE} $@); \ + done diff --git a/lib/alterl/include/thrift_constants.hrl b/lib/alterl/include/thrift_constants.hrl new file mode 100644 index 00000000..19480610 --- /dev/null +++ b/lib/alterl/include/thrift_constants.hrl @@ -0,0 +1,25 @@ +%%% Copyright (c) 2007- Facebook +%%% Distributed under the Thrift Software License +%%% +%%% See accompanying file LICENSE or visit the Thrift site at: +%%% http://developers.facebook.com/thrift/ + +%% TType +-define(tType_STOP, 0). +-define(tType_VOID, 1). +-define(tType_BOOL, 2). +-define(tType_BYTE, 3). +-define(tType_DOUBLE, 4). +-define(tType_I16, 6). +-define(tType_I32, 8). +-define(tType_I64, 10). +-define(tType_STRING, 11). +-define(tType_STRUCT, 12). +-define(tType_MAP, 13). +-define(tType_SET, 14). +-define(tType_LIST, 15). + +% TMessageType +-define(tMessageType_CALL, 1). +-define(tMessageType_REPLY, 2). +-define(tMessageType_EXCEPTION, 3). diff --git a/lib/alterl/include/thrift_protocol.hrl b/lib/alterl/include/thrift_protocol.hrl new file mode 100644 index 00000000..66222d62 --- /dev/null +++ b/lib/alterl/include/thrift_protocol.hrl @@ -0,0 +1,11 @@ +-ifndef(THRIFT_PROTOCOL_INCLUDED). +-define(THRIFT_PROTOCOL_INCLUDED, yea). + +-record(protocol_message_begin, {name, type, seqid}). +-record(protocol_field_begin, {name, type, id}). +-record(protocol_map_begin, {ktype, vtype, size}). +-record(protocol_list_begin, {etype, size}). +-record(protocol_set_begin, {etype, size}). + + +-endif. diff --git a/lib/alterl/src/thrift_binary_protocol.erl b/lib/alterl/src/thrift_binary_protocol.erl new file mode 100644 index 00000000..1593f0b8 --- /dev/null +++ b/lib/alterl/src/thrift_binary_protocol.erl @@ -0,0 +1,219 @@ +%%% Copyright (c) 2007- Facebook +%%% Distributed under the Thrift Software License +%%% +%%% See accompanying file LICENSE or visit the Thrift site at: +%%% http://developers.facebook.com/thrift/ + +-module(thrift_binary_protocol). + +-behavior(thrift_protocol). + +-include("thrift_constants.hrl"). +-include("thrift_protocol.hrl"). + +-export([new/1, + read/2, + write/2 +]). + +-record(binary_protocol, {transport}). + + +-define(VERSION_MASK, 16#FFFF0000). +-define(VERSION_1, 16#80010000). + + +new(Transport) -> + thrift_protocol:new(?MODULE, #binary_protocol{transport = Transport}). + + +%%% +%%% instance methods +%%% + +write(This, #protocol_message_begin{ + name = Name, + type = Type, + seqid = Seqid}) -> + write(This, {i32, ?VERSION_1 bor Type}), + write(This, {string, Name}), + write(This, {i32, Seqid}), + ok; + +write(This, message_end) -> ok; + +write(This, #protocol_field_begin{ + name = _Name, + type = Type, + id = Id}) -> + write(This, {byte, Type}), + write(This, {i16, Id}), + ok; + +write(This, field_stop) -> + write(This, {byte, ?tType_STOP}), + ok; + +write(This, field_end) -> ok; + +write(This, #protocol_map_begin{ + ktype = Ktype, + vtype = Vtype, + size = Size}) -> + write(This, {byte, Ktype}), + write(This, {byte, Vtype}), + write(This, {i32, Size}), + ok; + +write(This, map_end) -> ok; + +write(This, #protocol_list_begin{ + etype = Etype, + size = Size}) -> + write(This, {byte, Etype}), + write(This, {i32, Size}), + ok; + +write(This, list_end) -> ok; + +write(This, #protocol_set_begin{ + etype = Etype, + size = Size}) -> + write(This, {byte, Etype}), + write(This, {i32, Size}), + ok; + +write(This, set_end) -> ok; + +write(This, struct_begin) -> ok; +write(This, struct_end) -> ok; + + + +write(This, {bool, true}) -> write(This, {byte, 1}); +write(This, {bool, false}) -> write(This, {byte, 0}); + +write(This, {byte, Byte}) -> + write(This, <>); + +write(This, {i16, I16}) -> + write(This, <>); + +write(This, {i32, I32}) -> + write(This, <>); + +write(This, {i63, I64}) -> + write(This, <>); + +write(This, {double, Double}) -> + write(This, <>); + +write(This, {string, Str}) when is_list(Str) -> + write(This, {i32, length(Str)}), + write(This, list_to_binary(Str)); + +write(This, Binary) when is_binary(Binary) -> + thrift_transport:write(This#binary_protocol.transport, Binary). + +%% + +read(This, message_begin) -> + case read(This, i32) of + {ok, Version} when Version band ?VERSION_MASK == ?VERSION_1 -> + Type = Version band 16#000000ff, + {ok, Name} = read(This, string), + {ok, SeqId} = read(This, i32), + #protocol_message_begin{name = Name, + type = Type, + seqid = SeqId}; + Err = {error, closed} -> Err + end; + +read(This, message_end) -> ok; + +read(This, struct_begin) -> ok; +read(This, struct_end) -> ok; + +read(This, field_begin) -> + case read(This, byte) of + {ok, Type = ?tType_STOP} -> + #protocol_field_begin{type = Type, + id = 0}; % TODO(todd) 0 or undefined? + {ok, Type} -> + Id = read(This, i16), + #protocol_field_begin{type = Type, + id = Id} + end; + +read(This, field_end) -> ok; + +read(This, map_begin) -> + {ok, Ktype} = read(This, byte), + {ok, Vtype} = read(This, byte), + {ok, Size} = read(This, i32), + #protocol_map_begin{ktype = Ktype, + vtype = Vtype, + size = Size}; +read(This, map_end) -> ok; + +read(This, list_begin) -> + {ok, Etype} = read(This, byte), + {ok, Size} = read(This, i32), + #protocol_list_begin{etype = Etype, + size = Size}; +read(This, list_end) -> ok; + +read(This, set_begin) -> + {ok, Etype} = read(This, byte), + {ok, Size} = read(This, i32), + #protocol_set_begin{etype = Etype, + size = Size}; +read(This, set_end) -> ok; + +read(This, field_stop) -> + {ok, ?tType_STOP} = read(This, byte), + ok; + +%% + +read(This, bool) -> + Byte = read(This, byte), + {ok, (Byte /= 0)}; + + +read(This, byte) -> + case read(This, 1) of + {ok, <>} -> {ok, Val}; + Else -> Else + end; + +read(This, i16) -> + case read(This, 2) of + {ok, <>} -> {ok, Val}; + Else -> Else + end; + +read(This, i32) -> + case read(This, 4) of + {ok, <>} -> {ok, Val}; + Else -> Else + end; + +read(This, i64) -> + case read(This, 8) of + {ok, <>} -> {ok, Val}; + Else -> Else + end; + +read(This, double) -> + case read(This, 8) of + {ok, <>} -> {ok, Val}; + Else -> Else + end; + +read(This, string) -> + {ok, Sz} = read(This, i32), + read(This, Sz); + +read(This, Len) when is_integer(Len), Len >= 0 -> + thrift_transport:read(This#binary_protocol.transport, Len). diff --git a/lib/alterl/src/thrift_processor.erl b/lib/alterl/src/thrift_processor.erl new file mode 100644 index 00000000..ea6ea2d3 --- /dev/null +++ b/lib/alterl/src/thrift_processor.erl @@ -0,0 +1,64 @@ +%%%------------------------------------------------------------------- +%%% File : thrift_processor.erl +%%% Author : +%%% Description : +%%% +%%% Created : 28 Jan 2008 by +%%%------------------------------------------------------------------- +-module(thrift_processor). + +-export([start/4,init/4]). + +-include("thrift_constants.hrl"). +-include("thrift_protocol.hrl"). + +-record(state, {handler, in_protocol, out_protocol, service}). + +start(IProt, OProt, Service, Handler) -> + spawn(thrift_processor, init, [IProt, OProt, Service, Handler]). + +init(IProt, OProt, Service, Handler) -> + io:format("Processor started~n"), + loop(#state{in_protocol = IProt, + out_protocol = OProt, + service = Service, + handler = Handler}). + +loop(State = #state{in_protocol = IProto, + out_protocol = OProto}) -> + MessageBegin = thrift_protocol:read(IProto, message_begin), + io:format("Got message begin: ~p~n", [MessageBegin]), + + [ok, ok, ok, ok] = [thrift_protocol:read(IProto, X) + || X <- [struct_begin, field_stop, struct_end, message_end]], + io:format("Read everything okay!"), + + Packets = + [ + #protocol_message_begin{name = "getServiceStatus", + type = ?tMessageType_REPLY, + seqid = 0}, + struct_begin, + #protocol_field_begin{name = "success", + type = ?tType_MAP, + id = 0}, + #protocol_map_begin{ktype = ?tType_STRING, + vtype = ?tType_STRING, + size = 2}, + {string, "Hello"}, + {string, "World"}, + {string, "foo"}, + {string, "bar"}, + field_stop, + map_end, + field_end, + field_stop, + struct_end, + message_end + ], + + Results = [thrift_protocol:write(OProto, Packet) || Packet <- Packets], + receive + _ -> + loop(State) + end. diff --git a/lib/alterl/src/thrift_protocol.erl b/lib/alterl/src/thrift_protocol.erl new file mode 100644 index 00000000..66e19b38 --- /dev/null +++ b/lib/alterl/src/thrift_protocol.erl @@ -0,0 +1,120 @@ +-module(thrift_protocol). + +-export([new/2, + write/2, + read/2, + skip/2, + + typeid_to_atom/1, + + behaviour_info/1]). + +-include("thrift_constants.hrl"). +-include("thrift_protocol.hrl"). + +-record(protocol, {module, data}). + +behaviour_info(callbacks) -> + [ + {read, 2}, + {write, 2} + ]; +behaviour_info(_Else) -> undefined. + + +new(Module, Data) when is_atom(Module) -> + {ok, #protocol{module = Module, + data = Data}}. + + +write(#protocol{module = Module, + data = ModuleData}, Data) -> + Module:write(ModuleData, Data). + +typeid_to_atom(?tType_STOP) -> field_stop; +typeid_to_atom(?tType_VOID) -> void; +typeid_to_atom(?tType_BOOL) -> bool; +typeid_to_atom(?tType_BYTE) -> byte; +typeid_to_atom(?tType_DOUBLE) -> double; +typeid_to_atom(?tType_I16) -> i16; +typeid_to_atom(?tType_I32) -> i32; +typeid_to_atom(?tType_I64) -> i64; +typeid_to_atom(?tType_STRING) -> string; +typeid_to_atom(?tType_STRUCT) -> struct; +typeid_to_atom(?tType_MAP) -> map; +typeid_to_atom(?tType_SET) -> set; +typeid_to_atom(?tType_LIST) -> list. + +read(#protocol{module = Module, + data = ModuleData}, ProtocolType) -> + Module:read(ModuleData, ProtocolType). + + + +skip(Proto, struct) -> + ok = read(Proto, struct_begin), + ok = skip_struct_loop(Proto), + ok = read(Proto, struct_end); + +skip(Proto, map) -> + Map = read(Proto, map_begin), + ok = skip_map_loop(Proto, Map), + ok = read(Proto, map_end); + +skip(Proto, set) -> + Set = read(Proto, set_begin), + ok = skip_set_loop(Proto, Set), + ok = read(Proto, set_end); + +skip(Proto, list) -> + List = read(Proto, list_begin), + ok = skip_list_loop(Proto, List), + ok = read(Proto, list_end); + +skip(Proto, Type) when is_atom(Type) -> + _Ignore = read(Proto, Type), + ok. + + +skip_struct_loop(Proto) -> + #protocol_field_begin{type = Type} = read(Proto, field_begin), + case Type of + ?tType_STOP -> + ok; + _Else -> + skip(Proto, Type), + ok = read(Proto, field_end), + skip_struct_loop(Proto) + end. + +skip_map_loop(Proto, Map = #protocol_map_begin{ktype = Ktype, + vtype = Vtype, + size = Size}) -> + case Size of + N when N > 0 -> + skip(Proto, Ktype), + skip(Proto, Vtype), + skip_map_loop(Proto, + Map#protocol_map_begin{size = Size - 1}); + 0 -> ok + end. + +skip_set_loop(Proto, Map = #protocol_set_begin{etype = Etype, + size = Size}) -> + case Size of + N when N > 0 -> + skip(Proto, Etype), + skip_set_loop(Proto, + Map#protocol_set_begin{size = Size - 1}); + 0 -> ok + end. + +skip_list_loop(Proto, Map = #protocol_list_begin{etype = Etype, + size = Size}) -> + case Size of + N when N > 0 -> + skip(Proto, Etype), + skip_list_loop(Proto, + Map#protocol_list_begin{size = Size - 1}); + 0 -> ok + end. diff --git a/lib/alterl/src/thrift_server.erl b/lib/alterl/src/thrift_server.erl new file mode 100644 index 00000000..fd559f1d --- /dev/null +++ b/lib/alterl/src/thrift_server.erl @@ -0,0 +1,125 @@ +%%%------------------------------------------------------------------- +%%% File : thrift_server.erl +%%% Author : +%%% Description : +%%% +%%% Created : 28 Jan 2008 by +%%%------------------------------------------------------------------- +-module(thrift_server). + +-behaviour(gen_server). + +%% API +-export([start_link/3]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, {listen_socket, acceptor, service}). +-record(handler, {module}). + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +start_link(Port, Service, HandlerModule) when is_integer(Port), is_atom(HandlerModule) -> + gen_server:start_link({local, ?SERVER}, ?MODULE, {Port, Service, HandlerModule}, []). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init({Port, Service, HandlerModule}) -> + Handler = #handler{module = HandlerModule}, + {ok, Socket} = gen_tcp:listen(Port, + [binary, + {packet, 0}, + {active, false}, + {nodelay, true}, + {reuseaddr, true}]), + Acceptor = spawn_link(fun () -> acceptor(Socket, Service, Handler) end), + {ok, #state{listen_socket = Socket, + acceptor = Acceptor, + service = Service}}. + +%%-------------------------------------------------------------------- +%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% Description: Handling call messages +%%-------------------------------------------------------------------- +handle_call(_Request, _From, State) -> + Reply = ok, + {reply, Reply, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling cast messages +%%-------------------------------------------------------------------- +handle_cast(_Msg, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling all non call/cast messages +%%-------------------------------------------------------------------- +handle_info(_Info, State) -> + {noreply, State}. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any necessary +%% cleaning up. When it returns, the gen_server terminates with Reason. +%% The return value is ignored. +%%-------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%-------------------------------------------------------------------- +%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + State#state.acceptor ! refresh, + {ok, State}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +acceptor(ListenSocket, Service, Handler) + when is_port(ListenSocket), is_record(Handler, handler) -> + {ok, Socket} = gen_tcp:accept(ListenSocket), + error_logger:info_msg("Accepted client"), + + {ok, Transport} = thrift_socket_transport:new(Socket), + {ok, Protocol} = thrift_binary_protocol:new(Transport), + + thrift_processor:start(Protocol, Protocol, Service, Handler), + receive + refresh -> + error_logger:info_msg("Acceptor refreshing~n"), + ?MODULE:acceptor(ListenSocket, Service, Handler) + after 0 -> acceptor(ListenSocket, Service, Handler) + end. diff --git a/lib/alterl/src/thrift_service.erl b/lib/alterl/src/thrift_service.erl new file mode 100644 index 00000000..89479c8d --- /dev/null +++ b/lib/alterl/src/thrift_service.erl @@ -0,0 +1,6 @@ +-module(thrift_service). + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{service_info, 1}]. diff --git a/lib/alterl/src/thrift_socket_transport.erl b/lib/alterl/src/thrift_socket_transport.erl new file mode 100644 index 00000000..2921c20d --- /dev/null +++ b/lib/alterl/src/thrift_socket_transport.erl @@ -0,0 +1,18 @@ +-module(thrift_socket_transport). + +-behaviour(thrift_transport). + +-export([new/1, + + write/2, read/2]). + +-record(data, {socket}). + +new(Socket) -> + thrift_transport:new(?MODULE, #data{socket = Socket}). + +write(#data{socket = Socket}, Data) when is_binary(Data) -> + gen_tcp:send(Socket, Data). + +read(#data{socket = Socket}, Len) when is_integer(Len), Len >= 0 -> + gen_tcp:recv(Socket, Len). diff --git a/lib/alterl/src/thrift_transport.erl b/lib/alterl/src/thrift_transport.erl new file mode 100644 index 00000000..bf9dc53b --- /dev/null +++ b/lib/alterl/src/thrift_transport.erl @@ -0,0 +1,29 @@ +-module(thrift_transport). + +-export([behaviour_info/1, + + new/2, + write/2, + read/2 + ]). + +behaviour_info(callbacks) -> + [{write/2, + read/2}]; +behaviour_info(_Else) -> undefined. + + +-record(transport, { module, data }). + + +new(Module, Data) when is_atom(Module) -> + {ok, #transport{module = Module, + data = Data}}. + +write(Transport, Data) when is_binary(Data) -> + Module = Transport#transport.module, + Module:write(Transport#transport.data, Data). + +read(Transport, Len) when is_integer(Len) -> + Module = Transport#transport.module, + Module:read(Transport#transport.data, Len). diff --git a/lib/alterl/vsn.mk b/lib/alterl/vsn.mk new file mode 100644 index 00000000..d9b40014 --- /dev/null +++ b/lib/alterl/vsn.mk @@ -0,0 +1 @@ +THRIFT_VSN=0.1