mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
[KOE-24] Added per-account GAB resync and synchronous GAB resync.
This commit is contained in:
parent
c5fcf62e35
commit
edf48b595d
@ -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,16 +378,27 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do the resync
|
// Do the resync
|
||||||
int remaining = _gabsByDomainName.Count;
|
using (completion.Begin())
|
||||||
foreach (GABHandler gab in _gabsByDomainName.Values)
|
|
||||||
{
|
{
|
||||||
CompletionTracker partCompletion = new CompletionTracker(() => OnGabSyncFinished(gab));
|
foreach (GABHandler gab in _gabsByDomainName.Values)
|
||||||
// TODO: merge partCompletion into total completion
|
|
||||||
Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
|
|
||||||
Tasks.Task(partCompletion, this, "FullResync", () =>
|
|
||||||
{
|
{
|
||||||
gab.FullResync(partCompletion);
|
// Check if the gab is appropriate for the accounts
|
||||||
});
|
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);
|
||||||
|
Tasks.Task(partCompletion, this, "FullResync", () =>
|
||||||
|
{
|
||||||
|
gab.FullResync(partCompletion);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -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
|
||||||
@ -340,7 +377,15 @@ namespace Acacia.Features.SyncState
|
|||||||
|
|
||||||
private void ShowSyncState()
|
private void ShowSyncState()
|
||||||
{
|
{
|
||||||
new SyncStateDialog(this).ShowDialog();
|
_dialogOpen = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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)
|
||||||
_featureGAB.FullResync(null, _accounts);
|
{
|
||||||
return false;
|
// Already syncing, resync GAB asynchronously
|
||||||
|
_featureGAB.FullResync(null, _accounts);
|
||||||
|
// Cannot resync again until the dialog is reopened
|
||||||
|
_canResync[(int)ResyncOption.GAB] = 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user