fix: reduce repeater web panel pressure and improve mqtt diagnostics
Этот коммит содержится в:
@@ -120,6 +120,25 @@ const char* getWifiStateLabel(const MQTTPrefs& prefs, bool wifi_started) {
|
||||
return "down";
|
||||
}
|
||||
|
||||
#if MQTT_DEBUG
|
||||
void logMqttMemorySnapshot(const char* phase, const char* broker_label = nullptr) {
|
||||
MQTT_LOG("mem phase=%s broker=%s uptime_ms=%lu heap_free=%u heap_min=%u heap_max=%u psram_free=%u psram_min=%u "
|
||||
"psram_max=%u",
|
||||
phase != nullptr ? phase : "-",
|
||||
broker_label != nullptr ? broker_label : "-",
|
||||
millis(),
|
||||
ESP.getFreeHeap(),
|
||||
ESP.getMinFreeHeap(),
|
||||
ESP.getMaxAllocHeap(),
|
||||
ESP.getFreePsram(),
|
||||
ESP.getMinFreePsram(),
|
||||
ESP.getMaxAllocPsram());
|
||||
}
|
||||
#else
|
||||
void logMqttMemorySnapshot(const char*, const char* = nullptr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
const MQTTUplink::BrokerSpec MQTTUplink::kBrokerSpecs[3] = {
|
||||
@@ -398,6 +417,14 @@ bool MQTTUplink::refreshToken(BrokerState& broker) {
|
||||
}
|
||||
|
||||
void MQTTUplink::destroyBroker(BrokerState& broker, bool reset_retry_state) {
|
||||
bool had_runtime_state = broker.client != nullptr || broker.token != nullptr || broker.connected ||
|
||||
broker.connect_announced || broker.reconnect_pending || broker.next_connect_attempt != 0 ||
|
||||
broker.last_connect_attempt != 0 || broker.reconnect_failures != 0 ||
|
||||
broker.token_expires_at != 0;
|
||||
if (!had_runtime_state) {
|
||||
return;
|
||||
}
|
||||
logMqttMemorySnapshot("destroy-pre", broker.spec != nullptr ? broker.spec->label : nullptr);
|
||||
if (broker.client != nullptr) {
|
||||
MQTT_LOG("%s destroy broker client", broker.spec->label);
|
||||
esp_mqtt_client_stop(broker.client);
|
||||
@@ -408,6 +435,7 @@ void MQTTUplink::destroyBroker(BrokerState& broker, bool reset_retry_state) {
|
||||
broker.token = nullptr;
|
||||
broker.connected = false;
|
||||
broker.connect_announced = false;
|
||||
broker.connected_since_ms = 0;
|
||||
broker.token_expires_at = 0;
|
||||
if (reset_retry_state) {
|
||||
broker.reconnect_pending = false;
|
||||
@@ -415,6 +443,7 @@ void MQTTUplink::destroyBroker(BrokerState& broker, bool reset_retry_state) {
|
||||
broker.reconnect_failures = 0;
|
||||
broker.last_connect_attempt = 0;
|
||||
}
|
||||
logMqttMemorySnapshot("destroy-post", broker.spec != nullptr ? broker.spec->label : nullptr);
|
||||
}
|
||||
|
||||
void MQTTUplink::queuePublish(BrokerState& broker, const char* topic, const char* payload, bool retain) {
|
||||
@@ -423,7 +452,8 @@ void MQTTUplink::queuePublish(BrokerState& broker, const char* topic, const char
|
||||
}
|
||||
MQTT_LOG("%s publish topic=%s retain=%d bytes=%u", broker.spec->label, topic, retain ? 1 : 0,
|
||||
static_cast<unsigned>(strlen(payload)));
|
||||
esp_mqtt_client_enqueue(broker.client, topic, payload, 0, 1, retain, true);
|
||||
int enqueue_rc = esp_mqtt_client_enqueue(broker.client, topic, payload, 0, 1, retain, true);
|
||||
MQTT_LOG("%s enqueue topic=%s rc=%d connected=%d", broker.spec->label, topic, enqueue_rc, broker.connected ? 1 : 0);
|
||||
}
|
||||
|
||||
int MQTTUplink::buildStatusJson(char* buffer, size_t buffer_size, bool online) const {
|
||||
@@ -565,6 +595,7 @@ void MQTTUplink::publishOnlineStatus(BrokerState& broker) {
|
||||
}
|
||||
|
||||
void MQTTUplink::publishStatus(bool online) {
|
||||
logMqttMemorySnapshot(online ? "status-pre" : "status-offline-pre");
|
||||
char* payload = allocScratchBuffer(768);
|
||||
if (payload == nullptr) {
|
||||
return;
|
||||
@@ -580,6 +611,7 @@ void MQTTUplink::publishStatus(bool online) {
|
||||
}
|
||||
}
|
||||
freeScratchBuffer(payload);
|
||||
logMqttMemorySnapshot(online ? "status-post" : "status-offline-post");
|
||||
}
|
||||
|
||||
void MQTTUplink::handleMqttEvent(void* handler_args, esp_event_base_t, int32_t event_id, void* event_data) {
|
||||
@@ -588,6 +620,8 @@ void MQTTUplink::handleMqttEvent(void* handler_args, esp_event_base_t, int32_t e
|
||||
return;
|
||||
}
|
||||
auto* event = static_cast<esp_mqtt_event_handle_t>(event_data);
|
||||
unsigned long now_ms = millis();
|
||||
unsigned long connected_for_ms = broker->connected_since_ms != 0 ? (now_ms - broker->connected_since_ms) : 0;
|
||||
|
||||
switch (event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
@@ -595,33 +629,56 @@ void MQTTUplink::handleMqttEvent(void* handler_args, esp_event_base_t, int32_t e
|
||||
broker->reconnect_pending = false;
|
||||
broker->next_connect_attempt = 0;
|
||||
broker->reconnect_failures = 0;
|
||||
broker->connected_since_ms = now_ms;
|
||||
MQTT_LOG("%s connected", broker->spec->label);
|
||||
logMqttMemorySnapshot("connected", broker->spec->label);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
MQTT_LOG("%s disconnected", broker->spec->label);
|
||||
broker->connected = false;
|
||||
broker->connected_since_ms = 0;
|
||||
MQTT_LOG("%s disconnected wifi_status=%d rssi=%d connected_for_ms=%lu", broker->spec->label,
|
||||
static_cast<int>(WiFi.status()), WiFi.RSSI(), connected_for_ms);
|
||||
logMqttMemorySnapshot("disconnected", broker->spec->label);
|
||||
if (!broker->reconnect_pending) {
|
||||
if (broker->reconnect_failures < 10) {
|
||||
broker->reconnect_failures++;
|
||||
}
|
||||
broker->reconnect_pending = true;
|
||||
broker->next_connect_attempt = now_ms + getBrokerRetryDelayMillis(broker->reconnect_failures);
|
||||
MQTT_LOG("%s reconnect in %lu ms (failures=%u)", broker->spec->label,
|
||||
getBrokerRetryDelayMillis(broker->reconnect_failures),
|
||||
static_cast<unsigned>(broker->reconnect_failures));
|
||||
}
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
broker->connected = false;
|
||||
if (broker->reconnect_failures < 10) {
|
||||
broker->reconnect_failures++;
|
||||
broker->connected_since_ms = 0;
|
||||
if (event != nullptr && event->error_handle != nullptr) {
|
||||
MQTT_LOG("%s error type=%d tls_esp=0x%x tls_stack=0x%x cert_flags=0x%x sock_errno=%d conn_refused=%d "
|
||||
"connected_for_ms=%lu",
|
||||
broker->spec->label, event->error_handle->error_type, event->error_handle->esp_tls_last_esp_err,
|
||||
event->error_handle->esp_tls_stack_err, event->error_handle->esp_tls_cert_verify_flags,
|
||||
event->error_handle->esp_transport_sock_errno, event->error_handle->connect_return_code,
|
||||
connected_for_ms);
|
||||
} else {
|
||||
MQTT_LOG("%s error event connected_for_ms=%lu", broker->spec->label, connected_for_ms);
|
||||
}
|
||||
broker->reconnect_pending = true;
|
||||
broker->next_connect_attempt = millis() + getBrokerRetryDelayMillis(broker->reconnect_failures);
|
||||
if (event_id == MQTT_EVENT_ERROR) {
|
||||
if (event != nullptr && event->error_handle != nullptr) {
|
||||
MQTT_LOG("%s error type=%d tls_esp=0x%x tls_stack=0x%x cert_flags=0x%x sock_errno=%d conn_refused=%d",
|
||||
broker->spec->label, event->error_handle->error_type, event->error_handle->esp_tls_last_esp_err,
|
||||
event->error_handle->esp_tls_stack_err, event->error_handle->esp_tls_cert_verify_flags,
|
||||
event->error_handle->esp_transport_sock_errno, event->error_handle->connect_return_code);
|
||||
} else {
|
||||
MQTT_LOG("%s error event", broker->spec->label);
|
||||
MQTT_LOG("%s wifi_status=%d rssi=%d", broker->spec->label, static_cast<int>(WiFi.status()), WiFi.RSSI());
|
||||
logMqttMemorySnapshot("error", broker->spec->label);
|
||||
if (!broker->reconnect_pending) {
|
||||
if (broker->reconnect_failures < 10) {
|
||||
broker->reconnect_failures++;
|
||||
}
|
||||
broker->reconnect_pending = true;
|
||||
broker->next_connect_attempt = now_ms + getBrokerRetryDelayMillis(broker->reconnect_failures);
|
||||
MQTT_LOG("%s reconnect in %lu ms (failures=%u)", broker->spec->label,
|
||||
getBrokerRetryDelayMillis(broker->reconnect_failures),
|
||||
static_cast<unsigned>(broker->reconnect_failures));
|
||||
}
|
||||
MQTT_LOG("%s reconnect in %lu ms (failures=%u)", broker->spec->label,
|
||||
getBrokerRetryDelayMillis(broker->reconnect_failures),
|
||||
static_cast<unsigned>(broker->reconnect_failures));
|
||||
break;
|
||||
case MQTT_EVENT_BEFORE_CONNECT:
|
||||
MQTT_LOG("%s before connect", broker->spec->label);
|
||||
logMqttMemorySnapshot("before-connect", broker->spec->label);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -716,13 +773,17 @@ void MQTTUplink::updateTimeSync() {
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTUplink::ensureBroker(BrokerState& broker) {
|
||||
void MQTTUplink::ensureBroker(BrokerState& broker, bool allow_new_connect) {
|
||||
if (broker.spec == nullptr) {
|
||||
return;
|
||||
}
|
||||
bool enabled = (_prefs.enabled_mask & broker.spec->bit) != 0;
|
||||
if (!enabled) {
|
||||
destroyBroker(broker);
|
||||
if (broker.client != nullptr || broker.token != nullptr || broker.connected || broker.connect_announced ||
|
||||
broker.reconnect_pending || broker.next_connect_attempt != 0 || broker.last_connect_attempt != 0 ||
|
||||
broker.reconnect_failures != 0 || broker.token_expires_at != 0) {
|
||||
destroyBroker(broker);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -749,6 +810,9 @@ void MQTTUplink::ensureBroker(BrokerState& broker) {
|
||||
if (broker.next_connect_attempt != 0 && now_ms < broker.next_connect_attempt) {
|
||||
return;
|
||||
}
|
||||
if (!allow_new_connect) {
|
||||
return;
|
||||
}
|
||||
broker.last_connect_attempt = now_ms;
|
||||
broker.reconnect_pending = false;
|
||||
|
||||
@@ -759,8 +823,9 @@ void MQTTUplink::ensureBroker(BrokerState& broker) {
|
||||
}
|
||||
|
||||
refreshBrokerState(broker);
|
||||
MQTT_LOG("%s mqtt init host=%s port=%d path=%s client_id=%s heap_free=%u heap_max=%u", broker.spec->label,
|
||||
broker.spec->host, 443, "/mqtt", broker.client_id, ESP.getFreeHeap(), ESP.getMaxAllocHeap());
|
||||
MQTT_LOG("%s mqtt init host=%s port=%d path=%s client_id=%s", broker.spec->label, broker.spec->host, 443, "/mqtt",
|
||||
broker.client_id);
|
||||
logMqttMemorySnapshot("init-pre", broker.spec->label);
|
||||
esp_mqtt_client_config_t cfg = {};
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
cfg.broker.address.hostname = broker.spec->host;
|
||||
@@ -805,17 +870,21 @@ void MQTTUplink::ensureBroker(BrokerState& broker) {
|
||||
broker.client = esp_mqtt_client_init(&cfg);
|
||||
if (broker.client == nullptr) {
|
||||
MQTT_LOG("%s mqtt init failed", broker.spec->label);
|
||||
logMqttMemorySnapshot("init-failed", broker.spec->label);
|
||||
return;
|
||||
}
|
||||
logMqttMemorySnapshot("init-post", broker.spec->label);
|
||||
|
||||
esp_mqtt_client_register_event(broker.client, MQTT_EVENT_ANY, &MQTTUplink::handleMqttEvent, &broker);
|
||||
if (esp_mqtt_client_start(broker.client) != ESP_OK) {
|
||||
MQTT_LOG("%s mqtt start failed", broker.spec->label);
|
||||
logMqttMemorySnapshot("start-failed", broker.spec->label);
|
||||
broker.reconnect_pending = true;
|
||||
broker.next_connect_attempt = now_ms + kBrokerRetryBaseMillis;
|
||||
destroyBroker(broker, false);
|
||||
} else {
|
||||
MQTT_LOG("%s mqtt start requested", broker.spec->label);
|
||||
logMqttMemorySnapshot("start-requested", broker.spec->label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -865,8 +934,21 @@ void MQTTUplink::loop(const MQTTStatusSnapshot& snapshot) {
|
||||
_web_panel.lockSession();
|
||||
}
|
||||
|
||||
BrokerState* active_connecting_broker = nullptr;
|
||||
for (BrokerState& broker : _brokers) {
|
||||
ensureBroker(broker);
|
||||
if (broker.client != nullptr && !broker.connected && !broker.reconnect_pending) {
|
||||
active_connecting_broker = &broker;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool connect_started = false;
|
||||
for (BrokerState& broker : _brokers) {
|
||||
bool allow_new_connect = active_connecting_broker == nullptr && !connect_started;
|
||||
ensureBroker(broker, allow_new_connect);
|
||||
if (active_connecting_broker == nullptr && broker.client != nullptr && !broker.connected && !broker.reconnect_pending) {
|
||||
connect_started = true;
|
||||
}
|
||||
if (broker.connected && !broker.connect_announced) {
|
||||
publishOnlineStatus(broker);
|
||||
broker.connect_announced = true;
|
||||
@@ -1041,8 +1123,6 @@ bool MQTTUplink::setWebEnabled(bool enabled) {
|
||||
bool ok = savePrefs();
|
||||
if (_prefs.web_enabled != 0) {
|
||||
ensureWebServer();
|
||||
} else {
|
||||
stopWebServer();
|
||||
}
|
||||
return ok;
|
||||
#else
|
||||
|
||||
@@ -98,6 +98,7 @@ private:
|
||||
bool reconnect_pending;
|
||||
unsigned long last_connect_attempt;
|
||||
unsigned long next_connect_attempt;
|
||||
unsigned long connected_since_ms;
|
||||
time_t token_expires_at;
|
||||
uint8_t reconnect_failures;
|
||||
char username[70];
|
||||
@@ -144,7 +145,7 @@ private:
|
||||
void refreshIdentityStrings();
|
||||
void refreshBrokerIdentity(BrokerState& broker);
|
||||
void refreshBrokerState(BrokerState& broker);
|
||||
void ensureBroker(BrokerState& broker);
|
||||
void ensureBroker(BrokerState& broker, bool allow_new_connect);
|
||||
void destroyBroker(BrokerState& broker, bool reset_retry_state = true);
|
||||
bool refreshToken(BrokerState& broker);
|
||||
void publishStatus(bool online);
|
||||
|
||||
@@ -1219,8 +1219,8 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
const value = document.getElementById(inputId).value;
|
||||
runCommand(prefix + value);
|
||||
}
|
||||
async function loadField(cmd, inputId, format) {
|
||||
const result = await runCommand(cmd);
|
||||
async function loadField(cmd, inputId, format, options = {}) {
|
||||
const result = await runCommand(cmd, options);
|
||||
if (!result.ok) return;
|
||||
let value = parseReplyValue(result.text);
|
||||
if (format === "multiline") {
|
||||
@@ -1285,27 +1285,6 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
}
|
||||
return JSON.parse(text);
|
||||
});
|
||||
}
|
||||
function applyBootstrapData(data) {
|
||||
if (!data) return;
|
||||
if (typeof data.name === "string") document.getElementById("nodeName").value = data.name;
|
||||
if (typeof data.mqtt_iata === "string" && data.mqtt_iata.length) document.getElementById("mqttIata").value = data.mqtt_iata;
|
||||
if (typeof data.mqtt_owner === "string") document.getElementById("mqttOwner").value = data.mqtt_owner;
|
||||
if (typeof data.mqtt_email === "string") document.getElementById("mqttEmail").value = data.mqtt_email;
|
||||
if (typeof data.advert_interval === "string") document.getElementById("advertInterval").value = data.advert_interval;
|
||||
if (typeof data.flood_interval === "string") document.getElementById("floodInterval").value = data.flood_interval;
|
||||
if (typeof data.flood_max === "string") document.getElementById("floodMax").value = data.flood_max;
|
||||
if (typeof data.path_hash_mode === "string") document.getElementById("pathHashMode").value = data.path_hash_mode;
|
||||
if (typeof data.private_key === "string") document.getElementById("privateKey").value = data.private_key.toUpperCase();
|
||||
if (typeof data.radio === "string") currentRadioConfig = parseRadioValue(data.radio);
|
||||
if (typeof data.role === "string") document.getElementById("roleValue").value = data.role;
|
||||
if (typeof data.clock === "string") document.getElementById("clockUtc").value = data.clock;
|
||||
if (typeof data.public_key === "string") document.getElementById("publicKey").value = data.public_key.toUpperCase();
|
||||
if (typeof data.mqtt_eastmesh_au === "string") setBrokerToggle("mqttEastmeshAu", data.mqtt_eastmesh_au);
|
||||
if (typeof data.mqtt_letsmesh_eu === "string") setBrokerToggle("mqttLetsmeshEu", data.mqtt_letsmesh_eu);
|
||||
if (typeof data.mqtt_letsmesh_us === "string") setBrokerToggle("mqttLetsmeshUs", data.mqtt_letsmesh_us);
|
||||
syncRadioPresetUi();
|
||||
updateBrokerWarning();
|
||||
}
|
||||
function getLetsmeshMode() {
|
||||
const eu = document.getElementById("mqttLetsmeshEu");
|
||||
@@ -1376,17 +1355,13 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
refreshLetsmeshModeUi();
|
||||
}
|
||||
}
|
||||
function updateBrokerWarning() {
|
||||
document.getElementById("mqttBrokerWarning").textContent = "";
|
||||
}
|
||||
async function loadBrokerState(cmd, inputId) {
|
||||
const result = await runCommand(cmd);
|
||||
async function loadBrokerState(cmd, inputId, options = {}) {
|
||||
const result = await runCommand(cmd, options);
|
||||
if (!result.ok) return;
|
||||
setBrokerToggle(inputId, parseReplyValue(result.text));
|
||||
updateBrokerWarning();
|
||||
}
|
||||
async function loadRadioConfig() {
|
||||
const result = await runCommand("get radio");
|
||||
async function loadRadioConfig(options = {}) {
|
||||
const result = await runCommand("get radio", options);
|
||||
if (!result.ok) {
|
||||
setRadioPresetStatus("Unable to load current radio config.", true);
|
||||
return;
|
||||
@@ -1400,6 +1375,16 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
setRadioPresetStatus("");
|
||||
syncRadioPresetUi();
|
||||
}
|
||||
function pause(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
async function loadSection(title, tasks) {
|
||||
statusEl.textContent = title;
|
||||
for (const task of tasks) {
|
||||
await task();
|
||||
}
|
||||
await pause(40);
|
||||
}
|
||||
async function loadRadioPresets() {
|
||||
const selectEl = document.getElementById("radioPreset");
|
||||
const applyBtn = document.getElementById("applyRadioPresetBtn");
|
||||
@@ -1493,13 +1478,11 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
if (!result.ok) {
|
||||
refreshEastmeshModeUi();
|
||||
refreshLetsmeshModeUi();
|
||||
updateBrokerWarning();
|
||||
return;
|
||||
}
|
||||
setBrokerToggle("mqttEastmeshAu", enabled ? "on" : "off");
|
||||
refreshEastmeshModeUi();
|
||||
refreshLetsmeshModeUi();
|
||||
updateBrokerWarning();
|
||||
}
|
||||
const eastmeshModeSlider = document.getElementById("mqttEastmeshMode");
|
||||
if (eastmeshModeSlider) {
|
||||
@@ -1513,7 +1496,6 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
async function setLetsmeshMode(mode) {
|
||||
const eastmesh = document.getElementById("mqttEastmeshAu");
|
||||
if (mode === "both" && eastmesh && eastmesh.checked) {
|
||||
updateBrokerWarning();
|
||||
refreshLetsmeshModeUi();
|
||||
return;
|
||||
}
|
||||
@@ -1532,13 +1514,11 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
const result = await runCommand(command);
|
||||
if (!result.ok) {
|
||||
refreshLetsmeshModeUi();
|
||||
updateBrokerWarning();
|
||||
return;
|
||||
}
|
||||
setBrokerToggle(inputId, nextState);
|
||||
}
|
||||
refreshLetsmeshModeUi();
|
||||
updateBrokerWarning();
|
||||
}
|
||||
const letsmeshModeSlider = document.getElementById("mqttLetsmeshMode");
|
||||
if (letsmeshModeSlider) {
|
||||
@@ -1615,30 +1595,43 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
return;
|
||||
}
|
||||
showAuthedUi(true);
|
||||
const quiet = { recordHistory:false, updateInput:false };
|
||||
try {
|
||||
applyBootstrapData(await fetchJson("/api/bootstrap"));
|
||||
} catch (_) {
|
||||
await loadSection("Loading info...", [
|
||||
() => loadField("get role", "roleValue", null, quiet),
|
||||
() => loadField("clock", "clockUtc", null, quiet),
|
||||
() => loadField("get public.key", "publicKey", "uppercase", quiet)
|
||||
]);
|
||||
await loadSection("Loading repeater settings...", [
|
||||
() => loadField("get name", "nodeName", null, quiet),
|
||||
() => loadField("get lat", "nodeLat", null, quiet),
|
||||
() => loadField("get lon", "nodeLon", null, quiet),
|
||||
() => loadField("get prv.key", "privateKey", "uppercase", quiet),
|
||||
() => loadField("get owner.info", "ownerInfo", "multiline", quiet)
|
||||
]);
|
||||
await loadSection("Loading radio settings...", [
|
||||
() => loadRadioConfig(quiet),
|
||||
() => loadField("get path.hash.mode", "pathHashMode", null, quiet)
|
||||
]);
|
||||
await loadSection("Loading advertising...", [
|
||||
() => loadField("get advert.interval", "advertInterval", null, quiet),
|
||||
() => loadField("get flood.advert.interval", "floodInterval", null, quiet),
|
||||
() => loadField("get flood.max", "floodMax", null, quiet)
|
||||
]);
|
||||
await loadSection("Loading MQTT settings...", [
|
||||
() => loadField("get mqtt.iata", "mqttIata", null, quiet),
|
||||
() => loadField("get mqtt.owner", "mqttOwner", null, quiet),
|
||||
() => loadField("get mqtt.email", "mqttEmail", null, quiet),
|
||||
() => loadBrokerState("get mqtt.eastmesh-au", "mqttEastmeshAu", quiet),
|
||||
() => loadBrokerState("get mqtt.letsmesh-eu", "mqttLetsmeshEu", quiet),
|
||||
() => loadBrokerState("get mqtt.letsmesh-us", "mqttLetsmeshUs", quiet)
|
||||
]);
|
||||
statusEl.textContent = "Ready";
|
||||
} catch (error) {
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
await Promise.all([
|
||||
loadField("get name", "nodeName"),
|
||||
loadField("get mqtt.iata", "mqttIata"),
|
||||
loadField("get mqtt.owner", "mqttOwner"),
|
||||
loadField("get mqtt.email", "mqttEmail"),
|
||||
loadBrokerState("get mqtt.eastmesh-au", "mqttEastmeshAu"),
|
||||
loadBrokerState("get mqtt.letsmesh-eu", "mqttLetsmeshEu"),
|
||||
loadBrokerState("get mqtt.letsmesh-us", "mqttLetsmeshUs"),
|
||||
loadField("get advert.interval", "advertInterval"),
|
||||
loadField("get flood.advert.interval", "floodInterval"),
|
||||
loadField("get flood.max", "floodMax"),
|
||||
loadField("get path.hash.mode", "pathHashMode"),
|
||||
loadField("get prv.key", "privateKey", "uppercase"),
|
||||
loadField("get role", "roleValue"),
|
||||
loadField("clock", "clockUtc"),
|
||||
loadField("get public.key", "publicKey", "uppercase"),
|
||||
loadRadioConfig()
|
||||
]);
|
||||
statusEl.textContent = error && error.message ? error.message : "Unable to load repeater settings.";
|
||||
}
|
||||
loadRadioPresets();
|
||||
}
|
||||
@@ -1697,13 +1690,11 @@ bool WebPanelServer::start() {
|
||||
httpd_uri_t app_uri = {.uri = "/app", .method = HTTP_GET, .handler = &WebPanelServer::handleApp, .user_ctx = &_route_context};
|
||||
httpd_uri_t login_uri = {.uri = "/login", .method = HTTP_POST, .handler = &WebPanelServer::handleLogin, .user_ctx = &_route_context};
|
||||
httpd_uri_t command_uri = {.uri = "/api/command", .method = HTTP_POST, .handler = &WebPanelServer::handleCommand, .user_ctx = &_route_context};
|
||||
httpd_uri_t bootstrap_uri = {.uri = "/api/bootstrap", .method = HTTP_GET, .handler = &WebPanelServer::handleBootstrap, .user_ctx = &_route_context};
|
||||
httpd_uri_t stats_uri = {.uri = "/api/stats", .method = HTTP_GET, .handler = &WebPanelServer::handleStats, .user_ctx = &_route_context};
|
||||
httpd_register_uri_handler(_server, &index_uri);
|
||||
httpd_register_uri_handler(_server, &app_uri);
|
||||
httpd_register_uri_handler(_server, &login_uri);
|
||||
httpd_register_uri_handler(_server, &command_uri);
|
||||
httpd_register_uri_handler(_server, &bootstrap_uri);
|
||||
httpd_register_uri_handler(_server, &stats_uri);
|
||||
WEB_PANEL_LOG("server started on https://%s/", WiFi.localIP().toString().c_str());
|
||||
return true;
|
||||
@@ -1826,77 +1817,6 @@ esp_err_t WebPanelServer::handleCommand(httpd_req_t* req) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
esp_err_t WebPanelServer::handleBootstrap(httpd_req_t* req) {
|
||||
auto* ctx = static_cast<RouteContext*>(req->user_ctx);
|
||||
if (ctx == nullptr || ctx->self == nullptr || ctx->self->_runner == nullptr) {
|
||||
return httpd_resp_send_500(req);
|
||||
}
|
||||
if (!ctx->self->isAuthorized(req)) {
|
||||
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
|
||||
}
|
||||
|
||||
ctx->self->noteActivity();
|
||||
char* reply = allocScratchBuffer(kWebReplyBufferSize);
|
||||
if (reply == nullptr) {
|
||||
freeScratchBuffer(reply);
|
||||
return httpd_resp_send_500(req);
|
||||
}
|
||||
|
||||
const struct {
|
||||
const char* key;
|
||||
const char* command;
|
||||
} fields[] = {
|
||||
{"name", "get name"},
|
||||
{"mqtt_iata", "get mqtt.iata"},
|
||||
{"mqtt_owner", "get mqtt.owner"},
|
||||
{"mqtt_email", "get mqtt.email"},
|
||||
{"mqtt_eastmesh_au", "get mqtt.eastmesh-au"},
|
||||
{"mqtt_letsmesh_eu", "get mqtt.letsmesh-eu"},
|
||||
{"mqtt_letsmesh_us", "get mqtt.letsmesh-us"},
|
||||
{"advert_interval", "get advert.interval"},
|
||||
{"flood_interval", "get flood.advert.interval"},
|
||||
{"flood_max", "get flood.max"},
|
||||
{"path_hash_mode", "get path.hash.mode"},
|
||||
{"private_key", "get prv.key"},
|
||||
{"role", "get role"},
|
||||
{"clock", "clock"},
|
||||
{"public_key", "get public.key"},
|
||||
{"radio", "get radio"},
|
||||
};
|
||||
|
||||
httpd_resp_set_type(req, "application/json; charset=utf-8");
|
||||
httpd_resp_set_hdr(req, "Cache-Control", "no-store");
|
||||
if (sendChunk(req, "{") != ESP_OK) {
|
||||
freeScratchBuffer(reply);
|
||||
httpd_resp_sendstr_chunk(req, nullptr);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
for (size_t i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
|
||||
memset(reply, 0, kWebReplyBufferSize);
|
||||
ctx->self->_runner->runWebCommand(fields[i].command, reply, kWebReplyBufferSize);
|
||||
const char* value = reply;
|
||||
if (value[0] == '>' && value[1] == ' ') {
|
||||
value += 2;
|
||||
}
|
||||
if (strcmp(value, "-") == 0) {
|
||||
value = "";
|
||||
}
|
||||
if (sendJsonFieldChunk(req, fields[i].key, value, i != 0) != ESP_OK) {
|
||||
freeScratchBuffer(reply);
|
||||
httpd_resp_sendstr_chunk(req, nullptr);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
esp_err_t rc = sendChunk(req, "}");
|
||||
if (rc == ESP_OK) {
|
||||
rc = httpd_resp_sendstr_chunk(req, nullptr);
|
||||
} else {
|
||||
httpd_resp_sendstr_chunk(req, nullptr);
|
||||
}
|
||||
freeScratchBuffer(reply);
|
||||
return rc;
|
||||
}
|
||||
|
||||
esp_err_t WebPanelServer::handleStats(httpd_req_t* req) {
|
||||
auto* ctx = static_cast<RouteContext*>(req->user_ctx);
|
||||
if (ctx == nullptr || ctx->self == nullptr || ctx->self->_runner == nullptr) {
|
||||
|
||||
@@ -47,7 +47,6 @@ private:
|
||||
static esp_err_t handleApp(httpd_req_t* req);
|
||||
static esp_err_t handleLogin(httpd_req_t* req);
|
||||
static esp_err_t handleCommand(httpd_req_t* req);
|
||||
static esp_err_t handleBootstrap(httpd_req_t* req);
|
||||
static esp_err_t handleStats(httpd_req_t* req);
|
||||
|
||||
bool readRequestBody(httpd_req_t* req, char* buffer, size_t buffer_size) const;
|
||||
|
||||
Ссылка в новой задаче
Block a user