Beispiel #1
0
        internal static void Sync(Library library, bool restricted_metadata_sync, bool is_readonly, Dictionary <string, string> historical_sync_file, SynchronisationAction synchronisation_action)
        {
            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), "Performing metadata transfers");

            // For read only libraries, we need to overwrite any files that have been changed locally since the last sync
            if (is_readonly)
            {
                if (0 < synchronisation_action.states_to_upload.Count)
                {
                    Logging.Info("We are discarding {0} upload items because library is read-only.", synchronisation_action.states_to_upload.Count);
                    synchronisation_action.states_to_download.AddRange(synchronisation_action.states_to_upload);
                    synchronisation_action.states_to_upload.Clear();
                }

                if (0 < synchronisation_action.states_to_merge.Count)
                {
                    Logging.Info("We are discarding {0} merge items because library is read-only.", synchronisation_action.states_to_merge.Count);
                    synchronisation_action.states_to_download.AddRange(synchronisation_action.states_to_merge);
                    synchronisation_action.states_to_merge.Clear();
                }
            }

            DoMerges(library, restricted_metadata_sync, historical_sync_file, synchronisation_action);
            DoUploads(library, restricted_metadata_sync, historical_sync_file, synchronisation_action);
            int download_count = DoDownloads(library, restricted_metadata_sync, historical_sync_file, synchronisation_action);

            if (0 < download_count)
            {
                DoNotifyLibraryOfChanges(library, historical_sync_file, synchronisation_action);
            }

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), "Finished metadata transfers");
        }
Beispiel #2
0
        private static void DoUploads(Library library, bool restricted_metadata_sync, Dictionary <string, string> historical_sync_file, SynchronisationAction synchronisation_action)
        {
            int upload_count = 0;

            StatusManager.Instance.ClearCancelled(StatusCodes.SYNC_META(library));
            foreach (SynchronisationState ss in synchronisation_action.states_to_upload)
            {
                StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), String.Format("Uploading metadata to your Web/Intranet Library ({0} to go)", synchronisation_action.states_to_upload.Count - upload_count), upload_count, synchronisation_action.states_to_upload.Count, true);
                ++upload_count;

                // Has the user cancelled?
                if (StatusManager.Instance.IsCancelled(StatusCodes.SYNC_META(library)))
                {
                    Logging.Info("User has cancelled their metadata upload");
                    break;
                }

                // Only do some filetypes if we are in restricted sync (e.g. they haven't paid for a while)
                {
                    if (restricted_metadata_sync)
                    {
                        string extension = ss.extension;
                        extension = extension.ToLower();
                        if (!SynchronisationFileTypes.extensions_restricted_sync.Contains(extension))
                        {
                            Logging.Info("Not syncing {0} because we are on restricted sync", ss.filename);
                            continue;
                        }
                    }
                }

                // Upload the file
                {
                    Logging.Info("+Uploading {0}", ss.filename);

                    // --- TODO: Replace this with a pretty interface class ------------------------------------------------
                    if (false)
                    {
                    }
                    else if (library.WebLibraryDetail.IsIntranetLibrary)
                    {
                        SynchronisationExecutor_Intranet.DoUpload(library, ss);
                    }
                    else
                    {
                        throw new Exception(String.Format("Did not understand how to upload for library {0}", library.WebLibraryDetail.Title));
                    }
                    // -----------------------------------------------------------------------------------------------------

                    Logging.Info("-Uploading {0}");

                    historical_sync_file[ss.filename] = ss.library_item.md5;
                }
            }

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), String.Format("Uploaded {0} metadata to your Web/Intranet Library", upload_count));
        }
Beispiel #3
0
        private void Sync_BACKGROUND(SyncControlGridItem sync_control_grid_item)
        {
            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(sync_control_grid_item.library_sync_detail.web_library_detail), String.Format("Starting sync of {0}", sync_control_grid_item.LibraryTitle));

            var  sd            = sync_control_grid_item.library_sync_detail;
            bool done_anything = false;

            try
            {
                IntranetLibraryDetail.EnsureIntranetLibraryExists(sync_control_grid_item.library_sync_detail.web_library_detail);

                if (sync_control_grid_item.SyncLibrary)
                {
                    if (sd.sync_decision.can_sync)
                    {
                        Logging.Info("Syncing metadata for {0}", sd.web_library_detail.Title);
                        SynchronizeMetadata_INTERNAL_BACKGROUND(sd.web_library_detail, sync_control_grid_item.IsReadOnly);
                        SynchronizeDocuments_Upload_INTERNAL_BACKGROUND(sd.web_library_detail, sd.web_library_detail.Xlibrary.PDFDocuments, sync_control_grid_item.IsReadOnly);
                        Logging.Info("Downloading documents for {0}", sd.web_library_detail.Title);
                        SynchronizeDocuments_Download_INTERNAL_BACKGROUND(sd.web_library_detail, sd.web_library_detail.Xlibrary.PDFDocuments, sync_control_grid_item.IsReadOnly);
                        done_anything = true;
                    }
                    else
                    {
                        Logging.Info("Not synchronizing metadata or documents for {0}", sd.web_library_detail.Title);
                    }
                }

                // Indicate that we have synced
                if (done_anything)
                {
                    var now = DateTime.UtcNow;

                    sd.web_library_detail.LastSynced = now;

                    string syncfilepath = HistoricalSyncFile.GetSyncDbFilename(sd.web_library_detail);
                    File.SetCreationTimeUtc(syncfilepath, now);
                    File.SetLastWriteTimeUtc(syncfilepath, now);
                }
            }
            catch (Exception ex)
            {
                Logging.Error(ex, "There was a problem while trying to connect to this Intranet Library?  Are you sure you have permission to access this folder?  Your Network or System Administrator can grant you this permission.\n\nThe detailed error message is:\n" + ex.Message);
            }
            finally
            {
                sd.web_library_detail.Xlibrary.sync_in_progress = false;

                WebLibraryManager.Instance.NotifyOfChangeToWebLibraryDetail();
            }

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(sd.web_library_detail), String.Format("Finished sync of {0}", sync_control_grid_item.LibraryTitle));
        }
        private void Sync_BACKGROUND(SyncControlGridItem sync_control_grid_item)
        {
            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(sync_control_grid_item.library_sync_detail.web_library_detail.library), String.Format("Starting sync of {0}", sync_control_grid_item.LibraryTitle));

            try
            {
                if (sync_control_grid_item.SyncMetadata)
                {
                    if (sync_control_grid_item.library_sync_detail.sync_decision.can_sync)
                    {
                        Logging.Info("Syncing metadata for {0}", sync_control_grid_item.library_sync_detail.web_library_detail.Title);
                        SynchronizeMetadata_INTERNAL_BACKGROUND(sync_control_grid_item.library_sync_detail.web_library_detail.library, false, sync_control_grid_item.IsReadOnly);
                        SynchronizeDocuments_Upload_INTERNAL_BACKGROUND(sync_control_grid_item.library_sync_detail.web_library_detail.library, sync_control_grid_item.library_sync_detail.web_library_detail.library.PDFDocuments, sync_control_grid_item.IsReadOnly);
                    }
                    else
                    {
                        Logging.Info("Partial syncing metadata for {0}", sync_control_grid_item.library_sync_detail.web_library_detail.Title);
                        SynchronizeMetadata_INTERNAL_BACKGROUND(sync_control_grid_item.library_sync_detail.web_library_detail.library, true, sync_control_grid_item.IsReadOnly);

                        Logging.Info("Not uploading documents for {0}", sync_control_grid_item.library_sync_detail.web_library_detail.Title);
                    }
                }

                if (sync_control_grid_item.SyncDocuments)
                {
                    if (sync_control_grid_item.library_sync_detail.sync_decision.can_sync)
                    {
                        Logging.Info("Downloading documents for {0}", sync_control_grid_item.library_sync_detail.web_library_detail.Title);
                        SynchronizeDocuments_Download_INTERNAL_BACKGROUND(sync_control_grid_item.library_sync_detail.web_library_detail.library, sync_control_grid_item.library_sync_detail.web_library_detail.library.PDFDocuments, sync_control_grid_item.IsReadOnly);
                    }
                    else
                    {
                        Logging.Info("Not downloading documents for {0}", sync_control_grid_item.library_sync_detail.web_library_detail.Title);
                    }
                }
            }
            finally
            {
                sync_control_grid_item.library_sync_detail.web_library_detail.library.sync_in_progress = false;

                // Indicate that we have synced
                sync_control_grid_item.library_sync_detail.web_library_detail.library.WebLibraryDetail.LastSynced = DateTime.UtcNow;
                WebLibraryManager.Instance.NotifyOfChangeToWebLibraryDetail();
            }

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(sync_control_grid_item.library_sync_detail.web_library_detail.library), String.Format("Finished sync of {0}", sync_control_grid_item.LibraryTitle));
        }
        /// <summary>
        /// Builds a map of SynchronisationState objects of the form
        ///     filename -> SynchronisationState
        /// </summary>
        /// <returns></returns>
        internal static SynchronisationStates Build(Library library, Dictionary <string, string> historical_sync_file)
        {
            SynchronisationStates synchronisation_states = new SynchronisationStates();

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), "Building sync state from local history", 0, 1);
            BuildFromHistoricalSyncFile(historical_sync_file, ref synchronisation_states);

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), "Building sync state from local files", 0, 1);
            BuildFromLocal(library, ref synchronisation_states);

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), "Building sync state from Web/Intranet Library", 0, 1);
            BuildFromRemote(library, ref synchronisation_states);

            FilterSynchronisationStates(ref synchronisation_states);

            return(synchronisation_states);
        }
Beispiel #6
0
        private static void DoNotifyLibraryOfChanges(Library library, Dictionary <string, string> historical_sync_file, SynchronisationAction synchronisation_action)
        {
            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), "Notifying library of changes");

            HashSet <string> fingerprints_that_have_changed = new HashSet <string>();

            foreach (SynchronisationState ss in synchronisation_action.states_to_download)
            {
                fingerprints_that_have_changed.Add(ss.fingerprint);
            }

            foreach (string fingerprint in fingerprints_that_have_changed)
            {
                library.NotifyLibraryThatDocumentHasChangedExternally(fingerprint);
            }

            // Update grid
            library.NotifyLibraryThatDocumentListHasChangedExternally();

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), "Notified library of changes");
        }
Beispiel #7
0
        private static void DoUploads(WebLibraryDetail web_library_detail, Dictionary <string, string> historical_sync_file, SynchronisationAction synchronisation_action)
        {
            int upload_count = 0;

            StatusManager.Instance.ClearCancelled(StatusCodes.SYNC_META(web_library_detail));
            foreach (SynchronisationState ss in synchronisation_action.states_to_upload)
            {
                StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(web_library_detail), String.Format("Uploading metadata to your Web/Intranet Library ({0} to go)", synchronisation_action.states_to_upload.Count - upload_count), upload_count, synchronisation_action.states_to_upload.Count, true);
                ++upload_count;

                // Has the user canceled?
                if (StatusManager.Instance.IsCancelled(StatusCodes.SYNC_META(web_library_detail)))
                {
                    Logging.Info("User has canceled their metadata upload");
                    break;
                }

                // Upload the file
                {
                    Logging.Info("+Uploading {0}", ss.filename);

                    // TODO: Replace this with a pretty interface class ------------------------------------------------
                    if (web_library_detail.IsIntranetLibrary)
                    {
                        SynchronisationExecutor_Intranet.DoUpload(web_library_detail, ss);
                    }
                    else
                    {
                        throw new Exception(String.Format("Did not understand how to upload for library {0}", web_library_detail.Title));
                    }
                    // -----------------------------------------------------------------------------------------------------

                    Logging.Info("-Uploading {0}");

                    historical_sync_file[ss.filename] = ss.library_item.md5;
                }
            }

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(web_library_detail), String.Format("Uploaded {0} metadata to your Web/Intranet Library", upload_count));
        }
Beispiel #8
0
        internal static SynchronisationAction Build(WebLibraryDetail web_library_detail, SynchronisationStates synchronisation_states)
        {
            SynchronisationAction synchronisation_action = new SynchronisationAction();

            List <SynchronisationState> synchronisation_state_list = new List <SynchronisationState>(synchronisation_states.Values);

            for (int i = 0; i < synchronisation_state_list.Count; ++i)
            {
                SynchronisationState synchronisation_state = synchronisation_state_list[i];

                if (false ||
                    (0 == i % 20 && synchronisation_state_list.Count < 100) ||
                    (0 == i % 100 && synchronisation_state_list.Count < 1000) ||
                    (0 == i % 500)
                    )
                {
                    StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(web_library_detail), "Determining sync action", i, synchronisation_state_list.Count);
                }

                // NB: Ordering of these statements is important so don't reorder them!

                // Not local, not remote: something dodgy in the history file, ignore it
                if (null == synchronisation_state.md5_local && null == synchronisation_state.md5_remote)
                {
                    synchronisation_action.states_dodgy.Add(synchronisation_state);
                }

                // If we don't have it locally but we do remotely
                else if (null == synchronisation_state.md5_local && null != synchronisation_state.md5_remote)
                {
                    synchronisation_action.states_to_download.Add(synchronisation_state);
                }

                // If we don't have it remotely, but we do locally
                else if (null != synchronisation_state.md5_local && null == synchronisation_state.md5_remote)
                {
                    synchronisation_action.states_to_upload.Add(synchronisation_state);
                }

                // If local and remote match, do nothing
                else if (0 == synchronisation_state.md5_local.CompareTo(synchronisation_state.md5_remote))
                {
                    synchronisation_action.states_already_synced.Add(synchronisation_state);
                }

                // If local and remote don't match, but local has not changed
                else if (0 == synchronisation_state.md5_local.CompareTo(synchronisation_state.md5_previous))
                {
                    synchronisation_action.states_to_download.Add(synchronisation_state);
                }

                // If local and remote don't match, but remote has not changed
                else if (0 == synchronisation_state.md5_remote.CompareTo(synchronisation_state.md5_previous))
                {
                    synchronisation_action.states_to_upload.Add(synchronisation_state);
                }

                // If local and remote don't match and neither match the previous value, we have a merge conflict
                else
                {
                    synchronisation_action.states_to_merge.Add(synchronisation_state);
                }
            }

            return(synchronisation_action);
        }
Beispiel #9
0
        private static int DoDownloads(Library library, bool restricted_metadata_sync, Dictionary <string, string> historical_sync_file, SynchronisationAction synchronisation_action)
        {
            int download_count = 0;

            StatusManager.Instance.ClearCancelled(StatusCodes.SYNC_META(library));
            foreach (SynchronisationState ss in synchronisation_action.states_to_download)
            {
                StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), String.Format("Downloading metadata from your Web/Intranet Library ({0} to go)", synchronisation_action.states_to_download.Count - download_count), download_count, synchronisation_action.states_to_download.Count, true);
                ++download_count;

                // Has the user cancelled?
                if (StatusManager.Instance.IsCancelled(StatusCodes.SYNC_META(library)))
                {
                    Logging.Info("User has cancelled their metadata download");
                    break;
                }

                try
                {
                    Logging.Info("+Downloading {0}", ss.filename);

                    StoredUserFile stored_user_file = null;

                    // --- TODO: Replace this with a pretty interface class ------------------------------------------------
                    if (false)
                    {
                    }
                    else if (library.WebLibraryDetail.IsIntranetLibrary)
                    {
                        stored_user_file = SynchronisationExecutor_Intranet.DoDownload(library, ss);
                    }
                    else
                    {
                        throw new Exception(String.Format("Did not understand how to download for library {0}", library.WebLibraryDetail.Title));
                    }
                    // -----------------------------------------------------------------------------------------------------

                    Logging.Info("-Downloading {0}", ss.filename);

                    {
                        // Check that the MD5s match, or we have had some issue in the download
                        Logging.Info("Checking content");
                        string md5_metadata    = StreamMD5.FromBytes(stored_user_file.Content);
                        string header_etag     = stored_user_file.Md5;
                        string header_etag_nik = header_etag;
                        if (null != header_etag && !String.IsNullOrEmpty(header_etag) && 0 != String.Compare(md5_metadata, header_etag, true) && 0 != String.Compare(md5_metadata, header_etag_nik, true))
                        {
                            throw new Exception(String.Format("Local and remote MD5s do not match. local={0} remote={1} remote_nik={2}", md5_metadata, header_etag, header_etag_nik));
                        }

                        Logging.Info("Copying content");
                        library.LibraryDB.PutBlob(ss.fingerprint, ss.extension, stored_user_file.Content);

                        // Remember this MD5 for our sync clash detection
                        Logging.Info("Remembering md5");
                        historical_sync_file[ss.filename] = md5_metadata;
                    }
                }

                catch (Exception ex)
                {
                    Logging.Error(ex, "There was a problem downloading one of your sync files");
                }
            }

            StatusManager.Instance.UpdateStatus(StatusCodes.SYNC_META(library), String.Format("Downloaded {0} metadata from your Web/Intranet Library", download_count));

            return(download_count);
        }