diff options
Diffstat (limited to 'lib/megaco/examples/meas/megaco_codec_transform.erl')
-rw-r--r-- | lib/megaco/examples/meas/megaco_codec_transform.erl | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/lib/megaco/examples/meas/megaco_codec_transform.erl b/lib/megaco/examples/meas/megaco_codec_transform.erl new file mode 100644 index 0000000000..cfe832ff26 --- /dev/null +++ b/lib/megaco/examples/meas/megaco_codec_transform.erl @@ -0,0 +1,305 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Megaco message transformation +%% +%% Usage: From a base message file, messages for every codec is +%% generated. The file should have the following structure: +%% +%% {Codec, Messages}. +%% +%% Codec = pretty | compact | ber | per | erlang +%% Messages = [{Name, binary()}] +%% Name = atom +%% +%% The function messages/0 is used by the meas and mstone +%% tools, but messages/1 can also be used if another base +%% message file is to be used. +%% +%% The messages can also be exported to the old format, +%% e.g. a directory for each of the codec's and the +%% each message as a file in those directories. +%% +%% Pretty text: pretty +%% Compact text: compact +%% Binary ber: ber +%% Binary per: per +%% Erlang: erlang +%% +%% +%% <message package>/pretty/<message-files> +%% compact/<message-files> +%% per/<message-files> +%% ber/<message-files> +%% erlang/<message-files> +%% +%%---------------------------------------------------------------------- + +-module(megaco_codec_transform). + +-include_lib("kernel/include/file.hrl"). + +-export([ + codecs/0, + default_message_package/0, + messages/0, messages/1, + export_messages/0, export_messages/1 + ]). + +-define(DEFAULT_MESSAGE_PACKAGE, time_test). +-define(ALL_CODECS, [pretty, compact, per, ber, erlang]). +-define(V3, v3). + +codecs() -> + ?ALL_CODECS. + +default_message_package() -> + ?DEFAULT_MESSAGE_PACKAGE. + +messages() -> + messages(?DEFAULT_MESSAGE_PACKAGE). + +messages(MessagePackage) when is_atom(MessagePackage) -> + %% Try the CWD first, and if that does not work try the installation directory + case load_messages(".", MessagePackage) of + {error, _Reason} -> + AppLibDir = code:lib_dir(megaco), + Dir = filename:join([AppLibDir, examples, meas]), + load_messages(Dir, MessagePackage); + Else -> + Else + end. + +load_messages(Dir, MessagePackage) -> + %% io:format("try loading messages from ~s~n", [Dir]), + Filename = filename:join([Dir, atom_to_list(MessagePackage) ++ ".msgs"]), + case file:consult(Filename) of + {ok, [{Codec, Msgs}]} when is_atom(Codec) andalso is_list(Msgs) -> + case lists:member(Codec, ?ALL_CODECS) of + true -> + messages(Codec, Msgs); + false -> + {error, {unknown_codec, Codec}} + end; + + {ok, [{BadCodec, Msgs}]} when is_list(Msgs) -> + {error, {bad_codec, BadCodec}}; + + %% No codec specified, try with pretty + {ok, [Msgs]} when is_list(Msgs) -> + messages(pretty, Msgs); + + {ok, Crap} -> + {error, {bad_messages, Crap}}; + + Error -> + Error + end. + +messages(BaseCodec, Msgs) -> + OutCodecs = lists:delete(BaseCodec, ?ALL_CODECS), + transform_messages(BaseCodec, Msgs, OutCodecs). + + +export_messages() -> + export_messages(?DEFAULT_MESSAGE_PACKAGE). + +export_messages(MessagePackage) when is_atom(MessagePackage) -> + case messages(MessagePackage) of + TMsgs when is_list(TMsgs) -> + (catch export_messages(MessagePackage, TMsgs)); + Error -> + Error + end. + +export_messages(MessagePackage, TMsgs) -> + case file:make_dir(MessagePackage) of + ok -> + ok; + {error, eexist} -> + ok; + Error -> + throw(Error) + end, + do_export_messages(MessagePackage, TMsgs). + +do_export_messages(_MessagePackage, []) -> + ok; +do_export_messages(MessagePackage, [{Codec, Msgs} | TMsgs]) -> + ems(MessagePackage, Codec, Msgs), + do_export_messages(MessagePackage, TMsgs). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +transform_messages(BaseCodec, BaseMsgs, OutCodecs) -> + [{BaseCodec, BaseMsgs} | + [{Codec, tms(BaseMsgs, BaseCodec, Codec)} || Codec <- OutCodecs]]. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +tms(FromMsgs, FromCodec, ToCodec) -> + [{Name, tm(FromBin, FromCodec, ToCodec)} || {Name, FromBin} <- FromMsgs]. + +tm(FromBin, FromCodec, ToCodec) -> + FromMsg = decode_message(FromCodec, FromBin), + encode_message(ToCodec, FromMsg). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ems(MessagePackage, Codec, Msgs) -> + Dir = filename:join([MessagePackage, Codec]), + case file:make_dir(Dir) of + ok -> + ok; + {error, eexist} -> + ok; + Error -> + throw(Error) + end, + Extension = extension_of(Codec), + F = fun({Name, Bin}) -> em(MessagePackage, Codec, Name, Extension, Bin) end, + lists:foreach(F, Msgs). + +em(MessagePackage, Codec, Name, Extension, Bin) -> + Filename = filename:join([MessagePackage, Codec, atom_to_list(Name) ++ Extension]), + case file:open(Filename, [raw, binary, write]) of + {ok, Fd} -> + case file:write(Fd, Bin) of + ok -> + file:close(Fd), + ok; + {error, Reason} -> + S = format("failed writing ~w message ~w (~p bytes): ~p", + [Codec, Name, size(Bin), Reason]), + file:close(Fd), + throw({error, S}) + end; + + {error, Reason} -> + S = format("failed open file ~s: ~p", [Filename, Reason]), + throw({error, S}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +decode_message(pretty, BinMsg) -> + Mod = megaco_pretty_text_encoder, + Conf = [{version3,?V3}], + do_decode(Mod, Conf, BinMsg); +decode_message(compact, BinMsg) -> + Mod = megaco_compact_text_encoder, + Conf = [{version3,?V3}], + do_decode(Mod, Conf, BinMsg); +decode_message(ber, BinMsg) -> + Mod = megaco_ber_bin_encoder, + Conf = [{version3,?V3}], + do_decode(Mod, Conf, BinMsg); +decode_message(per, BinMsg) -> + Mod = megaco_per_bin_encoder, + Conf = [{version3,?V3}], + do_decode(Mod, Conf, BinMsg); +decode_message(erlang, BinMsg) -> + Mod = megaco_erl_dist_encoder, + Conf = [{version3,?V3}], + do_decode(Mod, Conf, BinMsg). + + +do_decode(Mod, Conf, Bin) -> + case (catch Mod:decode_message(Conf, Bin)) of + {ok, Msg} -> + Msg; + {error, Reason} -> + S = format("decode error: ~p", [Reason]), + throw({error, S}); + {'EXIT', Reason} -> + S = format("decode exit: ~p", [Reason]), + throw({error, S}); + Other -> + S = format("unknwon decode result: ~p", [Other]), + throw({error, S}) + end. + + +%% encode_message +%% Note: See note above (decode_message) + +encode_message(pretty, Msg) -> + Mod = megaco_pretty_text_encoder, + Conf = [{version3,?V3}], + do_encode(Mod, Conf, Msg); +encode_message(compact, Msg) -> + Mod = megaco_compact_text_encoder, + Conf = [{version3,?V3}], + do_encode(Mod, Conf, Msg); +encode_message(ber, Msg) -> + Mod = megaco_ber_bin_encoder, + Conf = [{version3,?V3}], + do_encode(Mod, Conf, Msg); +encode_message(per, Msg) -> + Mod = megaco_per_bin_encoder, + Conf = [{version3,?V3}], + do_encode(Mod, Conf, Msg); +encode_message(erlang, Msg) -> + Mod = megaco_erl_dist_encoder, + Conf = [{version3,?V3}], + do_encode(Mod, Conf, Msg). + + +do_encode(Mod, Conf, Msg) -> + case (catch Mod:encode_message(Conf, Msg)) of + {ok, Bin} -> + Bin; + {error, Reason} -> + S = format("encode error: ~p", [Reason]), + throw({error, S}); + {'EXIT', Reason} -> + S = format("encode exit: ~p", [Reason]), + throw({error, S}); + Other -> + S = format("unknwon encode result: ~p", [Other]), + throw({error, S}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +extension_of(pretty) -> + ".txt"; +extension_of(compact) -> + ".txt"; +extension_of(ber) -> + ".bin"; +extension_of(per) -> + ".bin"; +extension_of(erlang) -> + ".bin". + +%% d(F) -> +%% d(F, []). +%% d(F, A) -> +%% io:format(F ++ "~n", A). + +format(F, A) -> + lists:flatten(io_lib:format(F, A)). |