152 lines
4.3 KiB
Erlang
152 lines
4.3 KiB
Erlang
%% The contents of this file are subject to the Mozilla Public License
|
|
%% Version 1.1 (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.mozilla.org/MPL/
|
|
%%
|
|
%% Copyright (c) 2015 Petr Gotthard <petr.gotthard@centrum.cz>
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2017-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
|
%%
|
|
%% Licensed 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.
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% convenience functions for message construction
|
|
-module(emqx_coap_message).
|
|
|
|
-export([
|
|
request/2, request/3, request/4,
|
|
ack/1,
|
|
response/1, response/2,
|
|
reset/1,
|
|
piggyback/2, piggyback/3,
|
|
response/3
|
|
]).
|
|
|
|
-export([is_request/1]).
|
|
|
|
-export([
|
|
set/3,
|
|
set_payload/2,
|
|
get_option/2,
|
|
get_option/3,
|
|
set_payload_block/3, set_payload_block/4
|
|
]).
|
|
|
|
-include("emqx_coap.hrl").
|
|
|
|
request(Type, Method) ->
|
|
request(Type, Method, <<>>, []).
|
|
|
|
request(Type, Method, Payload) ->
|
|
request(Type, Method, Payload, []).
|
|
|
|
request(Type, Method, Payload, Options) when is_binary(Payload) ->
|
|
#coap_message{
|
|
type = Type,
|
|
method = Method,
|
|
payload = Payload,
|
|
options = to_options(Options)
|
|
}.
|
|
|
|
ack(#coap_message{id = Id}) ->
|
|
#coap_message{type = ack, id = Id}.
|
|
|
|
reset(#coap_message{id = Id}) ->
|
|
#coap_message{type = reset, id = Id}.
|
|
|
|
%% just make a response
|
|
response(Request) ->
|
|
response(undefined, Request).
|
|
|
|
response(Method, Request) ->
|
|
response(Method, <<>>, Request).
|
|
|
|
response(Method, Payload, #coap_message{
|
|
type = Type,
|
|
id = Id,
|
|
token = Token
|
|
}) ->
|
|
#coap_message{
|
|
type = Type,
|
|
id = Id,
|
|
token = Token,
|
|
method = Method,
|
|
payload = Payload
|
|
}.
|
|
|
|
%% make a response which maybe is a piggyback ack
|
|
piggyback(Method, Request) ->
|
|
piggyback(Method, <<>>, Request).
|
|
|
|
piggyback(Method, Payload, Request) ->
|
|
Reply = response(Method, Payload, Request),
|
|
case Reply of
|
|
#coap_message{type = con} ->
|
|
Reply#coap_message{type = ack};
|
|
_ ->
|
|
Reply
|
|
end.
|
|
|
|
%% omit option for its default value
|
|
set(max_age, ?DEFAULT_MAX_AGE, Msg) ->
|
|
Msg;
|
|
%% set non-default value
|
|
set(Option, Value, Msg = #coap_message{options = Options}) ->
|
|
Msg#coap_message{options = Options#{Option => Value}}.
|
|
|
|
get_option(Option, Msg) ->
|
|
get_option(Option, Msg, undefined).
|
|
|
|
get_option(Option, #coap_message{options = Options}, Def) ->
|
|
maps:get(Option, Options, Def).
|
|
|
|
set_payload(Payload, Msg) when is_binary(Payload) ->
|
|
Msg#coap_message{payload = Payload};
|
|
set_payload(Payload, Msg) when is_list(Payload) ->
|
|
Msg#coap_message{payload = list_to_binary(Payload)}.
|
|
|
|
set_payload_block(Content, Block, Msg = #coap_message{method = Method}) when is_atom(Method) ->
|
|
set_payload_block(Content, block1, Block, Msg);
|
|
set_payload_block(Content, Block, Msg = #coap_message{}) ->
|
|
set_payload_block(Content, block2, Block, Msg).
|
|
|
|
set_payload_block(Content, BlockId, {Num, _, Size}, Msg) ->
|
|
ContentSize = erlang:byte_size(Content),
|
|
OffsetBegin = Size * Num,
|
|
OffsetEnd = OffsetBegin + Size,
|
|
case ContentSize > OffsetEnd of
|
|
true ->
|
|
set(
|
|
BlockId,
|
|
{Num, true, Size},
|
|
set_payload(binary:part(Content, OffsetBegin, Size), Msg)
|
|
);
|
|
_ ->
|
|
set(
|
|
BlockId,
|
|
{Num, false, Size},
|
|
set_payload(binary:part(Content, OffsetBegin, ContentSize - OffsetBegin), Msg)
|
|
)
|
|
end.
|
|
|
|
is_request(#coap_message{method = Method}) when is_atom(Method) ->
|
|
Method =/= undefined;
|
|
is_request(_) ->
|
|
false.
|
|
|
|
to_options(Opts) when is_map(Opts) ->
|
|
Opts;
|
|
to_options(Opts) ->
|
|
maps:from_list(Opts).
|