overleaf/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.js

171 lines
No EOL
6.4 KiB
JavaScript

/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let DocUpdaterClient;
const Settings = require('settings-sharelatex');
const rclient = require("redis-sharelatex").createClient(Settings.redis.documentupdater);
const keys = Settings.redis.documentupdater.key_schema;
const request = require("request").defaults({jar: false});
const async = require("async");
const rclient_sub = require("redis-sharelatex").createClient(Settings.redis.pubsub);
rclient_sub.subscribe("applied-ops");
rclient_sub.setMaxListeners(0);
module.exports = (DocUpdaterClient = {
randomId() {
const chars = __range__(1, 24, true).map((i) =>
Math.random().toString(16)[2]);
return chars.join("");
},
subscribeToAppliedOps(callback) {
if (callback == null) { callback = function(message) {}; }
return rclient_sub.on("message", callback);
},
sendUpdate(project_id, doc_id, update, callback) {
if (callback == null) { callback = function(error) {}; }
return rclient.rpush(keys.pendingUpdates({doc_id}), JSON.stringify(update), function(error){
if (error != null) { return callback(error); }
const doc_key = `${project_id}:${doc_id}`;
return rclient.sadd("DocsWithPendingUpdates", doc_key, function(error) {
if (error != null) { return callback(error); }
return rclient.rpush("pending-updates-list", doc_key, callback);
});
});
},
sendUpdates(project_id, doc_id, updates, callback) {
if (callback == null) { callback = function(error) {}; }
return DocUpdaterClient.preloadDoc(project_id, doc_id, function(error) {
if (error != null) { return callback(error); }
const jobs = [];
for (let update of Array.from(updates)) {
((update => jobs.push(callback => DocUpdaterClient.sendUpdate(project_id, doc_id, update, callback))))(update);
}
return async.series(jobs, err => DocUpdaterClient.waitForPendingUpdates(project_id, doc_id, callback));
});
},
waitForPendingUpdates(project_id, doc_id, callback) {
return async.retry({times: 30, interval: 100}, cb => rclient.llen(keys.pendingUpdates({doc_id}), function(err, length) {
if (length > 0) {
return cb(new Error("updates still pending"));
} else {
return cb();
}
})
, callback);
},
getDoc(project_id, doc_id, callback) {
if (callback == null) { callback = function(error, res, body) {}; }
return request.get(`http://localhost:3003/project/${project_id}/doc/${doc_id}`, function(error, res, body) {
if ((body != null) && (res.statusCode >= 200) && (res.statusCode < 300)) {
body = JSON.parse(body);
}
return callback(error, res, body);
});
},
getDocAndRecentOps(project_id, doc_id, fromVersion, callback) {
if (callback == null) { callback = function(error, res, body) {}; }
return request.get(`http://localhost:3003/project/${project_id}/doc/${doc_id}?fromVersion=${fromVersion}`, function(error, res, body) {
if ((body != null) && (res.statusCode >= 200) && (res.statusCode < 300)) {
body = JSON.parse(body);
}
return callback(error, res, body);
});
},
preloadDoc(project_id, doc_id, callback) {
if (callback == null) { callback = function(error) {}; }
return DocUpdaterClient.getDoc(project_id, doc_id, callback);
},
flushDoc(project_id, doc_id, callback) {
if (callback == null) { callback = function(error) {}; }
return request.post(`http://localhost:3003/project/${project_id}/doc/${doc_id}/flush`, (error, res, body) => callback(error, res, body));
},
setDocLines(project_id, doc_id, lines, source, user_id, undoing, callback) {
if (callback == null) { callback = function(error) {}; }
return request.post({
url: `http://localhost:3003/project/${project_id}/doc/${doc_id}`,
json: {
lines,
source,
user_id,
undoing
}
}, (error, res, body) => callback(error, res, body));
},
deleteDoc(project_id, doc_id, callback) {
if (callback == null) { callback = function(error) {}; }
return request.del(`http://localhost:3003/project/${project_id}/doc/${doc_id}`, (error, res, body) => callback(error, res, body));
},
flushProject(project_id, callback) {
if (callback == null) { callback = function() {}; }
return request.post(`http://localhost:3003/project/${project_id}/flush`, callback);
},
deleteProject(project_id, callback) {
if (callback == null) { callback = function() {}; }
return request.del(`http://localhost:3003/project/${project_id}`, callback);
},
deleteProjectOnShutdown(project_id, callback) {
if (callback == null) { callback = function() {}; }
return request.del(`http://localhost:3003/project/${project_id}?background=true&shutdown=true`, callback);
},
flushOldProjects(callback) {
if (callback == null) { callback = function() {}; }
return request.get("http://localhost:3003/flush_queued_projects?min_delete_age=1", callback);
},
acceptChange(project_id, doc_id, change_id, callback) {
if (callback == null) { callback = function() {}; }
return request.post(`http://localhost:3003/project/${project_id}/doc/${doc_id}/change/${change_id}/accept`, callback);
},
removeComment(project_id, doc_id, comment, callback) {
if (callback == null) { callback = function() {}; }
return request.del(`http://localhost:3003/project/${project_id}/doc/${doc_id}/comment/${comment}`, callback);
},
getProjectDocs(project_id, projectStateHash, callback) {
if (callback == null) { callback = function() {}; }
return request.get(`http://localhost:3003/project/${project_id}/doc?state=${projectStateHash}`, function(error, res, body) {
if ((body != null) && (res.statusCode >= 200) && (res.statusCode < 300)) {
body = JSON.parse(body);
}
return callback(error, res, body);
});
},
sendProjectUpdate(project_id, userId, docUpdates, fileUpdates, version, callback) {
if (callback == null) { callback = function(error) {}; }
return request.post({
url: `http://localhost:3003/project/${project_id}`,
json: { userId, docUpdates, fileUpdates, version }
}, (error, res, body) => callback(error, res, body));
}
});
function __range__(left, right, inclusive) {
let range = [];
let ascending = left < right;
let end = !inclusive ? right : ascending ? right + 1 : right - 1;
for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) {
range.push(i);
}
return range;
}