Skip to content

Commit

Permalink
[coap] Better support for nested parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Jun 27, 2024
1 parent 1d6de19 commit b1f73d6
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 8 deletions.
33 changes: 29 additions & 4 deletions src/ossia/protocols/coap/coap_client_protocol.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "coap_client_protocol.hpp"


#include <ossia/network/base/node.hpp>
#include <ossia/network/base/node_functions.hpp>
#include <ossia/network/base/parameter.hpp>
#include <ossia/network/common/complex_type.hpp>
#include <ossia/protocols/coap/link_format_parser.hpp>
Expand Down Expand Up @@ -424,20 +426,38 @@ bool coap_client_protocol::observe(ossia::net::parameter_base& param, bool obs)
}

void coap_client_protocol::parse_namespace(
ossia::net::node_base& dev, std::string_view data)
ossia::net::node_base& parent, std::string_view data)
{
if(auto res = ossia::coap::parse_link_format(data))
{
for(const auto& [name, opts] : res->resources)
{
ossia::create_parameter(dev, name, "string");
// If answer is in link format, make a new request
if(auto it = opts.find("ct"); it != opts.end())
{
if(auto val = get_if<int64_t>(&it->second); val && *val == 40)
{
// Note : CoAP always gives absolute paths, e.g. given:
// GET coap://coap.me/location1
// =>
// </location1/location2>;...

ossia::net::create_node(parent, name);
request_namespace(parent, m_host + name);
continue;
}
}

ossia::create_parameter(parent, name, "string");
}
}
}
bool coap_client_protocol::update(ossia::net::node_base& node_base)

void coap_client_protocol::request_namespace(
ossia::net::node_base& node_base, std::string_view r)
{
auto req = m_client->get(
m_host + "/.well-known/core",
r,
[this,
&node_base](const coap_pdu_t* received, coap_mid_t mid) -> coap_reply_action {
size_t len;
Expand All @@ -452,6 +472,11 @@ bool coap_client_protocol::update(ossia::net::node_base& node_base)

return coap_reply_action::DeleteSession;
});
}

bool coap_client_protocol::update(ossia::net::node_base& node_base)
{
request_namespace(node_base, m_host + "/.well-known/core");
return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/ossia/protocols/coap/coap_client_protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class OSSIA_EXPORT coap_client_protocol
void stop() override;

private:
void request_namespace(ossia::net::node_base& root, std::string_view req);
void parse_namespace(ossia::net::node_base& dev, std::string_view data);

ossia::net::network_context_ptr m_context;
Expand Down
75 changes: 71 additions & 4 deletions src/ossia/protocols/coap/link_format_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,85 @@

#include <boost/spirit/home/x3.hpp>

#include <QDebug>

namespace ossia::coap
{

namespace
{
static void decode_uri(const char* src, int src_n, char* dst, int dst_n) noexcept
{
static constexpr auto digit = [](char c) constexpr {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
};

char a{}, b{};
while(src_n > 2 && dst_n > 0)
{
if((*src == '%') && ((a = src[1]) && (b = src[2])) && (digit(a) && digit(b)))
{
if(a >= 'a')
a -= 'a' - 'A';
if(a >= 'A')
a -= ('A' - 10);
else
a -= '0';
if(b >= 'a')
b -= 'a' - 'A';
if(b >= 'A')
b -= ('A' - 10);
else
b -= '0';
*dst++ = 16 * a + b;
dst_n--;
src += 3;
src_n -= 3;
}
else if(*src == '+')
{
*dst++ = ' ';
dst_n--;
src++;
src_n--;
}
else
{
*dst++ = *src++;
src_n--;
dst_n--;
}
}

while(src_n > 0 && dst_n > 0)
{
if(*src == '+')
{
*dst++ = ' ';
src++;
}
else
{
*dst++ = *src++;
}
dst_n--;
src_n--;
}
*dst++ = '\0';
}

struct actions
{
link_format res;
link_format::resource cur_resource;

void begin_resource(std::string x)
void begin_resource(std::string_view x)
{
cur_resource = {.path = std::move(x), .options = {}};
static thread_local std::string temp;
temp.clear();
temp.resize(x.size() * 3 + 16);
decode_uri(x.data(), x.size(), temp.data(), temp.size());
cur_resource = {.path = std::string(temp.data()), .options = {}};
}

void end_resource(const auto&...)
Expand Down Expand Up @@ -56,13 +122,13 @@ template <typename T> struct as_type {
};
static constexpr as_type<std::string> as_string{};

static const auto resource_identifier_char = x3::alnum | x3::char_('_') | x3::char_('/');
static const auto resource_identifier_char = x3::alnum | x3::char_('_') | x3::char_('/') | x3::char_('%') | x3::char_('-') | x3::char_('+');
static const auto resource_identifier = as_string(+resource_identifier_char);
static const auto resource_name = '<' >> resource_identifier[EVENT(begin_resource)] >> '>';

static const auto option_identifier_char = x3::alnum | x3::char_('_');
static const auto option_identifier = as_string(+option_identifier_char);
static const auto str_option = x3::lexeme['"' >> as_string(+(x3::char_ - '"')) >> '"'];
static const auto str_option = x3::lexeme['"' >> as_string(+((x3::char_ - '"') | x3::lit("\"\""))) >> '"'];
static const auto num_option = x3::int64;
static const auto option_value = (str_option | num_option);
static const auto option = (option_identifier >> -('=' >> option_value))[EVENT(pair_option)];
Expand All @@ -86,4 +152,5 @@ std::optional<ossia::coap::link_format> parse_link_format(std::string_view str)
return std::nullopt;
return std::move(r.res);
}

}

0 comments on commit b1f73d6

Please sign in to comment.