/// <summary>
        /// Uploads byte[] to specified Dropbox path
        /// </summary>
        /// <param name="dropboxPath">Dropbox path where to upload file. Example: /my_text.txt</param>
        /// <param name="bytes">Bytes array containing file data</param>
        /// <param name="onResult">Result callback that receives created remote file metadata</param>
        /// <param name="onProgress">Upload progress callback that receives float from 0 to 1</param>
        public void UploadFile(string dropboxPath, byte[] bytes, Action <DropboxRequestResult <DBXFile> > onResult,
                               Action <float> onProgress = null)
        {
            var prms = new DropboxUploadFileRequestParams(dropboxPath);

            MakeDropboxUploadRequest(UPLOAD_FILE_ENDPOINT, bytes, prms,
                                     onResponse: (fileMetadata) => {
                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(new DropboxRequestResult <DBXFile>(fileMetadata));
                });
            },
                                     onProgress: (progress) => {
                if (onProgress != null)
                {
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onProgress(progress);
                    });
                }
            },
                                     onWebError: (webErrorStr) => {
                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(DropboxRequestResult <DBXFile> .Error(webErrorStr));
                });
            });
        }
        /// <summary>
        /// Asynchronously retrieves file from Dropbox and returns path to local filesystem cached copy.f
        /// </summary>
        /// <param name="dropboxPath">Path to file on Dropbox or inside of Dropbox App folder (depending on accessToken type). Should start with "/". Example: /DropboxSyncExampleFolder/image.jpg</param>
        /// <param name="onResult">Result callback</param>
        /// <param name="onProgress">Callback function that receives progress as float from 0 to 1.</param>
        /// <param name="useCachedFirst">If True then first tries to get data from cache, if not cached then downloads.</param>
        /// <param name="useCachedIfOffline">If True and there's no Internet connection then retrieves file from cache if cached, otherwise produces error.</param>
        /// <param name="receiveUpdates">If True, then when there are remote updates on Dropbox, callback function onResult will be triggered again with updated version of the file.</param>
        public void GetFileAsLocalCachedPath(string dropboxPath, Action <DropboxRequestResult <string> > onResult, Action <float> onProgress = null, bool useCachedFirst = false,
                                             bool useCachedIfOffline = true, bool receiveUpdates = false)
        {
            Action <DropboxRequestResult <byte[]> > onResultMiddle = (res) => {
                if (res.error != null)
                {
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onResult(DropboxRequestResult <string> .Error(res.error));
                    });
                }
                else
                {
                    if (res.data != null)
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(new DropboxRequestResult <string>(GetPathInCache(dropboxPath)));
                        });
                    }
                    else
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(new DropboxRequestResult <string>(null));
                        });
                    }
                }
            };

            GetFileAsBytes(dropboxPath, onResultMiddle, onProgress, useCachedFirst, useCachedIfOffline, receiveUpdates);
        }
Example #3
0
        // METADATA


        private void GetMetadata <T>(string dropboxPath, Action <DropboxRequestResult <T> > onResult) where T : DBXItem
        {
            var prms = new DropboxGetMetadataRequestParams(dropboxPath);

            Log("GetMetadata for " + dropboxPath);
            MakeDropboxRequest(METADATA_ENDPOINT, prms,
                               onResponse: (jsonStr) => {
                Log("GetMetadata onResponse");
                var dict = JSON.FromJson <Dictionary <string, object> >(jsonStr);

                if (typeof(T) == typeof(DBXFolder))
                {
                    var folderMetadata = DBXFolder.FromDropboxDictionary(dict);
                    onResult(new DropboxRequestResult <T>(folderMetadata as T));
                }
                else if (typeof(T) == typeof(DBXFile))
                {
                    var fileMetadata = DBXFile.FromDropboxDictionary(dict);
                    onResult(new DropboxRequestResult <T>(fileMetadata as T));
                }
            },
                               onProgress: null,
                               onWebError: (error) => {
                Log("GetMetadata:onWebError");
                onResult(DropboxRequestResult <T> .Error(error));
            });
        }
        // UPLOADING FILE


        /// <summary>
        /// Uploads file from specified filepath in local filesystem to Dropbox
        /// </summary>
        /// <param name="dropboxPath">Dropbox path where to upload file. Example: /my_text.txt</param>
        /// <param name="localFilePath">Full file path in local filesystem. Example: C:\my_text.txt</param>
        /// <param name="onResult">Result callback that receives created remote file metadata</param>
        /// <param name="onProgress">Upload progress callback that receives float from 0 to 1</param>
        public void UploadFile(string dropboxPath, string localFilePath, Action <DropboxRequestResult <DBXFile> > onResult,
                               Action <float> onProgress = null)
        {
            // chec if specified local file path exists
            if (!File.Exists(localFilePath))
            {
                onResult(DropboxRequestResult <DBXFile> .Error(
                             new DBXError("Local file " + localFilePath + " does not exist.", DBXErrorType.LocalPathNotFound)
                             )
                         );
                return;
            }


            // read file bytes
            byte[] fileBytes = null;
            try{
                fileBytes = File.ReadAllBytes(localFilePath);
            }catch (Exception ex) {
                onResult(DropboxRequestResult <DBXFile> .Error(
                             new DBXError("Failed to read local file " + localFilePath + ": " + ex.Message, DBXErrorType.LocalFileSystemError)
                             )
                         );
                return;
            }


            // upload that bytes
            UploadFile(dropboxPath, fileBytes, onResult, onProgress);
        }
        // GETTING REMOTE CHANGES

        void FolderGetRemoteChanges(string dropboxFolderPath, Action <DropboxRequestResult <List <DBXFileChange> > > onResult, bool saveChangesInfoLocally = false)
        {
            GetFolderItems(dropboxFolderPath,
                           onResult: (res) => {
                if (res.error != null)
                {
                    onResult(DropboxRequestResult <List <DBXFileChange> > .Error(res.error));
                }
                else
                {
                    var fileChanges = new List <DBXFileChange>();

                    foreach (DBXFile remoteMetadata in res.data.Where(x => x.type == DBXItemType.File))
                    {
                        var localMetadata = GetLocalMetadataForFile(remoteMetadata.path);
                        if (localMetadata != null && !localMetadata.deletedOnRemote)
                        {
                            if (localMetadata.contentHash != remoteMetadata.contentHash)
                            {
                                fileChanges.Add(new DBXFileChange(remoteMetadata, DBXFileChangeType.Modified));
                            }
                        }
                        else
                        {
                            // no local metadata for this remote path - new object
                            fileChanges.Add(new DBXFileChange(remoteMetadata, DBXFileChangeType.Added));
                        }
                    }

                    // find other local files which were not in remote response (find deleted on remote files)
                    var processedDropboxFilePaths = res.data.Where(x => x.type == DBXItemType.File).Select(x => x.path).ToList();

                    //Log("Find all metadata paths");
                    var localDirectoryPath = GetPathInCache(dropboxFolderPath);
                    if (Directory.Exists(localDirectoryPath))
                    {
                        foreach (string localMetadataFilePath in Directory.GetFiles(localDirectoryPath, "*.dbxsync", SearchOption.AllDirectories))
                        {
                            var metadata    = ParseLocalMetadata(localMetadataFilePath);
                            var dropboxPath = metadata.path;
                            if (!processedDropboxFilePaths.Contains(dropboxPath) && !metadata.deletedOnRemote)
                            {
                                // wasnt in remote data - means removed
                                fileChanges.Add(new DBXFileChange(DBXFile.DeletedOnRemote(dropboxPath), DBXFileChangeType.Deleted));
                            }
                        }
                    }

                    if (saveChangesInfoLocally)
                    {
                        foreach (var fc in fileChanges)
                        {
                            SaveFileMetadata(fc.file);
                        }
                    }

                    onResult(new DropboxRequestResult <List <DBXFileChange> >(fileChanges));
                }
            }, recursive: true, onProgress: null);
        }
        /// <summary>
        /// Creates folder using path specified
        /// </summary>
        /// <param name="dropboxFolderPath">Path of folder to create</param>
        /// <param name="onResult">Result callback that contains metadata of the created folder</param>
        public void CreateFolder(string dropboxFolderPath, Action <DropboxRequestResult <DBXFolder> > onResult)
        {
            var path = DropboxSyncUtils.NormalizePath(dropboxFolderPath);

            var prms = new DropboxCreateFolderRequestParams();

            prms.path = path;

            MakeDropboxRequest(CREATE_FOLDER_ENDPOINT, prms, (jsonStr) => {
                DBXFolder folderMetadata = null;

                try {
                    var root       = JSON.FromJson <Dictionary <string, object> >(jsonStr);
                    folderMetadata = DBXFolder.FromDropboxDictionary(root["metadata"] as Dictionary <string, object>);
                }catch (Exception ex) {
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onResult(DropboxRequestResult <DBXFolder> .Error(new DBXError(ex.Message, DBXErrorType.ParsingError)));
                    });
                    return;
                }

                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(new DropboxRequestResult <DBXFolder>(folderMetadata));
                });
            }, onProgress: (progress) => {}, onWebError: (error) => {
                if (error.ErrorDescription.Contains("path/conflict/folder"))
                {
                    error.ErrorType = DBXErrorType.RemotePathAlreadyExists;
                }
                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(DropboxRequestResult <DBXFolder> .Error(error));
                });
            });
        }
        // FOLDERS

        /// <summary>
        /// Checks if dropbox path (file or folder) exists
        /// </summary>
        /// <param name="dropboxPath">Path to file or folder on Dropbox or inside of Dropbox App folder (depending on accessToken type). Should start with "/". Example:/DropboxSyncExampleFolder/image.jpg</param>
        /// <param name="onResult">Result callback containing bool that indicates existance on the item</param>
        public void PathExists(string dropboxPath, Action <DropboxRequestResult <bool> > onResult)
        {
            GetMetadata <DBXFolder>(dropboxPath, (res) => {
                if (res.error != null)
                {
                    if (res.error.ErrorType == DBXErrorType.RemotePathNotFound)
                    {
                        // path not found
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(new DropboxRequestResult <bool>(false));
                        });
                    }
                    else
                    {
                        // some other error
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(DropboxRequestResult <bool> .Error(res.error));
                        });
                    }
                }
                else
                {
                    // path exists
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onResult(new DropboxRequestResult <bool>(true));
                    });
                }
            });
        }
Example #8
0
        /// <summary>
        /// Moves file or folder from dropboxFromPath to dropboxToPath
        /// </summary>
        /// <param name="dropboxFromPath">From path</param>
        /// <param name="dropboxToPath">To path</param>
        /// <param name="onResult">Result callback containing metadata of moved object</param>
        public void Move(string dropboxFromPath, string dropboxToPath,
                         Action <DropboxRequestResult <DBXItem> > onResult)
        {
            var prms = new DropboxMoveFileRequestParams();

            prms.from_path = dropboxFromPath;
            prms.to_path   = dropboxToPath;

            MakeDropboxRequest(MOVE_ENDPOINT, prms, (jsonStr) => {
                DBXItem metadata = null;

                try {
                    var root          = JSON.FromJson <Dictionary <string, object> >(jsonStr);
                    var metadata_dict = root["metadata"] as Dictionary <string, object>;

                    if (metadata_dict[".tag"].ToString() == "file")
                    {
                        metadata = DBXFile.FromDropboxDictionary(metadata_dict);
                    }
                    else if (metadata_dict[".tag"].ToString() == "folder")
                    {
                        metadata = DBXFolder.FromDropboxDictionary(metadata_dict);
                    }
                }catch (Exception ex) {
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onResult(DropboxRequestResult <DBXItem> .Error(new DBXError(ex.Message, DBXErrorType.ParsingError)));
                    });
                    return;
                }

                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(new DropboxRequestResult <DBXItem>(metadata));
                });
            }, onProgress: (progress) => {}, onWebError: (error) => {
                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    if (error.ErrorType == DBXErrorType.RemotePathAlreadyExists)
                    {
                        error.ErrorDescription = "Can't move file: " + dropboxToPath + " already exists";
                    }
                    onResult(DropboxRequestResult <DBXItem> .Error(error));
                });
            });
        }
 /// <summary>
 /// Gets files and folders inside specified folder as a list without structure.
 /// </summary>
 /// <param name="path">Path to folder</param>
 /// <param name="onResult">Vallback function that receives result containing list of DBXItems</param>
 /// <param name="onProgress">Callback fnction that receives float from 0 to 1 intdicating the progress.</param>
 /// <param name="recursive">If True then gets all items recursively.</param>
 public void GetFolderItems(string path, Action <DropboxRequestResult <List <DBXItem> > > onResult, Action <float> onProgress = null, bool recursive = false)
 {
     _GetFolderItemsFlat(path, onResult: (items) => {
         _mainThreadQueueRunner.QueueOnMainThread(() => {
             onResult(new DropboxRequestResult <List <DBXItem> >(items));
         });
     },
                         onProgress: (progress) => {
         if (onProgress != null)
         {
             _mainThreadQueueRunner.QueueOnMainThread(() => {
                 onProgress(progress);
             });
         }
     },
                         onError: (errorStr) => {
         _mainThreadQueueRunner.QueueOnMainThread(() => {
             onResult(DropboxRequestResult <List <DBXItem> > .Error(errorStr));
         });
     }, recursive: recursive);
 }
        /// <summary>
        /// Retrieves structure of dropbox folders and files inside specified folder.
        /// </summary>
        /// <param name="dropboxFolderPath">Dropbox folder path</param>
        /// <param name="onResult">Callback function that receives result containing DBXFolder with all child nodes inside.</param>
        /// <param name="onProgress">Callback fnction that receives float from 0 to 1 intdicating the progress.</param>
        public void GetFolderStructure(string dropboxFolderPath, Action <DropboxRequestResult <DBXFolder> > onResult,
                                       Action <float> onProgress = null)
        {
            var path = DropboxSyncUtils.NormalizePath(dropboxFolderPath);

            _GetFolderItemsFlat(path, onResult: (items) => {
                DBXFolder rootFolder = null;

                // get root folder
                if (path == "/")
                {
                    rootFolder = new DBXFolder {
                        id = "", path = "/", name = "", items = new List <DBXItem>()
                    };
                }
                else
                {
                    rootFolder = items.Where(x => x.path == path).First() as DBXFolder;
                }
                // squash flat results
                rootFolder = BuildStructureFromFlat(rootFolder, items);

                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(new DropboxRequestResult <DBXFolder>(rootFolder));
                });
            },
                                onProgress: (progress) => {
                if (onProgress != null)
                {
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onProgress(progress);
                    });
                }
            },
                                onError: (errorStr) => {
                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(DropboxRequestResult <DBXFolder> .Error(errorStr));
                });
            }, recursive: true);
        }
Example #11
0
        // FILE OPERATIONS

        /// <summary>
        /// Deletes file or folder on Dropbox
        /// </summary>
        /// <param name="dropboxPath">Path to file or folder on Dropbox or inside of Dropbox App folder (depending on accessToken type). Should start with "/". Example:/DropboxSyncExampleFolder/image.jpg</param>
        /// <param name="onResult">Callback function that receives DropboxRequestResult with DBXItem metadata of deleted file or folder</param>
        public void Delete(string dropboxPath, Action <DropboxRequestResult <DBXItem> > onResult)
        {
            var prms = new DropboxDeletePathRequestParams();

            prms.path = dropboxPath;

            MakeDropboxRequest(DELETE_ENDPOINT, prms, (jsonStr) => {
                DBXItem metadata = null;

                try {
                    var root          = JSON.FromJson <Dictionary <string, object> >(jsonStr);
                    var metadata_dict = root["metadata"] as Dictionary <string, object>;

                    if (metadata_dict[".tag"].ToString() == "file")
                    {
                        metadata = DBXFile.FromDropboxDictionary(metadata_dict);
                    }
                    else if (metadata_dict[".tag"].ToString() == "folder")
                    {
                        metadata = DBXFolder.FromDropboxDictionary(metadata_dict);
                    }
                }catch (Exception ex) {
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onResult(DropboxRequestResult <DBXItem> .Error(new DBXError(ex.Message, DBXErrorType.ParsingError)));
                    });
                    return;
                }

                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(new DropboxRequestResult <DBXItem>(metadata));
                });
            }, onProgress: (progress) => {}, onWebError: (error) => {
                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(DropboxRequestResult <DBXItem> .Error(error));
                });
            });
        }
        // GETTING FILE

        /// <summary>
        /// Asynchronously retrieves file from Dropbox and tries to produce object of specified type T.
        /// </summary>
        /// <param name="dropboxPath">Path to file on Dropbox or inside of Dropbox App folder (depending on accessToken type). Should start with "/". Example: /DropboxSyncExampleFolder/image.jpg</param>
        /// <param name="onResult">Result callback</param>
        /// <param name="onProgress">Callback function that receives progress as float from 0 to 1.</param>
        /// <param name="useCachedFirst">If True then first tries to get data from cache, if not cached then downloads.</param>
        /// <param name="useCachedIfOffline">If True and there's no Internet connection then retrieves file from cache if cached, otherwise produces error.</param>
        /// <param name="receiveUpdates">If True, then when there are remote updates on Dropbox, callback function onResult will be triggered again with updated version of the file.</param>
        public void GetFile <T>(string dropboxPath, Action <DropboxRequestResult <T> > onResult, Action <float> onProgress = null, bool useCachedFirst = false,
                                bool useCachedIfOffline = true, bool receiveUpdates = false) where T : class
        {
            Action <DropboxRequestResult <byte[]> > onResultMiddle = null;

            if (typeof(T) == typeof(string))
            {
                //Log("GetFile: text type");

                // TEXT DATA
                onResultMiddle = (res) => {
                    if (res.error != null || res.data == null)
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(DropboxRequestResult <T> .Error(res.error));
                        });
                    }
                    else
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(new DropboxRequestResult <T>(DropboxSyncUtils.GetAutoDetectedEncodingStringFromBytes(res.data) as T));
                        });
                    }
                };
            }
            else if (typeof(T) == typeof(JsonObject) || typeof(T) == typeof(JsonArray))
            {
                //Log("GetFile: JSON type");

                // JSON OBJECT/ARRAY
                onResultMiddle = (res) => {
                    if (res.error != null)
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(DropboxRequestResult <T> .Error(res.error));
                        });
                    }
                    else
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(new DropboxRequestResult <T>(JSON.FromJson <T>(
                                                                      DropboxSyncUtils.GetAutoDetectedEncodingStringFromBytes(res.data)
                                                                      )));
                        });
                    }
                };
            }
            else if (typeof(T) == typeof(Texture2D))
            {
                //Log("GetFile: Texture2D type");
                // IMAGE DATA
                onResultMiddle = (res) => {
                    if (res.error != null)
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(DropboxRequestResult <T> .Error(res.error));
                        });
                    }
                    else
                    {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(new DropboxRequestResult <T>(DropboxSyncUtils.LoadImageToTexture2D(res.data) as T));
                        });
                    }
                };
            }
            else
            {
                _mainThreadQueueRunner.QueueOnMainThread(() => {
                    onResult(DropboxRequestResult <T> .Error(
                                 new DBXError(string.Format("Dont have a mapping byte[] -> {0}. Type {0} is not supported.", typeof(T).ToString()),
                                              DBXErrorType.NotSupported
                                              )
                                 )
                             );
                });
                return;
            }

            GetFileAsBytes(dropboxPath, onResultMiddle, onProgress, useCachedFirst, useCachedIfOffline, receiveUpdates);
        }
        /// <summary>
        /// Asynchronously retrieves file from Dropbox as byte[]
        /// </summary>
        /// <param name="dropboxPath">Path to file on Dropbox or inside of Dropbox App folder (depending on accessToken type). Should start with "/". Example: /DropboxSyncExampleFolder/image.jpg</param>
        /// <param name="onResult">Result callback</param>
        /// <param name="onProgress">Callback function that receives progress as float from 0 to 1.</param>
        /// <param name="useCachedFirst">If True then first tries to get data from cache, if not cached then downloads.</param>
        /// <param name="useCachedIfOffline">If True and there's no Internet connection then retrieves file from cache if cached, otherwise produces error.</param>
        /// <param name="receiveUpdates">If true , then when there are remote updates on Dropbox, callback function onResult will be triggered again with updated version of the file.</param>
        public void GetFileAsBytes(string dropboxPath, Action <DropboxRequestResult <byte[]> > onResult, Action <float> onProgress = null, bool useCachedFirst = false,
                                   bool useCachedIfOffline = true, bool receiveUpdates = false)
        {
            if (DropboxSyncUtils.IsBadDropboxPath(dropboxPath))
            {
                onResult(DropboxRequestResult <byte[]> .Error(
                             new DBXError("Cant get file: bad path " + dropboxPath, DBXErrorType.BadRequest)
                             )
                         );
                return;
            }

            Action returnCachedResult = () => {
                var cachedFilePath = GetPathInCache(dropboxPath);

                if (File.Exists(cachedFilePath))
                {
                    var bytes = File.ReadAllBytes(cachedFilePath);
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onResult(new DropboxRequestResult <byte[]>(bytes));
                    });
                }
                else
                {
                    Log("cache doesnt have file");
                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                        onResult(
                            DropboxRequestResult <byte[]> .Error(
                                new DBXError("File " + dropboxPath + " is removed on remote", DBXErrorType.RemotePathNotFound)
                                )
                            );
                    });
                }
            };

            Action subscribeToUpdatesAction = () => {
                SubscribeToFileChanges(dropboxPath, (fileChange) => {
                    UpdateFileFromRemote(dropboxPath, onSuccess: () => {
                        // return updated cached result
                        returnCachedResult();
                    }, onProgress: (progress) => {
                        if (onProgress != null)
                        {
                            _mainThreadQueueRunner.QueueOnMainThread(() => {
                                onProgress(progress);
                            });
                        }
                    }, onError: (error) => {
                        _mainThreadQueueRunner.QueueOnMainThread(() => {
                            onResult(DropboxRequestResult <byte[]> .Error(error));
                        });
                    });
                });
            };

            // maybe no need to do any remote requests
            if ((useCachedFirst) && IsFileCached(dropboxPath))
            {
                Log("GetFile: using cached version");
                returnCachedResult();

                if (receiveUpdates)
                {
                    subscribeToUpdatesAction();
                }
            }
            else
            {
                //Log("GetFile: check if online");
                // now check if we online

                DropboxSyncUtils.IsOnlineAsync((isOnline) => {
                    try {
                        if (isOnline)
                        {
                            Log("GetFile: internet available");
                            // check if have updates and load them
                            UpdateFileFromRemote(dropboxPath, onSuccess: () => {
                                Log("GetFile: state of dropbox file is " + dropboxPath + " is synced now");
                                // return updated cached result

                                returnCachedResult();


                                if (receiveUpdates)
                                {
                                    subscribeToUpdatesAction();
                                }
                            }, onProgress: (progress) => {
                                if (onProgress != null)
                                {
                                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                                        onProgress(progress);
                                    });
                                }
                            }, onError: (error) => {
                                //Log("error");
                                _mainThreadQueueRunner.QueueOnMainThread(() => {
                                    onResult(DropboxRequestResult <byte[]> .Error(error));
                                });

                                if (receiveUpdates)
                                {
                                    subscribeToUpdatesAction();
                                }
                            });
                        }
                        else
                        {
                            Log("GetFile: internet not available");

                            if (useCachedIfOffline && IsFileCached(dropboxPath))
                            {
                                Log("GetFile: cannot check for updates - using cached version");

                                returnCachedResult();


                                if (receiveUpdates)
                                {
                                    subscribeToUpdatesAction();
                                }
                            }
                            else
                            {
                                if (receiveUpdates)
                                {
                                    // try again when internet recovers
                                    _internetConnectionWatcher.SubscribeToInternetConnectionRecoverOnce(() => {
                                        GetFileAsBytes(dropboxPath, onResult, onProgress, useCachedFirst, useCachedIfOffline, receiveUpdates);
                                    });

                                    subscribeToUpdatesAction();
                                }
                                else
                                {
                                    // error
                                    _mainThreadQueueRunner.QueueOnMainThread(() => {
                                        onResult(DropboxRequestResult <byte[]> .Error(
                                                     new DBXError("GetFile: No internet connection", DBXErrorType.NetworkProblem)
                                                     )
                                                 );
                                    });
                                }
                            }
                        }
                    }catch (Exception ex) {
                        Debug.LogException(ex);
                    }
                });
            }
        }