mirror of
https://github.com/m5stack/StackChan.git
synced 2026-04-27 11:02:40 +00:00
247 lines
7.8 KiB
C++
247 lines
7.8 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
#include "hal.h"
|
|
#include "utils/secret_logic/secret_logic.h"
|
|
#include <settings.h>
|
|
#include <mooncake_log.h>
|
|
#include <memory>
|
|
#include <board.h>
|
|
#include <cJSON.h>
|
|
|
|
static const std::string_view _tag = "HAL-Account";
|
|
|
|
static const std::string_view _setting_ns = "account";
|
|
static const std::string_view _setting_username_key = "username";
|
|
static const std::string_view _setting_device_name_key = "device_name";
|
|
|
|
static const std::string_view _get_user_account_info_url = "http://47.113.125.164:12800/stackChan/device/user";
|
|
static const std::string_view _get_device_info_url = "http://47.113.125.164:12800/stackChan/device/info";
|
|
static const std::string_view _unbind_user_account_info_url = "http://47.113.125.164:12800/stackChan/device/unbind";
|
|
|
|
static bool request_authorized_get(std::string_view token, std::string_view url, std::string &response,
|
|
std::function<void(std::string_view)> onLog)
|
|
{
|
|
auto &board = Board::GetInstance();
|
|
auto network = board.GetNetwork();
|
|
auto http = network->CreateHttp(0);
|
|
|
|
if (!http) {
|
|
mclog::tagError(_tag, "failed to create http client");
|
|
onLog("Failed to create HTTP client");
|
|
return false;
|
|
}
|
|
|
|
http->SetHeader("Authorization", std::string(token));
|
|
if (!http->Open("GET", std::string(url))) {
|
|
mclog::tagError(_tag, "failed to open http request: {}", url);
|
|
onLog("Failed to connect to server");
|
|
return false;
|
|
}
|
|
|
|
int status_code = http->GetStatusCode();
|
|
if (status_code != 200) {
|
|
mclog::tagError(_tag, "http get failed, status code: {}, url: {}", status_code, url);
|
|
onLog("HTTP Request Failed");
|
|
return false;
|
|
}
|
|
|
|
response = http->ReadAll();
|
|
mclog::tagInfo(_tag, "response from {}: {}", url, response);
|
|
return true;
|
|
}
|
|
|
|
static bool fetch_username(std::string_view token, std::string &username, std::function<void(std::string_view)> onLog)
|
|
{
|
|
onLog("Updating user account info...");
|
|
|
|
std::string response;
|
|
if (!request_authorized_get(token, _get_user_account_info_url, response, onLog)) {
|
|
return false;
|
|
}
|
|
|
|
cJSON *root = cJSON_Parse(response.c_str());
|
|
if (!root) {
|
|
mclog::tagError(_tag, "failed to parse user account json");
|
|
onLog("Failed to parse response");
|
|
return false;
|
|
}
|
|
|
|
bool success = false;
|
|
cJSON *code = cJSON_GetObjectItem(root, "code");
|
|
cJSON *data = cJSON_GetObjectItem(root, "data");
|
|
|
|
const char *username_value = nullptr;
|
|
if (data && cJSON_IsString(data)) {
|
|
username_value = data->valuestring;
|
|
} else if (data && cJSON_IsObject(data)) {
|
|
cJSON *username_json = cJSON_GetObjectItem(data, "username");
|
|
if (username_json && cJSON_IsString(username_json)) {
|
|
username_value = username_json->valuestring;
|
|
}
|
|
}
|
|
|
|
if (code && cJSON_IsNumber(code) && code->valueint == 0 && username_value != nullptr) {
|
|
username = username_value;
|
|
success = true;
|
|
} else {
|
|
mclog::tagError(_tag, "invalid user account response format or error code");
|
|
onLog("Invalid response from server");
|
|
}
|
|
|
|
cJSON_Delete(root);
|
|
return success;
|
|
}
|
|
|
|
static bool fetch_device_name(std::string_view token, std::string &deviceName,
|
|
std::function<void(std::string_view)> onLog)
|
|
{
|
|
onLog("Updating device info...");
|
|
|
|
std::string response;
|
|
if (!request_authorized_get(token, _get_device_info_url, response, onLog)) {
|
|
return false;
|
|
}
|
|
|
|
cJSON *root = cJSON_Parse(response.c_str());
|
|
if (!root) {
|
|
mclog::tagError(_tag, "failed to parse device info json");
|
|
onLog("Failed to parse response");
|
|
return false;
|
|
}
|
|
|
|
bool success = false;
|
|
cJSON *code = cJSON_GetObjectItem(root, "code");
|
|
cJSON *data = cJSON_GetObjectItem(root, "data");
|
|
cJSON *target = root;
|
|
|
|
if (code && cJSON_IsNumber(code)) {
|
|
if (code->valueint != 0) {
|
|
mclog::tagError(_tag, "device info request failed, code: {}", code->valueint);
|
|
onLog("Invalid response from server");
|
|
cJSON_Delete(root);
|
|
return false;
|
|
}
|
|
if (data && cJSON_IsObject(data)) {
|
|
target = data;
|
|
}
|
|
}
|
|
|
|
cJSON *name_json = cJSON_GetObjectItem(target, "name");
|
|
if (name_json && cJSON_IsString(name_json)) {
|
|
deviceName = name_json->valuestring;
|
|
success = true;
|
|
} else {
|
|
mclog::tagError(_tag, "invalid device info response format");
|
|
onLog("Invalid response from server");
|
|
}
|
|
|
|
cJSON_Delete(root);
|
|
return success;
|
|
}
|
|
|
|
UserAccountInfo_t Hal::getUserAccountInfo()
|
|
{
|
|
UserAccountInfo_t info;
|
|
Settings settings(_setting_ns.data(), false);
|
|
info.username = settings.GetString(_setting_username_key.data(), "Account Info");
|
|
info.deviceName = settings.GetString(_setting_device_name_key.data(), "");
|
|
return info;
|
|
}
|
|
|
|
bool Hal::updateAccountInfo(std::function<void(std::string_view)> onLog)
|
|
{
|
|
std::string token = secret_logic::generate_auth_token();
|
|
|
|
std::string username;
|
|
if (!fetch_username(token, username, onLog)) {
|
|
return false;
|
|
}
|
|
|
|
std::string device_name;
|
|
if (!fetch_device_name(token, device_name, onLog)) {
|
|
return false;
|
|
}
|
|
|
|
Settings settings(_setting_ns.data(), true);
|
|
settings.SetString(_setting_username_key.data(), username);
|
|
settings.SetString(_setting_device_name_key.data(), device_name);
|
|
|
|
mclog::tagInfo(_tag, "account updated: username={}, device_name={}", username, device_name);
|
|
onLog(std::string("Account updated: ") + username);
|
|
return true;
|
|
}
|
|
|
|
bool Hal::unbindAccount(std::function<void(std::string_view)> onLog)
|
|
{
|
|
std::string token = secret_logic::generate_auth_token();
|
|
|
|
auto &board = Board::GetInstance();
|
|
auto network = board.GetNetwork();
|
|
auto http = network->CreateHttp(0);
|
|
|
|
if (!http) {
|
|
mclog::tagError(_tag, "failed to create http client");
|
|
onLog("Failed to create HTTP client");
|
|
return false;
|
|
}
|
|
|
|
http->SetHeader("Authorization", token);
|
|
http->SetContent(std::string());
|
|
mclog::tagInfo(_tag, "requesting to unbind account...");
|
|
onLog("Unbinding account...");
|
|
|
|
if (!http->Open("POST", std::string(_unbind_user_account_info_url))) {
|
|
mclog::tagError(_tag, "failed to open http request");
|
|
onLog("Failed to connect to server");
|
|
return false;
|
|
}
|
|
|
|
int status_code = http->GetStatusCode();
|
|
if (status_code != 200) {
|
|
mclog::tagError(_tag, "http post failed, status code: {}", status_code);
|
|
onLog("HTTP Request Failed");
|
|
return false;
|
|
}
|
|
|
|
std::string response = http->ReadAll();
|
|
mclog::tagInfo(_tag, "response: {}", response);
|
|
|
|
cJSON *root = cJSON_Parse(response.c_str());
|
|
if (!root) {
|
|
mclog::tagError(_tag, "failed to parse json");
|
|
onLog("Failed to parse response");
|
|
return false;
|
|
}
|
|
|
|
bool success = false;
|
|
cJSON *code = cJSON_GetObjectItem(root, "code");
|
|
|
|
if (code && cJSON_IsNumber(code) && code->valueint == 0) {
|
|
Settings settings(_setting_ns.data(), true);
|
|
settings.SetString(_setting_username_key.data(), "Account Info");
|
|
settings.SetString(_setting_device_name_key.data(), "");
|
|
mclog::tagInfo(_tag, "account unbound successfully");
|
|
onLog("Account unbound successfully");
|
|
success = true;
|
|
} else {
|
|
mclog::tagError(_tag, "invalid response format or error code");
|
|
cJSON *msg = cJSON_GetObjectItem(root, "message");
|
|
if (msg && cJSON_IsString(msg)) {
|
|
onLog(std::string("Unbind failed: ") + msg->valuestring);
|
|
} else {
|
|
onLog("Invalid response from server");
|
|
}
|
|
}
|
|
|
|
cJSON_Delete(root);
|
|
|
|
if (success) {
|
|
resetAppConfiged();
|
|
}
|
|
|
|
return success;
|
|
}
|