tink_http
tink_http copied to clipboard
Upload progress
Hmm. Off the top of my head, I'd say this can be implemented once in Client rather than in each ClientObject. Not sure that's better, but it's certainly less work ^^
How does that work?
Well. For starters we need something to monitor the progress of a source. This looks like it might do the trick:
class WithProgress<E> extends StreamBase<Chunk, E> {
var data:SourceObject<E>;
var progressed:Int->Void;
var written:Int;
override function get_depleted():Bool
return data.depleted;
public function new(data, progressed, written = 0) {
this.data = data;
this.progressed = progressed;
this.written = written;
}
override function next():Future<Step<Chunk, E>> {
return data.next().map(function (step) return switch step {
case Link(value, next):
var written = this.written + value.length;
progressed(written);
Link(value, new WithProgress(next, progressed, written));
default: step;
});
}
override function forEach<Safety>(handler:Handler<Chunk, Safety>):Future<Conclusion<Chunk, Safety, E>> {
var written = this.written;
return data.forEach(function (chunk) {
return handler.apply(chunk).map(function (h) {
if (h.match(Finish | Resume))
progressed(written += chunk.length);
return h;
});
}).map(function (conclusion):Conclusion<Chunk, Safety, E> return switch conclusion {
case Halted(rest): Halted(new WithProgress(rest, progressed, written));
case Clogged(error, at): Clogged(error, new WithProgress(at, progressed, written));
case Failed(error): Failed(error);
case Depleted: Depleted;
});
}
}
It's not 100% ideal. For example calling Stream::next will count as progress, no matter whether the bytes are actually processed or not. But in case the consumer then starts forEach on the original stream (rather than the tail of the Link), it starts counting again at 0, so the number should be correct. Or so I hope ^^
With that in place, in the presence of a progress handler, you can extract the total size from the corresponding message head (if set) and wrap the message body WithProgress so that it calls the handler appropriately.
But of course this presumes that the underlying client can actually gradually read the data from the Source, which some platforms might not allow.