Don't forget to flush twice!

I’ve been building with the std.crypto.tls.Client and after the recent Io changes found some unexpected behavior.
After writing to the Client’s cleartext writer, I made sure to flush. I then kept going and tried to read, but the client hung. After some digging, it finally occured to me that while I was flushing the cleartext, it was still buffering the ciphertext writer. I have to also flush the ciphertext writer if I want this to actually send the data to the server. Not too big a deal, but a potential cause for new users to experience some frustration if they don’t flush both writers.

Is it realistic to expect flushing the cleartext to write the ciphertext too? I guess there are cases where you write a lot of cleartext which will internally flush before you would be ready to send the ciphertext. This allows for more controll over the buffers.
Would it be good to add a secondary method that flushes both? Maybe on the client itself? This is the workaround I went with. My session has it’s own flush that clears both the cleartext and ciphertext out to the server.

Hi, sorry, random ex-lurker, feel free to ignore.

My session has it’s own flush that clears both the cleartext and ciphertext out to the server.

I think the assumption that calling flush on 1 writer inside of a struct that happens to have 1 or more other writers would flush all the writers breaks a lot of the ‘rules’ Zig has set for itself. IF struct has a complex internal state and is kinda just using the writers as an outbox, I think we (Zig users) generally expect that to be completely obscured by a API layer or a vtable implementation.

Like… yes, there’s no such thing as a non-evil boilerplate, but I also don’t think there’s such a thing as no boilerplate (especially in systems programming).

I think it’d be reasonable to have something like flushAll() on the parent struct that… literally flushes all of its component buffers, but that probably involves determining which buffers get flushed when. Are there cases where we want to NoOp a specific flush because -business logic-?

In those cases though, it will be something the developer would be expected to roll themselves, because there’s never going to be a set-in-stone relationship between two disparate writers, even if they are in the same host struct.

Just my 2c, I might be an idiot

5 Likes

I would say it depends on which interface you provide.
If your code provides a Writer as interface I would expect a flush in that interface pushes all data to the final destination.
I would probably provide a writer that does that, and allow access to both writers for users needing more control.

1 Like