-
Notifications
You must be signed in to change notification settings - Fork 10
/
index.js
233 lines (192 loc) · 5.67 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
var fs = require( "fs" );
var path = require( "path" );
var util = require( "util" );
var crypto = require( "crypto" );
var wordpress = require( "wordpress" );
var async = require( "async" );
var version = require( "./package" ).version;
exports.createClient = createClient;
exports.Client = Client;
function createClient( options ) {
return new Client( options );
}
function Client( options ) {
this.options = options;
this.verbose = options.verbose || false;
this.client = wordpress.createClient( options );
this.bindClientMethods();
}
Client.prototype.log = console.log;
Client.prototype.logError = console.error;
Client.prototype.bindClientMethods = function() {
var context = this;
var client = this.client;
function bindContext( property ) {
if ( typeof client[ property ] !== "function" ) {
return;
}
var original = client[ property ];
client[ property ] = function() {
if ( !arguments.length ) {
return;
}
var args = [].slice.apply( arguments );
var last = args.pop();
if ( typeof last === "function" ) {
last = last.bind( context );
}
args.push( last );
original.apply( client, args );
};
}
for ( var property in client ) {
bindContext( property );
}
};
Client.prototype.waterfall = function( steps, callback ) {
var context = this;
async.waterfall(
steps.map(function( step ) {
return step.bind( context );
}),
callback.bind( context )
);
};
Client.prototype.forEach = function( items, eachFn, complete ) {
async.forEachSeries( items, eachFn.bind( this ), complete.bind( this ) );
};
Client.prototype.path = function( partial ) {
return path.join( this.options.dir, partial );
};
// Async directory recursion, always walks all files before recursing
Client.prototype.recurse = function( rootdir, walkFn, complete ) {
complete = complete.bind( this );
try {
fs.statSync( rootdir );
} catch ( e ) {
// Directories are considered optional, especially if inherited
// from default setttings. Treat non-existant dir as empty dir.
complete();
return;
}
fs.readdir( rootdir, { withFileTypes: true }, function( error, entries ) {
if ( error ) {
return complete( error );
}
var directories = [];
var files = [];
entries.forEach(function( entry ) {
var fullPath = path.join( rootdir, entry.name );
if ( entry.isDirectory() ) {
directories.push( fullPath );
} else {
files.push( fullPath );
}
});
this.forEach( files, walkFn, function( error ) {
if ( error ) {
return complete( error );
}
this.forEach( directories, function( directory, directoryComplete ) {
this.recurse( directory, walkFn, directoryComplete );
}, complete );
});
}.bind( this ));
};
Client.prototype.createChecksum = (function() {
function flatten( obj ) {
if ( obj == null ) {
return "";
}
if ( typeof obj === "string" ) {
return obj;
}
if ( typeof obj === "number" ) {
return String( obj );
}
if ( util.isDate( obj ) ) {
return obj.toGMTString();
}
if ( util.isArray( obj ) ) {
return obj.map(function( item ) {
return flatten( item );
}).join( "," );
}
return Object.keys( obj ).sort().map(function( prop ) {
return prop + ":" + flatten( obj[ prop ] );
}).join( ";" );
}
return function( obj ) {
var md5 = crypto.createHash( "md5" );
md5.update( flatten( obj ), "utf8" );
return md5.digest( "hex" );
};
})();
Client.prototype.validateXmlrpcVersion = function( callback ) {
callback = callback.bind( this );
if ( this.verbose ) {
this.log( "Verifying XML-RPC version..." );
}
this.client.authenticatedCall( "gw.getVersion", function( error, xmlrpcVersion ) {
if ( error ) {
if ( error.code === "ECONNREFUSED" ) {
return callback( new Error( "Could not connect to WordPress." ) );
}
if ( error.code === -32601 ) {
return callback( new Error(
"XML-RPC extensions for Gilded WordPress are not installed." ) );
}
if ( !error.code ) {
error.message += "\nPlease ensure that your database server is running " +
"and WordPress is functioning properly.";
}
// XML-RPC is disabled or bad credentials
// WordPress provides good error messages, so we don't do any special handling
return callback( error );
}
// The server should have all capabilities expected by this client.
// The server must therefore be in the "^x.y.z" semver-range, whereby it
// implements the same major version, and the same (or newer) minor version.
var xmlrpcVersionParts = xmlrpcVersion.split( ".", 3 ).map( parseFloat );
var clientVersionParts = version.split( ".", 3 ).map( parseFloat );
if ( !( xmlrpcVersionParts[0] === clientVersionParts[0] && xmlrpcVersionParts[1] >= clientVersionParts[1] ) ) {
return callback( new Error( "Incompatible versions for Gilded WordPress. " +
"Version " + version + " is installed as a Node.js module, " +
"but the WordPress server is running version " + xmlrpcVersion + "." ) );
}
if ( this.verbose ) {
this.log( "XML-RPC version matches Node.js version." );
}
callback( null );
});
};
Client.prototype.validate = function( callback ) {
this.waterfall([
this.validateXmlrpcVersion,
this.validateTerms,
this.validatePosts
], function( error ) {
if ( error ) {
return callback( error );
}
callback( null );
});
};
Client.prototype.sync = function( callback ) {
this.waterfall([
this.syncTerms,
this.syncPosts,
this.syncResources
], function( error ) {
if ( error ) {
if ( error.code === "ECONNREFUSED" ) {
this.logError( "Could not connect to WordPress XML-RPC server." );
}
return callback( error );
}
callback( null );
});
};
[ "posts", "taxonomies", "resources" ].forEach(function( module ) {
require( "./lib/" + module )( Client );
});