/deps/rabbit/src/rabbit_direct_reply_to.erl

https://github.com/rabbitmq/rabbitmq-server · Erlang · 78 lines · 45 code · 12 blank · 21 comment · 0 complexity · 44ee6a720a8c6f69d78bac9cf44cf764 MD5 · raw file

  1. %% This Source Code Form is subject to the terms of the Mozilla Public
  2. %% License, v. 2.0. If a copy of the MPL was not distributed with this
  3. %% file, You can obtain one at https://mozilla.org/MPL/2.0/.
  4. %%
  5. %% Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved.
  6. %%
  7. -module(rabbit_direct_reply_to).
  8. %% API
  9. -export([
  10. %% Original amq.rabbitmq.reply-to target channel encoding
  11. compute_key_and_suffix_v1/1,
  12. decode_reply_to_v1/1,
  13. %% v2 amq.rabbitmq.reply-to target channel encoding
  14. compute_key_and_suffix_v2/1,
  15. decode_reply_to_v2/2
  16. ]).
  17. %%
  18. %% API
  19. %%
  20. -type decoded_pid_and_key() :: {ok, pid(), binary()} | {error, any()}.
  21. -spec compute_key_and_suffix_v1(pid()) -> {binary(), binary()}.
  22. %% This original pid encoding function produces values that exceed routing key length limit
  23. %% on nodes with long (say, 130+ characters) node names.
  24. compute_key_and_suffix_v1(Pid) ->
  25. Key = base64:encode(rabbit_guid:gen()),
  26. PidEnc = base64:encode(term_to_binary(Pid)),
  27. Suffix = <<PidEnc/binary, ".", Key/binary>>,
  28. {Key, Suffix}.
  29. -spec decode_reply_to_v1(binary()) -> decoded_pid_and_key() | {error, any()}.
  30. decode_reply_to_v1(Bin) ->
  31. case string:lexemes(Bin, ".") of
  32. [PidEnc, Key] -> Pid = binary_to_term(base64:decode(PidEnc)),
  33. {ok, Pid, unicode:characters_to_binary(Key)};
  34. _ -> {error, unrecognized_format}
  35. end.
  36. -spec compute_key_and_suffix_v2(pid()) -> {binary(), binary()}.
  37. %% This pid encoding function produces values that are of mostly fixed size
  38. %% regardless of the node name length.
  39. compute_key_and_suffix_v2(Pid) ->
  40. Key = base64:encode(rabbit_guid:gen()),
  41. PidParts0 = #{node := Node} = pid_recomposition:decompose(Pid),
  42. %% Note: we hash the entire node name. This is sufficient for our needs of shortening node name
  43. %% in the TTB-encoded pid, and helps avoid doing the node name split for every single cluster member
  44. %% in rabbit_nodes:all_running_with_hashes/0.
  45. %%
  46. %% We also use a synthetic node prefix because the hash alone will be sufficient to
  47. NodeHash = erlang:phash2(Node),
  48. PidParts = maps:update(node, rabbit_nodes_common:make("reply", integer_to_list(NodeHash)), PidParts0),
  49. RecomposedEncoded = base64:encode(pid_recomposition:to_binary(PidParts)),
  50. Suffix = <<RecomposedEncoded/binary, ".", Key/binary>>,
  51. {Key, Suffix}.
  52. -spec decode_reply_to_v2(binary(), #{non_neg_integer() => node()}) -> decoded_pid_and_key() | {error, any()}.
  53. decode_reply_to_v2(Bin, CandidateNodes) ->
  54. case string:lexemes(Bin, ".") of
  55. [PidEnc, Key] ->
  56. RawPidBin = base64:decode(PidEnc),
  57. PidParts0 = #{node := ShortenedNodename} = pid_recomposition:from_binary(RawPidBin),
  58. {_, NodeHash} = rabbit_nodes_common:parts(ShortenedNodename),
  59. case maps:get(list_to_integer(NodeHash), CandidateNodes, undefined) of
  60. undefined -> error;
  61. Candidate ->
  62. PidParts = maps:update(node, Candidate, PidParts0),
  63. {ok, pid_recomposition:recompose(PidParts), unicode:characters_to_binary(Key)}
  64. end;
  65. _ -> {error, unrecognized_format}
  66. end.