diff --git a/src/machi.proto b/src/machi.proto index 9dfa246..831e32c 100644 --- a/src/machi.proto +++ b/src/machi.proto @@ -83,6 +83,15 @@ message Mpb_FileInfo { required string file_name = 2; } +// #p_srvr{} type +message Mpb_P_Srvr { + required string name = 1; + required string proto_mod = 2; + required string address = 3; + required string port = 4; + required bytes props = 5; +} + ////////////////////////////////////////// // // requests & responses @@ -97,7 +106,21 @@ message Mpb_ErrorResp { optional bytes extra = 3; } -// ping() request & response +////////////////////////////////////////// +// +// High Level API requests: +// +// echo() : Mpb_EchoReq and Mpb_EchoResp +// auth() : Mpb_AuthReq and Mpb_AuthResp +// append_chunk() : Mpb_AppendChunkReq and Mpb_AppendChunkResp +// write_chunk() : Mpb_WriteChunkReq and Mpb_WriteChunkResp +// read_chunk() : Mpb_ReadChunkReq and Mpb_ReadChunkResp +// checksum_list() : Mpb_ChecksumListReq and Mpb_ChecksumListResp +// list_files() : Mpb_ListFilesReq and Mpb_ListFilesResp +// +////////////////////////////////////////// + +// High level API: echo() request & response message Mpb_EchoReq { optional string message = 1; @@ -107,7 +130,7 @@ message Mpb_EchoResp { optional string message = 1; } -// Authentication request & response +// High level API: auth() request & response (not yet implemented) message Mpb_AuthReq { required bytes user = 1; @@ -119,7 +142,7 @@ message Mpb_AuthResp { // TODO: not implemented yet } -// append_chunk() request & response +// High level API: append_chunk() request & response message Mpb_AppendChunkReq { optional bytes placement_key = 1; @@ -135,7 +158,7 @@ message Mpb_AppendChunkResp { optional Mpb_ChunkPos chunk_pos = 2; } -// write_chunk() request & response +// High level API: write_chunk() request & response message Mpb_WriteChunkReq { required string file = 1; @@ -148,7 +171,7 @@ message Mpb_WriteChunkResp { required Mpb_GeneralStatusCode status = 1; } -// read_chunk() request & response +// High level API: read_chunk() request & response message Mpb_ReadChunkReq { required string file = 1; @@ -167,7 +190,7 @@ message Mpb_ReadChunkResp { optional Mpb_ChunkCSum csum = 3; } -// checksum_list() request & response +// High level API: checksum_list() request & response message Mpb_ChecksumListReq { required string file = 1; @@ -178,7 +201,7 @@ message Mpb_ChecksumListResp { optional bytes chunk = 2; } -// list_files() request & response +// High level API: list_files() request & response message Mpb_ListFilesReq { } diff --git a/src/machi_pb_wrap.erl b/src/machi_pb_wrap.erl new file mode 100644 index 0000000..d79f3ae --- /dev/null +++ b/src/machi_pb_wrap.erl @@ -0,0 +1,125 @@ +%% ------------------------------------------------------------------- +%% +%% Machi: a small village of replicated files +%% +%% Copyright (c) 2014-2015 Basho Technologies, Inc. All Rights Reserved. +%% +%% This file is provided to you under the Apache License, +%% Version 2.0 (the "License"); you may not use this file +%% except in compliance with the License. You may obtain +%% a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%% ------------------------------------------------------------------- +-module(machi_pb_wrap). + +-include("machi_pb.hrl"). +-include("machi_projection.hrl"). + +-export([enc_p_srvr/1, dec_p_srvr/1, + enc_projection_v1/1, dec_projection_v1/1]). +-ifdef(TEST). +-compile(export_all). +-endif. % TEST + +enc_p_srvr(#p_srvr{name=Name, + proto_mod=ProtoMod, + address=Address, + port=Port, + props=Props}) -> + machi_pb:encode_mpb_p_srvr(#mpb_p_srvr{name=to_list(Name), + proto_mod=to_list(ProtoMod), + address=to_list(Address), + port=to_list(Port), + props=todo_enc_opaque(Props)}). + +dec_p_srvr(Bin) -> + #mpb_p_srvr{name=Name, + proto_mod=ProtoMod, + address=Address, + port=Port, + props=Props} = machi_pb:decode_mpb_p_srvr(Bin), + #p_srvr{name=to_atom(Name), + proto_mod=to_atom(ProtoMod), + address=to_list(Address), + port=to_integer(Port), + props=todo_dec_opaque(Props)}. + +enc_projection_v1(#projection_v1{dbg=Dbg, + dbg2=Dbg2, + members_dict=MembersDict} = P) -> + term_to_binary(P#projection_v1{dbg=enc_sexp(Dbg), + dbg2=enc_sexp(Dbg2), + members_dict=enc_members_dict(MembersDict)}). + +dec_projection_v1(Bin) -> + P = #projection_v1{dbg=Dbg, + dbg2=Dbg2, + members_dict=MembersDict} = binary_to_term(Bin), + P#projection_v1{dbg=dec_sexp(Dbg), + dbg2=dec_sexp(Dbg2), + members_dict=dec_members_dict(MembersDict)}. + +%%%%%%%%%%%%%%%%%%% + +enc_sexp(T) -> + lists:flatten(io_lib:format("~w.", [T])). + +dec_sexp(String) -> + {ok,Tks,_} = erl_scan:string(String), + {ok,E} = erl_parse:parse_exprs(Tks), + {value,Funs,_} = erl_eval:exprs(E,[]), + Funs. + +enc_members_dict(D) -> + %% Use list_to_binary() here to "flatten" the serialized #p_srvr{} + [{K, list_to_binary(enc_p_srvr(V))} || {K, V} <- orddict:to_list(D)]. + +dec_members_dict(List) -> + orddict:from_list([{K, dec_p_srvr(V)} || {K, V} <- List]). + +to_binary(X) when is_list(X) -> + list_to_binary(X); +to_binary(X) when is_integer(X) -> + list_to_binary(integer_to_list(X)); +to_binary(X) when is_atom(X) -> + erlang:atom_to_binary(X, latin1); +to_binary(X) when is_binary(X) -> + X. + +to_list(X) when is_atom(X) -> + atom_to_list(X); +to_list(X) when is_binary(X) -> + binary_to_list(X); +to_list(X) when is_integer(X) -> + integer_to_list(X); +to_list(X) when is_list(X) -> + X. + +to_atom(X) when is_list(X) -> + list_to_atom(X); +to_atom(X) when is_binary(X) -> + erlang:binary_to_atom(X, latin1); +to_atom(X) when is_atom(X) -> + X. + +to_integer(X) when is_list(X) -> + list_to_integer(X); +to_integer(X) when is_binary(X) -> + list_to_binary(binary_to_list(X)); +to_integer(X) when is_integer(X) -> + X. + +todo_enc_opaque(X) -> + erlang:term_to_binary(X). + +todo_dec_opaque(X) -> + erlang:binary_to_term(X). diff --git a/test/machi_pb_test.erl b/test/machi_pb_test.erl index 1044bf6..0712b7f 100644 --- a/test/machi_pb_test.erl +++ b/test/machi_pb_test.erl @@ -22,6 +22,7 @@ -module(machi_pb_test). -include("machi_pb.hrl"). +-include("machi_projection.hrl"). -compile(export_all). @@ -62,6 +63,22 @@ smoke_responses_test() -> ok. +smoke_p_srvr_test() -> + P1 = #p_srvr{name=a, address="localhost", port=5555, + props=[{dir,"./data.a"}]}, + P1 = machi_pb_wrap:dec_p_srvr( + list_to_binary(machi_pb_wrap:enc_p_srvr(P1))), + ok. + +smoke_projection_v1_test() -> + P1 = #p_srvr{name=a, address="localhost", port=5555, + props=[{dir,"./data.a"}]}, + D = orddict:from_list([ {P1#p_srvr.name, P1} ]), + Proj1 = machi_projection:new(a, D, [a], [], [], [{property, 42}]), + Proj1 = machi_pb_wrap:dec_projection_v1( + machi_pb_wrap:enc_projection_v1(Proj1)), + ok. + encdec_request(M) -> machi_pb:decode_mpb_request( list_to_binary(machi_pb:encode_mpb_request(M))).