Skip to content

Commit

Permalink
Merge branch 'release/1.0.0-rc.27'
Browse files Browse the repository at this point in the history
  • Loading branch information
aramallo committed Nov 13, 2024
2 parents 1160219 + a5049e0 commit 6b4913d
Show file tree
Hide file tree
Showing 25 changed files with 432 additions and 78 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# CHANGELOG

## 1.0.0-rc.27
## Changes
* Moved json encoding to `bondy_json` module which now uses the new `json` moduled instead of `jsone` when running on OTP27. In addition, float and date formatting has been implemented to mirror those existing in `jsone`. Also the defaul float format respects the deprecated `jsx` lib format for backwards compatibility.
* A new option `serializers.json.float_format` has been added to `bondy.conf` that takes a string representation of the options supported by `erlang:float_to_bionary/2`.
* **NOTICE**: This only affects HTTP Gateway JSON encoding at the moment and not WAMP. This will be addressed in the next release.

## 1.0.0-rc.26
### Fixes
* Fixed bug in password hash comparison for version 1.0 passwords (PR #40)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
![Docker Pulls](https://img.shields.io/docker/pulls/leapsight/bondy?style=for-the-badge)
![Docker Build (master)](https://img.shields.io/github/actions/workflow/status/bondy-io/bondy/docker_image_build.yaml?&branch=master&label=docker-master&style=for-the-badge)
![Docker Build (develop)](https://img.shields.io/github/actions/workflow/status/bondy-io/bondy/docker_image_build.yaml?&branch=develop&label=docker-develop&style=for-the-badge)
![Docker Build (latest-tag)](https://img.shields.io/github/actions/workflow/status/bondy-io/bondy/docker_image_build.yaml?&tag=version-1.0.0-rc.26&label=docker-1.0.0-rc.26&style=for-the-badge)
![Docker Build (latest-tag)](https://img.shields.io/github/actions/workflow/status/bondy-io/bondy/docker_image_build.yaml?&tag=version-1.0.0-rc.27&label=docker-1.0.0-rc.27&style=for-the-badge)
<br>![Architectures](https://img.shields.io/badge/architecture-linux%2Famd64%20%7C%20linux%2Farm64%20%7C%20macOS%2Fintel%20%7C%20macOS%2FM1-lightgrey?style=for-the-badge)


Expand Down Expand Up @@ -158,7 +158,7 @@ make release
Untar and copy the resulting tarball to the location where you want to install Bondy e.g. `~/tmp/bondy`.

```shell
tar -zxvf _build/prod/rel/bondy-1.0.0-rc.26.tar.qz -C ~/tmp/bondy
tar -zxvf _build/prod/rel/bondy-1.0.0-rc.27.tar.qz -C ~/tmp/bondy
```

#### Running
Expand Down
4 changes: 2 additions & 2 deletions apps/bondy/src/bondy.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
"Bondy implements the open Web Application Messaging Protocol (WAMP) "
"and is written in Erlang."
},
{vsn, "1.0.0-rc.26"},
{vsn, "1.0.0-rc.27"},
{registered, []},
%% We pass the version number in the bondy_app:start/2 arguments
{mod, {bondy_app, [{vsn, "1.0.0-rc.26"}]}},
{mod, {bondy_app, [{vsn, "1.0.0-rc.27"}]}},
{applications,[
%% Erlang/OTP
stdlib,
Expand Down
2 changes: 1 addition & 1 deletion apps/bondy/src/bondy_auth_wamp_cra.erl
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ challenge(_, Ctxt, #{password := PWD} = State) ->
bondy_auth:session_id(Ctxt)
),
Microsecs = erlang:system_time(microsecond),
Challenge = jsone:encode(#{
Challenge = bondy_json:encode(#{
authid => UserId,
authrole => Role,
authmethod => ?WAMP_CRA_AUTH,
Expand Down
2 changes: 1 addition & 1 deletion apps/bondy/src/bondy_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ set_vsn(Args) ->

%% @private
setup_mods() ->
ok = bondy_json:setup(),
ok = jose:json_module(bondy_json),
ok = configure_registry(),
ok = configure_jobs_pool().

Expand Down
265 changes: 255 additions & 10 deletions apps/bondy/src/bondy_json.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,283 @@
%% =============================================================================

%% -----------------------------------------------------------------------------
%% @doc A utiliy module use to customised the JSON encoding for 3rd-party libs
%% @doc A utility module use to customised the JSON encoding for 3rd-party libs
%% e.g. erlang_jose
%% @end
%% -----------------------------------------------------------------------------
-module(bondy_json).

-export([setup/0]).
%% For backwards compat with jsx lib default
-define(DEFAULT_FLOAT_FORMAT, [{decimals, 16}]).
-define(DEFAULT_ENCODE_OPTS, [{float_format, ?DEFAULT_FLOAT_FORMAT}]).

-if(?OTP_RELEASE >= 27).

-define(IS_UINT(X), (is_integer(X) andalso X >= 0)).
-define(IS_PNUM(X), (is_number(X) andalso X >= 0)).
-define(IS_DATETIME(Y, M, D, H, Mi, S),
(
?IS_UINT(Y) andalso
?IS_UINT(M) andalso
?IS_UINT(D) andalso
?IS_UINT(H) andalso
?IS_UINT(Mi) andalso
?IS_PNUM(S)
)
).

-define(SECONDS_PER_MINUTE, 60).
-define(SECONDS_PER_HOUR, 3600).

-endif.

-type encode_opt() :: {float_format, [float_format()]}.

%% idem erlang:float_to_binary/2 options
-type float_format() :: {scientific, Decimals :: 0..249}
| {decimals, Decimals :: 0..253}
| compact
| short.

-export([decode/1]).
-export([decode/2]).
-export([encode/1]).
-export([encode/2]).
-export([try_decode/1]).
-export([try_decode/2]).
-export([validate_opts/1]).


%% =============================================================================
%% BONDY_CONFIG_MANAGER CALLBACKS
%% API
%% =============================================================================
-spec encode(any()) -> binary().

encode(Term) ->
encode(Term, bondy_config:get(json, ?DEFAULT_ENCODE_OPTS)).


-spec encode(any(), [encode_opt()]) -> iodata() | binary().

encode(Term, Opts) ->
FloatOpts = float_opts(validate_opts(Opts)),
do_encode(Term, FloatOpts).


decode(Term) ->
decode(Term, []).


decode(Term, Opts) ->
do_decode(Term, Opts).


try_decode(Term) ->
try_decode(Term, []).


try_decode(Term, Opts) ->
try
{ok, decode(Term, Opts)}
catch
_:Reason ->
{error, Reason}
end.


setup() ->
jose:json_module(?MODULE).
validate_opts(List) when is_list(List) ->
lists:map(fun validate_opt/1, List).



%% =============================================================================
%% JOSE CALLBACKS
%% PRIVATE
%% =============================================================================


encode(Bin) ->
jsone:encode(Bin, [
%% @private
float_opts(Opts) ->
case lists:keyfind(float_format, 1, Opts) of
{float_format, FloatOpts} when is_list(FloatOpts) ->
FloatOpts;
false ->
?DEFAULT_FLOAT_FORMAT
end.


validate_opt({float_format, Opts}) ->
{float_format, validate_float_opts(Opts)};

validate_opt({datetime_format, _Opts} = Term) ->
%% TODO
Term.


validate_float_opts(Opts) ->
lists:map(fun validate_float_opt/1, Opts).

validate_float_opt({scientific, Decimals} = Term)
when is_integer(Decimals), Decimals >= 0, Decimals =< 249 ->
Term;

validate_float_opt({scientific, Decimals})
when is_integer(Decimals), Decimals >= 0 ->
%% Coerce to max
{scientific, 249};

validate_float_opt({decimals, Decimals} = Term)
when is_integer(Decimals), Decimals >= 0, Decimals =< 253 ->
Term;

validate_float_opt(compact = Term) ->
Term;

validate_float_opt(short = Term) ->
Term;

validate_float_opt(Arg) ->
error(badarg, {float_format, Arg}).


-if(?OTP_RELEASE >= 27).

do_encode(Term, FloatOpts) ->
json:encode(Term, fun
(undefined, _Encode) ->
<<"null">>;

(Value, _Encode) when is_float(Value) ->
float_to_binary(Value, FloatOpts);

({{Y, M, D}, {H, Mi, S}}, _Encode)
when ?IS_DATETIME(Y, M, D, H, Mi, S) ->
encode_datetime({{Y, M, D}, {H, Mi, S}});

(Value, Encode) ->
json:encode_value(Value, Encode)
end).

do_decode(Term, _Opts) ->
json:decode(Term).

-else.

do_encode(Term, FloatOpts) ->
jsone:encode(Term, [
undefined_as_null,
{float_format, FloatOpts},
{datetime_format, iso8601},
{object_key_type, string}
]).

do_decode(Term, _Opts) ->
jsone:decode(Term, [
undefined_as_null,
{object_format, map}
]).

-endif.









-if(?OTP_RELEASE >= 27).

%% =============================================================================
%% PRIVATE - BORROWED FROM JSONE LIBRARY
%%
%% Copyright (c) 2013-2016, Takeru Ohta <[email protected]>
%%
%% The MIT License
%%
%% 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.
%%
%% =============================================================================

-spec encode_datetime(calendar:datetime()) -> iodata().

encode_datetime({{Y, M, D}, {H, Mi, S}}) ->
[
format_year(Y), $-,
format2digit(M), $-,
format2digit(D), $T,
format2digit(H), $:,
format2digit(Mi), $:,
format_seconds(S), $Z
].


-spec format_year(non_neg_integer()) -> iodata().

format_year(Y) when Y > 999 ->
integer_to_binary(Y);

format_year(Y) ->
B = integer_to_binary(Y),
[lists:duplicate(4 - byte_size(B), $0) | B].


-spec format2digit(non_neg_integer()) -> iolist().

format2digit(0) ->
"00";
format2digit(1) ->
"01";
format2digit(2) ->
"02";
format2digit(3) ->
"03";
format2digit(4) ->
"04";
format2digit(5) ->
"05";
format2digit(6) ->
"06";
format2digit(7) ->
"07";
format2digit(8) ->
"08";
format2digit(9) ->
"09";
format2digit(X) ->
integer_to_list(X).


-spec format_seconds(non_neg_integer() | float()) -> iolist().

format_seconds(S) when is_integer(S) ->
format2digit(S);

format_seconds(S) when is_float(S) ->
io_lib:format("~6.3.0f", [S]).


%% -spec format_tz_(integer()) -> iolist().
%% format_tz_(S) ->
%% H = S div ?SECONDS_PER_HOUR,
%% S1 = S rem ?SECONDS_PER_HOUR,
%% M = S1 div ?SECONDS_PER_MINUTE,
%% [format2digit(H), $:, format2digit(M)].

decode(Bin) ->
jsone:decode(Bin, [undefined_as_null]).
-endif.
Loading

0 comments on commit 6b4913d

Please sign in to comment.