You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
5.2 KiB

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "debuglog.h"
#include "json.h"
#include "route_config_parse.h"
#include "tenant_config.h"
static const char *tenant_config_json_keys[tenant_config_member_len] = { "name", "port", "replenishment-period-us",
"max-budget-us", "routes" };
static inline int
tenant_config_set_key_once(bool *did_set, enum tenant_config_member member)
{
if (did_set[member]) {
debuglog("Redundant key %s\n", tenant_config_json_keys[member]);
return -1;
}
did_set[member] = true;
return 0;
}
static inline int
tenant_config_parse(struct tenant_config *config, const char *json_buf, jsmntok_t *tokens, size_t tokens_base,
int tokens_size)
{
int i = tokens_base;
char key[32] = { 0 };
bool did_set[tenant_config_member_len] = { false };
if (!has_valid_type(tokens[i], "Anonymous Tenant Config Object", JSMN_OBJECT, json_buf)) return -1;
if (!is_nonempty_object(tokens[i], "Anonymous Tenant Config Object")) return -1;
int tenant_key_count = tokens[i].size;
for (int tenant_key_idx = 0; tenant_key_idx < tenant_key_count; tenant_key_idx++) {
/* Advance to key */
i++;
if (!is_valid_key(tokens[i])) return -1;
if (!has_valid_size(tokens[i], key, 1)) return -1;
/* Copy Key */
sprintf(key, "%.*s", tokens[i].end - tokens[i].start, json_buf + tokens[i].start);
/* Advance to Value */
i++;
if (strcmp(key, tenant_config_json_keys[tenant_config_member_name]) == 0) {
if (!is_nonempty_string(tokens[i], key)) return -1;
if (tenant_config_set_key_once(did_set, tenant_config_member_name) == -1) return -1;
config->name = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start);
} else if (strcmp(key, tenant_config_json_keys[tenant_config_member_port]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (tenant_config_set_key_once(did_set, tenant_config_member_port) == -1) return -1;
int rc = parse_uint16_t(tokens[i], json_buf, tenant_config_json_keys[tenant_config_member_port],
&config->port);
if (rc < 0) return -1;
} else if (strcmp(key, tenant_config_json_keys[tenant_config_member_replenishment_period_us]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (tenant_config_set_key_once(did_set, tenant_config_member_replenishment_period_us) == -1)
return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
tenant_config_json_keys[tenant_config_member_replenishment_period_us],
&config->replenishment_period_us);
if (rc < 0) return -1;
} else if (strcmp(key, tenant_config_json_keys[tenant_config_member_max_budget_us]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (tenant_config_set_key_once(did_set, tenant_config_member_max_budget_us) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
tenant_config_json_keys[tenant_config_member_max_budget_us],
&config->max_budget_us);
if (rc < 0) return -1;
} else if (strcmp(key, tenant_config_json_keys[tenant_config_member_routes]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_ARRAY, json_buf)) return -1;
if (tenant_config_set_key_once(did_set, tenant_config_member_routes) == -1) return -1;
int routes_len = tokens[i].size;
config->routes_len = routes_len;
config->routes = (struct route_config *)calloc(routes_len, sizeof(struct route_config));
for (int route_idx = 0; route_idx < routes_len; route_idx++) {
/* Advance to object */
i++;
i = route_config_parse(&(config->routes)[route_idx], json_buf, tokens, i, tokens_size);
if (i == -1) return -1;
}
} else {
fprintf(stderr, "%s is not a valid key\n", key);
return -1;
}
}
if (tenant_config_validate(config, did_set) < 0) return -1;
#ifdef LOG_TENANT_LOADING
tenant_config_print(config);
#endif
return i;
}
/* Tenant Config Vec */
static inline int
tenant_config_vec_parse(struct tenant_config **tenant_config_vec, int *tenant_config_vec_len, const char *json_buf,
jsmntok_t *tokens, size_t tokens_base, int tokens_size)
{
int i = tokens_base;
if (tokens[i].type != JSMN_ARRAY) {
fprintf(stderr, "Outermost Config should be a JSON array, was a JSON %s\n", jsmn_type(tokens[0].type));
return -1;
}
*tenant_config_vec_len = tokens[i].size;
if (tenant_config_vec_len == 0) {
fprintf(stderr, "Config is an empty JSON array\n");
return -1;
}
*tenant_config_vec = (struct tenant_config *)calloc((size_t)(*tenant_config_vec_len),
sizeof(struct tenant_config));
if (*tenant_config_vec == NULL) {
perror("Failed to allocate vec");
return -1;
}
#ifdef LOG_TENANT_LOADING
fprintf(stderr, "Tenants Size: %d\n", *tenant_config_vec_len);
#endif
for (int tenant_idx = 0; tenant_idx < *tenant_config_vec_len; tenant_idx++) {
i++;
i = tenant_config_parse(&((*tenant_config_vec)[tenant_idx]), json_buf, tokens, i, tokens_size);
if (i == -1) return -1;
}
return i;
}