loleaflet/src/core/Socket.js | 30 ++++++++++++++++++++++++++++++ wsd/ClientSession.cpp | 7 +++++++ wsd/DocumentBroker.cpp | 8 +++++--- wsd/DocumentBroker.hpp | 6 ++++++ wsd/Storage.cpp | 10 +++++++--- wsd/Storage.hpp | 8 +++++++- wsd/protocol.txt | 4 ++++ 7 files changed, 66 insertions(+), 7 deletions(-)
New commits: commit 8f02d4b49d699d37ff979b2cb553564d8f11358b Author: Pranav Kant <pran...@collabora.co.uk> Date: Thu Jun 1 18:26:54 2017 +0530 If user commands, refresh the document for all in case of doc conflict Change-Id: I42c61fb8099b0bcc60f942e602561cc97486a918 (cherry picked from commit 4d61cae4c8b6ecc7890fb0426c9600e1cf77bbdb) Reviewed-on: https://gerrit.libreoffice.org/38529 Reviewed-by: Jan Holesovsky <ke...@collabora.com> Tested-by: Jan Holesovsky <ke...@collabora.com> diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index 894725aa..17d73b04 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -269,6 +269,21 @@ L.Socket = L.Class.extend({ } }, timeoutMs); } + else if (textMsg.startsWith('documentconflict')) { + var username = textMsg.substring('documentconflict '.length); + msg = _('%user asked to refresh the document. Document will now refresh automatically.').replace('%user', username); + + // Reload the document + this._map._active = false; + map = this._map; + vex.timer = setInterval(function() { + try { + // Activate and cancel timer and dialogs. + map._activate(); + } catch (error) { + } + }, 3000); + } // Close any open dialogs first. if (vex.dialogID > 0) { @@ -346,6 +361,21 @@ L.Socket = L.Class.extend({ else if (command.errorKind === 'documentconflict') { storageError = errorMessages.storage.documentconflict; + vex.dialog.confirm({ + message: _('Document has been changed in storage. Do you want to refresh the page to load the new document ? Cancelling will continue editing and overwrite.'), + callback: L.bind(function(value) { + if (value) { + // They want to refresh the page and load document again for all + this.sendMessage('closedocument'); + } else { + // They want to overwrite + this.sendMessage('documentconflict.overwrite'); + } + }, this) + }); + vex.dialogID = vex.globalID - 1; + + return; } // Parse the storage url as link diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp index 7c22b04d..84558297 100644 --- a/wsd/ClientSession.cpp +++ b/wsd/ClientSession.cpp @@ -171,6 +171,13 @@ bool ClientSession::_handleInput(const char *buffer, int length) LOG_DBG("Session [" << getId() << "] requested owner termination"); docBroker->closeDocument("ownertermination"); } + else if (docBroker->isDocumentChangedInStorage()) + { + LOG_DBG("Document marked as changed in storage and user [" + << getUserId() << ", " << getUserName() + << "] wants to refresh the document for all."); + docBroker->closeDocument("documentconflict " + getUserName()); + } return true; } diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 2157e191..2dc938ac 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -145,6 +145,7 @@ DocumentBroker::DocumentBroker(const std::string& uri, _docId(Util::encodeId(DocBrokerId++, 3)), _childRoot(childRoot), _cacheRoot(getCachePath(uriPublic.toString())), + _documentChangedInStorage(false), _lastSaveTime(std::chrono::steady_clock::now()), _lastSaveRequestTime(std::chrono::steady_clock::now() - std::chrono::milliseconds(COMMAND_TIMEOUT_MS)), _markToDestroy(false), @@ -493,6 +494,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s _documentLastModifiedTime != fileInfo._modifiedTime) { LOG_WRN("Document [" << _docKey << "] has been modified behind our back. Informing all clients."); + _documentChangedInStorage = true; // Inform all clients for (const auto& sessionIt : _sessions) { @@ -651,7 +653,7 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId, else if (storageSaveResult == StorageBase::SaveResult::DOC_CHANGED) { LOG_ERR("PutFile says that Document changed in storage"); - + _documentChangedInStorage = true; // Inform all clients for (const auto& sessionIt : _sessions) { @@ -1332,7 +1334,7 @@ bool DocumentBroker::forwardToClient(const std::shared_ptr<Message>& payload) void DocumentBroker::shutdownClients(const std::string& closeReason) { assertCorrectThread(); - LOG_INF("Terminating " << _sessions.size() << " clients of doc [" << _docKey << "]."); + LOG_INF("Terminating " << _sessions.size() << " clients of doc [" << _docKey << "] with reason: " << closeReason); // First copy into local container, since removeSession // will erase from _sessions, but will leave the last. @@ -1374,7 +1376,7 @@ void DocumentBroker::terminateChild(const std::string& closeReason, const bool r { assertCorrectThread(); - LOG_INF("Terminating doc [" << _docKey << "]."); + LOG_INF("Terminating doc [" << _docKey << "] with reason: " << closeReason); // Close all running sessions if (!rude) diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp index 23b699e4..5b9b1730 100644 --- a/wsd/DocumentBroker.hpp +++ b/wsd/DocumentBroker.hpp @@ -237,6 +237,8 @@ public: bool isLoaded() const { return _isLoaded; } void setLoaded(); + bool isDocumentChangedInStorage() { return _documentChangedInStorage; } + /// Save the document to Storage if it needs persisting. bool saveToStorage(const std::string& sesionId, bool success, const std::string& result = ""); bool isModified() const { return _isModified; } @@ -377,6 +379,10 @@ private: std::string _jailId; std::string _filename; + /// Set to true when document changed in storage and we are waiting + /// for user's command to act. + bool _documentChangedInStorage; + /// The last time we tried saving, regardless of whether the /// document was modified and saved or not. std::chrono::steady_clock::time_point _lastSaveTime; diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp index aee09ae9..f98769c8 100644 --- a/wsd/Storage.cpp +++ b/wsd/Storage.cpp @@ -668,9 +668,13 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const std::string& a Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, uriObject.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); request.set("X-WOPI-Override", "PUT"); - request.set("X-LOOL-WOPI-Timestamp", - Poco::DateTimeFormatter::format(Poco::DateTime(_fileInfo._modifiedTime), - Poco::DateTimeFormat::ISO8601_FRAC_FORMAT)); + if (!_forceOverwrite) + { + // Request WOPI host to not overwrite if timestamps mismatch + request.set("X-LOOL-WOPI-Timestamp", + Poco::DateTimeFormatter::format(Poco::DateTime(_fileInfo._modifiedTime), + Poco::DateTimeFormat::ISO8601_FRAC_FORMAT)); + } request.setContentType("application/octet-stream"); request.setContentLength(size); addStorageDebugCookie(request); diff --git a/wsd/Storage.hpp b/wsd/Storage.hpp index dc29685b..5310ea8e 100644 --- a/wsd/Storage.hpp +++ b/wsd/Storage.hpp @@ -77,7 +77,8 @@ public: _localStorePath(localStorePath), _jailPath(jailPath), _fileInfo("", "lool", Poco::Timestamp::fromEpochTime(0), 0), - _isLoaded(false) + _isLoaded(false), + _forceOverwrite(false) { LOG_DBG("Storage ctor: " << uri.toString()); } @@ -89,6 +90,10 @@ public: bool isLoaded() const { return _isLoaded; } + /// Asks the storage object to force overwrite to storage upon next save + /// even if document turned out to be changed in storage + void forceOverwrite() { _forceOverwrite = true; } + /// Returns the basic information about the file. const FileInfo& getFileInfo() const { return _fileInfo; } @@ -122,6 +127,7 @@ protected: std::string _jailedFilePath; FileInfo _fileInfo; bool _isLoaded; + bool _forceOverwrite; static bool FilesystemEnabled; static bool WopiEnabled; diff --git a/wsd/protocol.txt b/wsd/protocol.txt index d1de4ab3..8b5ea409 100644 --- a/wsd/protocol.txt +++ b/wsd/protocol.txt @@ -269,6 +269,10 @@ close: <reason> shutting down to let clients know they can try connecting after a short interval. + * documentconflict <user name> - All sessions of this document are going down + because file was changed in storage and one of the user ( with <user + name>) asked to reload the session for all. + getchildid: id=<id> Returns the child id _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits