mirror of
https://github.com/esphome/esphome.git
synced 2025-07-30 15:16:37 +00:00
[api] Fix string lifetime issue in Home Assistant service calls with templated values
This commit is contained in:
parent
d54db471bd
commit
0155769ffe
@ -759,7 +759,7 @@ message SubscribeHomeassistantServicesRequest {
|
|||||||
|
|
||||||
message HomeassistantServiceMap {
|
message HomeassistantServiceMap {
|
||||||
string key = 1;
|
string key = 1;
|
||||||
string value = 2;
|
string value = 2 [(no_zero_copy) = true];
|
||||||
}
|
}
|
||||||
|
|
||||||
message HomeassistantServiceResponse {
|
message HomeassistantServiceResponse {
|
||||||
|
@ -27,4 +27,5 @@ extend google.protobuf.MessageOptions {
|
|||||||
extend google.protobuf.FieldOptions {
|
extend google.protobuf.FieldOptions {
|
||||||
optional string field_ifdef = 1042;
|
optional string field_ifdef = 1042;
|
||||||
optional uint32 fixed_array_size = 50007;
|
optional uint32 fixed_array_size = 50007;
|
||||||
|
optional bool no_zero_copy = 50008 [default=false];
|
||||||
}
|
}
|
||||||
|
@ -845,11 +845,11 @@ void NoiseEncryptionSetKeyResponse::calculate_size(uint32_t &total_size) const {
|
|||||||
#endif
|
#endif
|
||||||
void HomeassistantServiceMap::encode(ProtoWriteBuffer buffer) const {
|
void HomeassistantServiceMap::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_string(1, this->key_ref_);
|
buffer.encode_string(1, this->key_ref_);
|
||||||
buffer.encode_string(2, this->value_ref_);
|
buffer.encode_string(2, this->value);
|
||||||
}
|
}
|
||||||
void HomeassistantServiceMap::calculate_size(uint32_t &total_size) const {
|
void HomeassistantServiceMap::calculate_size(uint32_t &total_size) const {
|
||||||
ProtoSize::add_string_field(total_size, 1, this->key_ref_.size());
|
ProtoSize::add_string_field(total_size, 1, this->key_ref_.size());
|
||||||
ProtoSize::add_string_field(total_size, 1, this->value_ref_.size());
|
ProtoSize::add_string_field(total_size, 1, this->value);
|
||||||
}
|
}
|
||||||
void HomeassistantServiceResponse::encode(ProtoWriteBuffer buffer) const {
|
void HomeassistantServiceResponse::encode(ProtoWriteBuffer buffer) const {
|
||||||
buffer.encode_string(1, this->service_ref_);
|
buffer.encode_string(1, this->service_ref_);
|
||||||
|
@ -1061,8 +1061,7 @@ class HomeassistantServiceMap : public ProtoMessage {
|
|||||||
public:
|
public:
|
||||||
StringRef key_ref_{};
|
StringRef key_ref_{};
|
||||||
void set_key(const StringRef &ref) { this->key_ref_ = ref; }
|
void set_key(const StringRef &ref) { this->key_ref_ = ref; }
|
||||||
StringRef value_ref_{};
|
std::string value{};
|
||||||
void set_value(const StringRef &ref) { this->value_ref_ = ref; }
|
|
||||||
void encode(ProtoWriteBuffer buffer) const override;
|
void encode(ProtoWriteBuffer buffer) const override;
|
||||||
void calculate_size(uint32_t &total_size) const override;
|
void calculate_size(uint32_t &total_size) const override;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
@ -1044,7 +1044,7 @@ void SubscribeHomeassistantServicesRequest::dump_to(std::string &out) const {
|
|||||||
void HomeassistantServiceMap::dump_to(std::string &out) const {
|
void HomeassistantServiceMap::dump_to(std::string &out) const {
|
||||||
MessageDumpHelper helper(out, "HomeassistantServiceMap");
|
MessageDumpHelper helper(out, "HomeassistantServiceMap");
|
||||||
dump_field(out, "key", this->key_ref_);
|
dump_field(out, "key", this->key_ref_);
|
||||||
dump_field(out, "value", this->value_ref_);
|
dump_field(out, "value", this->value);
|
||||||
}
|
}
|
||||||
void HomeassistantServiceResponse::dump_to(std::string &out) const {
|
void HomeassistantServiceResponse::dump_to(std::string &out) const {
|
||||||
MessageDumpHelper helper(out, "HomeassistantServiceResponse");
|
MessageDumpHelper helper(out, "HomeassistantServiceResponse");
|
||||||
|
@ -69,22 +69,19 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
|
|||||||
resp.data.emplace_back();
|
resp.data.emplace_back();
|
||||||
auto &kv = resp.data.back();
|
auto &kv = resp.data.back();
|
||||||
kv.set_key(StringRef(it.key));
|
kv.set_key(StringRef(it.key));
|
||||||
std::string value = it.value.value(x...);
|
kv.value = it.value.value(x...);
|
||||||
kv.set_value(StringRef(value));
|
|
||||||
}
|
}
|
||||||
for (auto &it : this->data_template_) {
|
for (auto &it : this->data_template_) {
|
||||||
resp.data_template.emplace_back();
|
resp.data_template.emplace_back();
|
||||||
auto &kv = resp.data_template.back();
|
auto &kv = resp.data_template.back();
|
||||||
kv.set_key(StringRef(it.key));
|
kv.set_key(StringRef(it.key));
|
||||||
std::string value = it.value.value(x...);
|
kv.value = it.value.value(x...);
|
||||||
kv.set_value(StringRef(value));
|
|
||||||
}
|
}
|
||||||
for (auto &it : this->variables_) {
|
for (auto &it : this->variables_) {
|
||||||
resp.variables.emplace_back();
|
resp.variables.emplace_back();
|
||||||
auto &kv = resp.variables.back();
|
auto &kv = resp.variables.back();
|
||||||
kv.set_key(StringRef(it.key));
|
kv.set_key(StringRef(it.key));
|
||||||
std::string value = it.value.value(x...);
|
kv.value = it.value.value(x...);
|
||||||
kv.set_value(StringRef(value));
|
|
||||||
}
|
}
|
||||||
this->parent_->send_homeassistant_service_call(resp);
|
this->parent_->send_homeassistant_service_call(resp);
|
||||||
}
|
}
|
||||||
|
@ -562,11 +562,16 @@ class StringType(TypeInfo):
|
|||||||
@property
|
@property
|
||||||
def public_content(self) -> list[str]:
|
def public_content(self) -> list[str]:
|
||||||
content: list[str] = []
|
content: list[str] = []
|
||||||
# Add std::string storage if message needs decoding
|
|
||||||
if self._needs_decode:
|
# Check if no_zero_copy option is set
|
||||||
|
no_zero_copy = get_field_opt(self._field, pb.no_zero_copy, False)
|
||||||
|
|
||||||
|
# Add std::string storage if message needs decoding OR if no_zero_copy is set
|
||||||
|
if self._needs_decode or no_zero_copy:
|
||||||
content.append(f"std::string {self.field_name}{{}};")
|
content.append(f"std::string {self.field_name}{{}};")
|
||||||
|
|
||||||
if self._needs_encode:
|
# Only add StringRef if encoding is needed AND no_zero_copy is not set
|
||||||
|
if self._needs_encode and not no_zero_copy:
|
||||||
content.extend(
|
content.extend(
|
||||||
[
|
[
|
||||||
# Add StringRef field if message needs encoding
|
# Add StringRef field if message needs encoding
|
||||||
@ -581,13 +586,28 @@ class StringType(TypeInfo):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def encode_content(self) -> str:
|
def encode_content(self) -> str:
|
||||||
return f"buffer.encode_string({self.number}, this->{self.field_name}_ref_);"
|
# Check if no_zero_copy option is set
|
||||||
|
no_zero_copy = get_field_opt(self._field, pb.no_zero_copy, False)
|
||||||
|
|
||||||
|
if no_zero_copy:
|
||||||
|
# Use the std::string directly
|
||||||
|
return f"buffer.encode_string({self.number}, this->{self.field_name});"
|
||||||
|
else:
|
||||||
|
# Use the StringRef
|
||||||
|
return f"buffer.encode_string({self.number}, this->{self.field_name}_ref_);"
|
||||||
|
|
||||||
def dump(self, name):
|
def dump(self, name):
|
||||||
|
# Check if no_zero_copy option is set
|
||||||
|
no_zero_copy = get_field_opt(self._field, pb.no_zero_copy, False)
|
||||||
|
|
||||||
# If name is 'it', this is a repeated field element - always use string
|
# If name is 'it', this is a repeated field element - always use string
|
||||||
if name == "it":
|
if name == "it":
|
||||||
return "append_quoted_string(out, StringRef(it));"
|
return "append_quoted_string(out, StringRef(it));"
|
||||||
|
|
||||||
|
# If no_zero_copy is set, always use std::string
|
||||||
|
if no_zero_copy:
|
||||||
|
return f'out.append("\'").append(this->{self.field_name}).append("\'");'
|
||||||
|
|
||||||
# For SOURCE_CLIENT only, always use std::string
|
# For SOURCE_CLIENT only, always use std::string
|
||||||
if not self._needs_encode:
|
if not self._needs_encode:
|
||||||
return f'out.append("\'").append(this->{self.field_name}).append("\'");'
|
return f'out.append("\'").append(this->{self.field_name}).append("\'");'
|
||||||
@ -607,6 +627,13 @@ class StringType(TypeInfo):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def dump_content(self) -> str:
|
def dump_content(self) -> str:
|
||||||
|
# Check if no_zero_copy option is set
|
||||||
|
no_zero_copy = get_field_opt(self._field, pb.no_zero_copy, False)
|
||||||
|
|
||||||
|
# If no_zero_copy is set, always use std::string
|
||||||
|
if no_zero_copy:
|
||||||
|
return f'dump_field(out, "{self.name}", this->{self.field_name});'
|
||||||
|
|
||||||
# For SOURCE_CLIENT only, use std::string
|
# For SOURCE_CLIENT only, use std::string
|
||||||
if not self._needs_encode:
|
if not self._needs_encode:
|
||||||
return f'dump_field(out, "{self.name}", this->{self.field_name});'
|
return f'dump_field(out, "{self.name}", this->{self.field_name});'
|
||||||
@ -622,8 +649,11 @@ class StringType(TypeInfo):
|
|||||||
return o
|
return o
|
||||||
|
|
||||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||||
# For SOURCE_CLIENT only messages, use the string field directly
|
# Check if no_zero_copy option is set
|
||||||
if not self._needs_encode:
|
no_zero_copy = get_field_opt(self._field, pb.no_zero_copy, False)
|
||||||
|
|
||||||
|
# For SOURCE_CLIENT only messages or no_zero_copy, use the string field directly
|
||||||
|
if not self._needs_encode or no_zero_copy:
|
||||||
return self._get_simple_size_calculation(name, force, "add_string_field")
|
return self._get_simple_size_calculation(name, force, "add_string_field")
|
||||||
|
|
||||||
# Check if this is being called from a repeated field context
|
# Check if this is being called from a repeated field context
|
||||||
|
Loading…
x
Reference in New Issue
Block a user