chore: initial commit
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "domain.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "platform.h"
|
||||
|
||||
static const char *TAG = "domain_fortune_store";
|
||||
|
||||
/* NVS namespace + keys (<=15 chars). The platform layer owns the raw storage;
|
||||
* the domain serializes its typed records as opaque struct blobs. */
|
||||
#define DOMAIN_FORTUNE_NVS_NAMESPACE "fortune"
|
||||
#define DOMAIN_FORTUNE_KEY_PROFILE "profile"
|
||||
#define DOMAIN_FORTUNE_KEY_RESULT "result"
|
||||
|
||||
static domain_birth_profile_observer_t s_birth_observer;
|
||||
static void *s_birth_observer_user_data;
|
||||
static domain_birth_profile_t s_birth_profile;
|
||||
static bool s_birth_profile_loaded;
|
||||
static bool s_birth_profile_valid;
|
||||
static portMUX_TYPE s_birth_profile_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static domain_fortune_result_t s_fortune_result;
|
||||
static bool s_fortune_result_loaded;
|
||||
static bool s_fortune_result_valid;
|
||||
static portMUX_TYPE s_fortune_result_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static bool domain_birth_profile_is_valid(const domain_birth_profile_t *profile)
|
||||
{
|
||||
return profile != NULL &&
|
||||
profile->valid &&
|
||||
profile->year > 0 &&
|
||||
profile->month >= 1 && profile->month <= 12 &&
|
||||
profile->day >= 1 && profile->day <= 31 &&
|
||||
profile->hour >= 0 && profile->hour <= 23 &&
|
||||
profile->minute >= 0 && profile->minute <= 59 &&
|
||||
profile->birth_place[0] != '\0';
|
||||
}
|
||||
|
||||
static bool domain_fortune_result_is_valid(const domain_fortune_result_t *result)
|
||||
{
|
||||
return result != NULL &&
|
||||
result->valid &&
|
||||
result->bazi[0] != '\0' &&
|
||||
result->element[0] != '\0' &&
|
||||
result->lucky_color[0] != '\0' &&
|
||||
result->wealth_direction[0] != '\0' &&
|
||||
result->target_date[0] != '\0' &&
|
||||
result->wealth_direction_index < domain_get_direction_count();
|
||||
}
|
||||
|
||||
void domain_runtime_register_birth_profile_observer(domain_birth_profile_observer_t cb, void *user_data)
|
||||
{
|
||||
portENTER_CRITICAL(&s_birth_profile_lock);
|
||||
s_birth_observer = cb;
|
||||
s_birth_observer_user_data = user_data;
|
||||
portEXIT_CRITICAL(&s_birth_profile_lock);
|
||||
}
|
||||
|
||||
esp_err_t domain_birth_profile_store_set(const domain_birth_profile_t *profile)
|
||||
{
|
||||
if (!domain_birth_profile_is_valid(profile)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
domain_birth_profile_t snapshot = *profile;
|
||||
snapshot.birth_place[sizeof(snapshot.birth_place) - 1U] = '\0';
|
||||
snapshot.current_residence[sizeof(snapshot.current_residence) - 1U] = '\0';
|
||||
snapshot.mbti[sizeof(snapshot.mbti) - 1U] = '\0';
|
||||
snapshot.timezone[sizeof(snapshot.timezone) - 1U] = '\0';
|
||||
|
||||
esp_err_t err = platform_storage_set_blob(DOMAIN_FORTUNE_NVS_NAMESPACE,
|
||||
DOMAIN_FORTUNE_KEY_PROFILE,
|
||||
&snapshot,
|
||||
sizeof(snapshot));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
domain_birth_profile_observer_t cb = NULL;
|
||||
void *user_data = NULL;
|
||||
portENTER_CRITICAL(&s_birth_profile_lock);
|
||||
s_birth_profile = snapshot;
|
||||
s_birth_profile_loaded = true;
|
||||
s_birth_profile_valid = true;
|
||||
cb = s_birth_observer;
|
||||
user_data = s_birth_observer_user_data;
|
||||
portEXIT_CRITICAL(&s_birth_profile_lock);
|
||||
|
||||
if (cb != NULL) {
|
||||
cb(&snapshot, user_data);
|
||||
}
|
||||
ESP_LOGI(TAG, "Birth profile stored (%04d-%02d-%02d, %s)",
|
||||
snapshot.year, snapshot.month, snapshot.day, snapshot.birth_place);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool domain_birth_profile_store_get(domain_birth_profile_t *out_profile)
|
||||
{
|
||||
if (out_profile == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&s_birth_profile_lock);
|
||||
bool loaded = s_birth_profile_loaded;
|
||||
bool valid = s_birth_profile_valid;
|
||||
if (loaded && valid) {
|
||||
*out_profile = s_birth_profile;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_birth_profile_lock);
|
||||
if (loaded) {
|
||||
return valid;
|
||||
}
|
||||
|
||||
domain_birth_profile_t persisted = {0};
|
||||
size_t actual = 0U;
|
||||
esp_err_t err = platform_storage_get_blob(DOMAIN_FORTUNE_NVS_NAMESPACE,
|
||||
DOMAIN_FORTUNE_KEY_PROFILE,
|
||||
&persisted,
|
||||
sizeof(persisted),
|
||||
&actual);
|
||||
bool persisted_valid = err == ESP_OK &&
|
||||
actual == sizeof(persisted) &&
|
||||
domain_birth_profile_is_valid(&persisted);
|
||||
|
||||
portENTER_CRITICAL(&s_birth_profile_lock);
|
||||
if (!s_birth_profile_loaded) {
|
||||
s_birth_profile_loaded = true;
|
||||
s_birth_profile_valid = persisted_valid;
|
||||
if (persisted_valid) {
|
||||
s_birth_profile = persisted;
|
||||
}
|
||||
}
|
||||
valid = s_birth_profile_valid;
|
||||
if (valid) {
|
||||
*out_profile = s_birth_profile;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_birth_profile_lock);
|
||||
return valid;
|
||||
}
|
||||
|
||||
esp_err_t domain_fortune_result_store_set(const domain_fortune_result_t *result)
|
||||
{
|
||||
if (!domain_fortune_result_is_valid(result)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
domain_fortune_result_t snapshot = *result;
|
||||
snapshot.bazi[sizeof(snapshot.bazi) - 1U] = '\0';
|
||||
snapshot.element[sizeof(snapshot.element) - 1U] = '\0';
|
||||
snapshot.lucky_color[sizeof(snapshot.lucky_color) - 1U] = '\0';
|
||||
snapshot.wealth_direction[sizeof(snapshot.wealth_direction) - 1U] = '\0';
|
||||
snapshot.target_date[sizeof(snapshot.target_date) - 1U] = '\0';
|
||||
|
||||
esp_err_t err = platform_storage_set_blob(DOMAIN_FORTUNE_NVS_NAMESPACE,
|
||||
DOMAIN_FORTUNE_KEY_RESULT,
|
||||
&snapshot,
|
||||
sizeof(snapshot));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&s_fortune_result_lock);
|
||||
s_fortune_result = snapshot;
|
||||
s_fortune_result_loaded = true;
|
||||
s_fortune_result_valid = true;
|
||||
portEXIT_CRITICAL(&s_fortune_result_lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool domain_fortune_result_store_get(domain_fortune_result_t *out_result)
|
||||
{
|
||||
if (out_result == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&s_fortune_result_lock);
|
||||
bool loaded = s_fortune_result_loaded;
|
||||
bool valid = s_fortune_result_valid;
|
||||
if (loaded && valid) {
|
||||
*out_result = s_fortune_result;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_fortune_result_lock);
|
||||
if (loaded) {
|
||||
return valid;
|
||||
}
|
||||
|
||||
domain_fortune_result_t persisted = {0};
|
||||
size_t actual = 0U;
|
||||
esp_err_t err = platform_storage_get_blob(DOMAIN_FORTUNE_NVS_NAMESPACE,
|
||||
DOMAIN_FORTUNE_KEY_RESULT,
|
||||
&persisted,
|
||||
sizeof(persisted),
|
||||
&actual);
|
||||
bool persisted_valid = err == ESP_OK &&
|
||||
actual == sizeof(persisted) &&
|
||||
domain_fortune_result_is_valid(&persisted);
|
||||
|
||||
portENTER_CRITICAL(&s_fortune_result_lock);
|
||||
if (!s_fortune_result_loaded) {
|
||||
s_fortune_result_loaded = true;
|
||||
s_fortune_result_valid = persisted_valid;
|
||||
if (persisted_valid) {
|
||||
s_fortune_result = persisted;
|
||||
}
|
||||
}
|
||||
valid = s_fortune_result_valid;
|
||||
if (valid) {
|
||||
*out_result = s_fortune_result;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_fortune_result_lock);
|
||||
return valid;
|
||||
}
|
||||
|
||||
esp_err_t domain_fortune_result_store_clear(void)
|
||||
{
|
||||
esp_err_t err = platform_storage_erase(DOMAIN_FORTUNE_NVS_NAMESPACE,
|
||||
DOMAIN_FORTUNE_KEY_RESULT);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&s_fortune_result_lock);
|
||||
memset(&s_fortune_result, 0, sizeof(s_fortune_result));
|
||||
s_fortune_result_loaded = true;
|
||||
s_fortune_result_valid = false;
|
||||
portEXIT_CRITICAL(&s_fortune_result_lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "domain.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "esp_log.h"
|
||||
#include "platform.h"
|
||||
|
||||
static const char *TAG = "domain_user_web";
|
||||
static const char *kFortuneTimezone = "Asia/Shanghai";
|
||||
|
||||
extern const uint8_t user_config_html_start[]
|
||||
asm("_binary_user_config_html_start");
|
||||
extern const uint8_t user_config_html_end[]
|
||||
asm("_binary_user_config_html_end");
|
||||
|
||||
static bool is_leap_year(int year)
|
||||
{
|
||||
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
|
||||
}
|
||||
|
||||
static bool is_valid_date(int year, int month, int day)
|
||||
{
|
||||
static const uint8_t days_per_month[] = {
|
||||
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
|
||||
};
|
||||
if (year < 1900 || year > 2100 || month < 1 || month > 12 || day < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int max_day = days_per_month[month - 1];
|
||||
if (month == 2 && is_leap_year(year)) {
|
||||
max_day = 29;
|
||||
}
|
||||
return day <= max_day;
|
||||
}
|
||||
|
||||
static void trim_ascii_whitespace(char *value)
|
||||
{
|
||||
if (value == NULL || value[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
char *start = value;
|
||||
while (*start != '\0' && isspace((unsigned char)*start)) {
|
||||
start++;
|
||||
}
|
||||
if (start != value) {
|
||||
memmove(value, start, strlen(start) + 1U);
|
||||
}
|
||||
|
||||
size_t len = strlen(value);
|
||||
while (len > 0U && isspace((unsigned char)value[len - 1U])) {
|
||||
value[--len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static bool json_get_required_int(const cJSON *root, const char *key, int *out_value)
|
||||
{
|
||||
const cJSON *item = cJSON_GetObjectItemCaseSensitive(root, key);
|
||||
if (!cJSON_IsNumber(item)) {
|
||||
return false;
|
||||
}
|
||||
*out_value = item->valueint;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool json_copy_string(const cJSON *root,
|
||||
const char *key,
|
||||
char *out,
|
||||
size_t out_len,
|
||||
bool required)
|
||||
{
|
||||
const cJSON *item = cJSON_GetObjectItemCaseSensitive(root, key);
|
||||
if (item == NULL && !required) {
|
||||
out[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
if (!cJSON_IsString(item) || item->valuestring == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t len = strlen(item->valuestring);
|
||||
if (len >= out_len) {
|
||||
return false;
|
||||
}
|
||||
memcpy(out, item->valuestring, len + 1U);
|
||||
trim_ascii_whitespace(out);
|
||||
return !required || out[0] != '\0';
|
||||
}
|
||||
|
||||
static esp_err_t response_copy(platform_lan_http_response_t *response,
|
||||
platform_lan_http_status_t status,
|
||||
platform_lan_http_content_type_t content_type,
|
||||
const uint8_t *body,
|
||||
size_t body_len)
|
||||
{
|
||||
if (body_len > response->body_capacity) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
if (body_len > 0U) {
|
||||
memcpy(response->body, body, body_len);
|
||||
}
|
||||
response->status = status;
|
||||
response->content_type = content_type;
|
||||
response->body_len = body_len;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t response_json_object(platform_lan_http_response_t *response,
|
||||
platform_lan_http_status_t status,
|
||||
cJSON *root)
|
||||
{
|
||||
if (response == NULL ||
|
||||
response->body == NULL ||
|
||||
response->body_capacity == 0U ||
|
||||
response->body_capacity > (size_t)INT_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!cJSON_PrintPreallocated(root,
|
||||
(char *)response->body,
|
||||
(int)response->body_capacity,
|
||||
false)) {
|
||||
response->body_len = 0U;
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
response->status = status;
|
||||
response->content_type = PLATFORM_LAN_HTTP_CONTENT_JSON;
|
||||
response->body_len = strlen((const char *)response->body);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t response_error(platform_lan_http_response_t *response,
|
||||
platform_lan_http_status_t status,
|
||||
const char *message)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
if (root == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
cJSON_AddBoolToObject(root, "success", false);
|
||||
cJSON_AddStringToObject(root, "error", message);
|
||||
esp_err_t err = response_json_object(response, status, root);
|
||||
cJSON_Delete(root);
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t handle_index(platform_lan_http_response_t *response)
|
||||
{
|
||||
size_t html_len = (size_t)(user_config_html_end - user_config_html_start);
|
||||
return response_copy(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_OK,
|
||||
PLATFORM_LAN_HTTP_CONTENT_HTML,
|
||||
user_config_html_start,
|
||||
html_len);
|
||||
}
|
||||
|
||||
static esp_err_t handle_get_profile(platform_lan_http_response_t *response)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
if (root == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
domain_birth_profile_t profile = {0};
|
||||
bool configured = domain_birth_profile_store_get(&profile);
|
||||
cJSON_AddBoolToObject(root, "configured", configured);
|
||||
if (configured) {
|
||||
cJSON_AddNumberToObject(root, "birthYear", profile.year);
|
||||
cJSON_AddNumberToObject(root, "birthMonth", profile.month);
|
||||
cJSON_AddNumberToObject(root, "birthDay", profile.day);
|
||||
cJSON_AddNumberToObject(root, "birthHour", profile.hour);
|
||||
cJSON_AddNumberToObject(root, "birthMinute", profile.minute);
|
||||
cJSON_AddStringToObject(root, "birthPlace", profile.birth_place);
|
||||
cJSON_AddStringToObject(root, "currentResidence", profile.current_residence);
|
||||
cJSON_AddStringToObject(root, "mbti", profile.mbti);
|
||||
cJSON_AddStringToObject(root, "timezone", profile.timezone);
|
||||
}
|
||||
|
||||
esp_err_t err = response_json_object(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_OK,
|
||||
root);
|
||||
cJSON_Delete(root);
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool parse_profile(const uint8_t *body,
|
||||
size_t body_len,
|
||||
domain_birth_profile_t *out_profile,
|
||||
const char **out_error)
|
||||
{
|
||||
if (body == NULL || body_len == 0U) {
|
||||
*out_error = "Request body is empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
cJSON *root = cJSON_ParseWithLength((const char *)body, body_len);
|
||||
if (root == NULL) {
|
||||
*out_error = "Invalid JSON";
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(out_profile, 0, sizeof(*out_profile));
|
||||
bool valid = json_get_required_int(root, "birthYear", &out_profile->year) &&
|
||||
json_get_required_int(root, "birthMonth", &out_profile->month) &&
|
||||
json_get_required_int(root, "birthDay", &out_profile->day) &&
|
||||
json_get_required_int(root, "birthHour", &out_profile->hour) &&
|
||||
json_get_required_int(root, "birthMinute", &out_profile->minute) &&
|
||||
json_copy_string(root,
|
||||
"birthPlace",
|
||||
out_profile->birth_place,
|
||||
sizeof(out_profile->birth_place),
|
||||
true) &&
|
||||
json_copy_string(root,
|
||||
"currentResidence",
|
||||
out_profile->current_residence,
|
||||
sizeof(out_profile->current_residence),
|
||||
false) &&
|
||||
json_copy_string(root,
|
||||
"mbti",
|
||||
out_profile->mbti,
|
||||
sizeof(out_profile->mbti),
|
||||
false);
|
||||
cJSON_Delete(root);
|
||||
|
||||
if (!valid) {
|
||||
*out_error = "Missing or oversized profile field";
|
||||
return false;
|
||||
}
|
||||
if (!is_valid_date(out_profile->year, out_profile->month, out_profile->day)) {
|
||||
*out_error = "Invalid birth date";
|
||||
return false;
|
||||
}
|
||||
if (out_profile->hour < 0 || out_profile->hour > 23 ||
|
||||
out_profile->minute < 0 || out_profile->minute > 59) {
|
||||
*out_error = "Invalid birth time";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (char *cursor = out_profile->mbti; *cursor != '\0'; ++cursor) {
|
||||
*cursor = (char)toupper((unsigned char)*cursor);
|
||||
}
|
||||
strlcpy(out_profile->timezone, kFortuneTimezone, sizeof(out_profile->timezone));
|
||||
out_profile->valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static esp_err_t handle_post_profile(const platform_lan_http_request_t *request,
|
||||
platform_lan_http_response_t *response)
|
||||
{
|
||||
domain_birth_profile_t profile = {0};
|
||||
const char *error_message = NULL;
|
||||
if (!parse_profile(request->body,
|
||||
request->body_len,
|
||||
&profile,
|
||||
&error_message)) {
|
||||
return response_error(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_BAD_REQUEST,
|
||||
error_message);
|
||||
}
|
||||
|
||||
esp_err_t err = domain_birth_profile_store_set(&profile);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Persist birth profile failed: %s", esp_err_to_name(err));
|
||||
return response_error(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_INTERNAL_ERROR,
|
||||
"Failed to persist profile");
|
||||
}
|
||||
|
||||
err = domain_fortune_result_store_clear();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Invalidate previous fortune failed: %s", esp_err_to_name(err));
|
||||
return response_error(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_INTERNAL_ERROR,
|
||||
"Profile saved but previous result could not be invalidated");
|
||||
}
|
||||
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
if (root == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
cJSON_AddBoolToObject(root, "success", true);
|
||||
cJSON_AddStringToObject(root, "status", "pending");
|
||||
err = response_json_object(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_ACCEPTED,
|
||||
root);
|
||||
cJSON_Delete(root);
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t handle_get_fortune(platform_lan_http_response_t *response)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
if (root == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
domain_birth_profile_t profile = {0};
|
||||
domain_fortune_result_t result = {0};
|
||||
if (!domain_birth_profile_store_get(&profile)) {
|
||||
cJSON_AddStringToObject(root, "status", "not_configured");
|
||||
} else if (!domain_fortune_result_store_get(&result)) {
|
||||
cJSON_AddStringToObject(root, "status", "pending");
|
||||
} else {
|
||||
cJSON_AddStringToObject(root, "status", "ready");
|
||||
cJSON_AddStringToObject(root, "bazi", result.bazi);
|
||||
cJSON_AddStringToObject(root, "element", result.element);
|
||||
cJSON_AddStringToObject(root, "luckyColor", result.lucky_color);
|
||||
cJSON_AddStringToObject(root, "wealthDirection", result.wealth_direction);
|
||||
cJSON_AddStringToObject(root, "targetDate", result.target_date);
|
||||
}
|
||||
|
||||
esp_err_t err = response_json_object(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_OK,
|
||||
root);
|
||||
cJSON_Delete(root);
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t user_config_http_handler(
|
||||
const platform_lan_http_request_t *request,
|
||||
platform_lan_http_response_t *response,
|
||||
void *user_data)
|
||||
{
|
||||
(void)user_data;
|
||||
|
||||
if (strcmp(request->path, "/") == 0) {
|
||||
if (request->method != PLATFORM_LAN_HTTP_METHOD_GET) {
|
||||
return response_error(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_METHOD_NOT_ALLOWED,
|
||||
"Method not allowed");
|
||||
}
|
||||
return handle_index(response);
|
||||
}
|
||||
if (strcmp(request->path, "/api/profile") == 0) {
|
||||
if (request->method == PLATFORM_LAN_HTTP_METHOD_GET) {
|
||||
return handle_get_profile(response);
|
||||
}
|
||||
if (request->method == PLATFORM_LAN_HTTP_METHOD_POST) {
|
||||
return handle_post_profile(request, response);
|
||||
}
|
||||
return response_error(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_METHOD_NOT_ALLOWED,
|
||||
"Method not allowed");
|
||||
}
|
||||
if (strcmp(request->path, "/api/fortune") == 0) {
|
||||
if (request->method != PLATFORM_LAN_HTTP_METHOD_GET) {
|
||||
return response_error(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_METHOD_NOT_ALLOWED,
|
||||
"Method not allowed");
|
||||
}
|
||||
return handle_get_fortune(response);
|
||||
}
|
||||
|
||||
return response_error(response,
|
||||
PLATFORM_LAN_HTTP_STATUS_NOT_FOUND,
|
||||
"Route not found");
|
||||
}
|
||||
|
||||
esp_err_t domain_user_config_server_start(
|
||||
const domain_user_config_server_config_t *config)
|
||||
{
|
||||
if (config == NULL ||
|
||||
config->port == 0U ||
|
||||
config->hostname[0] == '\0' ||
|
||||
strnlen(config->hostname, sizeof(config->hostname)) >= sizeof(config->hostname)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
platform_lan_http_server_config_t platform_config = {
|
||||
.port = config->port,
|
||||
.handler = user_config_http_handler,
|
||||
.user_data = NULL,
|
||||
};
|
||||
strlcpy(platform_config.hostname,
|
||||
config->hostname,
|
||||
sizeof(platform_config.hostname));
|
||||
return platform_lan_http_server_start(&platform_config);
|
||||
}
|
||||
|
||||
esp_err_t domain_user_config_server_stop(int timeout_ms)
|
||||
{
|
||||
return platform_lan_http_server_stop(timeout_ms);
|
||||
}
|
||||
|
||||
esp_err_t domain_user_config_server_get_state(
|
||||
domain_user_config_server_state_t *out_state)
|
||||
{
|
||||
if (out_state == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
platform_lan_http_server_state_t platform_state = {0};
|
||||
esp_err_t err = platform_lan_http_server_get_state(&platform_state);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(out_state, 0, sizeof(*out_state));
|
||||
out_state->running = platform_state.running;
|
||||
out_state->port = platform_state.port;
|
||||
strlcpy(out_state->hostname,
|
||||
platform_state.hostname,
|
||||
sizeof(out_state->hostname));
|
||||
return ESP_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user