Skip to content

Commit

Permalink
Add getters and versioned API to DynamicJSEndpointRegistry (#6234)
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyashton authored Jun 7, 2024
1 parent 3ba5e01 commit e7464e4
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 61 deletions.
3 changes: 2 additions & 1 deletion include/ccf/js/bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ namespace ccf::js
{
struct Metadata
{
// Path -> {HTTP Method -> Properties}
std::map<
std::string,
ccf::endpoints::URI,
std::map<std::string, ccf::endpoints::EndpointProperties>>
endpoints;
};
Expand Down
28 changes: 26 additions & 2 deletions include/ccf/js/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,32 @@ namespace ccf::js
* Call this to populate the KV with JS endpoint definitions, so they can
* later be dispatched to.
*/
void install_custom_endpoints(
ccf::endpoints::EndpointContext& ctx, const ccf::js::Bundle& bundle);
ccf::ApiResult install_custom_endpoints_v1(
kv::Tx& tx, const ccf::js::Bundle& bundle);

/**
* Retrieve all endpoint definitions currently in-use. This returns the same
* bundle written by a recent call to install_custom_endpoints. Note that
* some values (module paths, casing of HTTP methods) may differ slightly
* due to internal normalisation.
*/
ccf::ApiResult get_custom_endpoints_v1(
ccf::js::Bundle& bundle, kv::ReadOnlyTx& tx);

/**
* Retrieve property definition for a single JS endpoint.
*/
ccf::ApiResult get_custom_endpoint_properties_v1(
ccf::endpoints::EndpointProperties& properties,
kv::ReadOnlyTx& tx,
const ccf::RESTVerb& verb,
const ccf::endpoints::URI& uri);

/**
* Retrieve content of a single JS module.
*/
ccf::ApiResult get_custom_endpoint_module_v1(
std::string& code, kv::ReadOnlyTx& tx, const std::string& module_name);

/// \defgroup Overrides for base EndpointRegistry functions, looking up JS
/// endpoints before delegating to base implementation.
Expand Down
90 changes: 89 additions & 1 deletion samples/apps/basic/basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,18 @@ namespace basicapp
caller_identity.content.begin(), caller_identity.content.end());
const auto wrapper = j.get<ccf::js::Bundle>();

install_custom_endpoints(ctx, wrapper);
result = install_custom_endpoints_v1(ctx.tx, wrapper);
if (result != ccf::ApiResult::OK)
{
ctx.rpc_ctx->set_error(
HTTP_STATUS_INTERNAL_SERVER_ERROR,
ccf::errors::InternalError,
fmt::format(
"Failed to install endpoints: {}",
ccf::api_result_to_str(result)));
return;
}

ctx.rpc_ctx->set_response_status(HTTP_STATUS_NO_CONTENT);
};

Expand All @@ -167,6 +178,83 @@ namespace basicapp
{ccf::user_cose_sign1_auth_policy})
.set_auto_schema<ccf::js::Bundle, void>()
.install();

auto get_custom_endpoints = [this](ccf::endpoints::EndpointContext& ctx) {
ccf::js::Bundle bundle;

auto result = get_custom_endpoints_v1(bundle, ctx.tx);
if (result != ccf::ApiResult::OK)
{
ctx.rpc_ctx->set_error(
HTTP_STATUS_INTERNAL_SERVER_ERROR,
ccf::errors::InternalError,
fmt::format(
"Failed to get endpoints: {}", ccf::api_result_to_str(result)));
return;
}

ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
ctx.rpc_ctx->set_response_header(
http::headers::CONTENT_TYPE, http::headervalues::contenttype::JSON);
ctx.rpc_ctx->set_response_body(nlohmann::json(bundle).dump(2));
};

make_endpoint(
"/custom_endpoints",
HTTP_GET,
get_custom_endpoints,
{ccf::empty_auth_policy})
.set_auto_schema<void, ccf::js::Bundle>()
.install();

auto get_custom_endpoints_module =
[this](ccf::endpoints::EndpointContext& ctx) {
std::string module_name;

{
const auto parsed_query =
http::parse_query(ctx.rpc_ctx->get_request_query());

std::string error;
if (!http::get_query_value(
parsed_query, "module_name", module_name, error))
{
ctx.rpc_ctx->set_error(
HTTP_STATUS_BAD_REQUEST,
ccf::errors::InvalidQueryParameterValue,
std::move(error));
return;
}
}

std::string code;

auto result =
get_custom_endpoint_module_v1(code, ctx.tx, module_name);
if (result != ccf::ApiResult::OK)
{
ctx.rpc_ctx->set_error(
HTTP_STATUS_INTERNAL_SERVER_ERROR,
ccf::errors::InternalError,
fmt::format(
"Failed to get module: {}", ccf::api_result_to_str(result)));
return;
}

ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
ctx.rpc_ctx->set_response_header(
http::headers::CONTENT_TYPE,
http::headervalues::contenttype::JAVASCRIPT);
ctx.rpc_ctx->set_response_body(std::move(code));
};

make_endpoint(
"/custom_endpoints/modules",
HTTP_GET,
get_custom_endpoints_module,
{ccf::empty_auth_policy})
.add_query_parameter<std::string>("module_name")
.install();
}
};
}
Expand Down
Loading

0 comments on commit e7464e4

Please sign in to comment.