Darin has proposed a new method: nsIStreamObserver::OnFailure() (or something like that).

Currently nsIStreamObserver has OnStartRequest and OnStopRequest. Those callbacks indicate when the "transaction" has started and when it has stopped.

Sigs for each (grrr. I hate it when sigs change and comments don't reflect it!):

/**  * Called to signify the beginning of an asyncronous request  */
void onStartRequest(in nsIChannel channel,
in nsISupports ctxt);

/**
* Called to signify the end of an asyncronous request.
* @param notif - a notification object containing any error code and error parameters
* (may be null if the notification status is NS_OK)
*/
void onStopRequest(in nsIChannel channel,
in nsISupports ctxt,
in ! nsresult status,
in wstring statusArg);

Currently, let's say I want to popup a status dialog when for a transaction. I would do this when my onStart (ie. throw dialog w/ text "Starting Request") was called, then I'd tear it down when my onStop (ie. change text to "Error occured", then tear down the dialog) was called.

Under the current semantics (which dictate OnStart|OnStop combinations for *every* transaction; whether the transaction is successful or an error), I don't have enough info to *not* throw the dialog if there's an error. I've committed *something*... some level of setup. In my example it was a dialog being thrown and maybe some internal state. In the context of a browser, that may be ok??? We always want to indicate that the user has started something; I think. (ie. "Connecting to host..." -> "Connected ...." -> "Document:done").

You could argue, and some nsIStreamObserver impls support this argument, that OnStart is useless. If I don't want to commit anything because there might be an error (and I don't want to indicated that something has "started"), I'll just have my OnStart() do nothing but return NS_OK. If the transaction is successful my nsIStreamLIstener::OnDataAvailable() will be called (w/ a status code (maybe an error occured *after the connection*)). If the transaction has an error, I can get that info from the OnStop()'s error code. So, I can do everything I want using nsIStreamListener::OnData() and nsISTreamObserver::OnStop(). That's fine, I can do whatever I want w/ my impl. Maybe I don't need OnStart, but other's might.

So, we could change the nsIStreamObserver semantics to:
- you will *always* get an OnStop, indicating the transaction is over (check the status param for success or failure).
- you will only get an OnStart if things are going to work.

Problem w/ the above is that things can fail *after* the transaction has started (server timeout for example), so the 2nd behavior cannot be achieved (thus it's existance to begin w/).

So, back to Darin's suggestion. We currently provide transaction start/stop apis and dictate that errors are indicated in the status param of OnStop(). This binds successful transaction assumptions (setup costs in OnStart) to the api, when there's certainly the possibility for error (in which case you don't want to set anything up). If we provide an OnFailure(), it seems we'd be doing double duty in some cases (failure cases). If things are looking up, I'll fire an OnStart() callback, then the server could timeout, which would cause an OnStop() to get fired w/ a failure status code. Would OnFailure get called before or after the onstop? Seems redundant. Would the semantics of OnFaiure() subsume an OnStop()? then we've just recreated OnStop.

I see the benifit of getting a single callback indicating error. That would allow me to not do anything if I wasn't going to have a successfull transaction, but it feels like an edge case. I'm thinking we should add a nsresult param to OnStart() so the consumer can skip initialization/setup if things have already hit the fan at that point.

Jud


Reply via email to