https://www.mediawiki.org/wiki/Special:Code/MediaWiki/109604

Revision: 109604
Author:   gwicke
Date:     2012-01-20 02:36:18 +0000 (Fri, 20 Jan 2012)
Log Message:
-----------
Collapse all requests per template into a single outstanding request using an
event-emitting TemplateRequest object and a request queue.

Modified Paths:
--------------
    trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js
    trunk/extensions/VisualEditor/modules/parser/mediawiki.DOMConverter.js
    trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js
    trunk/extensions/VisualEditor/modules/parser/parse.js

Modified: 
trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js
===================================================================
--- trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js    
2012-01-20 02:36:05 UTC (rev 109603)
+++ trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js    
2012-01-20 02:36:18 UTC (rev 109604)
@@ -12,6 +12,7 @@
  */
 var $ = require('jquery'),
        request = require('request'),
+       events = require('events'),
        qs = require('querystring'),
        AttributeTransformManager = 
require('./mediawiki.TokenTransformManager.js')
                                                                        
.AttributeTransformManager;
@@ -290,7 +291,7 @@
 TemplateHandler.prototype._fetchTemplateAndTitle = function ( title, callback, 
tplExpandData ) {
        // @fixme normalize name?
        var self = this;
-       if (title in this.manager.env.pageCache) {
+       if (this.manager.env.pageCache[title]) {
                // Unroll the stack here
                process.nextTick(
                                function () {
@@ -300,115 +301,20 @@
        } else if ( ! this.manager.env.fetchTemplates ) {
                callback('Page/template fetching disabled, and no cache for ' + 
title);
        } else {
-               // Not found in the pageCache, so go fetch the source using the
-               // MediaWiki API.
-
+               
                // We are about to start an async request for a template, so 
mark this
                // template expansion as such.
                tplExpandData.overallAsync = true;
                this.manager.env.dp( 'trying to fetch ' + title );
-               //console.log(this.manager.env.pageCache);
-               var url = this.manager.env.wgScriptPath + '/api' + 
-                       this.manager.env.wgScriptExtension +
-                       '?' + 
-                       qs.stringify( {
-                               format: 'json',
-                               action: 'query',
-                               prop: 'revisions',
-                               rvprop: 'content',
-                               titles: title
-                       } );
-                       
//'?format=json&action=query&prop=revisions&rvprop=content&titles=' + title;
 
-               request({
-                       method: 'GET',
-                       followRedirect: true,
-                       url: url,
-                       headers: { 
-                               'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; 
rv:9.0.1) ' +
-                                                               'Gecko/20100101 
Firefox/9.0.1 Iceweasel/9.0.1' 
-                       }
-               }, 
-               function (error, response, body) {
-                       //console.log( 'response for ' + title + ' :' + body + 
':' );
-                       if(error) {
-                               self.manager.env.dp(error);     
-                               callback('Page/template fetch failure for title 
' + title, title);
-                               return ;
-                       }
+               // Start a new request if none is outstanding
+               this.manager.env.dp( 'requestQueue: ', 
this.manager.env.requestQueue)
+               if ( this.manager.env.requestQueue[title] === undefined ) {
+                       this.manager.env.requestQueue[title] = new 
TemplateRequest( this.manager, title );
+               }
+               // Append a listener to the request
+               this.manager.env.requestQueue[title].addListener( 'src', 
callback );
 
-                       if(response.statusCode ==  200) {
-                               var src = '';
-                               try {
-                                       //console.log( 'body: ' + body );
-                                       var data = JSON.parse( body );
-                               } catch(e) {
-                                       console.log( "Error: while parsing 
result. Error was: " );
-                                       console.log( e );
-                                       console.log( "Response that didn't 
parse was:");
-                                       console.log( 
"------------------------------------------\n" + body );
-                                       console.log( 
"------------------------------------------" );
-                               }
-                               try {
-                                       $.each(data.query.pages, function(i, 
page) {
-                                               if (page.revisions && 
page.revisions.length) {
-                                                       src = 
page.revisions[0]['*'];
-                                                       title = page.title;
-                                               }
-                                       });
-                               } catch ( e ) {
-                                       console.log( 'Did not find page 
revisions in the returned body:' + body );
-                                       src = '';
-                               }
-                               //console.log( 'Page ' + title + ': got ' + src 
);
-                               self.manager.env.dp( 'Success for ' + title + ' 
:' + body + ':' );
-                               self.manager.env.pageCache[title] = src;
-                               callback(src, title);
-                               self.manager.env.dp(data);
-                       }
-               });
-
-               /*
-                * XXX: The jQuery version does not quite work with node, but 
we keep
-                * it around for now.
-               $.ajax({
-                       url: url,
-                       data: {
-                               format: 'json',
-                               action: 'query',
-                               prop: 'revisions',
-                               rvprop: 'content',
-                               titles: title
-                       },
-                       success: function(data, statusString, xhr) {
-                               console.log( 'Page ' + title + ' success ' + 
JSON.stringify( data ) );
-                               var src = null, title = null;
-                               $.each(data.query.pages, function(i, page) {
-                                       if (page.revisions && 
page.revisions.length) {
-                                               src = page.revisions[0]['*'];
-                                               title = page.title;
-                                       }
-                               });
-                               if (typeof src !== 'string') {
-                                       console.log( 'Page ' + title + 'not 
found! Got ' + src );
-                                       callback( 'Page ' + title + ' not 
found' );
-                               } else {
-                                       // Add to cache
-                                       console.log( 'Page ' + title + ': got ' 
+ src );
-                                       this.manager.env.pageCache[title] = src;
-                                       callback(src, title);
-                               }
-                       },
-                       error: function(xhr, msg, err) {
-                               console.log( 'Page/template fetch failure for 
title ' + 
-                                               title + ', url=' + url + 
JSON.stringify(xhr) + ', err=' + err );
-                               callback('Page/template fetch failure for title 
' + title);
-                       },
-                       dataType: 'json',
-                       cache: false, // @fixme caching, versions etc?
-                       crossDomain: true
-               });
-               */
        }
 };
 
@@ -468,6 +374,123 @@
        }
 };
 
+
+/***************** Template fetch request helper class ********/
+
+function TemplateRequest ( manager, title ) {
+       // Increase the number of maximum listeners a bit..
+       this.setMaxListeners( 1000 );
+       var self = this,
+               url = manager.env.wgScriptPath + '/api' + 
+               manager.env.wgScriptExtension +
+               '?' + 
+               qs.stringify( {
+                       format: 'json',
+                       action: 'query',
+                       prop: 'revisions',
+                       rvprop: 'content',
+                       titles: title
+               } );
+               
//'?format=json&action=query&prop=revisions&rvprop=content&titles=' + title;
+
+       request({
+               method: 'GET',
+               followRedirect: true,
+               url: url,
+               headers: { 
+                       'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; 
rv:9.0.1) ' +
+                                                       'Gecko/20100101 
Firefox/9.0.1 Iceweasel/9.0.1' 
+               }
+       }, 
+       function (error, response, body) {
+               //console.log( 'response for ' + title + ' :' + body + ':' );
+               if(error) {
+                       manager.env.dp(error);  
+                       callback('Page/template fetch failure for title ' + 
title, title);
+                       return ;
+               }
+
+               if(response.statusCode ==  200) {
+                       var src = '';
+                       try {
+                               //console.log( 'body: ' + body );
+                               var data = JSON.parse( body );
+                       } catch(e) {
+                               console.log( "Error: while parsing result. 
Error was: " );
+                               console.log( e );
+                               console.log( "Response that didn't parse was:");
+                               console.log( 
"------------------------------------------\n" + body );
+                               console.log( 
"------------------------------------------" );
+                       }
+                       try {
+                               $.each(data.query.pages, function(i, page) {
+                                       if (page.revisions && 
page.revisions.length) {
+                                               src = page.revisions[0]['*'];
+                                               title = page.title;
+                                       }
+                               });
+                       } catch ( e ) {
+                               console.log( 'Did not find page revisions in 
the returned body:' + body );
+                               src = '';
+                       }
+                       //console.log( 'Page ' + title + ': got ' + src );
+                       manager.env.dp( 'Success for ' + title + ' :' + body + 
':' );
+                       manager.env.pageCache[title] = src;
+                       manager.env.dp(data);
+                       self.emit( 'src', src, title );
+                       // Remove self from request queue
+                       delete manager.env.requestQueue[title];
+               }
+       });
+}
+
+               /*
+                * XXX: The jQuery version does not quite work with node, but 
we keep
+                * it around for now.
+               $.ajax({
+                       url: url,
+                       data: {
+                               format: 'json',
+                               action: 'query',
+                               prop: 'revisions',
+                               rvprop: 'content',
+                               titles: title
+                       },
+                       success: function(data, statusString, xhr) {
+                               console.log( 'Page ' + title + ' success ' + 
JSON.stringify( data ) );
+                               var src = null, title = null;
+                               $.each(data.query.pages, function(i, page) {
+                                       if (page.revisions && 
page.revisions.length) {
+                                               src = page.revisions[0]['*'];
+                                               title = page.title;
+                                       }
+                               });
+                               if (typeof src !== 'string') {
+                                       console.log( 'Page ' + title + 'not 
found! Got ' + src );
+                                       callback( 'Page ' + title + ' not 
found' );
+                               } else {
+                                       // Add to cache
+                                       console.log( 'Page ' + title + ': got ' 
+ src );
+                                       this.manager.env.pageCache[title] = src;
+                                       callback(src, title);
+                               }
+                       },
+                       error: function(xhr, msg, err) {
+                               console.log( 'Page/template fetch failure for 
title ' + 
+                                               title + ', url=' + url + 
JSON.stringify(xhr) + ', err=' + err );
+                               callback('Page/template fetch failure for title 
' + title);
+                       },
+                       dataType: 'json',
+                       cache: false, // @fixme caching, versions etc?
+                       crossDomain: true
+               });
+               */
+
+// Inherit from EventEmitter
+TemplateRequest.prototype = new events.EventEmitter();
+TemplateHandler.prototype.constructor = TemplateRequest;
+
+
 if (typeof module == "object") {
        module.exports.TemplateHandler = TemplateHandler;
 }

Modified: trunk/extensions/VisualEditor/modules/parser/mediawiki.DOMConverter.js
===================================================================
--- trunk/extensions/VisualEditor/modules/parser/mediawiki.DOMConverter.js      
2012-01-20 02:36:05 UTC (rev 109603)
+++ trunk/extensions/VisualEditor/modules/parser/mediawiki.DOMConverter.js      
2012-01-20 02:36:18 UTC (rev 109604)
@@ -1,5 +1,7 @@
 /**
  * Conversions between HTML DOM and WikiDom
+ *
+ * @author Gabriel Wicke <gwi...@wikimedia.org>
  * 
  * @class
  * @constructor

Modified: 
trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js
===================================================================
--- 
trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js    
    2012-01-20 02:36:05 UTC (rev 109603)
+++ 
trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js    
    2012-01-20 02:36:18 UTC (rev 109604)
@@ -12,6 +12,10 @@
        $.extend(this, options);
 };
 
+// Outstanding page requests (for templates etc)
+// Class-static
+MWParserEnvironment.prototype.requestQueue = {};
+
 MWParserEnvironment.prototype.lookupKV = function ( kvs, key ) {
        if ( ! kvs ) {
                return null;

Modified: trunk/extensions/VisualEditor/modules/parser/parse.js
===================================================================
--- trunk/extensions/VisualEditor/modules/parser/parse.js       2012-01-20 
02:36:05 UTC (rev 109603)
+++ trunk/extensions/VisualEditor/modules/parser/parse.js       2012-01-20 
02:36:18 UTC (rev 109604)
@@ -1,6 +1,9 @@
 /**
  * Command line wikidom parse utility.
  * Read from STDIN, write to STDOUT.
+ *
+ * @author Neil Kandalgaonkar <ne...@wikimedia.org>
+ * @author Gabriel Wicke <gwi...@wikimedia.org>
  */
 
 
@@ -12,7 +15,11 @@
                optimist = require('optimist');
 
        var env = new ParserEnv( { 
+                                               // fetch templates from enwiki 
by default..
+                                               wgScriptPath: 
"http://en.wikipedia.org/w";,
+                                               wgScriptExtension: ".php",
                                                fetchTemplates: true,
+                                               // enable/disable debug output 
using this switch        
                                                debug: false
                                        } ),
                parser = new ParserPipeline( env );


_______________________________________________
MediaWiki-CVS mailing list
MediaWiki-CVS@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to