Merge branch 'implement_buffer_queue' into frame_helper_optimize_cleanup_api

This commit is contained in:
J. Nick Koston
2025-05-15 01:54:52 -05:00
4 changed files with 46 additions and 38 deletions

View File

@@ -91,12 +91,14 @@ APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
// Try to send the remaining data in this buffer
ssize_t sent = this->socket_->write(front_buffer.current_data(), front_buffer.remaining());
if (this->is_would_block(sent)) {
// Socket would block, we'll try again later
} else if (sent == -1) {
ESP_LOGVV(TAG, "%s: Socket write failed with errno %d", this->info_.c_str(), errno);
this->state_ = State::FAILED;
return APIError::SOCKET_WRITE_FAILED; // Socket write failed
if (sent == -1) {
if (errno != EWOULDBLOCK && errno != EAGAIN) {
// Real socket error (not just would block)
ESP_LOGVV(TAG, "%s: Socket write failed with errno %d", this->info_.c_str(), errno);
this->state_ = State::FAILED;
return APIError::SOCKET_WRITE_FAILED; // Socket write failed
}
// Socket would block, we'll try again later and continue execution to append new data to the buffer
} else if (sent > 0 && static_cast<size_t>(sent) < front_buffer.remaining()) {
// Partially sent, update offset
front_buffer.offset += sent;
@@ -129,19 +131,20 @@ APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
// Try to send directly if no buffered data
ssize_t sent = this->socket_->writev(iov, iovcnt);
if (this->is_would_block(sent)) {
// Socket would block, buffer the data
SendBuffer buffer;
buffer.data.reserve(total_write_len);
if (sent == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
// Socket would block, buffer the data
SendBuffer buffer;
buffer.data.reserve(total_write_len);
for (int i = 0; i < iovcnt; i++) {
const uint8_t *data = reinterpret_cast<uint8_t *>(iov[i].iov_base);
buffer.data.insert(buffer.data.end(), data, data + iov[i].iov_len);
for (int i = 0; i < iovcnt; i++) {
const uint8_t *data = reinterpret_cast<uint8_t *>(iov[i].iov_base);
buffer.data.insert(buffer.data.end(), data, data + iov[i].iov_len);
}
this->tx_buf_.push_back(std::move(buffer));
return APIError::OK; // Success, data buffered
}
this->tx_buf_.push_back(std::move(buffer));
return APIError::OK; // Success, data buffered
} else if (sent == -1) {
// Socket error
ESP_LOGVV(TAG, "%s: Socket write failed with errno %d", this->info_.c_str(), errno);
this->state_ = State::FAILED;
@@ -184,10 +187,11 @@ APIError APIFrameHelper::try_send_tx_buf_() {
// Try to send the remaining data in this buffer
ssize_t sent = this->socket_->write(front_buffer.current_data(), front_buffer.remaining());
if (this->is_would_block(sent)) {
// Socket would block, try again later
break;
} else if (sent == -1) {
if (sent == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
// Socket would block, try again later
break;
}
// Socket error
state_ = State::FAILED;
ESP_LOGVV(TAG, "%s: Socket write failed with errno %d", this->info_.c_str(), errno);

View File

@@ -164,14 +164,6 @@ class APIFrameHelper {
// Try to send data from the tx buffer
APIError try_send_tx_buf_();
// Check if the socket would block based on return value
inline bool is_would_block(ssize_t ret) const {
if (ret == -1) {
return errno == EWOULDBLOCK || errno == EAGAIN;
}
return ret == 0;
}
};
#ifdef USE_API_NOISE

View File

@@ -20,16 +20,26 @@ class ProtoVarInt {
explicit ProtoVarInt(uint64_t value) : value_(value) {}
static optional<ProtoVarInt> parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed) {
if (consumed != nullptr)
*consumed = 0;
if (len == 0)
if (len == 0) {
if (consumed != nullptr)
*consumed = 0;
return {};
}
uint64_t result = 0;
uint8_t bitpos = 0;
// Most common case: single-byte varint (values 0-127)
if ((buffer[0] & 0x80) == 0) {
if (consumed != nullptr)
*consumed = 1;
return ProtoVarInt(buffer[0]);
}
for (uint32_t i = 0; i < len; i++) {
// General case for multi-byte varints
// Since we know buffer[0]'s high bit is set, initialize with its value
uint64_t result = buffer[0] & 0x7F;
uint8_t bitpos = 7;
// Start from the second byte since we've already processed the first
for (uint32_t i = 1; i < len; i++) {
uint8_t val = buffer[i];
result |= uint64_t(val & 0x7F) << uint64_t(bitpos);
bitpos += 7;
@@ -40,7 +50,9 @@ class ProtoVarInt {
}
}
return {};
if (consumed != nullptr)
*consumed = 0;
return {}; // Incomplete or invalid varint
}
uint32_t as_uint32() const { return this->value_; }

View File

@@ -19,7 +19,7 @@ puremagic==1.29
ruamel.yaml==0.18.10 # dashboard_import
esphome-glyphsets==0.2.0
pillow==10.4.0
cairosvg==2.8.0
cairosvg==2.8.1
freetype-py==2.5.1
# esp-idf requires this, but doesn't bundle it by default