Skip to content
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

Client upload progress #57

Open
kevinresol opened this issue Dec 7, 2016 · 9 comments
Open

Client upload progress #57

kevinresol opened this issue Dec 7, 2016 · 9 comments

Comments

@kevinresol
Copy link
Member

Suggest changing the api to:

function request(request:OutgoingRequest): Signal<Progress<IncomingResponse>>

and enum Progress<T> { Done(data:<T>); Progress(fraction:Float); Failed(error:Error);}

@kevinresol
Copy link
Member Author

or to make sure the response won't get lost, request could return:

{
  progress: Signal<Float>,
  repsonse: Future<IncomingResponse>,
}

@kevinresol
Copy link
Member Author

Hm... should even split to uploadProgress and downloadProgress

@kevinresol
Copy link
Member Author

and need a way to abort

@back2dos
Copy link
Member

back2dos commented Dec 7, 2016

Progress is tricky, because in either direction content-length needn't be set. I guess this is roughly the best we can do:

interface HttpTransaction {
  var bytesWritten(get, never):Observable<Int>;
  var bytesRead(get, never):Observable<Int>;
  var response(get, never):Future<IncomingResponse>;
  function abort():Future<Bool>;
}

Aborting is going to be a PITA, I can tell you. A lot of fun stuff like ensuring the body of the OutgoingRequest is properly closed to avoid keeping files open and what not. But sure, it can be done :)

@kevinresol
Copy link
Member Author

Can we still include content length and make it Optional?

@kevinresol
Copy link
Member Author

Now we have tink.state.Progress, any new API proposal here?

@kevinresol
Copy link
Member Author

I think it is just:

function request(req:OutgoingRequest):Progress<Outcome<IncomingResponse, Error>>;

@back2dos
Copy link
Member

Hmm. Looking at the signature, I would probably expect to the progress to report on the download, rather than the upload.

I'm still inclined to think that we might want to return a more complex object that has an upload and download progress and the response. Or it could be something like:

function request(req:OutgoingRequest, ?handlers:{ ?upload:ProgressValue->Void, ?download:ProgressValue->Void }):Progress<Outcome<IncomingResponse, Error>>;

Still doesn't really handle the topic of cancelation though.

@kevinresol
Copy link
Member Author

kevinresol commented Nov 27, 2020

I wrongly thought that the response is only available after the upload is finished but it should not be the case. I think HTTP can produce a response header as soon as the request header is received, without the completely receiving the request body. So Progress<Outcome<IncomingResponse, Error>> is really no good.

As for download progress I thought it should be deduced from the reading of the response body Source, so I am not sure if we need/want a separate observer, unless the response body is given as a complete Chunk.

public function all():Promise<CompleteResponse> {
return this.next(function(r) {
return r.body.all().next(function(chunk) {
return
if(r.header.statusCode >= 400)
Error.withData(r.header.statusCode, r.header.reason, chunk.toString());
else
new CompleteResponse(r.header, chunk);
});
});
}
#if (tink_core >= "2")
public function progress():Promise<ProgressResponse> {
return this.next(function(r) {
return
if(r.header.statusCode >= 400)
r.body.all().next(function(chunk) return Error.withData(r.header.statusCode, r.header.reason, chunk.toString()));
else
new ProgressResponse(
r.header,
tink.core.Progress.make(function(progress, finish) {
var total = switch r.header.getContentLength() {
case Success(len): Some((len:Float));
case Failure(_): None;
}
var chunk = Chunk.EMPTY;
progress(chunk.length, total);
return r.body.chunked()
.forEach(function(part) {
chunk = chunk & part;
progress(chunk.length, total);
return Resume;
})
.handle(function(o) switch o {
case Depleted: finish(Success(chunk));
case Failed(e): finish(Failure(e));
case Halted(_): finish(Failure(new Error('unreachable')));
});
})
);
});
}
#end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants