Current section

Files

Jump to
cloudi_service_api_requests src cloudi_service_api_requests.erl
Raw

src/cloudi_service_api_requests.erl

%-*-Mode:erlang;coding:utf-8;tab-width:4;c-basic-offset:4;indent-tabs-mode:()-*-
% ex: set ft=erlang fenc=utf-8 sts=4 ts=4 sw=4 et nomod:
%%%
%%%------------------------------------------------------------------------
%%% @doc
%%% ==CloudI Service API Requests==
%%% A service that exposes dynamic configuration of CloudI.
%%% @end
%%%
%%% MIT License
%%%
%%% Copyright (c) 2011-2019 Michael Truog <mjtruog at protonmail dot com>
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a
%%% copy of this software and associated documentation files (the "Software"),
%%% to deal in the Software without restriction, including without limitation
%%% the rights to use, copy, modify, merge, publish, distribute, sublicense,
%%% and/or sell copies of the Software, and to permit persons to whom the
%%% Software is furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in
%%% all copies or substantial portions of the Software.
%%%
%%% 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
%%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
%%% DEALINGS IN THE SOFTWARE.
%%%
%%% @author Michael Truog <mjtruog at protonmail dot com>
%%% @copyright 2011-2019 Michael Truog
%%% @version 1.8.0 {@date} {@time}
%%%------------------------------------------------------------------------
-module(cloudi_service_api_requests).
-author('mjtruog at protonmail dot com').
-behaviour(cloudi_service).
%% external interface
-export([from_erl/2,
from_json/2,
to_erl/2,
to_erl/3,
to_json/2,
to_json/3]).
%% cloudi_service callbacks
-export([cloudi_service_init/4,
cloudi_service_handle_request/11,
cloudi_service_terminate/3]).
-include_lib("cloudi_core/include/cloudi_logger.hrl").
-include_lib("cloudi_core/include/cloudi_service_api.hrl").
-record(state,
{
functions :: trie:trie(), % name -> {method,arity}
prefix :: cloudi:service_name_pattern()
}).
-define(FORMAT_ERLANG, "erl").
-define(FORMAT_JSON, "json").
%%%------------------------------------------------------------------------
%%% External interface functions
%%%------------------------------------------------------------------------
-spec from_erl(_Method :: atom(),
Request :: binary()) ->
any().
from_erl(_Method, Request) ->
convert_erlang_to_term(Request).
-spec from_json(Method :: atom(),
Request :: binary()) ->
any().
from_json(Method, Request) ->
convert_json_to_term(Method, Request).
-spec to_erl(Method :: atom(),
Result :: any()) ->
binary().
to_erl(Method, Result) ->
to_erl(Method, Result, true).
-spec to_erl(Method :: atom(),
Result :: any(),
Space :: boolean()) ->
binary().
to_erl(Method, Result, Space) ->
convert_term_to_erlang(convert_api_data(Method, Result), Space).
-spec to_json(Method :: atom(),
Result :: any()) ->
binary().
to_json(Method, Result) ->
to_json(Method, Result, true).
-spec to_json(Method :: atom(),
Result :: any(),
Space :: boolean()) ->
binary().
to_json(Method, Result, Space) ->
convert_term_to_json(convert_api_data(Method, Result), Method, Space).
%%%------------------------------------------------------------------------
%%% Callback functions from cloudi_service
%%%------------------------------------------------------------------------
cloudi_service_init([], Prefix, _Timeout, Dispatcher) ->
Exports = reltool_util:module_exports(cloudi_service_api),
CloudIServiceAPI = lists:foldl(fun({Method, Arity} = F, Functions) ->
% service names are (prefix)rpc/(method)(format-extension)
% (content-type hint as a file extension)
FormatSuffix = if
Arity == 1 ->
"/get";
Arity == 2 ->
"/post"
end,
MethodName = erlang:atom_to_list(Method),
lists:foreach(fun(Format) ->
FormatName = "rpc/" ++ MethodName ++ "." ++ Format,
cloudi_service:subscribe(Dispatcher, FormatName),
cloudi_service:subscribe(Dispatcher, FormatName ++ FormatSuffix)
end, [?FORMAT_ERLANG, ?FORMAT_JSON]),
trie:store(MethodName, F, Functions)
end, trie:new(), Exports),
% service names for JSON-RPC are:
cloudi_service:subscribe(Dispatcher, "rpc.json"),
cloudi_service:subscribe(Dispatcher, "rpc.json/post"),
{ok, #state{functions = CloudIServiceAPI,
prefix = Prefix}}.
cloudi_service_handle_request(_RequestType, Name, _Pattern,
_RequestInfo, Request,
Timeout, _Priority, _TransId, _Pid,
#state{prefix = Prefix} = State, _Dispatcher) ->
Response = case cloudi_service_name:suffix(Prefix, Name) of
"rpc/" ++ MethodSuffix ->
format_rpc(cloudi_string:beforel($/, MethodSuffix, input),
Request, Timeout, State);
"rpc.json" ++ _ ->
format_json_rpc(Request, Timeout, State)
end,
{reply, Response, State}.
cloudi_service_terminate(_Reason, _Timeout, _State) ->
ok.
%%%------------------------------------------------------------------------
%%% Private functions
%%%------------------------------------------------------------------------
format_rpc(MethodFormat, Request, Timeout,
#state{functions = Functions}) ->
{MethodName, Format} = cloudi_string:splitr($., MethodFormat),
{Method, Arity} = trie:fetch(MethodName, Functions),
case Format of
?FORMAT_ERLANG ->
format_erlang_call(Method, Arity, Request, Timeout);
?FORMAT_JSON ->
format_json_call(Method, Arity, Request, Timeout)
end.
format_erlang_call(_, _, Request, _)
when not is_binary(Request) ->
<<>>;
format_erlang_call(Method, 1, _, Timeout) ->
try cloudi_service_api_call(Method, Timeout) of
Result ->
convert_term_to_erlang(Result)
catch
ErrorType:Error ->
?LOG_DEBUG("~p ~p", [ErrorType, Error]),
<<>>
end;
format_erlang_call(Method, 2, Request, Timeout) ->
Arg1 = convert_erlang_to_term(Request),
try cloudi_service_api_call(Method, Arg1, Timeout) of
Result ->
convert_term_to_erlang(Result)
catch
exit:invalid_input ->
<<>>;
ErrorType:Error ->
?LOG_DEBUG("~p ~p", [ErrorType, Error]),
<<>>
end.
format_json_call(_, _, Request, _)
when not is_binary(Request) ->
<<>>;
format_json_call(Method, 1, _, Timeout) ->
try cloudi_service_api_call(Method, Timeout) of
Result ->
convert_term_to_json(Result, Method, true)
catch
ErrorType:Error ->
?LOG_DEBUG("~p ~p", [ErrorType, Error]),
<<>>
end;
format_json_call(Method, 2, Request, Timeout) ->
Arg1 = convert_json_to_term(Method, Request),
try cloudi_service_api_call(Method, Arg1, Timeout) of
Result ->
convert_term_to_json(Result, Method, true)
catch
exit:invalid_input ->
<<>>;
ErrorType:Error ->
?LOG_DEBUG("~p ~p", [ErrorType, Error]),
<<>>
end.
-spec format_json_rpc(Request :: any(),
Timeout :: cloudi:timeout_value_milliseconds(),
State :: #state{}) -> binary().
format_json_rpc(Request, _, _)
when not is_binary(Request) ->
cloudi_json_rpc:error_parsing();
format_json_rpc(Request, Timeout,
#state{functions = Functions}) ->
try cloudi_json_rpc:request_to_term(Request) of
{MethodNameBin, Params, Id} ->
MethodName = erlang:binary_to_list(MethodNameBin),
case trie:find(MethodName, Functions) of
error ->
cloudi_json_rpc:error_method_not_found(Id);
{ok, {Method, 1}} when Params == [] ->
format_json_rpc_call(Method, 1, undefined, Timeout, Id);
{ok, {Method, 2}} when length(Params) == 1 ->
format_json_rpc_call(Method, 2, hd(Params), Timeout, Id);
{ok, _} ->
cloudi_json_rpc:error_invalid_params(Id)
end
catch
_:_ ->
cloudi_json_rpc:error_invalid_request()
end.
format_json_rpc_call(Method, 1, _, Timeout, Id) ->
try cloudi_service_api_call(Method, Timeout) of
Result ->
ResultJSON = convert_term_to_json(Result, Method, false),
cloudi_json_rpc:response_to_json(ResultJSON, Id)
catch
ErrorType:Error ->
?LOG_DEBUG("~p ~p", [ErrorType, Error]),
<<>>
end;
format_json_rpc_call(_, 2, Param, _, Id)
when not is_binary(Param) ->
cloudi_json_rpc:error_invalid_params(Id);
format_json_rpc_call(Method, 2, Param, Timeout, Id) ->
Arg1 = convert_json_to_term(Method, Param),
try cloudi_service_api_call(Method, Arg1, Timeout) of
Result ->
ResultJSON = convert_term_to_json(Result, Method, false),
cloudi_json_rpc:response_to_json(ResultJSON, Id)
catch
exit:invalid_input ->
<<>>;
ErrorType:Error ->
?LOG_DEBUG("~p ~p", [ErrorType, Error]),
<<>>
end.
cloudi_service_api_call(Method, Timeout) ->
convert_api_data(Method, cloudi_service_api:Method(Timeout)).
cloudi_service_api_call(_, invalid, _) ->
erlang:exit(invalid_input);
cloudi_service_api_call(Method, Input, Timeout) ->
convert_api_data(Method, cloudi_service_api:Method(Input, Timeout)).
convert_api_data(Method,
{ok, L})
when Method =:= services;
Method =:= services_search;
Method =:= services_status ->
{ok, [{service_id(ID), Data} || {ID, Data} <- L]};
convert_api_data(code_status,
{ok, Status}) ->
{runtime_cloudi_changes,
RuntimeChanges} = lists:keyfind(runtime_cloudi_changes, 1, Status),
RuntimeChangesNew = lists:map(fun(RuntimeChange) ->
{service_ids,
IDs} = lists:keyfind(service_ids, 1, RuntimeChange),
lists:keyreplace(service_ids, 1, RuntimeChange,
{service_ids, [service_id(ID) || ID <- IDs]})
end, RuntimeChanges),
StatusNew = lists:keyreplace(runtime_cloudi_changes, 1, Status,
{runtime_cloudi_changes,
RuntimeChangesNew}),
{ok, StatusNew};
convert_api_data(services_add,
{ok, L}) ->
{ok, [service_id(ID) || ID <- L]};
convert_api_data(services_update,
{ok, SuccessSet}) ->
{ok, [[service_id(ID) || ID <- L] || L <- SuccessSet]};
convert_api_data(services_update,
{error, {ErrorL, Reason}, SuccessSet}) ->
{error,
{[service_id(ID) || ID <- ErrorL], Reason},
[[service_id(ID) || ID <- L] || L <- SuccessSet]};
convert_api_data(_Method, Result) ->
Result.
convert_erlang_to_term(Request) ->
try cloudi_string:binary_to_term(Request)
catch
_:_ ->
invalid
end.
convert_term_to_erlang(Result) ->
convert_term_to_erlang(Result, true).
convert_term_to_erlang({ok, Result}, Space) ->
convert_term_to_erlang_string(Result, Space);
convert_term_to_erlang(Result, Space) ->
convert_term_to_erlang_string(Result, Space).
convert_term_to_erlang_string(Result, true) ->
cloudi_string:format_to_binary("~p", [Result]);
convert_term_to_erlang_string(Result, false) ->
cloudi_string:term_to_binary_compact(Result).
convert_json_to_term(Method, Request)
when Method =:= acl_add ->
case json_decode(Request) of
[_ | _] = L ->
convert_json_to_term_acl_add(L);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= acl_remove;
Method =:= nodes_status ->
case json_decode(Request) of
List when is_list(List) ->
convert_json_to_term_atoms_existing(List);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= service_subscriptions;
Method =:= logging_file_set;
Method =:= code_path_add;
Method =:= code_path_remove ->
case json_decode(Request) of
Binary when is_binary(Binary) ->
erlang:binary_to_list(Binary);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= services_add ->
case json_decode(Request) of
[_ | _] = L ->
convert_json_to_term_services(L);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= services_remove;
Method =:= services_restart;
Method =:= services_status ->
case json_decode(Request) of
List when is_list(List) ->
convert_json_to_term_strings(List);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= services_search ->
case json_decode(Request) of
Binary when is_binary(Binary) ->
erlang:binary_to_list(Binary);
[{ScopeBinary, NameBinary}]
when is_binary(ScopeBinary),
is_binary(NameBinary) ->
{erlang:binary_to_existing_atom(ScopeBinary, utf8),
erlang:binary_to_list(NameBinary)};
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= services_update ->
case json_decode(Request) of
List when is_list(List) ->
convert_json_to_term_updates(List);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= nodes_add;
Method =:= nodes_remove ->
case json_decode(Request) of
List when is_list(List) ->
convert_json_to_term_atoms(List);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= logging_level_set;
Method =:= logging_stdout_set ->
case json_decode(Request) of
Binary when is_binary(Binary) ->
erlang:binary_to_existing_atom(Binary, utf8);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= nodes_set;
Method =:= logging_set ->
case json_decode(Request) of
List when is_list(List) ->
convert_json_to_term_options(List);
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= logging_syslog_set;
Method =:= logging_formatters_set ->
case json_decode(Request) of
List when is_list(List) ->
convert_json_to_term_options(List);
<<"undefined">> ->
undefined;
_ ->
invalid
end;
convert_json_to_term(Method, Request)
when Method =:= logging_redirect_set ->
case json_decode(Request) of
Binary when is_binary(Binary) ->
erlang:binary_to_atom(Binary, utf8);
_ ->
invalid
end.
convert_json_to_term_acl_add(AddL) ->
convert_json_to_term_acl_add(AddL, []).
convert_json_to_term_acl_add([], L) ->
lists:reverse(L);
convert_json_to_term_acl_add([{KeyBinary, ValueL} | AddL], L) ->
Key = erlang:binary_to_atom(KeyBinary, utf8),
Value = if
is_binary(ValueL) ->
cloudi_string:binary_to_term(ValueL);
is_list(ValueL) ->
convert_json_to_term_strings(ValueL)
end,
convert_json_to_term_acl_add(AddL, [{Key, Value} | L]);
convert_json_to_term_acl_add([Unknown | AddL], L) ->
convert_json_to_term_acl_add(AddL, [Unknown | L]).
convert_json_to_term_services([]) ->
[];
convert_json_to_term_services([Service | L]) ->
[convert_json_to_term_service(Service) |
convert_json_to_term_services(L)].
convert_json_to_term_service(Service) ->
convert_json_to_term_service(Service, []).
convert_json_to_term_service([], L) ->
lists:reverse(L);
convert_json_to_term_service([{<<"type">>, TypeBinary} | Service], L) ->
Type = erlang:binary_to_existing_atom(TypeBinary, utf8),
convert_json_to_term_service(Service, [{type, Type} | L]);
convert_json_to_term_service([{<<"prefix">>, PrefixBinary} | Service], L) ->
Prefix = erlang:binary_to_list(PrefixBinary),
convert_json_to_term_service(Service, [{prefix, Prefix} | L]);
convert_json_to_term_service([{<<"module">>, ModuleBinary} | Service], L) ->
Module = case erlang:binary_to_list(ModuleBinary) of
[$' | ModuleName0] ->
[$' | ModuleNameN] = lists:reverse(ModuleName0),
erlang:list_to_atom(lists:reverse(ModuleNameN));
[$" | FileName0] ->
[$" | FileNameN] = lists:reverse(FileName0),
lists:reverse(FileNameN);
_ ->
erlang:binary_to_atom(ModuleBinary, utf8)
end,
convert_json_to_term_service(Service, [{module, Module} | L]);
convert_json_to_term_service([{<<"file_path">>, FileBinary} | Service], L) ->
FilePath = erlang:binary_to_list(FileBinary),
convert_json_to_term_service(Service, [{file_path, FilePath} | L]);
convert_json_to_term_service([{<<"args">>, ArgsBinary} | Service], L) ->
Args = case erlang:binary_to_list(ArgsBinary) of
[$[ | _] = ArgsList ->
cloudi_string:list_to_term(ArgsList);
ArgsString ->
ArgsString
end,
convert_json_to_term_service(Service, [{args, Args} | L]);
convert_json_to_term_service([{<<"env">>, EnvL} | Service], L)
when is_list(EnvL) ->
Env = [cloudi_string:splitl($=, erlang:binary_to_list(EnvString))
|| EnvString <- EnvL],
convert_json_to_term_service(Service, [{env, Env} | L]);
convert_json_to_term_service([{<<"dest_refresh">>, Binary} | Service], L) ->
DestRefresh = erlang:binary_to_existing_atom(Binary, utf8),
convert_json_to_term_service(Service, [{dest_refresh, DestRefresh} | L]);
convert_json_to_term_service([{<<"protocol">>, Binary} | Service], L) ->
Protocol = erlang:binary_to_existing_atom(Binary, utf8),
convert_json_to_term_service(Service, [{protocol, Protocol} | L]);
convert_json_to_term_service([{<<"buffer_size">>, Value} | Service], L) ->
BufferSize = if
Value == <<"default">> ->
default;
true ->
Value
end,
convert_json_to_term_service(Service, [{buffer_size, BufferSize} | L]);
convert_json_to_term_service([{<<"timeout_init">>, Value} | Service], L) ->
convert_json_to_term_service(Service, [{timeout_init, Value} | L]);
convert_json_to_term_service([{<<"timeout_async">>, Value} | Service], L) ->
convert_json_to_term_service(Service, [{timeout_async, Value} | L]);
convert_json_to_term_service([{<<"timeout_sync">>, Value} | Service], L) ->
convert_json_to_term_service(Service, [{timeout_sync, Value} | L]);
convert_json_to_term_service([{<<"dest_list_deny">>, DenyL} | Service], L) ->
Deny = if
is_binary(DenyL) ->
cloudi_string:binary_to_term(DenyL);
is_list(DenyL) ->
convert_json_to_term_strings(DenyL)
end,
convert_json_to_term_service(Service, [{dest_list_deny, Deny} | L]);
convert_json_to_term_service([{<<"dest_list_allow">>, AllowL} | Service], L) ->
Allow = if
is_binary(AllowL) ->
cloudi_string:binary_to_term(AllowL);
is_list(AllowL) ->
convert_json_to_term_strings(AllowL)
end,
convert_json_to_term_service(Service, [{dest_list_allow, Allow} | L]);
convert_json_to_term_service([{<<"count_process">>, Value} | Service], L) ->
convert_json_to_term_service(Service, [{count_process, Value} | L]);
convert_json_to_term_service([{<<"count_thread">>, Value} | Service], L) ->
convert_json_to_term_service(Service, [{count_thread, Value} | L]);
convert_json_to_term_service([{<<"max_r">>, Value} | Service], L) ->
convert_json_to_term_service(Service, [{max_r, Value} | L]);
convert_json_to_term_service([{<<"max_t">>, Value} | Service], L) ->
convert_json_to_term_service(Service, [{max_t, Value} | L]);
convert_json_to_term_service([{<<"options">>, OptionsL} | Service], L) ->
Options = if
is_binary(OptionsL) ->
cloudi_string:binary_to_term(OptionsL);
is_list(OptionsL) ->
convert_json_to_term_options(OptionsL)
end,
convert_json_to_term_service(Service, [{options, Options} | L]);
convert_json_to_term_service([Unknown | Service], L) ->
convert_json_to_term_service(Service, [Unknown | L]).
convert_json_to_term_updates([]) ->
[];
convert_json_to_term_updates([{ServiceId, Options} | Update]) ->
[{erlang:binary_to_list(ServiceId),
convert_json_to_term_options(Options)} |
convert_json_to_term_updates(Update)].
convert_json_to_term_options([]) ->
[];
convert_json_to_term_options([{Key, Value} | Options]) ->
[{erlang:binary_to_existing_atom(Key, utf8),
convert_json_to_term_option(Value)} |
convert_json_to_term_options(Options)].
convert_json_to_term_option(<<"#{", _/binary>> = Value) ->
cloudi_string:binary_to_term(Value);
convert_json_to_term_option(<<"[", _/binary>> = Value) ->
cloudi_string:binary_to_term(Value);
convert_json_to_term_option(<<"{", _/binary>> = Value) ->
cloudi_string:binary_to_term(Value);
convert_json_to_term_option(<<"\"", _/binary>> = Value) ->
cloudi_string:binary_to_term(Value);
convert_json_to_term_option(<<"'", _/binary>> = Value) ->
cloudi_string:binary_to_term(Value);
convert_json_to_term_option(Value)
when is_binary(Value) ->
erlang:binary_to_list(Value);
convert_json_to_term_option(Value)
when is_number(Value); is_boolean(Value) ->
Value;
convert_json_to_term_option(Value)
when is_list(Value) ->
convert_json_to_term_options(Value).
convert_json_to_term_strings([]) ->
[];
convert_json_to_term_strings([H | L])
when is_binary(H) ->
[erlang:binary_to_list(H) |
convert_json_to_term_strings(L)];
convert_json_to_term_strings([_ | _]) ->
invalid.
convert_json_to_term_atoms_existing([]) ->
[];
convert_json_to_term_atoms_existing([H | L])
when is_binary(H) ->
[erlang:binary_to_existing_atom(H, utf8) |
convert_json_to_term_atoms_existing(L)];
convert_json_to_term_atoms_existing([_ | _]) ->
invalid.
convert_json_to_term_atoms([]) ->
[];
convert_json_to_term_atoms([H | L])
when is_binary(H) ->
[erlang:binary_to_atom(H, utf8) |
convert_json_to_term_atoms(L)];
convert_json_to_term_atoms([_ | _]) ->
invalid.
convert_term_to_json(ok, _, Space) ->
json_encode([{<<"success">>, true}], Space);
convert_term_to_json({error, Reason}, _, Space) ->
ReasonBinary = cloudi_string:term_to_binary_compact(Reason),
json_encode([{<<"success">>, false},
{<<"error">>, ReasonBinary}], Space);
convert_term_to_json({error, {ErrorL, Reason}, SuccessL},
services_update, Space) ->
ReasonBinary = cloudi_string:term_to_binary_compact(Reason),
json_encode([{<<"success">>, false},
{<<"success_ids">>,
convert_term_to_json_strings(SuccessL)},
{<<"error">>, ReasonBinary},
{<<"error_ids">>,
convert_term_to_json_strings(ErrorL)}], Space);
convert_term_to_json({ok, Services}, Method, Space)
when Method =:= services;
Method =:= services_search ->
json_encode([{<<"success">>, true},
{erlang:atom_to_binary(Method, utf8),
[convert_term_to_json_service(Service, Id)
|| {Id, Service} <- Services]}], Space);
convert_term_to_json({ok, Statuses}, services_status = Method, Space) ->
json_encode([{<<"success">>, true},
{erlang:atom_to_binary(Method, utf8),
[[{<<"id">>, erlang:list_to_binary(Id)} |
convert_term_to_json_options(Status)]
|| {Id, Status} <- Statuses]}], Space);
convert_term_to_json({ok, SuccessL}, Method, Space)
when Method =:= services_add;
Method =:= services_update;
Method =:= code_path ->
json_encode([{<<"success">>, true},
{erlang:atom_to_binary(Method, utf8),
convert_term_to_json_strings(SuccessL)}], Space);
convert_term_to_json({ok, SuccessL}, Method, Space)
when Method =:= nodes;
Method =:= nodes_alive;
Method =:= nodes_dead ->
json_encode([{<<"success">>, true},
{erlang:atom_to_binary(Method, utf8),
convert_term_to_json_atoms(SuccessL)}], Space);
convert_term_to_json({ok, Statuses}, nodes_status = Method, Space) ->
json_encode([{<<"success">>, true},
{erlang:atom_to_binary(Method, utf8),
[[{<<"node">>, erlang:atom_to_binary(Node, utf8)} |
convert_term_to_json_options(Status)]
|| {Node, Status} <- Statuses]}], Space);
convert_term_to_json({ok, Options}, Method, Space)
when Method =:= acl;
Method =:= nodes_get;
Method =:= logging;
Method =:= code_status ->
json_encode([{<<"success">>, true},
{erlang:atom_to_binary(Method, utf8),
convert_term_to_json_options(Options)}], Space).
convert_term_to_json_service(#internal{prefix = Prefix,
module = Module,
args = Args,
dest_refresh = DestRefresh,
timeout_init = TimeoutInit,
timeout_async = TimeoutAsync,
timeout_sync = TimeoutSync,
dest_list_deny = DestListDeny,
dest_list_allow = DestListAllow,
count_process = CountProcess,
max_r = MaxR,
max_t = MaxT,
options = Options}, Id) ->
Service0 = [{<<"count_process">>, CountProcess},
{<<"max_r">>, MaxR},
{<<"max_t">>, MaxT},
{<<"options">>, convert_term_to_json_options(Options)}],
Service1 = if
DestListAllow =:= undefined ->
Service0;
is_list(DestListAllow) ->
[{<<"dest_list_allow">>,
[erlang:list_to_binary(DestAllow)
|| DestAllow <- DestListAllow]} | Service0]
end,
Service2 = if
DestListDeny =:= undefined ->
Service1;
is_list(DestListDeny) ->
[{<<"dest_list_deny">>,
[erlang:list_to_binary(DestDeny)
|| DestDeny <- DestListDeny]} | Service1]
end,
Service3 = [{<<"timeout_init">>, TimeoutInit},
{<<"timeout_async">>, TimeoutAsync},
{<<"timeout_sync">>, TimeoutSync} | Service2],
ServiceN = if
DestRefresh =:= none ->
Service3;
is_atom(DestRefresh) ->
[{<<"dest_refresh">>,
erlang:atom_to_binary(DestRefresh, utf8)} | Service3]
end,
[{<<"id">>, erlang:list_to_binary(Id)},
{<<"type">>, <<"internal">>},
{<<"prefix">>, erlang:list_to_binary(Prefix)},
{<<"module">>, erlang:atom_to_binary(Module, utf8)},
{<<"args">>, cloudi_string:term_to_binary_compact(Args)} | ServiceN];
convert_term_to_json_service(#external{prefix = Prefix,
file_path = FilePath,
args = Args,
env = Env,
dest_refresh = DestRefresh,
protocol = Protocol,
buffer_size = BufferSize,
timeout_init = TimeoutInit,
timeout_async = TimeoutAsync,
timeout_sync = TimeoutSync,
dest_list_deny = DestListDeny,
dest_list_allow = DestListAllow,
count_process = CountProcess,
count_thread = CountThread,
max_r = MaxR,
max_t = MaxT,
options = Options}, Id) ->
Service0 = [{<<"count_process">>, CountProcess},
{<<"count_thread">>, CountThread},
{<<"max_r">>, MaxR},
{<<"max_t">>, MaxT},
{<<"options">>, convert_term_to_json_options(Options)}],
Service1 = if
DestListAllow =:= undefined ->
Service0;
is_list(DestListAllow) ->
[{<<"dest_list_allow">>,
[erlang:list_to_binary(DestAllow)
|| DestAllow <- DestListAllow]} | Service0]
end,
Service2 = if
DestListDeny =:= undefined ->
Service1;
is_list(DestListDeny) ->
[{<<"dest_list_deny">>,
[erlang:list_to_binary(DestDeny)
|| DestDeny <- DestListDeny]} | Service1]
end,
Service3 = [{<<"protocol">>, erlang:atom_to_binary(Protocol, utf8)},
{<<"buffer_size">>, BufferSize},
{<<"timeout_init">>, TimeoutInit},
{<<"timeout_async">>, TimeoutAsync},
{<<"timeout_sync">>, TimeoutSync} | Service2],
ServiceN = if
DestRefresh =:= none ->
Service3;
is_atom(DestRefresh) ->
[{<<"dest_refresh">>,
erlang:atom_to_binary(DestRefresh, utf8)} | Service3]
end,
[{<<"id">>, erlang:list_to_binary(Id)},
{<<"type">>, <<"external">>},
{<<"prefix">>, erlang:list_to_binary(Prefix)},
{<<"file_path">>, erlang:list_to_binary(FilePath)},
{<<"args">>, erlang:list_to_binary(Args)},
{<<"env">>,
[erlang:list_to_binary(Key ++ "=" ++ Value)
|| {Key, Value} <- Env]} | ServiceN].
convert_term_to_json_option([] = Value) ->
Value;
convert_term_to_json_option([{Key, _} | _] = Value)
when is_atom(Key) ->
convert_term_to_json_options(Value);
convert_term_to_json_option([[{Key, _} | _] | _] = Value)
when is_atom(Key) ->
[convert_term_to_json_options(Options)
|| Options <- Value];
convert_term_to_json_option([H | _] = Value)
when is_integer(H), H > 0 ->
erlang:list_to_binary(Value);
convert_term_to_json_option([[H | _] | _] = Value)
when is_integer(H), H > 0 ->
convert_term_to_json_strings(Value);
convert_term_to_json_option([A | _] = Value)
when is_atom(A) ->
convert_term_to_json_atoms(Value);
convert_term_to_json_option([_ | _] = Value) ->
cloudi_string:term_to_binary_compact(Value);
convert_term_to_json_option(Value)
when is_number(Value) ->
Value;
convert_term_to_json_option(Value)
when is_atom(Value) ->
if
is_boolean(Value) ->
Value;
true ->
erlang:atom_to_binary(Value, utf8)
end;
convert_term_to_json_option(Value)
when is_tuple(Value); is_map(Value) ->
cloudi_string:term_to_binary_compact(Value).
convert_term_to_json_options([]) ->
[];
convert_term_to_json_options([{Key, Value} | Options]) ->
[{erlang:atom_to_binary(Key, utf8),
convert_term_to_json_option(Value)} |
convert_term_to_json_options(Options)].
convert_term_to_json_strings([]) ->
[];
convert_term_to_json_strings([S | L]) ->
[erlang:list_to_binary(S) |
convert_term_to_json_strings(L)].
convert_term_to_json_atoms([]) ->
[];
convert_term_to_json_atoms([A | L]) ->
[erlang:atom_to_binary(A, utf8) |
convert_term_to_json_atoms(L)].
json_encode(Term, true) ->
jsx:encode(Term, [{indent, 1}]);
json_encode(Term, false) ->
jsx:encode(Term).
json_decode(Binary) ->
try jsx:decode(Binary)
catch
_:_ ->
invalid
end.
service_id(ID) ->
uuid:uuid_to_string(ID, list_nodash).