This commit is contained in:
Alexey Golubev
2018-07-17 17:08:50 +03:00
11 changed files with 318 additions and 247 deletions

View File

@ -182,7 +182,8 @@
}
},
"license" : {
"license_file": ""
"license_file": "",
"warning_limit_percents": "70"
},
"FileConverter": {
"converter": {

View File

@ -47,7 +47,8 @@
}
},
"license": {
"license_file": "./../../license.lic"
"license_file": "./../../license.lic",
"warning_limit_percents": "70"
},
"FileConverter": {
"converter": {

View File

@ -47,7 +47,8 @@
}
},
"license": {
"license_file": "./../../license.lic"
"license_file": "./../../license.lic",
"warning_limit_percents": "70"
},
"FileConverter": {
"converter": {

View File

@ -42,7 +42,8 @@
}
},
"license": {
"license_file": "/var/www/onlyoffice/Data/license.lic"
"license_file": "/var/www/onlyoffice/Data/license.lic",
"warning_limit_percents": "70"
},
"FileConverter": {
"converter": {

View File

@ -42,7 +42,8 @@
}
},
"license": {
"license_file": "./../../license.lic"
"license_file": "./../../license.lic",
"warning_limit_percents": "70"
},
"FileConverter": {
"converter": {

View File

@ -53,14 +53,16 @@ exports.LICENSE_MODE = {
};
exports.LICENSE_RESULT = {
Error : 1,
Expired : 2,
Success : 3,
UnknownUser : 4,
Connections : 5,
ExpiredTrial: 6,
SuccessLimit: 7,
UsersCount : 8
Error : 1,
Expired : 2,
Success : 3,
UnknownUser : 4,
Connections : 5,
ExpiredTrial : 6,
SuccessLimit : 7,
UsersCount : 8,
ConnectionsOS : 9,
UsersCountOS : 10
};
exports.LICENSE_CONNECTIONS = 20;
@ -223,3 +225,5 @@ exports.CONTENT_DISPOSITION_INLINE = 'inline';
exports.CONTENT_DISPOSITION_ATTACHMENT = 'attachment';
exports.CONN_CLOSED = 3;
exports.FILE_STATUS_UPDATE_VERSION = 'updateversion';

View File

@ -63,12 +63,13 @@ exports.readLicense = function*() {
branding: false,
connections: constants.LICENSE_CONNECTIONS,
usersCount: 0,
usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY
usersExpire: constants.LICENSE_EXPIRE_USERS_ONE_DAY,
hasLicense: false
};
let checkFile = false;
try {
const oFile = fs.readFileSync(configL.get('license_file')).toString();
checkFile = true;
res.hasLicense = checkFile = true;
const oLicense = JSON.parse(oFile);
const sign = oLicense['signature'];
delete oLicense['signature'];
@ -127,7 +128,7 @@ exports.readLicense = function*() {
}
if (res.type === c_LR.Expired || res.type === c_LR.ExpiredTrial) {
res.count = 1;
logger.error('License Expired!!!');
logger.error('License: License Expired!!!');
}
if (checkFile) {

View File

@ -143,6 +143,7 @@ const cfgForceSaveStep = ms(config.get('autoAssembly.step'));
const cfgQueueRetentionPeriod = configCommon.get('queue.retentionPeriod');
const cfgForgottenFiles = config.get('server.forgottenfiles');
const cfgMaxRequestChanges = config.get('server.maxRequestChanges');
const cfgWarningLimitPercents = configCommon.get('license.warning_limit_percents') / 100;
const redisKeySaveLock = cfgRedisPrefix + constants.REDIS_KEY_SAVE_LOCK;
const redisKeyPresenceHash = cfgRedisPrefix + constants.REDIS_KEY_PRESENCE_HASH;
@ -829,7 +830,7 @@ function handleDeadLetter(data) {
* @param callback
* @param baseUrl
*/
function* sendStatusDocument(docId, bChangeBase, userAction, callback, baseUrl, opt_userData) {
function* sendStatusDocument(docId, bChangeBase, userAction, callback, baseUrl, opt_userData, opt_forceClose) {
if (!callback) {
var getRes = yield* getCallback(docId);
if (getRes) {
@ -847,7 +848,7 @@ function* sendStatusDocument(docId, bChangeBase, userAction, callback, baseUrl,
var participants = yield* getOriginalParticipantsId(docId);
if (0 === participants.length) {
var puckerIndex = yield* getChangesIndex(docId);
if (!(puckerIndex > 0)) {
if (!(puckerIndex > 0) || opt_forceClose) {
status = c_oAscServerStatus.Closed;
}
}
@ -999,10 +1000,10 @@ function* cleanDocumentOnExit(docId, deleteChanges) {
yield storage.deletePath(cfgForgottenFiles + '/' + docId);
}
}
function* cleanDocumentOnExitNoChanges(docId, opt_userId) {
function* cleanDocumentOnExitNoChanges(docId, opt_userId, opt_forceClose) {
var userAction = opt_userId ? new commonDefines.OutputAction(commonDefines.c_oAscUserAction.Out, opt_userId) : null;
// Отправляем, что все ушли и нет изменений (чтобы выставить статус на сервере об окончании редактирования)
yield* sendStatusDocument(docId, c_oAscChangeBase.No, userAction);
yield* sendStatusDocument(docId, c_oAscChangeBase.No, userAction, undefined, undefined, undefined, opt_forceClose);
//если пользователь зашел в документ, соединение порвалось, на сервере удалилась вся информация,
//при восстановлении соединения userIndex сохранится и он совпадет с userIndex следующего пользователя
yield* cleanDocumentOnExit(docId, false);
@ -2052,6 +2053,8 @@ exports.install = function(server, callbackFunction) {
// error version
yield* sendFileErrorAuth(conn, data.sessionId, 'Update Version error');
return;
} else if (taskResult.FileStatus.None === status && conn.encrypted) {
//ok
} else {
// Other error
yield* sendFileErrorAuth(conn, data.sessionId, 'Other error');
@ -2695,6 +2698,7 @@ exports.install = function(server, callbackFunction) {
}
function* _checkLicenseAuth(userId) {
let licenseWarningLimit = false;
const c_LR = constants.LICENSE_RESULT;
let licenseType = licenseInfo.type;
if (licenseInfo.usersCount) {
@ -2712,6 +2716,7 @@ exports.install = function(server, callbackFunction) {
} else {
licenseType = -1 === execRes[0].indexOf(userId) ? c_LR.UsersCount : c_LR.Success;
}
licenseWarningLimit = licenseInfo.usersCount * cfgWarningLimitPercents <= execRes[0].length;
}
} else {
// Warning. Cluster version or if workers > 1 will work with increasing numbers.
@ -2727,6 +2732,7 @@ exports.install = function(server, callbackFunction) {
return true !== el.isCloseCoAuthoring && el.user.view !== true;
})).length;
licenseType = (connectionsCount > editConnectionsCount) ? licenseType : c_LR.Connections;
licenseWarningLimit = connectionsCount * cfgWarningLimitPercents <= editConnectionsCount;
}
/*if (constants.PACKAGE_TYPE_OS === licenseInfo.packageType && c_LR.Error === licenseType) {
licenseType = c_LR.SuccessLimit;
@ -2760,6 +2766,20 @@ exports.install = function(server, callbackFunction) {
}
}*/
}
if (c_LR.UsersCount === licenseType) {
if (!licenseInfo.hasLicense) {
licenseType = c_LR.UsersCountOS;
}
logger.error('License: User limit exceeded!!!');
} else if (c_LR.Connections === licenseType) {
if (!licenseInfo.hasLicense) {
licenseType = c_LR.ConnectionsOS;
}
logger.error('License: Connection limit exceeded!!!');
} else if (licenseWarningLimit) {
logger.warn('License: Warning limit exceeded!!!');
}
return licenseType;
}

View File

@ -139,7 +139,7 @@ function* getOutputData(cmd, outputData, key, status, statusInfo, optConn, optAd
(!opt_bIsRestore && taskResult.FileStatus.UpdateVersion === status &&
Date.now() - statusInfo * 60000 > cfgExpUpdateVersionStatus)) {
if ((optConn && optConn.user.view) || optConn.isCloseCoAuthoring) {
outputData.setStatus('updateversion');
outputData.setStatus(constants.FILE_STATUS_UPDATE_VERSION);
} else {
if (taskResult.FileStatus.UpdateVersion === status) {
logger.warn("UpdateVersion expired: docId = %s", docId);
@ -155,11 +155,11 @@ function* getOutputData(cmd, outputData, key, status, statusInfo, optConn, optAd
if (updateIfRes.affectedRows > 0) {
outputData.setStatus('ok');
} else {
outputData.setStatus('updateversion');
outputData.setStatus(constants.FILE_STATUS_UPDATE_VERSION);
}
}
} else {
outputData.setStatus('updateversion');
outputData.setStatus(constants.FILE_STATUS_UPDATE_VERSION);
}
var command = cmd.getCommand();
if ('open' != command && 'reopen' != command && !cmd.getOutputUrls()) {
@ -317,7 +317,13 @@ function* commandOpen(conn, cmd, outputData, opt_upsertRes, opt_bIsRestore) {
if (!bCreate) {
needAddTask = yield* commandOpenFillOutput(conn, cmd, outputData, opt_bIsRestore);
}
if (needAddTask) {
if (conn.encrypted) {
logger.debug("commandOpen encrypted %j: docId = %s", outputData, cmd.getDocId());
if (constants.FILE_STATUS_UPDATE_VERSION !== outputData.getStatus()) {
//don't send output data
outputData.setStatus(undefined);
}
} else if (needAddTask) {
let updateMask = new taskResult.TaskResultData();
updateMask.key = cmd.getDocId();
updateMask.status = taskResult.FileStatus.None;
@ -328,35 +334,35 @@ function* commandOpen(conn, cmd, outputData, opt_upsertRes, opt_bIsRestore) {
task.statusInfo = constants.NO_ERROR;
let updateIfRes = yield taskResult.updateIf(task, updateMask);
if (updateIfRes.affectedRows > 0) {
let forgottenId = cfgForgottenFiles + '/' + cmd.getDocId();
let forgotten = yield storage.listObjects(forgottenId);
//replace url with forgotten file because it absorbed all lost changes
if (forgotten.length > 0) {
logger.debug("commandOpen from forgotten: docId = %s", cmd.getDocId());
cmd.setUrl(undefined);
cmd.setForgotten(forgottenId);
if (updateIfRes.affectedRows > 0) {
let forgottenId = cfgForgottenFiles + '/' + cmd.getDocId();
let forgotten = yield storage.listObjects(forgottenId);
//replace url with forgotten file because it absorbed all lost changes
if (forgotten.length > 0) {
logger.debug("commandOpen from forgotten: docId = %s", cmd.getDocId());
cmd.setUrl(undefined);
cmd.setForgotten(forgottenId);
}
//add task
cmd.setOutputFormat(constants.AVS_OFFICESTUDIO_FILE_CANVAS);
cmd.setEmbeddedFonts(false);
var dataQueue = new commonDefines.TaskQueueData();
dataQueue.setCmd(cmd);
dataQueue.setToFile('Editor.bin');
var priority = constants.QUEUE_PRIORITY_HIGH;
var formatIn = formatChecker.getFormatFromString(cmd.getFormat());
//decrease pdf, djvu, xps convert priority becase long open time
if (constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === formatIn ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_DJVU === formatIn ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_XPS === formatIn) {
priority = constants.QUEUE_PRIORITY_LOW;
}
yield* docsCoServer.addTask(dataQueue, priority);
} else {
yield* commandOpenFillOutput(conn, cmd, outputData, opt_bIsRestore);
}
//add task
cmd.setOutputFormat(constants.AVS_OFFICESTUDIO_FILE_CANVAS);
cmd.setEmbeddedFonts(false);
var dataQueue = new commonDefines.TaskQueueData();
dataQueue.setCmd(cmd);
dataQueue.setToFile('Editor.bin');
var priority = constants.QUEUE_PRIORITY_HIGH;
var formatIn = formatChecker.getFormatFromString(cmd.getFormat());
//decrease pdf, djvu, xps convert priority becase long open time
if (constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF === formatIn ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_DJVU === formatIn ||
constants.AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_XPS === formatIn) {
priority = constants.QUEUE_PRIORITY_LOW;
}
yield* docsCoServer.addTask(dataQueue, priority);
} else {
yield* commandOpenFillOutput(conn, cmd, outputData, opt_bIsRestore);
}
}
}
function* commandOpenFillOutput(conn, cmd, outputData, opt_bIsRestore) {
let needAddTask = false;
let selectRes = yield taskResult.select(cmd.getDocId());
@ -401,15 +407,6 @@ function* commandReopen(cmd) {
}
return res;
}
function* commandOpenEncrypted(cmd) {
//todo if None, NeedPassword
let updateTask = new taskResult.TaskResultData();
updateTask.key = cmd.getDocId();
updateTask.status = taskResult.FileStatus.Ok;
updateTask.statusInfo = constants.NO_ERROR;
yield taskResult.update(updateTask);
}
function* commandSave(cmd, outputData) {
var completeParts = yield* saveParts(cmd, "Editor.bin");
if (completeParts) {
@ -640,191 +637,207 @@ function checkAuthorizationLength(authorization, data){
function* commandSfcCallback(cmd, isSfcm, isEncrypted) {
var docId = cmd.getDocId();
logger.debug('Start commandSfcCallback: docId = %s', docId);
var saveKey = cmd.getSaveKey();
var statusInfo = cmd.getStatusInfo();
var isError = constants.NO_ERROR != statusInfo;
var isErrorCorrupted = constants.CONVERT_CORRUPTED == statusInfo;
var savePathDoc = saveKey + '/' + cmd.getOutputPath();
var savePathChanges = saveKey + '/changes.zip';
var savePathHistory = saveKey + '/changesHistory.json';
var getRes = yield* docsCoServer.getCallback(docId);
var forceSave = cmd.getForceSave();
var forceSaveType = forceSave ? forceSave.getType() : commonDefines.c_oAscForceSaveTypes.Command;
var isSfcmSuccess = false;
let storeForgotten = false;
let replyStr;
var statusOk;
var statusErr;
if (isSfcm) {
statusOk = docsCoServer.c_oAscServerStatus.MustSaveForce;
statusErr = docsCoServer.c_oAscServerStatus.CorruptedForce;
} else {
statusOk = docsCoServer.c_oAscServerStatus.MustSave;
statusErr = docsCoServer.c_oAscServerStatus.Corrupted;
}
let updateMask = new taskResult.TaskResultData();
updateMask.key = docId;
if (!isEncrypted) {
updateMask.status = taskResult.FileStatus.SaveVersion;
updateMask.statusInfo = cmd.getData();
} else {
updateMask.status = taskResult.FileStatus.Ok;
}
let updateIfTask = new taskResult.TaskResultData();
updateIfTask.status = taskResult.FileStatus.UpdateVersion;
updateIfTask.statusInfo = Math.floor(Date.now() / 60000);//minutes
let updateIfRes;
if (getRes) {
logger.debug('Callback commandSfcCallback: docId = %s callback = %s', docId, getRes.server.href);
var outputSfc = new commonDefines.OutputSfcData();
outputSfc.setKey(docId);
outputSfc.setEncrypted(isEncrypted);
var users = [];
let isOpenFromForgotten = false;
//setUserId - set from changes in convert
//setUserActionId - used in case of save without changes(forgotten files)
let userLastChangeId = cmd.getUserId() || cmd.getUserActionId();
if (userLastChangeId) {
users.push(userLastChangeId);
if (constants.EDITOR_CHANGES !== statusInfo || isSfcm) {
var saveKey = cmd.getSaveKey();
var isError = constants.NO_ERROR != statusInfo;
var isErrorCorrupted = constants.CONVERT_CORRUPTED == statusInfo;
var savePathDoc = saveKey + '/' + cmd.getOutputPath();
var savePathChanges = saveKey + '/changes.zip';
var savePathHistory = saveKey + '/changesHistory.json';
var getRes = yield* docsCoServer.getCallback(docId);
var forceSave = cmd.getForceSave();
var forceSaveType = forceSave ? forceSave.getType() : commonDefines.c_oAscForceSaveTypes.Command;
var isSfcmSuccess = false;
let storeForgotten = false;
var statusOk;
var statusErr;
if (isSfcm) {
statusOk = docsCoServer.c_oAscServerStatus.MustSaveForce;
statusErr = docsCoServer.c_oAscServerStatus.CorruptedForce;
} else {
statusOk = docsCoServer.c_oAscServerStatus.MustSave;
statusErr = docsCoServer.c_oAscServerStatus.Corrupted;
}
outputSfc.setUsers(users);
if (!isSfcm) {
var actions = [];
//use UserId case UserActionId miss in gc convertion
var userActionId = cmd.getUserActionId() || cmd.getUserId();
if (userActionId) {
actions.push(new commonDefines.OutputAction(commonDefines.c_oAscUserAction.Out, userActionId));
}
outputSfc.setActions(actions);
}
outputSfc.setUserData(cmd.getUserData());
if (!isError || isErrorCorrupted) {
try {
let forgottenId = cfgForgottenFiles + '/' + docId;
let forgotten = yield storage.listObjects(forgottenId);
let isSendHistory = 0 === forgotten.length;
if (!isSendHistory) {
//check indicator file to determine if opening was from the forgotten file
var forgottenMarkPath = docId + '/' + cfgForgottenFilesName + '.txt';
var forgottenMark = yield storage.listObjects(forgottenMarkPath);
isOpenFromForgotten = 0 !== forgottenMark.length;
isSendHistory = !isOpenFromForgotten;
logger.debug('commandSfcCallback forgotten no empty: docId = %s isSendHistory = %s', docId, isSendHistory);
}
if (isSendHistory && !isEncrypted) {
//don't send history info because changes isn't from file in storage
var data = yield storage.getObject(savePathHistory);
outputSfc.setChangeHistory(JSON.parse(data.toString('utf-8')));
let changeUrl = yield storage.getSignedUrl(getRes.baseUrl, savePathChanges,
commonDefines.c_oAscUrlTypes.Temporary);
outputSfc.setChangeUrl(changeUrl);
} else {
//for backward compatibility. remove this when Community is ready
outputSfc.setChangeHistory({});
}
let url = yield storage.getSignedUrl(getRes.baseUrl, savePathDoc, commonDefines.c_oAscUrlTypes.Temporary);
outputSfc.setUrl(url);
} catch (e) {
logger.error('Error commandSfcCallback: docId = %s\r\n%s', docId, e.stack);
}
if (outputSfc.getUrl() && outputSfc.getUsers().length > 0) {
outputSfc.setStatus(statusOk);
let recoverTask = new taskResult.TaskResultData();
recoverTask.status = taskResult.FileStatus.Ok;
recoverTask.statusInfo = constants.NO_ERROR;
let updateMask = new taskResult.TaskResultData();
updateMask.key = docId;
if (!isEncrypted) {
updateMask.status = taskResult.FileStatus.SaveVersion;
updateMask.statusInfo = cmd.getData();
} else {
let selectRes = yield taskResult.select(docId);
let row = selectRes.length > 0 ? selectRes[0] : null;
if (row) {
recoverTask.status = updateMask.status = row.status;
recoverTask.statusInfo = updateMask.statusInfo = row.status_info;
} else {
isError = true;
}
}
if (isError) {
outputSfc.setStatus(statusErr);
}
var uri = getRes.server.href;
if (isSfcm) {
var selectRes = yield taskResult.select(docId);
var row = selectRes.length > 0 ? selectRes[0] : null;
//send only if FileStatus.Ok to prevent forcesave after final save
if (row && row.status == taskResult.FileStatus.Ok) {
if (forceSave) {
outputSfc.setForceSaveType(forceSaveType);
outputSfc.setLastSave(new Date(forceSave.getTime()).toISOString());
let updateIfTask = new taskResult.TaskResultData();
updateIfTask.status = taskResult.FileStatus.UpdateVersion;
updateIfTask.statusInfo = Math.floor(Date.now() / 60000);//minutes
let updateIfRes;
if (getRes) {
logger.debug('Callback commandSfcCallback: docId = %s callback = %s', docId, getRes.server.href);
var outputSfc = new commonDefines.OutputSfcData();
outputSfc.setKey(docId);
outputSfc.setEncrypted(isEncrypted);
var users = [];
let isOpenFromForgotten = false;
//setUserId - set from changes in convert
//setUserActionId - used in case of save without changes(forgotten files)
let userLastChangeId = cmd.getUserId() || cmd.getUserActionId();
if (userLastChangeId) {
users.push(userLastChangeId);
}
outputSfc.setUsers(users);
if (!isSfcm) {
var actions = [];
//use UserId case UserActionId miss in gc convertion
var userActionId = cmd.getUserActionId() || cmd.getUserId();
if (userActionId) {
actions.push(new commonDefines.OutputAction(commonDefines.c_oAscUserAction.Out, userActionId));
}
outputSfc.setActions(actions);
}
outputSfc.setUserData(cmd.getUserData());
if (!isError || isErrorCorrupted) {
try {
replyStr = yield* docsCoServer.sendServerRequest(docId, uri, outputSfc, checkAuthorizationLength);
let replyData = docsCoServer.parseReplyData(docId, replyStr);
isSfcmSuccess = replyData && commonDefines.c_oAscServerCommandErrors.NoError == replyData.error;
} catch (err) {
logger.error('sendServerRequest error: docId = %s;url = %s;data = %j\r\n%s', docId, uri, outputSfc, err.stack);
let forgottenId = cfgForgottenFiles + '/' + docId;
let forgotten = yield storage.listObjects(forgottenId);
let isSendHistory = 0 === forgotten.length;
if (!isSendHistory) {
//check indicator file to determine if opening was from the forgotten file
var forgottenMarkPath = docId + '/' + cfgForgottenFilesName + '.txt';
var forgottenMark = yield storage.listObjects(forgottenMarkPath);
isOpenFromForgotten = 0 !== forgottenMark.length;
isSendHistory = !isOpenFromForgotten;
logger.debug('commandSfcCallback forgotten no empty: docId = %s isSendHistory = %s', docId, isSendHistory);
}
if (isSendHistory && !isEncrypted) {
//don't send history info because changes isn't from file in storage
var data = yield storage.getObject(savePathHistory);
outputSfc.setChangeHistory(JSON.parse(data.toString('utf-8')));
let changeUrl = yield storage.getSignedUrl(getRes.baseUrl, savePathChanges,
commonDefines.c_oAscUrlTypes.Temporary);
outputSfc.setChangeUrl(changeUrl);
} else {
//for backward compatibility. remove this when Community is ready
outputSfc.setChangeHistory({});
}
let url = yield storage.getSignedUrl(getRes.baseUrl, savePathDoc, commonDefines.c_oAscUrlTypes.Temporary);
outputSfc.setUrl(url);
} catch (e) {
logger.error('Error commandSfcCallback: docId = %s\r\n%s', docId, e.stack);
}
if (outputSfc.getUrl() && outputSfc.getUsers().length > 0) {
outputSfc.setStatus(statusOk);
} else {
isError = true;
}
}
} else {
//if anybody in document stop save
let editorsCount = yield docsCoServer.getEditorsCountPromise(docId);
logger.debug('commandSfcCallback presence: docId = %s count = %d', docId, editorsCount);
if (0 === editorsCount || (isEncrypted && 1 === editorsCount)) {
let lastSave = yield* docsCoServer.getLastSave(docId);
let notModified = yield* docsCoServer.getLastForceSave(docId, lastSave);
var lastSaveDate = lastSave ? new Date(lastSave.time) : new Date();
outputSfc.setLastSave(lastSaveDate.toISOString());
outputSfc.setNotModified(notModified);
updateIfRes = yield taskResult.updateIf(updateIfTask, updateMask);
if (updateIfRes.affectedRows > 0) {
updateMask.status = updateIfTask.status;
updateMask.statusInfo = updateIfTask.statusInfo;
if (isError) {
outputSfc.setStatus(statusErr);
}
var uri = getRes.server.href;
if (isSfcm) {
var selectRes = yield taskResult.select(docId);
var row = selectRes.length > 0 ? selectRes[0] : null;
//send only if FileStatus.Ok to prevent forcesave after final save
if (row && row.status == taskResult.FileStatus.Ok) {
if (forceSave) {
outputSfc.setForceSaveType(forceSaveType);
outputSfc.setLastSave(new Date(forceSave.getTime()).toISOString());
}
try {
replyStr = yield* docsCoServer.sendServerRequest(docId, uri, outputSfc, checkAuthorizationLength);
let replyData = docsCoServer.parseReplyData(docId, replyStr);
isSfcmSuccess = replyData && commonDefines.c_oAscServerCommandErrors.NoError == replyData.error;
} catch (err) {
logger.error('sendServerRequest error: docId = %s;url = %s;data = %j\r\n%s', docId, uri, outputSfc, err.stack);
}
var requestRes = false;
var replyData = docsCoServer.parseReplyData(docId, replyStr);
if (replyData && commonDefines.c_oAscServerCommandErrors.NoError == replyData.error) {
//в случае comunity server придет запрос в CommandService проверяем результат
var multi = redisClient.multi([
['get', redisKeySaved + docId],
['del', redisKeySaved + docId]
]);
var execRes = yield utils.promiseRedis(multi, multi.exec);
var savedVal = execRes[0];
requestRes = (null == savedVal || '1' === savedVal);
}
if (requestRes) {
updateIfTask = undefined;
yield docsCoServer.cleanDocumentOnExitPromise(docId, true);
if (isOpenFromForgotten) {
//remove forgotten file in cache
yield cleanupCache(docId);
}
} else {
//if anybody in document stop save
let editorsCount = yield docsCoServer.getEditorsCountPromise(docId);
logger.debug('commandSfcCallback presence: docId = %s count = %d', docId, editorsCount);
if (0 === editorsCount || (isEncrypted && 1 === editorsCount)) {
let lastSave = yield* docsCoServer.getLastSave(docId);
let notModified = yield* docsCoServer.getLastForceSave(docId, lastSave);
var lastSaveDate = lastSave ? new Date(lastSave.time) : new Date();
outputSfc.setLastSave(lastSaveDate.toISOString());
outputSfc.setNotModified(notModified);
updateIfRes = yield taskResult.updateIf(updateIfTask, updateMask);
if (updateIfRes.affectedRows > 0) {
updateMask.status = updateIfTask.status;
updateMask.statusInfo = updateIfTask.statusInfo;
try {
replyStr = yield* docsCoServer.sendServerRequest(docId, uri, outputSfc, checkAuthorizationLength);
} catch (err) {
logger.error('sendServerRequest error: docId = %s;url = %s;data = %j\r\n%s', docId, uri, outputSfc, err.stack);
}
var requestRes = false;
var replyData = docsCoServer.parseReplyData(docId, replyStr);
if (replyData && commonDefines.c_oAscServerCommandErrors.NoError == replyData.error) {
//в случае comunity server придет запрос в CommandService проверяем результат
var multi = redisClient.multi([
['get', redisKeySaved + docId],
['del', redisKeySaved + docId]
]);
var execRes = yield utils.promiseRedis(multi, multi.exec);
var savedVal = execRes[0];
requestRes = (null == savedVal || '1' === savedVal);
}
if (requestRes) {
updateIfTask = undefined;
yield docsCoServer.cleanDocumentOnExitPromise(docId, true);
if (isOpenFromForgotten) {
//remove forgotten file in cache
yield cleanupCache(docId);
}
} else {
storeForgotten = true;
}
} else {
storeForgotten = true;
updateIfTask = undefined;
}
} else {
updateIfTask = undefined;
}
}
} else {
logger.warn('Empty Callback commandSfcCallback: docId = %s', docId);
storeForgotten = true;
}
if (undefined !== updateIfTask && !isSfcm) {
logger.debug('commandSfcCallback restore %d status: docId = %s', recoverTask.status, docId);
updateIfTask.status = recoverTask.status;
updateIfTask.statusInfo = recoverTask.statusInfo;
updateIfRes = yield taskResult.updateIf(updateIfTask, updateMask);
if (!(updateIfRes.affectedRows > 0)) {
logger.debug('commandSfcCallback restore %d status failed: docId = %s', recoverTask.status, docId);
}
}
if (storeForgotten && (!isError || isErrorCorrupted)) {
try {
logger.debug("storeForgotten: docId = %s", docId);
let forgottenName = cfgForgottenFilesName + pathModule.extname(cmd.getOutputPath());
yield storage.copyObject(savePathDoc, cfgForgottenFiles + '/' + docId + '/' + forgottenName);
} catch (err) {
logger.error('Error storeForgotten: docId = %s\r\n%s', docId, err.stack);
}
}
if (forceSave) {
yield* docsCoServer.setForceSave(docId, forceSave, cmd, isSfcmSuccess && !isError);
}
} else {
logger.warn('Empty Callback commandSfcCallback: docId = %s', docId);
storeForgotten = true;
}
if (undefined !== updateIfTask && !isSfcm) {
logger.debug('commandSfcCallback restore FileStatus.Ok status: docId = %s', docId);
updateIfTask.status = taskResult.FileStatus.Ok;
updateIfTask.statusInfo = constants.NO_ERROR;
updateIfRes = yield taskResult.updateIf(updateIfTask, updateMask);
if (!(updateIfRes.affectedRows > 0)) {
logger.debug('commandSfcCallback restore FileStatus.Ok status failed: docId = %s', docId);
}
}
if (storeForgotten && (!isError || isErrorCorrupted)) {
try {
logger.debug("storeForgotten: docId = %s", docId);
let forgottenName = cfgForgottenFilesName + pathModule.extname(cmd.getOutputPath());
yield storage.copyObject(savePathDoc, cfgForgottenFiles + '/' + docId + '/' + forgottenName);
} catch (err) {
logger.error('Error storeForgotten: docId = %s\r\n%s', docId, err.stack);
}
}
if (forceSave) {
yield* docsCoServer.setForceSave(docId, forceSave, cmd, isSfcmSuccess && !isError);
logger.debug('commandSfcCallback cleanDocumentOnExitNoChangesPromise: docId = %s', docId);
yield docsCoServer.cleanDocumentOnExitNoChangesPromise(docId, undefined, true);
}
if ((docsCoServer.getIsShutdown() && !isSfcm) || cmd.getRedisKey()) {
let keyRedis = cmd.getRedisKey() ? cmd.getRedisKey() : redisKeyShutdown;
yield utils.promiseRedis(redisClient, redisClient.srem, keyRedis, docId);
@ -904,11 +917,7 @@ exports.openDocument = function(conn, cmd, opt_upsertRes, opt_bIsRestore) {
let res = true;
switch (cmd.getCommand()) {
case 'open':
if (!conn.encrypted) {
yield* commandOpen(conn, cmd, outputData, opt_upsertRes, opt_bIsRestore);
} else {
yield* commandOpenEncrypted(cmd);
}
yield* commandOpen(conn, cmd, outputData, opt_upsertRes, opt_bIsRestore);
break;
case 'reopen':
res = yield* commandReopen(cmd);
@ -1031,7 +1040,7 @@ exports.saveFile = function(req, res) {
let strCmd = req.query['cmd'];
let cmd = new commonDefines.InputCommand(JSON.parse(strCmd));
docId = cmd.getDocId();
logger.debug('Start saveFile: docId = %s %s', docId);
logger.debug('Start saveFile: docId = %s', docId);
if (cfgTokenEnableBrowser) {
let isValidJwt = false;

View File

@ -52,6 +52,8 @@ var cfgImageSize = configServer.get('limits_image_size');
var cfgTypesUpload = configUtils.get('limits_image_types_upload');
var cfgTokenEnableBrowser = config.get('services.CoAuthoring.token.enable.browser');
const PATTERN_ENCRYPTED = 'ENCRYPTED;';
exports.uploadTempFile = function(req, res) {
return co(function* () {
var docId = 'uploadTempFile';
@ -85,7 +87,7 @@ exports.uploadTempFile = function(req, res) {
});
};
function checkJwtUpload(docId, errorName, token){
var res = {err: true, docId: null, userid: null};
var res = {err: true, docId: null, userid: null, encrypted: null};
var checkJwtRes = docsCoServer.checkJwt(docId, token, commonDefines.c_oAscSecretType.Session);
if (checkJwtRes.decoded) {
var doc = checkJwtRes.decoded.document;
@ -93,6 +95,7 @@ function checkJwtUpload(docId, errorName, token){
if (!edit.ds_view && !edit.ds_isCloseCoAuthoring) {
res.err = false;
res.docId = doc.key;
res.encrypted = doc.ds_encrypted;
if (edit.user) {
res.userid = edit.user.id;
}
@ -190,9 +193,11 @@ exports.uploadImageFile = function(req, res) {
return co(function* () {
var isError = true;
var docId = 'null';
let output = {};
try {
docId = req.params.docid;
var userid = req.params.userid;
let encrypted = false;
logger.debug('Start uploadImageFile: docId = %s', docId);
var isValidJwt = true;
@ -201,6 +206,7 @@ exports.uploadImageFile = function(req, res) {
if (!checkJwtRes.err) {
docId = checkJwtRes.docId || docId;
userid = checkJwtRes.userid || userid;
encrypted = checkJwtRes.encrypted;
} else {
isValidJwt = false;
}
@ -208,29 +214,45 @@ exports.uploadImageFile = function(req, res) {
var index = parseInt(req.params.index);
if (isValidJwt && docId && req.body && Buffer.isBuffer(req.body)) {
var buffer = req.body;
var format = formatChecker.getImageFormat(buffer);
var formatStr = formatChecker.getStringFromFormat(format);
var supportedFormats = cfgTypesUpload || 'jpg';
if (formatStr && -1 !== supportedFormats.indexOf(formatStr) && buffer.length <= cfgImageSize) {
//в начале пишется хеш, чтобы избежать ошибок при параллельном upload в совместном редактировании
var strImageName = utils.crc32(userid).toString(16) + '_image' + index;
var strPathRel = 'media/' + strImageName + '.' + formatStr;
var strPath = docId + '/' + strPathRel;
yield storageBase.putObject(strPath, buffer, buffer.length);
var output = {};
output[strPathRel] = yield storageBase.getSignedUrl(utils.getBaseUrlByRequest(req), strPath,
commonDefines.c_oAscUrlTypes.Session);
res.send(JSON.stringify(output));
isError = false;
let buffer = req.body;
if (buffer.length <= cfgImageSize) {
var format = formatChecker.getImageFormat(buffer, undefined);
var formatStr = formatChecker.getStringFromFormat(format);
var supportedFormats = cfgTypesUpload || 'jpg';
let formatLimit = formatStr && -1 !== supportedFormats.indexOf(formatStr);
if (!formatLimit && encrypted && PATTERN_ENCRYPTED == buffer.toString('utf8', 0, PATTERN_ENCRYPTED.length)) {
formatLimit = true;
formatStr = buffer.toString('utf8', PATTERN_ENCRYPTED.length, buffer.indexOf(';', PATTERN_ENCRYPTED.length));
}
if (formatLimit) {
//в начале пишется хеш, чтобы избежать ошибок при параллельном upload в совместном редактировании
var strImageName = utils.crc32(userid).toString(16) + '_image' + index;
var strPathRel = 'media/' + strImageName + '.' + formatStr;
var strPath = docId + '/' + strPathRel;
yield storageBase.putObject(strPath, buffer, buffer.length);
output[strPathRel] = yield storageBase.getSignedUrl(utils.getBaseUrlByRequest(req), strPath,
commonDefines.c_oAscUrlTypes.Session);
isError = false;
} else {
logger.debug('uploadImageFile format is not supported: docId = %s', docId);
}
} else {
logger.debug('uploadImageFile size limit exceeded: buffer.length = %d docId = %s', buffer.length, docId);
}
}
logger.debug('End uploadImageFile: isError = %d docId = %s', isError, docId);
} catch (e) {
isError = true;
logger.error('Error uploadImageFile: docId = %s\r\n%s', docId, e.stack);
} finally {
if (isError) {
res.sendStatus(400);
try {
if (!isError) {
res.send(JSON.stringify(output));
} else {
res.sendStatus(400);
}
logger.debug('End uploadImageFile: isError = %s docId = %s', isError, docId);
} catch (e) {
logger.error('Error uploadImageFile: docId = %s\r\n%s', docId, e.stack);
}
}
});

View File

@ -307,6 +307,7 @@ function* downloadFileFromStorage(id, strPath, dir) {
}
}
function* processDownloadFromStorage(dataConvert, cmd, task, tempDirs) {
let res = constants.NO_ERROR;
let needConcatFiles = false;
if (task.getFromOrigin() || task.getFromSettings()) {
dataConvert.fileFrom = path.join(tempDirs.source, 'origin.' + cmd.getFormat());
@ -326,8 +327,9 @@ function* processDownloadFromStorage(dataConvert, cmd, task, tempDirs) {
yield* concatFiles(tempDirs.source);
}
if (task.getFromChanges()) {
yield* processChanges(tempDirs, cmd);
res = yield* processChanges(tempDirs, cmd);
}
return res;
}
function* concatFiles(source) {
@ -356,6 +358,7 @@ function* concatFiles(source) {
}
function* processChanges(tempDirs, cmd) {
let res = constants.NO_ERROR;
let changesDir = path.join(tempDirs.source, 'changes');
fs.mkdirSync(changesDir);
let indexFile = 0;
@ -378,6 +381,12 @@ function* processChanges(tempDirs, cmd) {
let changes = yield baseConnector.getChangesPromise(cmd.getDocId(), curIndexStart, curIndexEnd, forceSaveTime);
for (let i = 0; i < changes.length; ++i) {
let change = changes[i];
if (change.change_data.startsWith('ENCRYPTED;')) {
logger.warn('processChanges encrypted changes (id=%s)', cmd.getDocId());
//todo sql request instead?
res = constants.EDITOR_CHANGES;
break;
}
if (null === changesAuthor || changesAuthor !== change.user_id_original) {
if (null !== changesAuthor) {
yield* streamEnd(streamObj, ']');
@ -406,6 +415,7 @@ function* processChanges(tempDirs, cmd) {
}
cmd.setUserId(changesAuthor);
fs.writeFileSync(path.join(tempDirs.result, 'changesHistory.json'), JSON.stringify(changesHistory), 'utf8');
return res;
}
function* streamCreate(docId, changesDir, indexFile, opt_options) {
@ -576,7 +586,7 @@ function* ExecuteTask(task) {
clientStatsD.timing('conv.downloadFileFromStorage', new Date() - curDate);
curDate = new Date();
}
yield* processDownloadFromStorage(dataConvert, cmd, task, tempDirs);
error = yield* processDownloadFromStorage(dataConvert, cmd, task, tempDirs);
} else if (cmd.getForgotten()) {
yield* downloadFileFromStorage(cmd.getDocId(), cmd.getForgotten(), tempDirs.source);
logger.debug('downloadFileFromStorage complete(id=%s)', dataConvert.key);