mirror of https://github.com/arendst/Tasmota.git
Berry Webclient: Change StreamBytes to StreamBeBytesWriter, and improve wc_getbytes (#18837)
This reduces allocation to a single allocaiton, but also theroetically allows the Bytes object to grow if content-length was unset. (cherry picked from commit 936477f5977dd1a4f899498cc7cc0baf05b34a89)
This commit is contained in:
parent
6aed929e17
commit
63cc575c8b
|
@ -654,21 +654,59 @@ extern "C" {
|
|||
}
|
||||
}
|
||||
|
||||
class StreamBytes: public Stream
|
||||
|
||||
// a stream which writes to the Bytes object on the top of the stack
|
||||
class StreamBeBytesWriter: public Stream
|
||||
{
|
||||
public:
|
||||
StreamBytes(uint8_t * buf_in, int len_in) : buf(buf_in), offset(0), len(len_in) {};
|
||||
StreamBeBytesWriter(bvm *vm_in, int increment = 1024) : vm(vm_in), offset(0), incr(increment) {};
|
||||
|
||||
size_t write(const uint8_t *buffer, size_t size) override {
|
||||
// AddLog(LOG_LEVEL_INFO, "FLASH: addr=%p hex=%*_H size=%i", addr_start + offset, 32, buffer, size);
|
||||
if (size > 0) {
|
||||
if (offset + size > len){
|
||||
AddLog(LOG_LEVEL_ERROR, "BERRYWC: bufer overrun");
|
||||
return size;
|
||||
// we need size, not len, so can;t just get len with be_tobytes
|
||||
be_getmember(vm, -1, ".size");
|
||||
int32_t signed_size = be_toint(vm, -1);
|
||||
be_pop(vm, 1); /* bytes() instance is at top */
|
||||
|
||||
// if it won't fit, make the bytes object bigger
|
||||
if (offset + size > signed_size){
|
||||
int newsize = offset + size + incr;
|
||||
AddLog(LOG_LEVEL_INFO, "BE: realloc bytes in StreamBeBytesWriter newsize=%i", newsize);
|
||||
be_getmember(vm, -1, "resize");
|
||||
be_pushvalue(vm, -2);
|
||||
be_pushint(vm, size);
|
||||
be_call(vm, 2); /* call b.resize(size) */
|
||||
be_pop(vm, 3); /* bytes() instance is at top */
|
||||
|
||||
// checkw e got it, because Berry just maxes out?
|
||||
be_getmember(vm, -1, ".size");
|
||||
signed_size = be_toint(vm, -1);
|
||||
be_pop(vm, 1); /* bytes() instance is at top */
|
||||
if (offset + size > signed_size){
|
||||
// what should we raise here???
|
||||
be_raise(vm, "alloc_error", "did not get enough extra bytes");
|
||||
}
|
||||
memcpy(buf+offset, buffer, size);
|
||||
offset += size;
|
||||
}
|
||||
|
||||
// AddLog(LOG_LEVEL_INFO, "FLASH: addr=%p hex=%*_H size=%i", addr_start + offset, 32, buffer, size);
|
||||
if (offset + size > signed_size){
|
||||
AddLog(LOG_LEVEL_ERROR, "BERRYWC: buffer overrun");
|
||||
return size;
|
||||
}
|
||||
|
||||
char *bytebuf = (char*) be_tobytes(vm, -1, NULL); /* we get the address of the internam buffer of size 'size' */
|
||||
if (!bytebuf){
|
||||
AddLog(LOG_LEVEL_ERROR, "BERRYWC: buffer null??");
|
||||
return size;
|
||||
}
|
||||
|
||||
// stream in our chunk
|
||||
memcpy(bytebuf + offset, buffer, size);
|
||||
offset += size;
|
||||
|
||||
// set the len
|
||||
be_pushint(vm, offset);
|
||||
be_setmember(vm, -2, ".len");
|
||||
be_pop(vm, 1);
|
||||
return size;
|
||||
}
|
||||
size_t write(uint8_t data) override {
|
||||
|
@ -682,9 +720,9 @@ public:
|
|||
void flush() override { }
|
||||
|
||||
protected:
|
||||
uint8_t *buf; // start address
|
||||
bvm *vm; // the berry VM
|
||||
uint32_t offset; // how many bytes have already been written
|
||||
uint32_t len; // allocated len
|
||||
size_t incr; // amount to add to size if it does not fit.
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
@ -693,14 +731,16 @@ extern "C" {
|
|||
HTTPClientLight * cl = wc_getclient(vm);
|
||||
int32_t sz = cl->getSize();
|
||||
// abort if we exceed 32KB size, things will not go well otherwise
|
||||
if (sz >= 32767 || sz < 0) {
|
||||
be_raise(vm, "value_error", "response size -1 or too big (>32KB)");
|
||||
if (sz >= 32767) {
|
||||
be_raise(vm, "value_error", "response size too big (>32KB)");
|
||||
}
|
||||
uint8_t * buf = (uint8_t*) be_pushbuffer(vm, sz);
|
||||
StreamBytes memory_writer(buf, sz);
|
||||
// default to 1K starter if contetn-length not present
|
||||
if (sz < 0) sz = 1024;
|
||||
// create a bytes object at top of stack.
|
||||
// the streamwriter knows how to get it.
|
||||
uint8_t * buf = (uint8_t*) be_pushbytes(vm, nullptr, sz);
|
||||
StreamBeBytesWriter memory_writer(vm);
|
||||
int32_t written = cl->writeToStream(&memory_writer);
|
||||
|
||||
be_pushbytes(vm, buf, sz);
|
||||
cl->end(); // free allocated memory ~16KB
|
||||
be_return(vm); /* return code */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue