mirror of
				https://github.com/Kopano-dev/kopano-ol-extension.git
				synced 2023-10-10 11:37:40 +00:00 
			
		
		
		
	[KOE-24] Added per-account GAB resync and synchronous GAB resync.
This commit is contained in:
		| @@ -361,7 +361,7 @@ namespace Acacia.Features.GAB | |||||||
|                                 { |                                 { | ||||||
|                                     try |                                     try | ||||||
|                                     { |                                     { | ||||||
|                                         if (IsGABContactsFolder(folder)) |                                         if (IsGABContactsFolder(folder, accounts)) | ||||||
|                                         { |                                         { | ||||||
|                                             Logger.Instance.Debug(this, "FullResync: Deleting contacts folder: {0}", folder.Name); |                                             Logger.Instance.Debug(this, "FullResync: Deleting contacts folder: {0}", folder.Name); | ||||||
|                                             folder.Delete(); |                                             folder.Delete(); | ||||||
| @@ -378,11 +378,20 @@ namespace Acacia.Features.GAB | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // Do the resync |                 // Do the resync | ||||||
|                 int remaining = _gabsByDomainName.Count; |                 using (completion.Begin()) | ||||||
|  |                 { | ||||||
|                     foreach (GABHandler gab in _gabsByDomainName.Values) |                     foreach (GABHandler gab in _gabsByDomainName.Values) | ||||||
|                     { |                     { | ||||||
|                     CompletionTracker partCompletion = new CompletionTracker(() => OnGabSyncFinished(gab)); |                         // Check if the gab is appropriate for the accounts | ||||||
|                     // TODO: merge partCompletion into total completion |                         if (accounts == null || accounts.Contains(gab.ActiveAccount)) | ||||||
|  |                         { | ||||||
|  |                             completion.Begin(); | ||||||
|  |                             CompletionTracker partCompletion = new CompletionTracker(() => | ||||||
|  |                             { | ||||||
|  |                                 OnGabSyncFinished(gab); | ||||||
|  |                                 completion.End(); | ||||||
|  |                             }); | ||||||
|  |  | ||||||
|                             Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName); |                             Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName); | ||||||
|                             Tasks.Task(partCompletion, this, "FullResync", () => |                             Tasks.Task(partCompletion, this, "FullResync", () => | ||||||
|                             { |                             { | ||||||
| @@ -390,6 +399,8 @@ namespace Acacia.Features.GAB | |||||||
|                             }); |                             }); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             finally |             finally | ||||||
|             { |             { | ||||||
|                 EndProcessing(); |                 EndProcessing(); | ||||||
| @@ -499,9 +510,30 @@ namespace Acacia.Features.GAB | |||||||
|             return GABInfo.Get(folder); |             return GABInfo.Get(folder); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static bool IsGABContactsFolder(IFolder folder) |         /// <summary> | ||||||
|  |         /// Checks if the folder is a relevant GAB contacts folder. | ||||||
|  |         /// </summary> | ||||||
|  |         /// <param name="folder">The folder.</param> | ||||||
|  |         /// <param name="accounts">If specified, the folder is considered relevant only if it is the GAB for one of the specified | ||||||
|  |         /// accounts. Otherwise, any GAB folder is considered relevant.</param> | ||||||
|  |         public static bool IsGABContactsFolder(IFolder folder, ZPushAccount[] accounts) | ||||||
|         { |         { | ||||||
|             return GetGABContactsFolderInfo(folder) != null; |             // Check if this is a GAB folder at all | ||||||
|  |             GABInfo gab = GetGABContactsFolderInfo(folder); | ||||||
|  |             if (gab == null) | ||||||
|  |                 return false; | ||||||
|  |  | ||||||
|  |             // If we don't have a list of accounts, it is what we're looking for | ||||||
|  |             if (accounts == null) | ||||||
|  |                 return true; | ||||||
|  |  | ||||||
|  |             // Check if the domain is specified | ||||||
|  |             foreach(ZPushAccount account in accounts) | ||||||
|  |             { | ||||||
|  |                 if (account.Account.DomainName == gab.Domain) | ||||||
|  |                     return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void AccountDiscovered(ZPushAccount zpush) |         private void AccountDiscovered(ZPushAccount zpush) | ||||||
|   | |||||||
| @@ -41,6 +41,39 @@ namespace Acacia.Features.SyncState | |||||||
|  |  | ||||||
|     public class FeatureSyncState : FeatureDisabled, FeatureWithRibbon |     public class FeatureSyncState : FeatureDisabled, FeatureWithRibbon | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  |         #region Sync configuration | ||||||
|  |  | ||||||
|  |         [AcaciaOption("Sets the period to check synchronisation state if a sync is in progress.")] | ||||||
|  |         public TimeSpan CheckPeriod | ||||||
|  |         { | ||||||
|  |             get { return GetOption(OPTION_CHECK_PERIOD); } | ||||||
|  |             set { SetOption(OPTION_CHECK_PERIOD, value); } | ||||||
|  |         } | ||||||
|  |         private static readonly TimeSpanOption OPTION_CHECK_PERIOD = new TimeSpanOption("CheckPeriod", new TimeSpan(0, 5, 0)); | ||||||
|  |  | ||||||
|  |         [AcaciaOption("Sets the period to check synchronisation state if a sync is in progress and the dialog is open.")] | ||||||
|  |         public TimeSpan CheckPeriodDialog | ||||||
|  |         { | ||||||
|  |             get { return GetOption(OPTION_CHECK_PERIOD_DIALOG); } | ||||||
|  |             set { SetOption(OPTION_CHECK_PERIOD_DIALOG, value); } | ||||||
|  |         } | ||||||
|  |         private static readonly TimeSpanOption OPTION_CHECK_PERIOD_DIALOG = new TimeSpanOption("CheckPeriodDialog", new TimeSpan(0, 1, 0)); | ||||||
|  |  | ||||||
|  |         private TimeSpan DelayTime | ||||||
|  |         { | ||||||
|  |             get | ||||||
|  |             { | ||||||
|  |                 if (_dialogOpen) | ||||||
|  |                     return CheckPeriodDialog; | ||||||
|  |                 else | ||||||
|  |                     return CheckPeriod; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         private bool _dialogOpen; | ||||||
|  |  | ||||||
|  |         #endregion | ||||||
|  |  | ||||||
|         // TODO: this is largely about progress bars, separate that? |         // TODO: this is largely about progress bars, separate that? | ||||||
|         private class SyncStateData : DataProvider |         private class SyncStateData : DataProvider | ||||||
|         { |         { | ||||||
| @@ -152,7 +185,7 @@ namespace Acacia.Features.SyncState | |||||||
|         public override void Startup() |         public override void Startup() | ||||||
|         { |         { | ||||||
|             _state = new SyncStateData(this); |             _state = new SyncStateData(this); | ||||||
|             _button = RegisterButton(this, "Progress", true, ShowSyncState, ZPushBehaviour.Disable); |             _button = RegisterButton(this, "Progress", true, ShowSyncState, ZPushBehaviour.None); | ||||||
|             _button.DataProvider = _state; |             _button.DataProvider = _state; | ||||||
|             // Add a sync task to start checking. If this finds it's not fully synchronised, it will check more often |             // Add a sync task to start checking. If this finds it's not fully synchronised, it will check more often | ||||||
|             Watcher.Sync.AddTask(this, Name, CheckSyncState); |             Watcher.Sync.AddTask(this, Name, CheckSyncState); | ||||||
| @@ -306,10 +339,14 @@ namespace Acacia.Features.SyncState | |||||||
|                 DeviceDetails details = deviceService.Execute(new GetDeviceDetailsRequest()); |                 DeviceDetails details = deviceService.Execute(new GetDeviceDetailsRequest()); | ||||||
|  |  | ||||||
|                 // Determine the totals |                 // Determine the totals | ||||||
|                 details.Calculate(); |                 details?.Calculate(); | ||||||
|  |  | ||||||
|                 // And store with the account |                 // And store with the account | ||||||
|                 account.SetFeatureData(this, null, details); |                 account.SetFeatureData(this, null, details); | ||||||
|  |  | ||||||
|  |                 // If syncing, check again soon. | ||||||
|  |                 if (details?.IsSyncing == true) | ||||||
|  |                     Util.Delayed(this, (int)DelayTime.TotalMilliseconds, () => CheckSyncState(account)); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Update the total for all accounts |             // Update the total for all accounts | ||||||
| @@ -339,9 +376,17 @@ namespace Acacia.Features.SyncState | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void ShowSyncState() |         private void ShowSyncState() | ||||||
|  |         { | ||||||
|  |             _dialogOpen = true; | ||||||
|  |             try | ||||||
|             { |             { | ||||||
|                 new SyncStateDialog(this).ShowDialog(); |                 new SyncStateDialog(this).ShowDialog(); | ||||||
|             } |             } | ||||||
|  |             finally | ||||||
|  |             { | ||||||
|  |                 _dialogOpen = false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         private class SyncStateImpl : SyncState |         private class SyncStateImpl : SyncState | ||||||
|         { |         { | ||||||
| @@ -362,7 +407,6 @@ namespace Acacia.Features.SyncState | |||||||
|                 _canResync[(int)ResyncOption.Signatures] = _featureSignatures != null; |                 _canResync[(int)ResyncOption.Signatures] = _featureSignatures != null; | ||||||
|                 _canResync[(int)ResyncOption.ServerData] = ThisAddIn.Instance.Watcher.Sync.Enabled; |                 _canResync[(int)ResyncOption.ServerData] = ThisAddIn.Instance.Watcher.Sync.Enabled; | ||||||
|                 _canResync[(int)ResyncOption.Full] = true; |                 _canResync[(int)ResyncOption.Full] = true; | ||||||
|                 Update(); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             public long Done |             public long Done | ||||||
| @@ -399,14 +443,29 @@ namespace Acacia.Features.SyncState | |||||||
|             { |             { | ||||||
|                 if (!CanResync(option)) |                 if (!CanResync(option)) | ||||||
|                     return true; |                     return true; | ||||||
|                 _canResync [(int)option] = false; |  | ||||||
|  |  | ||||||
|                 switch(option) |                 switch(option) | ||||||
|                 { |                 { | ||||||
|                     case ResyncOption.GAB: |                     case ResyncOption.GAB: | ||||||
|                         // TODO: use completion tracker if not synching |                         if (IsSyncing) | ||||||
|  |                         { | ||||||
|  |                             // Already syncing, resync GAB asynchronously | ||||||
|                             _featureGAB.FullResync(null, _accounts); |                             _featureGAB.FullResync(null, _accounts); | ||||||
|  |                             // Cannot resync again until the dialog is reopened | ||||||
|  |                             _canResync[(int)ResyncOption.GAB] = false; | ||||||
|                             return false; |                             return false; | ||||||
|  |                         } | ||||||
|  |                         else | ||||||
|  |                         { | ||||||
|  |                             ProgressDialog.Execute("GABSync", | ||||||
|  |                                 (ct, tracker) => | ||||||
|  |                                 { | ||||||
|  |                                     _featureGAB.FullResync(tracker, _accounts); | ||||||
|  |                                     return 0; | ||||||
|  |                                 } | ||||||
|  |                             ); | ||||||
|  |                             return true; | ||||||
|  |                         } | ||||||
|                     case ResyncOption.Signatures: |                     case ResyncOption.Signatures: | ||||||
|                         ProgressDialog.Execute("SignaturesSync", |                         ProgressDialog.Execute("SignaturesSync", | ||||||
|                             (ct) => |                             (ct) => | ||||||
|   | |||||||
| @@ -50,6 +50,15 @@ namespace Acacia.Features.SyncState | |||||||
|             // Add the accounts |             // Add the accounts | ||||||
|             foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts()) |             foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts()) | ||||||
|                 comboAccounts.Items.Add(account); |                 comboAccounts.Items.Add(account); | ||||||
|  |  | ||||||
|  |             // Add a timer to update the UI | ||||||
|  |             Timer timer = new Timer(); | ||||||
|  |             timer.Interval = 2500; | ||||||
|  |             timer.Tick += (o, args) => | ||||||
|  |             { | ||||||
|  |                 UpdateUI(); | ||||||
|  |             }; | ||||||
|  |             timer.Start(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void ShowHint(object sender, KHintButton.HintEventArgs e) |         private void ShowHint(object sender, KHintButton.HintEventArgs e) | ||||||
| @@ -119,6 +128,8 @@ namespace Acacia.Features.SyncState | |||||||
|  |  | ||||||
|         private void UpdateUI() |         private void UpdateUI() | ||||||
|         { |         { | ||||||
|  |             _syncState.Update(); | ||||||
|  |  | ||||||
|             // Set up the UI |             // Set up the UI | ||||||
|             foreach (ResyncOption option in Enum.GetValues(typeof(ResyncOption))) |             foreach (ResyncOption option in Enum.GetValues(typeof(ResyncOption))) | ||||||
|             { |             { | ||||||
| @@ -127,7 +138,7 @@ namespace Acacia.Features.SyncState | |||||||
|  |  | ||||||
|             if (_syncState.IsSyncing) |             if (_syncState.IsSyncing) | ||||||
|             { |             { | ||||||
|                 textRemaining.Text = _syncState.Remaining.ToString(); |                 textRemaining.Text = _syncState.Remaining.ToString() + " / " + _syncState.Total.ToString(); | ||||||
|                 progress.Value = (int)(_syncState.Done * 100.0 / _syncState.Total); |                 progress.Value = (int)(_syncState.Done * 100.0 / _syncState.Total); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|   | |||||||
| @@ -168,6 +168,24 @@ namespace Acacia.Properties { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to The global address book is being synchronised.. | ||||||
|  |         /// </summary> | ||||||
|  |         internal static string GABSync_Label { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("GABSync_Label", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         ///   Looks up a localized string similar to Global Address Book. | ||||||
|  |         /// </summary> | ||||||
|  |         internal static string GABSync_Title { | ||||||
|  |             get { | ||||||
|  |                 return ResourceManager.GetString("GABSync_Title", resourceCulture); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///   Looks up a localized resource of type System.Drawing.Icon similar to (Icon). |         ///   Looks up a localized resource of type System.Drawing.Icon similar to (Icon). | ||||||
|         /// </summary> |         /// </summary> | ||||||
|   | |||||||
| @@ -494,4 +494,10 @@ | |||||||
|   <data name="ServerSync_Title" xml:space="preserve"> |   <data name="ServerSync_Title" xml:space="preserve"> | ||||||
|     <value>Server data</value> |     <value>Server data</value> | ||||||
|   </data> |   </data> | ||||||
|  |   <data name="GABSync_Label" xml:space="preserve"> | ||||||
|  |     <value>The global address book is being synchronised.</value> | ||||||
|  |   </data> | ||||||
|  |   <data name="GABSync_Title" xml:space="preserve"> | ||||||
|  |     <value>Global Address Book</value> | ||||||
|  |   </data> | ||||||
| </root> | </root> | ||||||
| @@ -89,6 +89,61 @@ namespace Acacia.UI | |||||||
|             return task.Result; |             return task.Result; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public static ResultType Execute<ResultType>(string resourcePrefix, Func<CancellationToken, CompletionTracker, ResultType> action) | ||||||
|  |         { | ||||||
|  |             // TODO: merge with above | ||||||
|  |  | ||||||
|  |             Logger.Instance.Info(typeof(ProgressDialog), "Opening"); | ||||||
|  |             // Determine the UI context, creating a new one if required | ||||||
|  |             if (SynchronizationContext.Current == null) | ||||||
|  |                 SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext()); | ||||||
|  |             var context = TaskScheduler.FromCurrentSynchronizationContext(); | ||||||
|  |  | ||||||
|  |             // Create the dialog, so it is available for the task | ||||||
|  |             ProgressDialog dlg = new ProgressDialog(); | ||||||
|  |             // Set the strings | ||||||
|  |             dlg.Text = StringUtil.GetResourceString(resourcePrefix + "_Title"); | ||||||
|  |             dlg.labelMessage.Text = StringUtil.GetResourceString(resourcePrefix + "_Label"); | ||||||
|  |  | ||||||
|  |             // Start the task | ||||||
|  |             Exception caught = null; | ||||||
|  |             Task<ResultType> task = null; | ||||||
|  |             // And close the dialog when done | ||||||
|  |             CompletionTracker tracker = new CompletionTracker(() =>  | ||||||
|  |             { | ||||||
|  |                 // This extra step is needed to go back into the thread context | ||||||
|  |                 task.ContinueWith(_ => { dlg._isComplete = true; dlg.DialogResult = DialogResult.OK; }, context); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             task = Task.Factory.StartNew( | ||||||
|  |                 () => | ||||||
|  |                 { | ||||||
|  |                     try | ||||||
|  |                     { | ||||||
|  |                         return action(dlg.cancel.Token, tracker); | ||||||
|  |                     } | ||||||
|  |                     catch (Exception e) | ||||||
|  |                     { | ||||||
|  |                         caught = e; | ||||||
|  |                         return default(ResultType); | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 dlg.cancel.Token); | ||||||
|  |             dlg.task = task; | ||||||
|  |  | ||||||
|  |             // Show the dialog | ||||||
|  |             if (dlg.ShowDialog() != DialogResult.OK) | ||||||
|  |                 return default(ResultType); | ||||||
|  |  | ||||||
|  |             // Rethrow any exception. | ||||||
|  |             // The framework already handles this, but that causes breaks into the debugger | ||||||
|  |             if (caught != null) | ||||||
|  |                 throw caught; | ||||||
|  |  | ||||||
|  |             // Result the result | ||||||
|  |             return task.Result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         private void ProgressDialog_FormClosing(object sender, FormClosingEventArgs e) |         private void ProgressDialog_FormClosing(object sender, FormClosingEventArgs e) | ||||||
|         { |         { | ||||||
|             if (!_isComplete) |             if (!_isComplete) | ||||||
|   | |||||||
| @@ -125,7 +125,7 @@ namespace Acacia.ZPush | |||||||
|  |  | ||||||
|         private static bool IsCustomFolder(IFolder folder) |         private static bool IsCustomFolder(IFolder folder) | ||||||
|         { |         { | ||||||
|             return Features.GAB.FeatureGAB.IsGABContactsFolder(folder); |             return Features.GAB.FeatureGAB.IsGABContactsFolder(folder, null); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private static void HideAllFolders(IStore store) |         private static void HideAllFolders(IStore store) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user