From 6f41ef6cd3d3a74b0306b439b4b7379853e56dbb Mon Sep 17 00:00:00 2001 From: "Sergey.Konovalov" Date: Wed, 24 Feb 2016 14:49:30 +0000 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=20=D0=B7=D0=B0=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=88=D0=B5=D0=BD=D0=B8=D1=8E=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20=D1=81=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D1=83=20=D1=83=D0=B4=D0=B0=D0=BB=D1=8F=D0=B5=D0=BC=20?= =?UTF-8?q?=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D1=83=D1=8E=20=D0=B8?= =?UTF-8?q?=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D1=8E,=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=B6=D0=B4=D0=B5=D0=BC=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D0=B4=D1=8B=20=D0=BD=D0=B0=20commandService.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://192.168.3.15/activex/AVS/Sources/TeamlabOffice/trunk/nodeJSProjects@68398 954022d7-b5bf-4e40-9824-e11837661b57 --- Common/sources/commondefines.js | 8 ++ DocService/sources/DocsCoServer.js | 111 ++++++++++++---------------- DocService/sources/canvasservice.js | 2 +- 3 files changed, 56 insertions(+), 65 deletions(-) diff --git a/Common/sources/commondefines.js b/Common/sources/commondefines.js index 471dab7b..072b1e29 100644 --- a/Common/sources/commondefines.js +++ b/Common/sources/commondefines.js @@ -603,6 +603,13 @@ var c_oAscUserAction = { In: 1, AllIn: 2 }; +var c_oAscServerCommandErrors = { + NoError: 0, + DocumentIdError: 1, + ParseError: 2, + CommandError: 3, + NotModify: 4 +}; exports.TaskQueueData = TaskQueueData; exports.CMailMergeSendData = CMailMergeSendData; @@ -615,3 +622,4 @@ exports.c_oAscEncodings = c_oAscEncodings; exports.c_oAscEncodingsMap = c_oAscEncodingsMap; exports.c_oAscCodePageUtf8 = c_oAscCodePageUtf8; exports.c_oAscUserAction = c_oAscUserAction; +exports.c_oAscServerCommandErrors = c_oAscServerCommandErrors; diff --git a/DocService/sources/DocsCoServer.js b/DocService/sources/DocsCoServer.js index 8960492a..dbacc2df 100644 --- a/DocService/sources/DocsCoServer.js +++ b/DocService/sources/DocsCoServer.js @@ -162,14 +162,6 @@ var c_oAscChangeBase = { All: 2 }; -var c_oAscServerCommandErrors = { - NoError: 0, - DocumentIdError: 1, - ParseError: 2, - CommandError: 3, - NotModify: 4 -}; - var c_oAscSaveTimeOutDelay = 5000; // Время ожидания для сохранения на сервере (для отработки F5 в браузере) var c_oAscLockTimeOutDelay = 500; // Время ожидания для сохранения, когда зажата база данных @@ -621,43 +613,32 @@ function* sendStatusDocument(docId, bChangeBase, userAction, callback, baseUrl) } yield* onReplySendStatusDocument(docId, replyData); } -function* onReplySendStatusDocument(docId, replyData) { - var res = false; +function parseReplyData(docId, replyData) { + var res = null; if (replyData) { - var oData; try { - oData = JSON.parse(replyData); + res = JSON.parse(replyData); } catch (e) { - logger.error("error reply SendStatusDocument: docId = %s\r\n%s", docId, e.stack); - oData = null; - } - - if (oData && c_oAscServerCommandErrors.NoError == oData.error) { - res = true; + logger.error("error parseReplyData: docId = %s; data = %s\r\n%s", docId, replyData, e.stack); + res = null; } } - if (!res) { + return res; +} +function* onReplySendStatusDocument(docId, replyData) { + var oData = parseReplyData(docId, replyData); + if (!(oData && commonDefines.c_oAscServerCommandErrors.NoError == oData.error)) { // Ошибка подписки на callback, посылаем warning yield* publish({type: PublishType.warning, docId: docId, description: 'Error on save server subscription!'}); } } function* dropUsersFromDocument(docId, replyData) { - if (!replyData) { - return; - } - var oData, users; - try { - oData = JSON.parse(replyData); - } catch (e) { - logger.error("error reply SendStatusDocument: docId = %s\r\n%s", docId, e.stack); - oData = null; - } - if (!oData) { - return; - } - users = Array.isArray(oData) ? oData : oData.users; - if (Array.isArray(users)) { - yield* publish({type: PublishType.drop, docId: docId, users: users, description: ''}); + var oData = parseReplyData(docId, replyData); + if (oData) { + users = Array.isArray(oData) ? oData : oData.users; + if (Array.isArray(users)) { + yield* publish({type: PublishType.drop, docId: docId, users: users, description: ''}); + } } } @@ -689,7 +670,7 @@ function* bindEvents(docId, callback, baseUrl, opt_userAction) { } else { oCallbackUrl = parseUrl(callback); if (null === oCallbackUrl) { - return c_oAscServerCommandErrors.ParseError; + return commonDefines.c_oAscServerCommandErrors.ParseError; } bChangeBase = c_oAscChangeBase.All; } @@ -697,28 +678,25 @@ function* bindEvents(docId, callback, baseUrl, opt_userAction) { yield* sendStatusDocument(docId, bChangeBase, userAction, oCallbackUrl, baseUrl); } -// Удаляем изменения из памяти (используется только с основного сервера, для очистки!) -function* removeChanges(id, isCorrupted, isConvertService) { - logger.info('removeChanges: %s', id); - // remove locks, editors, messages from memory - yield utils.promiseRedis(redisClient, redisClient.del, redisKeyLocks + id, redisKeyEditors + id, redisKeyMessage + id); - - yield* deleteCallback(id); - - if (!isCorrupted) { - // remove UserIndex, ChangeIndex from memory - yield utils.promiseRedis(redisClient, redisClient.del, redisKeyUserIndex + id, redisKeyChangeIndex + id, redisKeyForceSave + id, redisKeyLastSave + id); - // Нужно удалить изменения из базы - sqlBase.deleteChanges(id, null); - } else { - // Обновим статус файла (т.к. ошибка, выставим, что не собиралось) - sqlBase.updateStatusFile(id); - logger.error('saved corrupted id = %s convert = %s', id, isConvertService); +function* cleanDocumentOnExit(docId, deleteChanges, deleteUserIndex) { + //clean redis + var redisArgs = [redisClient, redisClient.del, redisKeyLocks + docId, redisKeyEditors + docId, + redisKeyMessage + docId, redisKeyChangeIndex + docId, redisKeyForceSave + docId, redisKeyLastSave + docId]; + if (deleteUserIndex) { + redisArgs.push(redisKeyUserIndex + docId); + } + utils.promiseRedis.apply(this, redisArgs); + //remove callback + yield* deleteCallback(docId); + //remove changes + if (deleteChanges) { + sqlBase.deleteChanges(docId, null); } } function* cleanDocumentOnExitNoChanges(docId, opt_userId) { - yield utils.promiseRedis(redisClient, redisClient.del, redisKeyLocks + docId, redisKeyEditors + docId, - redisKeyMessage + docId, redisKeyUserIndex + docId, redisKeyChangeIndex + docId, redisKeyForceSave + docId, redisKeyLastSave + docId); + //если пользователь зашел в документ, соединение порвалось, на сервере удалилась вся информация, + //при восстановлении соединения userIndex сохранится и он совпадет с userIndex следующего пользователя + yield* cleanDocumentOnExit(docId, false, false); var userAction = opt_userId ? new commonDefines.OutputAction(commonDefines.c_oAscUserAction.Out, opt_userId) : null; // Отправляем, что все ушли и нет изменений (чтобы выставить статус на сервере об окончании редактирования) yield* sendStatusDocument(docId, c_oAscChangeBase.All, userAction); @@ -728,6 +706,7 @@ exports.version = asc_coAuthV; exports.c_oAscServerStatus = c_oAscServerStatus; exports.sendData = sendData; exports.parseUrl = parseUrl; +exports.parseReplyData = parseReplyData; exports.sendServerRequest = sendServerRequest; exports.PublishType = PublishType; exports.publish = publish; @@ -735,7 +714,7 @@ exports.addTask = addTask; exports.removeResponse = removeResponse; exports.hasEditors = hasEditors; exports.getCallback = getCallback; -exports.deleteCallback= deleteCallback; +exports.cleanDocumentOnExit = cleanDocumentOnExit; exports.setForceSave= setForceSave; exports.install = function(server, callbackFunction) { 'use strict'; @@ -1974,7 +1953,7 @@ exports.install = function(server, callbackFunction) { // Команда с сервера (в частности teamlab) exports.commandFromServer = function (req, res) { utils.spawn(function* () { - var result = c_oAscServerCommandErrors.NoError; + var result = commonDefines.c_oAscServerCommandErrors.NoError; var docId = 'null'; var saveUrl = undefined; try { @@ -1982,7 +1961,7 @@ exports.commandFromServer = function (req, res) { // Ключ id-документа docId = query.key; if (null == docId) { - result = c_oAscServerCommandErrors.DocumentIdError; + result = commonDefines.c_oAscServerCommandErrors.DocumentIdError; } else { logger.debug('Start commandFromServer: docId = %s c = %s', docId, query.c); switch (query.c) { @@ -1999,7 +1978,11 @@ exports.commandFromServer = function (req, res) { break; case 'saved': // Результат от менеджера документов о статусе обработки сохранения файла после сборки - yield* removeChanges(docId, '1' !== query.status, '1' === query.conv); + if ('1' !== query.status) { + logger.error('saved corrupted id = %s status = %s conv = %s', docId, query.status, query.conv); + } else { + logger.info('saved id = %s status = %s conv = %s', docId, query.status, query.conv); + } break; case 'forcesave': var lastSave = yield utils.promiseRedis(redisClient, redisClient.get, redisKeyLastSave + docId); @@ -2011,7 +1994,7 @@ exports.commandFromServer = function (req, res) { ]); var execRes = yield utils.promiseRedis(multi, multi.exec); if (0 == execRes[0]) { - result = c_oAscServerCommandErrors.NotModify; + result = commonDefines.c_oAscServerCommandErrors.NotModify; var hsetGet = yield utils.promiseRedis(redisClient, redisClient.hget, redisKeyForceSave + docId, lastSave); if (hsetGet) { saveUrl = yield storage.getSignedUrl(baseUrl, hsetGet); @@ -2019,20 +2002,20 @@ exports.commandFromServer = function (req, res) { } else { var status = yield* converterService.convertFromChanges(docId, baseUrl, lastSave); if (constants.NO_ERROR !== status.err) { - result = c_oAscServerCommandErrors.CommandError; + result = commonDefines.c_oAscServerCommandErrors.CommandError; } } } else { - result = c_oAscServerCommandErrors.NotModify; + result = commonDefines.c_oAscServerCommandErrors.NotModify; } break; default: - result = c_oAscServerCommandErrors.CommandError; + result = commonDefines.c_oAscServerCommandErrors.CommandError; break; } } } catch (err) { - result = c_oAscServerCommandErrors.CommandError; + result = commonDefines.c_oAscServerCommandErrors.CommandError; logger.error('Error commandFromServer: docId = %s\r\n%s', docId, err.stack); } finally { var output = JSON.stringify({'key': req.query.key, 'error': result, 'saveUrl': saveUrl}); diff --git a/DocService/sources/canvasservice.js b/DocService/sources/canvasservice.js index bc034057..b684d4b5 100644 --- a/DocService/sources/canvasservice.js +++ b/DocService/sources/canvasservice.js @@ -1 +1 @@ -var pathModule = require('path'); var urlModule = require('url'); var sqlBase = require('./baseConnector'); var docsCoServer = require('./DocsCoServer'); var taskResult = require('./taskresult'); var logger = require('./../../Common/sources/logger'); var utils = require('./../../Common/sources/utils'); var constants = require('./../../Common/sources/constants'); var commonDefines = require('./../../Common/sources/commondefines'); var storage = require('./../../Common/sources/storage-base'); var formatChecker = require('./../../Common/sources/formatchecker'); var statsDClient = require('./../../Common/sources/statsdclient'); var config = require('config'); var config_server = config.get('services.CoAuthoring.server'); var config_utils = config.get('services.CoAuthoring.utils'); var cfgTypesUpload = config_utils.get('limits_image_types_upload'); var cfgTypesCopy = config_utils.get('limits_image_types_copy'); var cfgImageSize = config_server.get('limits_image_size'); var cfgImageDownloadTimeout = config_server.get('limits_image_download_timeout'); var SAVE_TYPE_PART_START = 0; var SAVE_TYPE_PART = 1; var SAVE_TYPE_COMPLETE = 2; var SAVE_TYPE_COMPLETE_ALL = 3; var clientStatsD = statsDClient.getClient(); function OutputDataWrap(type, data) { this['type'] = type; this['data'] = data; } OutputDataWrap.prototype = { fromObject: function(data) { this['type'] = data['type']; this['data'] = new OutputData(); this['data'].fromObject(data['data']); }, getType: function() { return this['type']; }, setType: function(data) { this['type'] = data; }, getData: function() { return this['data']; }, setData: function(data) { this['data'] = data; } }; function OutputData(type) { this['type'] = type; this['status'] = undefined; this['data'] = undefined; } OutputData.prototype = { fromObject: function(data) { this['type'] = data['type']; this['status'] = data['status']; this['data'] = data['data']; }, getType: function() { return this['type']; }, setType: function(data) { this['type'] = data; }, getStatus: function() { return this['status']; }, setStatus: function(data) { this['status'] = data; }, getData: function() { return this['data']; }, setData: function(data) { this['data'] = data; } }; function* getOutputData(cmd, outputData, key, status, statusInfo, optConn, optAdditionalOutput) { var docId = cmd.getDocId(); switch (status) { case taskResult.FileStatus.SaveVersion: case taskResult.FileStatus.UpdateVersion: case taskResult.FileStatus.Ok: if(taskResult.FileStatus.Ok == status) { outputData.setStatus('ok'); } else if(taskResult.FileStatus.SaveVersion == status) { if (optConn && optConn.user.view) { outputData.setStatus('updateversion'); } else { var updateMask = new taskResult.TaskResultData(); updateMask.key = docId; updateMask.status = status; updateMask.statusInfo = statusInfo; var updateTask = new taskResult.TaskResultData(); updateTask.status = taskResult.FileStatus.Ok; updateTask.statusInfo = constants.NO_ERROR; var updateIfRes = yield taskResult.updateIf(updateTask, updateMask); if (updateIfRes.affectedRows > 0) { outputData.setStatus('ok'); } else { outputData.setStatus('updateversion'); } } } else { outputData.setStatus('updateversion'); } var command = cmd.getCommand(); if ('open' != command && 'reopen' != command) { var strPath = key + '/' + cmd.getOutputPath(); if (optConn) { outputData.setData(yield storage.getSignedUrl(optConn.baseUrl, strPath, null, cmd.getTitle())); } else if (optAdditionalOutput) { optAdditionalOutput.needUrlKey = strPath; optAdditionalOutput.needUrlMethod = 2; } } else { if (optConn) { outputData.setData(yield storage.getSignedUrls(optConn.baseUrl, key)); } else if (optAdditionalOutput) { optAdditionalOutput.needUrlKey = key; optAdditionalOutput.needUrlMethod = 0; } } break; case taskResult.FileStatus.NeedParams: outputData.setStatus('needparams'); var settingsPath = key + '/' + 'settings.json'; if (optConn) { outputData.setData(yield storage.getSignedUrl(optConn.baseUrl, settingsPath)); } else if (optAdditionalOutput) { optAdditionalOutput.needUrlKey = settingsPath; optAdditionalOutput.needUrlMethod = 1; } break; case taskResult.FileStatus.Err: case taskResult.FileStatus.ErrToReload: outputData.setStatus('err'); outputData.setData(statusInfo); if (taskResult.FileStatus.ErrToReload == status) { yield taskResult.remove(key); } break; } } function* addRandomKeyTaskCmd(cmd) { var task = yield* taskResult.addRandomKeyTask(cmd.getDocId()); cmd.setSaveKey(task.key); } function* saveParts(cmd) { var result = false; var saveType = cmd.getSaveType(); var filename; if (SAVE_TYPE_COMPLETE_ALL === saveType) { filename = 'Editor.bin'; } else { filename = 'Editor' + (cmd.getSaveIndex() || '') + '.bin'; } if (SAVE_TYPE_PART_START === saveType || SAVE_TYPE_COMPLETE_ALL === saveType) { yield* addRandomKeyTaskCmd(cmd); } if (cmd.getUrl()) { result = true; } else { var buffer = cmd.getData(); yield storage.putObject(cmd.getSaveKey() + '/' + filename, buffer, buffer.length); //delete data to prevent serialize into json cmd.data = null; result = (SAVE_TYPE_COMPLETE_ALL === saveType || SAVE_TYPE_COMPLETE === saveType); } return result; } function getSaveTask(cmd) { cmd.setData(null); var queueData = new commonDefines.TaskQueueData(); queueData.setCmd(cmd); queueData.setToFile(constants.OUTPUT_NAME + '.' + formatChecker.getStringFromFormat(cmd.getOutputFormat())); //todo paid //if (cmd.vkey) { // bool // bPaid; // Signature.getVKeyParams(cmd.vkey, out bPaid); // oTaskQueueData.m_bPaid = bPaid; //} return queueData; } function getUpdateResponse(cmd) { var updateTask = new taskResult.TaskResultData(); updateTask.key = cmd.getSaveKey() ? cmd.getSaveKey() : cmd.getDocId(); var statusInfo = cmd.getStatusInfo(); if (constants.NO_ERROR == statusInfo) { updateTask.status = taskResult.FileStatus.Ok; } else if (constants.CONVERT_DOWNLOAD == statusInfo) { updateTask.status = taskResult.FileStatus.ErrToReload; } else if (constants.CONVERT_NEED_PARAMS == statusInfo) { updateTask.status = taskResult.FileStatus.NeedParams; } else { updateTask.status = taskResult.FileStatus.Err; } updateTask.statusInfo = statusInfo; if (cmd.getTitle()) { updateTask.title = cmd.getTitle(); } return updateTask; } function* commandOpen(conn, cmd, outputData) { var task = new taskResult.TaskResultData(); task.key = cmd.getDocId(); task.format = cmd.getFormat(); task.status = taskResult.FileStatus.WaitQueue; task.statusInfo = constants.NO_ERROR; task.title = cmd.getTitle(); var upsertRes = yield taskResult.upsert(task); //if CLIENT_FOUND_ROWS don't specify 1 row is inserted , 2 row is updated, and 0 row is set to its current values //http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html var bCreate = upsertRes.affectedRows == 1; if (!bCreate) { var selectRes = yield taskResult.select(task); if (selectRes.length > 0) { var row = selectRes[0]; yield* getOutputData(cmd, outputData, cmd.getDocId(), row.tr_status, row.tr_status_info, conn); } } else { //add task cmd.setOutputFormat(constants.AVS_OFFICESTUDIO_FILE_CANVAS); cmd.setEmbeddedFonts(false); var dataQueue = new commonDefines.TaskQueueData(); dataQueue.setCmd(cmd); dataQueue.setToFile('Editor.bin'); yield* docsCoServer.addTask(dataQueue, constants.QUEUE_PRIORITY_HIGH); } } function* commandReopen(cmd) { var task = new taskResult.TaskResultData(); task.key = cmd.getDocId(); task.status = taskResult.FileStatus.WaitQueue; task.statusInfo = constants.NO_ERROR; var upsertRes = yield taskResult.update(task); if (upsertRes.affectedRows > 0) { //add task cmd.setUrl(null);//url may expire cmd.setSaveKey(cmd.getDocId()); cmd.setOutputFormat(constants.AVS_OFFICESTUDIO_FILE_CANVAS); cmd.setEmbeddedFonts(false); var dataQueue = new commonDefines.TaskQueueData(); dataQueue.setCmd(cmd); dataQueue.setToFile('Editor.bin'); dataQueue.setFromSettings(true); yield* docsCoServer.addTask(dataQueue, constants.QUEUE_PRIORITY_HIGH); } } function* commandSave(cmd, outputData) { var completeParts = yield* saveParts(cmd); if (completeParts) { var queueData = getSaveTask(cmd); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); } outputData.setStatus('ok'); outputData.setData(cmd.getSaveKey()); } function* commandSendMailMerge(cmd, outputData) { var completeParts = yield* saveParts(cmd); var isErr = false; if (completeParts) { isErr = true; var getRes = yield* docsCoServer.getCallback(cmd.getDocId()); if (getRes) { var mailMergeSend = cmd.getMailMergeSend(); mailMergeSend.setUrl(getRes.server.href); mailMergeSend.setBaseUrl(getRes.baseUrl); //меняем JsonKey и SaveKey, новый key нужет потому что за одну конвертацию делается часть, а json нужен всегда mailMergeSend.setJsonKey(cmd.getSaveKey()); yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); isErr = false; } } if (isErr) { outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); } else { outputData.setStatus('ok'); outputData.setData(cmd.getSaveKey()); } } function* commandSfctByCmd(cmd) { yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); queueData.setFromChanges(true); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); } function* commandSfct(cmd, outputData) { yield* commandSfctByCmd(cmd); outputData.setStatus('ok'); } function isDisplayedImage(strName) { var res = 0; if (strName) { //шаблон display[N]image.ext var findStr = constants.DISPLAY_PREFIX; var index = strName.indexOf(findStr); if (-1 != index) { if (index + findStr.length < strName.length) { var displayN = parseInt(strName[index + findStr.length]); if (1 <= displayN && displayN <= 6) { var imageIndex = index + findStr.length + 1; if (imageIndex == strName.indexOf("image", imageIndex)) res = displayN; } } } } return res; } function* commandImgurls(conn, cmd, outputData) { var supportedFormats; var urls; var errorCode = constants.NO_ERROR; var isImgUrl = 'imgurl' == cmd.getCommand(); if (isImgUrl) { urls = [cmd.getData()]; supportedFormats = cfgTypesUpload || 'jpg'; } else { urls = cmd.getData(); supportedFormats = cfgTypesCopy || 'jpg'; } //todo Promise.all() var displayedImageMap = {};//to make one imageIndex for ole object urls var imageCount = 0; var outputUrls = []; for (var i = 0; i < urls.length; ++i) { var urlSource = urls[i]; var urlParsed; var data = undefined; if (urlSource.startsWith('data:')) { var delimiterIndex = urlSource.indexOf(','); if (-1 != delimiterIndex && (urlSource.length - (delimiterIndex + 1)) * 0.75 <= cfgImageSize) { data = new Buffer(urlSource.substring(delimiterIndex + 1), 'base64'); } } else if(urlSource) { //todo stream data = yield utils.downloadUrlPromise(urlSource, cfgImageDownloadTimeout * 1000, cfgImageSize); urlParsed = urlModule.parse(urlSource); } var outputUrl = {url: 'error', path: 'error'}; if (data) { var format = formatChecker.getImageFormat(data); var formatStr; if (constants.AVS_OFFICESTUDIO_FILE_UNKNOWN == format && urlParsed) { //bin, txt occur in ole object case var ext = pathModule.extname(urlParsed.pathname); if ('.bin' == ext || '.txt' == ext) { formatStr = ext.substring(1); } } else { formatStr = formatChecker.getStringFromFormat(format); } if (formatStr && -1 !== supportedFormats.indexOf(formatStr)) { var userid = cmd.getUserId(); var imageIndex = cmd.getSaveIndex() + imageCount; imageCount++; var strLocalPath = 'media/' + utils.crc32(userid).toString(16) + '_'; if (urlParsed) { var urlBasename = pathModule.basename(urlParsed.pathname); var displayN = isDisplayedImage(urlBasename); if (displayN > 0) { var displayedImageName = urlBasename.substring(0, urlBasename.length - formatStr.length - 1); var tempIndex = displayedImageMap[displayedImageName]; if (null != tempIndex) { imageIndex = tempIndex; imageCount--; } else { displayedImageMap[displayedImageName] = imageIndex; } strLocalPath += constants.DISPLAY_PREFIX + displayN; } } strLocalPath += 'image' + imageIndex + '.' + formatStr; var strPath = cmd.getDocId() + '/' + strLocalPath; yield storage.putObject(strPath, data, data.length); var imgUrl = yield storage.getSignedUrl(conn.baseUrl, strPath); outputUrl = {url: imgUrl, path: strLocalPath}; } } if (isImgUrl && ('error' === outputUrl.url || 'error' === outputUrl.path)) { errorCode = constants.UPLOAD_EXTENSION; break; } outputUrls.push(outputUrl); } if (constants.NO_ERROR !== errorCode) { outputData.setStatus('err'); outputData.setData(errorCode); } else { outputData.setStatus('ok'); outputData.setData(outputUrls); } } function* commandSaveFromOrigin(cmd, outputData) { yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); queueData.setFromOrigin(true); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); outputData.setStatus('ok'); outputData.setData(cmd.getSaveKey()); } function* commandSfcCallback(cmd, isSfcm) { 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 && 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); if (getRes) { logger.debug('Callback commandSfcCallback: docId = %s callback = %s', docId, getRes.server.href); var outputSfc = new commonDefines.OutputSfcData(); outputSfc.setKey(docId); if (cmd.getUserId()) { outputSfc.setUsers([cmd.getUserId()]); } //use UserId case UserActionId miss in gc convertion var userActionId = cmd.getUserActionId() || cmd.getUserId(); if (userActionId) { outputSfc.setActions([new commonDefines.OutputAction(commonDefines.c_oAscUserAction.Out, userActionId)]); } if (isError) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.Corrupted); } else { try { var data = yield storage.getObject(savePathHistory); outputSfc.setChangeHistory(data.toString('utf-8')); outputSfc.setUrl(yield storage.getSignedUrl(getRes.baseUrl, savePathDoc)); outputSfc.setChangeUrl(yield storage.getSignedUrl(getRes.baseUrl, savePathChanges)); } catch (e) { logger.error('Error commandSfcCallback: docId = %s\r\n%s', docId, e.stack); } if (outputSfc.getUrl() && outputSfc.getUsers().length > 0) { if (isSfcm) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.MustSaveForce); } else { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.MustSave); } } else { if (isSfcm) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.CorruptedForce); } else { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.Corrupted); } } } var uri = getRes.server.href; var postData = JSON.stringify(outputSfc); if (isSfcm) { var lastSave = cmd.getLastSave(); if (lastSave && !isError) { yield* docsCoServer.setForceSave(docId, lastSave, savePathDoc); } try { yield* docsCoServer.sendServerRequest(docId, uri, postData); } catch (err) { logger.error('sendServerRequest error: docId = %s;url = %s;data = %s\r\n%s', docId, uri, postData, err.stack); } } else { //if anybody in document stop save var hasEditors = yield* docsCoServer.hasEditors(docId); logger.debug('hasEditors commandSfcCallback: docId = %s hasEditors = %d', docId, hasEditors); if (!hasEditors) { var updateMask = new taskResult.TaskResultData(); updateMask.key = docId; updateMask.status = taskResult.FileStatus.SaveVersion; updateMask.statusInfo = cmd.getData(); var updateIfTask = new taskResult.TaskResultData(); updateIfTask.status = taskResult.FileStatus.UpdateVersion; updateIfTask.statusInfo = constants.NO_ERROR; var updateIfRes = yield taskResult.updateIf(updateIfTask, updateMask); if (updateIfRes.affectedRows > 0) { var isSend = true; try { yield* docsCoServer.sendServerRequest(docId, uri, postData); } catch (err) { isSend = false; logger.error('sendServerRequest error: docId = %s;url = %s;data = %s\r\n%s', docId, uri, postData, err.stack); } if (isSend) { yield* docsCoServer.deleteCallback(docId); } else { var updateTask = new taskResult.TaskResultData(); updateTask.key = docId; updateTask.status = taskResult.FileStatus.Ok; updateTask.statusInfo = constants.NO_ERROR; yield taskResult.update(updateTask); } } } } } logger.debug('End commandSfcCallback: docId = %s', docId); } function* commandSendMMCallback(cmd) { var docId = cmd.getDocId(); logger.debug('Start commandSendMMCallback: docId = %s', docId); var saveKey = cmd.getSaveKey(); var statusInfo = cmd.getStatusInfo(); var outputSfc = new commonDefines.OutputSfcData(); outputSfc.setKey(docId); if (constants.NO_ERROR == statusInfo) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.MailMerge); } else { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.Corrupted); } var mailMergeSendData = cmd.getMailMergeSend(); var outputMailMerge = new commonDefines.OutputMailMerge(mailMergeSendData); outputSfc.setMailMerge(outputMailMerge); outputSfc.setUsers([mailMergeSendData.getUserId()]); var data = yield storage.getObject(saveKey + '/' + cmd.getOutputPath()); var xml = data.toString('utf8'); var files = xml.match(/[< ]file.*?\/>/g); var recordRemain = (mailMergeSendData.getRecordTo() - mailMergeSendData.getRecordFrom() + 1); var recordIndexStart = mailMergeSendData.getRecordCount() - recordRemain; for (var i = 0; i < files.length; ++i) { var file = files[i]; var fieldRes = /field=["'](.*?)["']/.exec(file); outputMailMerge.setTo(fieldRes[1]); outputMailMerge.setRecordIndex(recordIndexStart + i); var pathRes = /path=["'](.*?)["']/.exec(file); var signedUrl = yield storage.getSignedUrl(mailMergeSendData.getBaseUrl(), saveKey + '/' + pathRes[1]); outputSfc.setUrl(signedUrl); var uri = mailMergeSendData.getUrl(); var postData = JSON.stringify(outputSfc); try { yield* docsCoServer.sendServerRequest(docId, uri, postData); } catch (err) { logger.error('sendServerRequest error: docId = %s;url = %s;data = %s\r\n%s', docId, uri, postData, err.stack); } } var newRecordFrom = mailMergeSendData.getRecordFrom() + Math.max(files.length, 1); if (newRecordFrom <= mailMergeSendData.getRecordTo()) { mailMergeSendData.setRecordFrom(newRecordFrom); yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); } else { logger.debug('End MailMerge: docId = %s', docId); } logger.debug('End commandSendMMCallback: docId = %s', docId); } exports.openDocument = function(conn, input) { utils.spawn(function* () { var outputData; var docId = conn ? conn.docId : 'null'; try { var startDate = null; if(clientStatsD) { startDate = new Date(); } var cmd = new commonDefines.InputCommand(input.message); logger.debug('Start command: docId = %s %s', docId, JSON.stringify(cmd)); outputData = new OutputData(cmd.getCommand()); switch (cmd.getCommand()) { case 'open': //yield utils.sleep(5000); yield* commandOpen(conn, cmd, outputData); break; case 'reopen': yield* commandReopen(cmd); break; case 'imgurl': case 'imgurls': yield* commandImgurls(conn, cmd, outputData); break; default: outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); break; } if(clientStatsD) { clientStatsD.timing('coauth.openDocument.' + cmd.getCommand(), new Date() - startDate); } } catch (e) { logger.error('Error openDocument: docId = %s\r\n%s', docId, e.stack); if (!outputData) { outputData = new OutputData(); } outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); } finally { if (outputData && outputData.getStatus()) { logger.debug('Response command: docId = %s %s', docId, JSON.stringify(outputData)); docsCoServer.sendData(conn, new OutputDataWrap('documentOpen', outputData)); } logger.debug('End command: docId = %s', docId); } }); }; exports.downloadAs = function(req, res) { utils.spawn(function* () { var docId = 'null'; try { var startDate = null; if(clientStatsD) { startDate = new Date(); } var strCmd = req.query['cmd']; var cmd = new commonDefines.InputCommand(JSON.parse(strCmd)); docId = cmd.getDocId(); logger.debug('Start downloadAs: docId = %s %s', docId, strCmd); cmd.setData(req.body); var outputData = new OutputData(cmd.getCommand()); switch (cmd.getCommand()) { case 'save': yield* commandSave(cmd, outputData); break; case 'savefromorigin': yield* commandSaveFromOrigin(cmd, outputData); break; case 'sendmm': yield* commandSendMailMerge(cmd, outputData); break; case 'sfct': yield* commandSfct(cmd, outputData); break; default: outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); break; } var strRes = JSON.stringify(outputData); res.send(strRes); logger.debug('End downloadAs: docId = %s %s', docId, strRes); if(clientStatsD) { clientStatsD.timing('coauth.downloadAs.' + cmd.getCommand(), new Date() - startDate); } } catch (e) { logger.error('Error downloadAs: docId = %s\r\n%s', docId, e.stack); res.sendStatus(400); } }); }; exports.saveFromChanges = function(docId, optFormat, opt_userId) { utils.spawn(function* () { try { var startDate = null; if(clientStatsD) { startDate = new Date(); } logger.debug('Start saveFromChanges: docId = %s', docId); if (null == optFormat) { optFormat = constants.AVS_OFFICESTUDIO_FILE_OTHER_TEAMLAB_INNER; } var updateMask = new taskResult.TaskResultData(); updateMask.key = docId; updateMask.status = taskResult.FileStatus.Ok; var updateTask = new taskResult.TaskResultData(); updateTask.status = taskResult.FileStatus.SaveVersion; updateTask.statusInfo = utils.getMillisecondsOfHour(new Date()); var updateIfRes = yield taskResult.updateIf(updateTask, updateMask); if (updateIfRes.affectedRows > 0) { var cmd = new commonDefines.InputCommand(); cmd.setCommand('sfc'); cmd.setDocId(docId); cmd.setOutputFormat(optFormat); cmd.setData(updateTask.statusInfo); cmd.setUserActionId(opt_userId); yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); queueData.setFromChanges(true); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_NORMAL); logger.debug('AddTask saveFromChanges: docId = %s', docId); } if(clientStatsD) { clientStatsD.timing('coauth.saveFromChanges', new Date() - startDate); } } catch (e) { logger.error('Error saveFromChanges: docId = %s\r\n%s', docId, e.stack); } }); }; exports.receiveTask = function(data, dataRaw) { utils.spawn(function* () { var docId = 'null'; try { var task = new commonDefines.TaskQueueData(JSON.parse(data)); if (task) { var cmd = task.getCmd(); docId = cmd.getDocId(); logger.debug('Start receiveTask: docId = %s %s', docId, data); var updateTask = getUpdateResponse(cmd); var updateRes = yield taskResult.update(updateTask); if (updateRes.affectedRows > 0) { var outputData = new OutputData(cmd.getCommand()); var command = cmd.getCommand(); var additionalOutput = {needUrlKey: null, needUrlMethod: null}; if ('open' == command || 'reopen' == command) { //yield utils.sleep(5000); yield* getOutputData(cmd, outputData, cmd.getDocId(), updateTask.status, updateTask.statusInfo, null, additionalOutput); } else if ('save' == command || 'savefromorigin' == command || 'sfct' == command) { yield* getOutputData(cmd, outputData, cmd.getSaveKey(), updateTask.status, updateTask.statusInfo, null, additionalOutput); } else if ('sfcm' == command) { yield* commandSfcCallback(cmd, true); } else if ('sfc' == command) { yield* commandSfcCallback(cmd, false); } else if ('sendmm' == command) { yield* commandSendMMCallback(cmd); } else if ('conv' == command) { //nothing } if (outputData.getStatus()) { logger.debug('Send receiveTask: docId = %s %s', docId, JSON.stringify(outputData)); var output = new OutputDataWrap('documentOpen', outputData); yield* docsCoServer.publish({ type: docsCoServer.PublishType.receiveTask, cmd: cmd, output: output, needUrlKey: additionalOutput.needUrlKey, needUrlMethod: additionalOutput.needUrlMethod }); } } yield* docsCoServer.removeResponse(dataRaw); logger.debug('End receiveTask: docId = %s', docId); } } catch (err) { logger.debug('Error receiveTask: docId = %s\r\n%s', docId, err.stack); } }); }; exports.commandSfctByCmd = commandSfctByCmd; exports.OutputDataWrap = OutputDataWrap; exports.OutputData = OutputData; \ No newline at end of file +var pathModule = require('path'); var urlModule = require('url'); var sqlBase = require('./baseConnector'); var docsCoServer = require('./DocsCoServer'); var taskResult = require('./taskresult'); var logger = require('./../../Common/sources/logger'); var utils = require('./../../Common/sources/utils'); var constants = require('./../../Common/sources/constants'); var commonDefines = require('./../../Common/sources/commondefines'); var storage = require('./../../Common/sources/storage-base'); var formatChecker = require('./../../Common/sources/formatchecker'); var statsDClient = require('./../../Common/sources/statsdclient'); var config = require('config'); var config_server = config.get('services.CoAuthoring.server'); var config_utils = config.get('services.CoAuthoring.utils'); var cfgTypesUpload = config_utils.get('limits_image_types_upload'); var cfgTypesCopy = config_utils.get('limits_image_types_copy'); var cfgImageSize = config_server.get('limits_image_size'); var cfgImageDownloadTimeout = config_server.get('limits_image_download_timeout'); var SAVE_TYPE_PART_START = 0; var SAVE_TYPE_PART = 1; var SAVE_TYPE_COMPLETE = 2; var SAVE_TYPE_COMPLETE_ALL = 3; var clientStatsD = statsDClient.getClient(); function OutputDataWrap(type, data) { this['type'] = type; this['data'] = data; } OutputDataWrap.prototype = { fromObject: function(data) { this['type'] = data['type']; this['data'] = new OutputData(); this['data'].fromObject(data['data']); }, getType: function() { return this['type']; }, setType: function(data) { this['type'] = data; }, getData: function() { return this['data']; }, setData: function(data) { this['data'] = data; } }; function OutputData(type) { this['type'] = type; this['status'] = undefined; this['data'] = undefined; } OutputData.prototype = { fromObject: function(data) { this['type'] = data['type']; this['status'] = data['status']; this['data'] = data['data']; }, getType: function() { return this['type']; }, setType: function(data) { this['type'] = data; }, getStatus: function() { return this['status']; }, setStatus: function(data) { this['status'] = data; }, getData: function() { return this['data']; }, setData: function(data) { this['data'] = data; } }; function* getOutputData(cmd, outputData, key, status, statusInfo, optConn, optAdditionalOutput) { var docId = cmd.getDocId(); switch (status) { case taskResult.FileStatus.SaveVersion: case taskResult.FileStatus.UpdateVersion: case taskResult.FileStatus.Ok: if(taskResult.FileStatus.Ok == status) { outputData.setStatus('ok'); } else if(taskResult.FileStatus.SaveVersion == status) { if (optConn && optConn.user.view) { outputData.setStatus('updateversion'); } else { var updateMask = new taskResult.TaskResultData(); updateMask.key = docId; updateMask.status = status; updateMask.statusInfo = statusInfo; var updateTask = new taskResult.TaskResultData(); updateTask.status = taskResult.FileStatus.Ok; updateTask.statusInfo = constants.NO_ERROR; var updateIfRes = yield taskResult.updateIf(updateTask, updateMask); if (updateIfRes.affectedRows > 0) { outputData.setStatus('ok'); } else { outputData.setStatus('updateversion'); } } } else { outputData.setStatus('updateversion'); } var command = cmd.getCommand(); if ('open' != command && 'reopen' != command) { var strPath = key + '/' + cmd.getOutputPath(); if (optConn) { outputData.setData(yield storage.getSignedUrl(optConn.baseUrl, strPath, null, cmd.getTitle())); } else if (optAdditionalOutput) { optAdditionalOutput.needUrlKey = strPath; optAdditionalOutput.needUrlMethod = 2; } } else { if (optConn) { outputData.setData(yield storage.getSignedUrls(optConn.baseUrl, key)); } else if (optAdditionalOutput) { optAdditionalOutput.needUrlKey = key; optAdditionalOutput.needUrlMethod = 0; } } break; case taskResult.FileStatus.NeedParams: outputData.setStatus('needparams'); var settingsPath = key + '/' + 'settings.json'; if (optConn) { outputData.setData(yield storage.getSignedUrl(optConn.baseUrl, settingsPath)); } else if (optAdditionalOutput) { optAdditionalOutput.needUrlKey = settingsPath; optAdditionalOutput.needUrlMethod = 1; } break; case taskResult.FileStatus.Err: case taskResult.FileStatus.ErrToReload: outputData.setStatus('err'); outputData.setData(statusInfo); if (taskResult.FileStatus.ErrToReload == status) { yield taskResult.remove(key); } break; } } function* addRandomKeyTaskCmd(cmd) { var task = yield* taskResult.addRandomKeyTask(cmd.getDocId()); cmd.setSaveKey(task.key); } function* saveParts(cmd) { var result = false; var saveType = cmd.getSaveType(); var filename; if (SAVE_TYPE_COMPLETE_ALL === saveType) { filename = 'Editor.bin'; } else { filename = 'Editor' + (cmd.getSaveIndex() || '') + '.bin'; } if (SAVE_TYPE_PART_START === saveType || SAVE_TYPE_COMPLETE_ALL === saveType) { yield* addRandomKeyTaskCmd(cmd); } if (cmd.getUrl()) { result = true; } else { var buffer = cmd.getData(); yield storage.putObject(cmd.getSaveKey() + '/' + filename, buffer, buffer.length); //delete data to prevent serialize into json cmd.data = null; result = (SAVE_TYPE_COMPLETE_ALL === saveType || SAVE_TYPE_COMPLETE === saveType); } return result; } function getSaveTask(cmd) { cmd.setData(null); var queueData = new commonDefines.TaskQueueData(); queueData.setCmd(cmd); queueData.setToFile(constants.OUTPUT_NAME + '.' + formatChecker.getStringFromFormat(cmd.getOutputFormat())); //todo paid //if (cmd.vkey) { // bool // bPaid; // Signature.getVKeyParams(cmd.vkey, out bPaid); // oTaskQueueData.m_bPaid = bPaid; //} return queueData; } function getUpdateResponse(cmd) { var updateTask = new taskResult.TaskResultData(); updateTask.key = cmd.getSaveKey() ? cmd.getSaveKey() : cmd.getDocId(); var statusInfo = cmd.getStatusInfo(); if (constants.NO_ERROR == statusInfo) { updateTask.status = taskResult.FileStatus.Ok; } else if (constants.CONVERT_DOWNLOAD == statusInfo) { updateTask.status = taskResult.FileStatus.ErrToReload; } else if (constants.CONVERT_NEED_PARAMS == statusInfo) { updateTask.status = taskResult.FileStatus.NeedParams; } else { updateTask.status = taskResult.FileStatus.Err; } updateTask.statusInfo = statusInfo; if (cmd.getTitle()) { updateTask.title = cmd.getTitle(); } return updateTask; } function* commandOpen(conn, cmd, outputData) { var task = new taskResult.TaskResultData(); task.key = cmd.getDocId(); task.format = cmd.getFormat(); task.status = taskResult.FileStatus.WaitQueue; task.statusInfo = constants.NO_ERROR; task.title = cmd.getTitle(); var upsertRes = yield taskResult.upsert(task); //if CLIENT_FOUND_ROWS don't specify 1 row is inserted , 2 row is updated, and 0 row is set to its current values //http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html var bCreate = upsertRes.affectedRows == 1; if (!bCreate) { var selectRes = yield taskResult.select(task); if (selectRes.length > 0) { var row = selectRes[0]; yield* getOutputData(cmd, outputData, cmd.getDocId(), row.tr_status, row.tr_status_info, conn); } } else { //add task cmd.setOutputFormat(constants.AVS_OFFICESTUDIO_FILE_CANVAS); cmd.setEmbeddedFonts(false); var dataQueue = new commonDefines.TaskQueueData(); dataQueue.setCmd(cmd); dataQueue.setToFile('Editor.bin'); yield* docsCoServer.addTask(dataQueue, constants.QUEUE_PRIORITY_HIGH); } } function* commandReopen(cmd) { var task = new taskResult.TaskResultData(); task.key = cmd.getDocId(); task.status = taskResult.FileStatus.WaitQueue; task.statusInfo = constants.NO_ERROR; var upsertRes = yield taskResult.update(task); if (upsertRes.affectedRows > 0) { //add task cmd.setUrl(null);//url may expire cmd.setSaveKey(cmd.getDocId()); cmd.setOutputFormat(constants.AVS_OFFICESTUDIO_FILE_CANVAS); cmd.setEmbeddedFonts(false); var dataQueue = new commonDefines.TaskQueueData(); dataQueue.setCmd(cmd); dataQueue.setToFile('Editor.bin'); dataQueue.setFromSettings(true); yield* docsCoServer.addTask(dataQueue, constants.QUEUE_PRIORITY_HIGH); } } function* commandSave(cmd, outputData) { var completeParts = yield* saveParts(cmd); if (completeParts) { var queueData = getSaveTask(cmd); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); } outputData.setStatus('ok'); outputData.setData(cmd.getSaveKey()); } function* commandSendMailMerge(cmd, outputData) { var completeParts = yield* saveParts(cmd); var isErr = false; if (completeParts) { isErr = true; var getRes = yield* docsCoServer.getCallback(cmd.getDocId()); if (getRes) { var mailMergeSend = cmd.getMailMergeSend(); mailMergeSend.setUrl(getRes.server.href); mailMergeSend.setBaseUrl(getRes.baseUrl); //меняем JsonKey и SaveKey, новый key нужет потому что за одну конвертацию делается часть, а json нужен всегда mailMergeSend.setJsonKey(cmd.getSaveKey()); yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); isErr = false; } } if (isErr) { outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); } else { outputData.setStatus('ok'); outputData.setData(cmd.getSaveKey()); } } function* commandSfctByCmd(cmd) { yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); queueData.setFromChanges(true); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); } function* commandSfct(cmd, outputData) { yield* commandSfctByCmd(cmd); outputData.setStatus('ok'); } function isDisplayedImage(strName) { var res = 0; if (strName) { //шаблон display[N]image.ext var findStr = constants.DISPLAY_PREFIX; var index = strName.indexOf(findStr); if (-1 != index) { if (index + findStr.length < strName.length) { var displayN = parseInt(strName[index + findStr.length]); if (1 <= displayN && displayN <= 6) { var imageIndex = index + findStr.length + 1; if (imageIndex == strName.indexOf("image", imageIndex)) res = displayN; } } } } return res; } function* commandImgurls(conn, cmd, outputData) { var supportedFormats; var urls; var errorCode = constants.NO_ERROR; var isImgUrl = 'imgurl' == cmd.getCommand(); if (isImgUrl) { urls = [cmd.getData()]; supportedFormats = cfgTypesUpload || 'jpg'; } else { urls = cmd.getData(); supportedFormats = cfgTypesCopy || 'jpg'; } //todo Promise.all() var displayedImageMap = {};//to make one imageIndex for ole object urls var imageCount = 0; var outputUrls = []; for (var i = 0; i < urls.length; ++i) { var urlSource = urls[i]; var urlParsed; var data = undefined; if (urlSource.startsWith('data:')) { var delimiterIndex = urlSource.indexOf(','); if (-1 != delimiterIndex && (urlSource.length - (delimiterIndex + 1)) * 0.75 <= cfgImageSize) { data = new Buffer(urlSource.substring(delimiterIndex + 1), 'base64'); } } else if(urlSource) { //todo stream data = yield utils.downloadUrlPromise(urlSource, cfgImageDownloadTimeout * 1000, cfgImageSize); urlParsed = urlModule.parse(urlSource); } var outputUrl = {url: 'error', path: 'error'}; if (data) { var format = formatChecker.getImageFormat(data); var formatStr; if (constants.AVS_OFFICESTUDIO_FILE_UNKNOWN == format && urlParsed) { //bin, txt occur in ole object case var ext = pathModule.extname(urlParsed.pathname); if ('.bin' == ext || '.txt' == ext) { formatStr = ext.substring(1); } } else { formatStr = formatChecker.getStringFromFormat(format); } if (formatStr && -1 !== supportedFormats.indexOf(formatStr)) { var userid = cmd.getUserId(); var imageIndex = cmd.getSaveIndex() + imageCount; imageCount++; var strLocalPath = 'media/' + utils.crc32(userid).toString(16) + '_'; if (urlParsed) { var urlBasename = pathModule.basename(urlParsed.pathname); var displayN = isDisplayedImage(urlBasename); if (displayN > 0) { var displayedImageName = urlBasename.substring(0, urlBasename.length - formatStr.length - 1); var tempIndex = displayedImageMap[displayedImageName]; if (null != tempIndex) { imageIndex = tempIndex; imageCount--; } else { displayedImageMap[displayedImageName] = imageIndex; } strLocalPath += constants.DISPLAY_PREFIX + displayN; } } strLocalPath += 'image' + imageIndex + '.' + formatStr; var strPath = cmd.getDocId() + '/' + strLocalPath; yield storage.putObject(strPath, data, data.length); var imgUrl = yield storage.getSignedUrl(conn.baseUrl, strPath); outputUrl = {url: imgUrl, path: strLocalPath}; } } if (isImgUrl && ('error' === outputUrl.url || 'error' === outputUrl.path)) { errorCode = constants.UPLOAD_EXTENSION; break; } outputUrls.push(outputUrl); } if (constants.NO_ERROR !== errorCode) { outputData.setStatus('err'); outputData.setData(errorCode); } else { outputData.setStatus('ok'); outputData.setData(outputUrls); } } function* commandSaveFromOrigin(cmd, outputData) { yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); queueData.setFromOrigin(true); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); outputData.setStatus('ok'); outputData.setData(cmd.getSaveKey()); } function* commandSfcCallback(cmd, isSfcm) { 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 && 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); if (getRes) { logger.debug('Callback commandSfcCallback: docId = %s callback = %s', docId, getRes.server.href); var outputSfc = new commonDefines.OutputSfcData(); outputSfc.setKey(docId); if (cmd.getUserId()) { outputSfc.setUsers([cmd.getUserId()]); } //use UserId case UserActionId miss in gc convertion var userActionId = cmd.getUserActionId() || cmd.getUserId(); if (userActionId) { outputSfc.setActions([new commonDefines.OutputAction(commonDefines.c_oAscUserAction.Out, userActionId)]); } if (isError) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.Corrupted); } else { try { var data = yield storage.getObject(savePathHistory); outputSfc.setChangeHistory(data.toString('utf-8')); outputSfc.setUrl(yield storage.getSignedUrl(getRes.baseUrl, savePathDoc)); outputSfc.setChangeUrl(yield storage.getSignedUrl(getRes.baseUrl, savePathChanges)); } catch (e) { logger.error('Error commandSfcCallback: docId = %s\r\n%s', docId, e.stack); } if (outputSfc.getUrl() && outputSfc.getUsers().length > 0) { if (isSfcm) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.MustSaveForce); } else { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.MustSave); } } else { if (isSfcm) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.CorruptedForce); } else { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.Corrupted); } } } var uri = getRes.server.href; var postData = JSON.stringify(outputSfc); if (isSfcm) { var lastSave = cmd.getLastSave(); if (lastSave && !isError) { yield* docsCoServer.setForceSave(docId, lastSave, savePathDoc); } try { yield* docsCoServer.sendServerRequest(docId, uri, postData); } catch (err) { logger.error('sendServerRequest error: docId = %s;url = %s;data = %s\r\n%s', docId, uri, postData, err.stack); } } else { //if anybody in document stop save var hasEditors = yield* docsCoServer.hasEditors(docId); logger.debug('hasEditors commandSfcCallback: docId = %s hasEditors = %d', docId, hasEditors); if (!hasEditors) { var updateMask = new taskResult.TaskResultData(); updateMask.key = docId; updateMask.status = taskResult.FileStatus.SaveVersion; updateMask.statusInfo = cmd.getData(); var updateIfTask = new taskResult.TaskResultData(); updateIfTask.status = taskResult.FileStatus.UpdateVersion; updateIfTask.statusInfo = constants.NO_ERROR; var updateIfRes = yield taskResult.updateIf(updateIfTask, updateMask); if (updateIfRes.affectedRows > 0) { var replyStr = null; try { replyStr = yield* docsCoServer.sendServerRequest(docId, uri, postData); } catch (err) { replyStr = null; logger.error('sendServerRequest error: docId = %s;url = %s;data = %s\r\n%s', docId, uri, postData, err.stack); } var replyData = docsCoServer.parseReplyData(docId, replyStr); if (replyData && commonDefines.c_oAscServerCommandErrors.NoError == replyData.error) { yield* docsCoServer.cleanDocumentOnExit(docId, true, true); } else { var updateTask = new taskResult.TaskResultData(); updateTask.key = docId; updateTask.status = taskResult.FileStatus.Ok; updateTask.statusInfo = constants.NO_ERROR; yield taskResult.update(updateTask); } } } } } logger.debug('End commandSfcCallback: docId = %s', docId); } function* commandSendMMCallback(cmd) { var docId = cmd.getDocId(); logger.debug('Start commandSendMMCallback: docId = %s', docId); var saveKey = cmd.getSaveKey(); var statusInfo = cmd.getStatusInfo(); var outputSfc = new commonDefines.OutputSfcData(); outputSfc.setKey(docId); if (constants.NO_ERROR == statusInfo) { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.MailMerge); } else { outputSfc.setStatus(docsCoServer.c_oAscServerStatus.Corrupted); } var mailMergeSendData = cmd.getMailMergeSend(); var outputMailMerge = new commonDefines.OutputMailMerge(mailMergeSendData); outputSfc.setMailMerge(outputMailMerge); outputSfc.setUsers([mailMergeSendData.getUserId()]); var data = yield storage.getObject(saveKey + '/' + cmd.getOutputPath()); var xml = data.toString('utf8'); var files = xml.match(/[< ]file.*?\/>/g); var recordRemain = (mailMergeSendData.getRecordTo() - mailMergeSendData.getRecordFrom() + 1); var recordIndexStart = mailMergeSendData.getRecordCount() - recordRemain; for (var i = 0; i < files.length; ++i) { var file = files[i]; var fieldRes = /field=["'](.*?)["']/.exec(file); outputMailMerge.setTo(fieldRes[1]); outputMailMerge.setRecordIndex(recordIndexStart + i); var pathRes = /path=["'](.*?)["']/.exec(file); var signedUrl = yield storage.getSignedUrl(mailMergeSendData.getBaseUrl(), saveKey + '/' + pathRes[1]); outputSfc.setUrl(signedUrl); var uri = mailMergeSendData.getUrl(); var postData = JSON.stringify(outputSfc); try { yield* docsCoServer.sendServerRequest(docId, uri, postData); } catch (err) { logger.error('sendServerRequest error: docId = %s;url = %s;data = %s\r\n%s', docId, uri, postData, err.stack); } } var newRecordFrom = mailMergeSendData.getRecordFrom() + Math.max(files.length, 1); if (newRecordFrom <= mailMergeSendData.getRecordTo()) { mailMergeSendData.setRecordFrom(newRecordFrom); yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_LOW); } else { logger.debug('End MailMerge: docId = %s', docId); } logger.debug('End commandSendMMCallback: docId = %s', docId); } exports.openDocument = function(conn, input) { utils.spawn(function* () { var outputData; var docId = conn ? conn.docId : 'null'; try { var startDate = null; if(clientStatsD) { startDate = new Date(); } var cmd = new commonDefines.InputCommand(input.message); logger.debug('Start command: docId = %s %s', docId, JSON.stringify(cmd)); outputData = new OutputData(cmd.getCommand()); switch (cmd.getCommand()) { case 'open': //yield utils.sleep(5000); yield* commandOpen(conn, cmd, outputData); break; case 'reopen': yield* commandReopen(cmd); break; case 'imgurl': case 'imgurls': yield* commandImgurls(conn, cmd, outputData); break; default: outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); break; } if(clientStatsD) { clientStatsD.timing('coauth.openDocument.' + cmd.getCommand(), new Date() - startDate); } } catch (e) { logger.error('Error openDocument: docId = %s\r\n%s', docId, e.stack); if (!outputData) { outputData = new OutputData(); } outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); } finally { if (outputData && outputData.getStatus()) { logger.debug('Response command: docId = %s %s', docId, JSON.stringify(outputData)); docsCoServer.sendData(conn, new OutputDataWrap('documentOpen', outputData)); } logger.debug('End command: docId = %s', docId); } }); }; exports.downloadAs = function(req, res) { utils.spawn(function* () { var docId = 'null'; try { var startDate = null; if(clientStatsD) { startDate = new Date(); } var strCmd = req.query['cmd']; var cmd = new commonDefines.InputCommand(JSON.parse(strCmd)); docId = cmd.getDocId(); logger.debug('Start downloadAs: docId = %s %s', docId, strCmd); cmd.setData(req.body); var outputData = new OutputData(cmd.getCommand()); switch (cmd.getCommand()) { case 'save': yield* commandSave(cmd, outputData); break; case 'savefromorigin': yield* commandSaveFromOrigin(cmd, outputData); break; case 'sendmm': yield* commandSendMailMerge(cmd, outputData); break; case 'sfct': yield* commandSfct(cmd, outputData); break; default: outputData.setStatus('err'); outputData.setData(constants.UNKNOWN); break; } var strRes = JSON.stringify(outputData); res.send(strRes); logger.debug('End downloadAs: docId = %s %s', docId, strRes); if(clientStatsD) { clientStatsD.timing('coauth.downloadAs.' + cmd.getCommand(), new Date() - startDate); } } catch (e) { logger.error('Error downloadAs: docId = %s\r\n%s', docId, e.stack); res.sendStatus(400); } }); }; exports.saveFromChanges = function(docId, optFormat, opt_userId) { utils.spawn(function* () { try { var startDate = null; if(clientStatsD) { startDate = new Date(); } logger.debug('Start saveFromChanges: docId = %s', docId); if (null == optFormat) { optFormat = constants.AVS_OFFICESTUDIO_FILE_OTHER_TEAMLAB_INNER; } var updateMask = new taskResult.TaskResultData(); updateMask.key = docId; updateMask.status = taskResult.FileStatus.Ok; var updateTask = new taskResult.TaskResultData(); updateTask.status = taskResult.FileStatus.SaveVersion; updateTask.statusInfo = utils.getMillisecondsOfHour(new Date()); var updateIfRes = yield taskResult.updateIf(updateTask, updateMask); if (updateIfRes.affectedRows > 0) { var cmd = new commonDefines.InputCommand(); cmd.setCommand('sfc'); cmd.setDocId(docId); cmd.setOutputFormat(optFormat); cmd.setData(updateTask.statusInfo); cmd.setUserActionId(opt_userId); yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); queueData.setFromChanges(true); yield* docsCoServer.addTask(queueData, constants.QUEUE_PRIORITY_NORMAL); logger.debug('AddTask saveFromChanges: docId = %s', docId); } if(clientStatsD) { clientStatsD.timing('coauth.saveFromChanges', new Date() - startDate); } } catch (e) { logger.error('Error saveFromChanges: docId = %s\r\n%s', docId, e.stack); } }); }; exports.receiveTask = function(data, dataRaw) { utils.spawn(function* () { var docId = 'null'; try { var task = new commonDefines.TaskQueueData(JSON.parse(data)); if (task) { var cmd = task.getCmd(); docId = cmd.getDocId(); logger.debug('Start receiveTask: docId = %s %s', docId, data); var updateTask = getUpdateResponse(cmd); var updateRes = yield taskResult.update(updateTask); if (updateRes.affectedRows > 0) { var outputData = new OutputData(cmd.getCommand()); var command = cmd.getCommand(); var additionalOutput = {needUrlKey: null, needUrlMethod: null}; if ('open' == command || 'reopen' == command) { //yield utils.sleep(5000); yield* getOutputData(cmd, outputData, cmd.getDocId(), updateTask.status, updateTask.statusInfo, null, additionalOutput); } else if ('save' == command || 'savefromorigin' == command || 'sfct' == command) { yield* getOutputData(cmd, outputData, cmd.getSaveKey(), updateTask.status, updateTask.statusInfo, null, additionalOutput); } else if ('sfcm' == command) { yield* commandSfcCallback(cmd, true); } else if ('sfc' == command) { yield* commandSfcCallback(cmd, false); } else if ('sendmm' == command) { yield* commandSendMMCallback(cmd); } else if ('conv' == command) { //nothing } if (outputData.getStatus()) { logger.debug('Send receiveTask: docId = %s %s', docId, JSON.stringify(outputData)); var output = new OutputDataWrap('documentOpen', outputData); yield* docsCoServer.publish({ type: docsCoServer.PublishType.receiveTask, cmd: cmd, output: output, needUrlKey: additionalOutput.needUrlKey, needUrlMethod: additionalOutput.needUrlMethod }); } } yield* docsCoServer.removeResponse(dataRaw); logger.debug('End receiveTask: docId = %s', docId); } } catch (err) { logger.debug('Error receiveTask: docId = %s\r\n%s', docId, err.stack); } }); }; exports.commandSfctByCmd = commandSfctByCmd; exports.OutputDataWrap = OutputDataWrap; exports.OutputData = OutputData; \ No newline at end of file