[Libreoffice-commits] online.git: ios/Mobile wsd/DocumentBroker.cpp

Tor Lillqvist (via logerrit) logerrit at kemper.freedesktop.org
Tue Apr 7 22:01:51 UTC 2020


 ios/Mobile/CODocument.h              |    1 
 ios/Mobile/CODocument.mm             |   20 +++++++++----------
 ios/Mobile/DocumentViewController.mm |   36 +++++++++++++++++++----------------
 wsd/DocumentBroker.cpp               |    8 +++----
 4 files changed, 35 insertions(+), 30 deletions(-)

New commits:
commit 0930286e2d8fd2ba1e4820758246ee3766040254
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Tue Apr 7 21:21:55 2020 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Wed Apr 8 00:01:30 2020 +0200

    Fix problems after my 293f4913d2cdfe5385e2cdc0e3bebde281da1578
    
    It is enough to call the -[UIDocument
    saveToURL:forSaveOperation:completionHandler:] only in
    DocumentBroker::sendUnoSave(). And on the other hand, in
    -[DocumentViewController bye] we can't want for the
    LOOLWSD::lokit_main_mutex as the main queue is needed for parts of
    what the saveToURL does.
    
    Also, use a separate copy of the document as the file that is actually
    edited by LO core. This matches what the Android app does. I think it
    is useful to do this in order to avoid some hangs that I noticed. They
    probably were caused by both LO core and the system frameworks
    occasionally accessing the same document file at the same time.
    
    Change-Id: Idb65be23a7cb6ad1288fbbd23c7471e0fb8d52f4
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/91851
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Tor Lillqvist <tml at collabora.com>

diff --git a/ios/Mobile/CODocument.h b/ios/Mobile/CODocument.h
index 82e2e80e3..79f772a1b 100644
--- a/ios/Mobile/CODocument.h
+++ b/ios/Mobile/CODocument.h
@@ -18,6 +18,7 @@
 @interface CODocument : UIDocument {
 @public
     int fakeClientFd;
+    NSURL *copyFileURL;
 }
 
 @property (weak) DocumentViewController *viewController;
diff --git a/ios/Mobile/CODocument.mm b/ios/Mobile/CODocument.mm
index 095d449ea..5dcd9b136 100644
--- a/ios/Mobile/CODocument.mm
+++ b/ios/Mobile/CODocument.mm
@@ -37,14 +37,7 @@
 @implementation CODocument
 
 - (id)contentsForType:(NSString*)typeName error:(NSError **)errorPtr {
-    // Somehow this doesn't feel right, creating an NSFileWrapper around the file that was given to
-    // us for loadFromContents. I get the vague feeling that the file is perhaps just a temporary
-    // data container created by the system for us to be used while loading the document data, and
-    // not the actual permanent document, especially in the case of things like NextCloud. Or is it?
-    // Is saving back to the file (which we have already saved to in the core code by the time we
-    // get here) correct? This does seem to work, though. Sadly the Apple documentation is a bit
-    // lacking about how these things *really* work.
-    return [[NSFileWrapper alloc] initWithURL:[self fileURL] options:0 error:errorPtr];
+    return [NSData dataWithContentsOfFile:[copyFileURL path] options:0 error:errorPtr];
 }
 
 - (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)errorPtr {
@@ -55,11 +48,18 @@
         return YES;
 
     fakeClientFd = fakeSocketSocket();
-    NSString *uri = [[self fileURL] absoluteString];
+
+    copyFileURL = [[[NSFileManager defaultManager] temporaryDirectory] URLByAppendingPathComponent:[[[self fileURL] path] lastPathComponent]];
+
+    NSError *error;
+    [[NSFileManager defaultManager] removeItemAtURL:copyFileURL error:nil];
+    [[NSFileManager defaultManager] copyItemAtURL:[self fileURL] toURL:copyFileURL error:&error];
+    if (error != nil)
+        return NO;
 
     NSURL *url = [[NSBundle mainBundle] URLForResource:@"loleaflet" withExtension:@"html"];
     NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
-    components.queryItems = @[ [NSURLQueryItem queryItemWithName:@"file_path" value:uri],
+    components.queryItems = @[ [NSURLQueryItem queryItemWithName:@"file_path" value:[copyFileURL absoluteString]],
                                [NSURLQueryItem queryItemWithName:@"closebutton" value:@"1"],
                                [NSURLQueryItem queryItemWithName:@"permission" value:@"edit"],
                                [NSURLQueryItem queryItemWithName:@"lang" value:app_locale]
diff --git a/ios/Mobile/DocumentViewController.mm b/ios/Mobile/DocumentViewController.mm
index 94dbd839c..97ac7ab96 100644
--- a/ios/Mobile/DocumentViewController.mm
+++ b/ios/Mobile/DocumentViewController.mm
@@ -348,7 +348,7 @@ static IMP standardImpOfInputAccessoryView = nil;
 
             // First we simply send it the URL. This corresponds to the GET request with Upgrade to
             // WebSocket.
-            std::string url([[[self.document fileURL] absoluteString] UTF8String]);
+            std::string url([[self.document->copyFileURL absoluteString] UTF8String]);
             p.fd = self.document->fakeClientFd;
             p.events = POLLOUT;
             fakeSocketPoll(&p, 1, -1);
@@ -469,21 +469,25 @@ static IMP standardImpOfInputAccessoryView = nil;
     // Close one end of the socket pair, that will wake up the forwarding thread above
     fakeSocketClose(closeNotificationPipeForForwardingThread[0]);
 
-    // I suspect that what this will do (in -[CODocument contentsForType:error:]) is to read the
-    // contents of the file that LO core already saved, and overwrite it with the same contents.
-    [self.document saveToURL:[self.document fileURL]
-            forSaveOperation:UIDocumentSaveForOverwriting
-           completionHandler:^(BOOL success) {
-              LOG_TRC("save completion handler gets " << (success?"YES":"NO"));
-           }];
-
-    // Wait for lokit_main thread to exit
-    std::lock_guard<std::mutex> lock(LOOLWSD::lokit_main_mutex);
-
-    theSingleton = nil;
-
-    // And only then let the document browsing view show up again
-    [self dismissDocumentViewController];
+    // We can't wait for the LOOLWSD::lokit_main_mutex directly here because this is called on the
+    // main queue and the main queue must be ready to execute code dispatched by the system APIs
+    // used to do document saving.
+    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+                   ^{
+                       // Wait for lokit_main thread to exit
+                       std::lock_guard<std::mutex> lock(LOOLWSD::lokit_main_mutex);
+
+                       theSingleton = nil;
+
+                       [[NSFileManager defaultManager] removeItemAtURL:self.document->copyFileURL error:nil];
+
+                       // And only then let the document browsing view show up again. The
+                       // dismissViewControllerAnimated must be done on the main queue.
+                       dispatch_async(dispatch_get_main_queue(),
+                                      ^{
+                                          [self dismissDocumentViewController];
+                                      });
+                   });
 }
 
 + (DocumentViewController*)singleton {
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 0d5ce909d..4287624e9 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1289,14 +1289,14 @@ bool DocumentBroker::sendUnoSave(const std::string& sessionId, bool dontTerminat
         forwardToChild(sessionId, command);
         _lastSaveRequestTime = std::chrono::steady_clock::now();
 #ifdef IOS
-        // We need to do this so that file provider extensions notice. Just like in
-        // -[DocumentViewController bye] I suspect that will read the file and then overwrite it
-        // with the same contents, but oh well.
+        // We need to do this here, also for auto-save, so that file provider extensions notice.
+
         CODocument *document = [[DocumentViewController singleton] document];
+
         [document saveToURL:[[[DocumentViewController singleton] document] fileURL]
            forSaveOperation:UIDocumentSaveForOverwriting
           completionHandler:^(BOOL success) {
-                LOG_TRC("save completion handler gets " << (success?"YES":"NO"));
+                LOG_TRC("DocumentBroker::sendUnoSave() save completion handler gets " << (success?"YES":"NO"));
             }];
 #endif
         return true;


More information about the Libreoffice-commits mailing list