-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Addition of PsychicStreamResponse & update to PsychicFileResponse. #45
Conversation
…used, _chunked not used.
…Length already set it.
Okay, this is awesome. I'm a bit busy with the holidays now, but I will check this out and merge it shortly. |
All good, check it over and see if the other additions I mentioned might be worth it. Also, I'm confident the Enjoy your new year. |
I have added another commit which adds an override for the This makes Also, moving the implementation to a cpp file prevents duplication as it is used between |
I have also updated |
if(_buffer) | ||
return ESP_OK; | ||
|
||
//Buffer to hold ChunkPrinter and stream buffer. Using placement new will keep us at a single allocation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's clever!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cheers, seeing as this response type is split (begin/end) placement new suits this situation well.
The response stream could be derived directly from the ChunkPrinter
, however that would require the memory to be allocated during the constructor; and short lived allocations help prevent fragmentation on our constrained hardware target.
This also follows the trend of the other responses by allocating buffers once send()
is called.
Sorry about the delay in merging this. Its been a busy holiday season. @Chris--A is that Content-Disposition header in the constructor really necessary? Just don't want to have a situation where someone wants to remove it for something we didnt expect and cause other breakages in code that relies on it. |
@hoeken, are you referring to the 2 param constructor (inline disposition), or both constructors? |
Hi, I tried to use the PsychicStreamResponse to serialize a JsonDocument, but it's slow and the header "Content-Type:" reponse was almost always garbage, causing problems on the client side.
Sending a text buffer is faster and without any header garbage.
J. |
First, this PR makes a few changes to
PsychicFileResponse
. There are a few instance variables that are not needed, and a few redundant calls. Resolves #44The main feature is a new class
PsychicStreamResponse
to allow using thePrint
interface to stream raw data.I stayed away from copying what ESPAsyncWebServer does, especially as their implementation is limited in size (me-no-dev/ESPAsyncWebServer#179 (comment)).
This implementation makes use of the existing
ChunkPrinter
using a small buffer and supports unlimited size (no content length header is sent).I was going to create two classes:
PsychicStreamResponse
to keep with the typical fashion of passing aStream
to the constructor and usingresponse.send()
to initiate the copy.PsychicResponseStream
to use aPrint
interface (like ESPAsyncWebServer).However, by adding the
copyFrom()
function to this candidate, it covers both classes in one.Basic rundown of features:
Serial
.Print
object.Stream
to the response to send the entire stream.Example 1 - Using the
Print
interface:Example 2 - Passing to other functions as a
Print
object:Sending a file can be done using
PsychicFileResponse
, this example is just to highlight thePrint
base class.Example 3 - Copying from a
Stream
:Sending a file can be done using
PsychicFileResponse
, this example is just to highlight copying anyStream
.Example 4 - Sending a download.
There are two constructors, the 2 param constructor in the above examples sends the response as
inline
. The 3 param constructor takes a name which is used as the download file name.I have a number of ideas we can discuss if warranted, this was the version I ended up with for the easiest use and safety.
One idea is to add a
send()
function. It can internally call thebeginSend()
&endSend()
. An extra check will be needed to ensure no printer is setup afterendSend()
is called.Another overload could handle a
Stream
:return response.send(myStream);
However, there is no accommodation for closing a
FIle
if it is passed in, so another specific overload would be needed forFile
which can call theStream
overload, then close the file.Although these ideas might make for some nice looking syntax, and can prevent using
beginSend()
&endSend()
, they do not really add much value. But I'm open to adding these in (already tested) as they allow the user to choose.