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

Reply via email to