Closed Bug 1530938 Opened 6 years ago Closed 6 years ago

calendar/resources/content/publish.js relies on asyncOpen taking context as second argument which is defunct since bug 1520868

Categories

(Calendar :: General, enhancement)

enhancement
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: mkmelin, Assigned: pmorris)

References

Details

Attachments

(1 file, 5 obsolete files)

publish.js needs to be updated to not rely in passing a context as second argument to asyncOpen. That version no longer exists since bug 1520868.

https://searchfox.org/comm-central/source/calendar/resources/content/publish.js#175

175: channel.asyncOpen(publishingListener, aProgressDialog);

Paul, can you give this a shot?

I looked briefly, but this code is fairly messed up, and could do with some serious reworking IMHO. The interaction between this and publishDialog.{js,xul} is quite odd passing globals around it seems. Don't know why the linter doesn't complain about the undeclared |self| either (the declaration of which must be coming from some other file - ouch!)

Assignee: nobody → paul

The minimal fix would need to figure out how the error handling will get to the progressdialog object, since that object can no longer be receive via asyncOpen. I.e. change to channel.asyncOpen(publishingListener), and find out how to get the progress dialog in this new scenario.

Hey Magnus, Yeah, I'll give it a go, thanks for the explanations. Took a quick look and the 'self' here is likely window.self.

Ah - of course.

Attached patch publish-async-open-0.patch (obsolete) β€” β€” Splinter Review

There may be more to do here, but this solves the asyncOpen issue. Now that there's no context argument, we can provide access to the dialog window by binding it to the callback in the listener object (that gets passed to asyncOpen).

I tested this by publishing a calendar using a bogus URL, and when the request failed, I saw the progress bar stopped indicating progress (as expected). I also used a temporary console.log to see that "onStopUpload" was indeed fired.

Attachment #9047085 - Flags: review?(philipp)
Attachment #9047085 - Flags: review?(mkmelin+mozilla)

Hmm, I see there are 11 uses of asyncOpen in the calendar code, all passing a second context argument. So maybe a more general solution is in order?

I think searchfox hasn't had the time to reindex yet. Bug 1528681 removed a lot.

Status: NEW → ASSIGNED
Comment on attachment 9047085 [details] [diff] [review] publish-async-open-0.patch Review of attachment 9047085 [details] [diff] [review]: ----------------------------------------------------------------- ::: calendar/resources/content/publish.js @@ +199,5 @@ > + * @param aRequest Request being observed > + * @param aContext User defined context (apparently no longer used, see bug 1520868) > + * @param aStatusCode Reason for stopping (NS_OK if completed successfully) > + */ > +function onStopRequestWithDialog(aProgressDialog, aRequest, aContext, aStatusCode) { as this is used only once, I'd move the implementation there @@ +229,5 @@ > + * to provide access to the dialog when the request is done. > + * @param aProgressDialog Dialog window > + * @returns {Object} Listener > + */ > +function makePublishingListener(aProgressDialog) { maybe clearer to have this be a constructor for an object, instead of some kind of factory? @@ +238,5 @@ > + }, > + > + onStopRequest: onStopRequestWithDialog.bind(null, aProgressDialog), > + > + onDataAvailable: function(aRequest, aContext, inStream, sourceOffset, count) { please don't use the aStyle, and do not mix with that style
Attachment #9047085 - Flags: review?(mkmelin+mozilla)
Attached patch publish-async-open-1.patch (obsolete) β€” β€” Splinter Review

as this is used only once, I'd move the implementation there

Okay, I've moved it inline, and switched to capturing the dialog argument via a closure rather than with "bind". (Bind is easier to understand with a separate/named function, and I generally like using bind rather than closures because that's more explicit. But inline with a closure is not bad here.)

maybe clearer to have this be a constructor for an object, instead of some kind of factory?

Okay, I've changed this to a constructor function that uses 'new'. (I tend to prefer factory functions which are more explicit and straightforward to understand than the implicitness of JS's 'new' operator.)

please don't use the aStyle, and do not mix with that style

Ah, yes, good call on not mixing. I've dropped the aStyle throughout this patch. Thanks for additional info on IRC.

Attachment #9047085 - Attachment is obsolete: true
Attachment #9047085 - Flags: review?(philipp)
Attachment #9049295 - Flags: review?(mkmelin+mozilla)
Comment on attachment 9049295 [details] [diff] [review] publish-async-open-1.patch Review of attachment 9049295 [details] [diff] [review]: ----------------------------------------------------------------- The patch doesn't apply at all anymore for some reason. I was thinking it could be something like this (untested) /** * @implements {nsIStreamListener} */ class PublishingListener { constructor(progressDialog) { this.progressDialog = progressDialog; } onStartRequest(request, context) { } onStopRequest(request, context, statusCode) { this.progressDialog.wrappedJSObject.onStopUpload(); let channel; let requestSucceeded; try { channel = request.QueryInterface(Ci.nsIHttpChannel); requestSucceeded = channel.requestSucceeded; } catch (e) { // Don't fail if it is not an http channel, will be handled below } if (channel && !requestSucceeded) { let body = cal.l10n.getCalString("httpPutError", [ channel.responseStatus, channel.responseStatusText ]); Services.prompt.alert(null, cal.l10n.getCalString("genericErrorTitle"), body); } else if (!channel && !Components.isSuccessCode(request.status)) { // XXX this should be made human-readable. let body = cal.l10n.getCalString("otherPutError", [request.status.toString(16)]); Services.prompt.alert(null, cal.l10n.getCalString("genericErrorTitle"), body); } } onDataAvailable(request, context, inStream, sourceOffset, count) { } QueryInterface: ChromeUtils.generateQI([Ci.nsIStreamListener]) }
Attachment #9049295 - Flags: review?(mkmelin+mozilla)
Attached patch publish-async-open-2.patch (obsolete) β€” β€” Splinter Review

Ah, I see, thanks. Yeah, that works. (I'm still getting used to this JS class syntax business.)

Redone with class syntax and rebased. (Merge conflict was due to changes in bug 1531307.) Still works when I tested it: "onStopUnload" is called and the progress indicator stops indicating progress.

Attachment #9049295 - Attachment is obsolete: true
Attachment #9049543 - Flags: review?(mkmelin+mozilla)
Comment on attachment 9049543 [details] [diff] [review] publish-async-open-2.patch Review of attachment 9049543 [details] [diff] [review]: ----------------------------------------------------------------- ::: calendar/resources/content/publish.js @@ +197,5 @@ > + */ > +class PublishingListener { > + constructor(progressDialog) { > + this.progressDialog = progressDialog; > + this.QueryInterface = ChromeUtils.generateQI([Ci.nsIStreamListener]); why not this one as a method?

(In reply to Magnus Melin [:mkmelin] from comment #12)

Comment on attachment 9049543 [details] [diff] [review]
publish-async-open-2.patch

Review of attachment 9049543 [details] [diff] [review]:

::: calendar/resources/content/publish.js
@@ +197,5 @@

  • */
    +class PublishingListener {
  • constructor(progressDialog) {
  •    this.progressDialog = progressDialog;
    
  •    this.QueryInterface = ChromeUtils.generateQI([Ci.nsIStreamListener]);
    

why not this one as a method?

You can't assign prototype methods from the result of a function call in es6 classes, and you don't want to run generateQI on each get. I created this helper: https://searchfox.org/comm-central/source/calendar/base/modules/calUtils.jsm#152 but assigning it in the constructor might actually be less bulky than I thought.

The best thing you can do is this:

class foo {

}
foo.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsIStreamListener]);

but then you put the QI after the class, which isn't great from a readability standpoint.

(In reply to Magnus Melin [:mkmelin] from comment #12)

Comment on attachment 9049543 [details] [diff] [review]
publish-async-open-2.patch

Review of attachment 9049543 [details] [diff] [review]:

::: calendar/resources/content/publish.js
@@ +197,5 @@

  • */
    +class PublishingListener {
  • constructor(progressDialog) {
  •    this.progressDialog = progressDialog;
    
  •    this.QueryInterface = ChromeUtils.generateQI([Ci.nsIStreamListener]);
    

why not this one as a method?

I didn't want to call .generateQI on each access/use of QueryInterface as making it a method would need to do. Better to call it once (per instantiation) in the constructor.

As Philipp mentions, better to put it on the prototype, so it's only ever calculated/fetched once, but you can't do that using ES6 class syntax. (The class syntax sugar is a bit of a "leaky abstraction" here...) You have to do this after the class declaration:

foo.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsIStreamListener]);

I could see doing that, and adding a comment in the class to alert readers. But since we have a helper function for this (that Philipp references), I think I'll use that.

Attached patch publish-async-open-3.patch (obsolete) β€” β€” Splinter Review

This patch uses the helper function to generate the QueryInterface method. Still works as before when tested: "onStopUnload" is called and the progress indicator stops indicating progress.

One benefit of the helper function is that it is lazy, deferring the call to generateQI until it's needed. Although, that probably doesn't matter in this case (where assigning it in the constructor wouldn't be that much different since the object is a "use once and throw away" object), we might as well use the helper for consistency's sake.

Attachment #9049543 - Attachment is obsolete: true
Attachment #9049543 - Flags: review?(mkmelin+mozilla)
Attachment #9050062 - Flags: review?(mkmelin+mozilla)
Attached patch publish-async-open-4.patch (obsolete) β€” β€” Splinter Review

The previous patch accidentally still had "context" parameters for onStopRequest and friends. The context parameters had been removed from that interface, and are no longer there in this patch.

Attachment #9050062 - Attachment is obsolete: true
Attachment #9050062 - Flags: review?(mkmelin+mozilla)
Attachment #9050066 - Flags: review?(mkmelin+mozilla)

sigh The previous patch unintentionally removed the 3rd (unused) argument "errorMsg" from "onStopRequest". Now it's back, and this is really ready for review this time. (Need to check the diffs more thoroughly before uploading patches.)

Attachment #9050066 - Attachment is obsolete: true
Attachment #9050066 - Flags: review?(mkmelin+mozilla)
Attachment #9050074 - Flags: ui-review?(mkmelin+mozilla)
Attachment #9050074 - Flags: ui-review?(mkmelin+mozilla) → review?(mkmelin+mozilla)
Comment on attachment 9050074 [details] [diff] [review] publish-async-open-5.patch Review of attachment 9050074 [details] [diff] [review]: ----------------------------------------------------------------- Sweet, r=mkmelin
Attachment #9050074 - Flags: review?(mkmelin+mozilla) → review+

Pushed by mozilla@jorgk.com:
https://hg.mozilla.org/comm-central/rev/02fa6334f4ed
asyncOpen() no longer takes 'context' as second argument, pass it as property on the listener object. r=mkmelin

Status: ASSIGNED → RESOLVED
Closed: 6 years ago
Resolution: --- → FIXED

First bug, haha, at least under the new circumstances ;-)

Please provide a meaningful commit message, copying the bug summary is mostly not a good idea.

Target Milestone: --- → 6.9

Without having read the whole bug, after M-C discontinued the context parameter and before this patch, what wasn't working? IOW, does it need the parameter or could it just have been dropped? There is no test for this functionality?

In hindsight, maybe a Calendar peer should have reviewed this?

Flags: needinfo?(mkmelin+mozilla)

(In reply to Paul Morris [:pmorris] from comment #17)

sigh The previous patch unintentionally removed the 3rd (unused) argument
"errorMsg" from "onStopRequest". Now it's back, and this is really ready
for review this time.

Heh, that errorMsg arg should actually have been removed now following bug 1525319

-onStopRequest(request, status, errorMsg) {
+onStopRequest(request, status) {

(In reply to Jorg K (GMT+1) from comment #21)

Without having read the whole bug, after M-C discontinued the context
parameter and before this patch, what wasn't working?

Originally when this bug was filed, you would not have got an error message for publishing failure.
It seems that part was actually "fixed" through https://hg.mozilla.org/comm-central/rev/0022c92d1421
Or well, that fix is wrong and would not work here.

In hindsight, maybe a Calendar peer should have reviewed this?

Theoretically yes, but I think they have their hands full with other changes than adapting to breakage.

Flags: needinfo?(mkmelin+mozilla)
Pushed by mozilla@jorgk.com: https://hg.mozilla.org/comm-central/rev/970bdd9dd9bd Follow-up: remove 'error' parameter from onStopRequest(). r=mkmelin

Thanks, Magnus. Looking at the changes closer, yes, we need the dialog in onStopRequest(), so I agree with passing it this way now that the context parameter has disappeared. I assume there is no test for the publishing functionality.

Thanks Jorg, for the push and the follow-up! Good to land my first one under new circumstances. :) Will write a better commit message next time. I just did a search and did not find a test for publishing functionality.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: