mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
[KOE-24] Partial implementation of sync state display. Committing with disabled feature for backup and to allow build to succeed.
This commit is contained in:
parent
55e4109c8c
commit
1279a62e42
@ -242,6 +242,7 @@
|
||||
<Compile Include="Controls\KUIUtil.cs" />
|
||||
<Compile Include="DebugOptions.cs" />
|
||||
<Compile Include="Features\BCC\FeatureBCC.cs" />
|
||||
<Compile Include="Features\DeliveryReceipts\FeatureDeliveryReceipts.cs" />
|
||||
<Compile Include="Features\FreeBusy\FreeBusyServlet.cs" />
|
||||
<Compile Include="Features\FreeBusy\Servlet.cs" />
|
||||
<Compile Include="Features\SecondaryContacts\FeatureSecondaryContacts.cs" />
|
||||
@ -352,6 +353,7 @@
|
||||
<Compile Include="ZPush\API\SharedFolders\SharedFolder.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\Types.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapException.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapFieldAttribute.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapParameters.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\SharedFoldersAPI.cs" />
|
||||
<Compile Include="Features\SharedFolders\SharedFoldersDialog.cs">
|
||||
@ -652,6 +654,7 @@
|
||||
<Content Include="Resources\Icons\Ribbon_WebMeetings.png" />
|
||||
<Content Include="Resources\Icons\Ribbon_WebMeetings_Small.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
@ -27,11 +27,18 @@ using Acacia.ZPush.API.SharedFolders;
|
||||
using static Acacia.DebugOptions;
|
||||
using Acacia.UI.Outlook;
|
||||
using System.Drawing;
|
||||
using Acacia.ZPush.Connect;
|
||||
using Acacia.ZPush.Connect.Soap;
|
||||
|
||||
// Prevent field assignment warnings
|
||||
#pragma warning disable 0649
|
||||
|
||||
namespace Acacia.Features.SyncState
|
||||
{
|
||||
|
||||
public class FeatureSyncState : FeatureDisabled, FeatureWithRibbon
|
||||
{
|
||||
// TODO: this is largely about progress bars, separate that?
|
||||
private class SyncStateData : DataProvider
|
||||
{
|
||||
private FeatureSyncState _feature;
|
||||
@ -39,7 +46,7 @@ namespace Acacia.Features.SyncState
|
||||
/// <summary>
|
||||
/// Number in range [0,1]
|
||||
/// </summary>
|
||||
private double _syncProgress;
|
||||
private double _syncProgress = 1;
|
||||
public double SyncProgress
|
||||
{
|
||||
get { return _syncProgress; }
|
||||
@ -142,10 +149,12 @@ namespace Acacia.Features.SyncState
|
||||
{
|
||||
_button = RegisterButton(this, "Progress", true, ShowSyncState, ZPushBehaviour.None);
|
||||
_button.DataProvider = new SyncStateData(this);
|
||||
Watcher.Sync.AddTask(this, Name, CheckSyncState);
|
||||
|
||||
|
||||
// Debug timer to increase progress
|
||||
var timer = new System.Windows.Forms.Timer();
|
||||
timer.Interval = 1000;
|
||||
timer.Interval = 15000;
|
||||
timer.Tick += (o, args) =>
|
||||
{
|
||||
SyncStateData data = (SyncStateData)_button.DataProvider;
|
||||
@ -153,9 +162,121 @@ namespace Acacia.Features.SyncState
|
||||
if (val > 1.01)
|
||||
val = 0;
|
||||
data.SyncProgress = val;
|
||||
};
|
||||
timer.Start();
|
||||
|
||||
foreach(ZPushAccount account in Watcher.Accounts.GetAccounts())
|
||||
{
|
||||
CheckSyncState(account);
|
||||
}
|
||||
};
|
||||
//timer.Start();
|
||||
}
|
||||
|
||||
private class DeviceDetails : ISoapSerializable<DeviceDetails.Data>
|
||||
{
|
||||
public class SyncData
|
||||
{
|
||||
public string status;
|
||||
public long total;
|
||||
public long done;
|
||||
public long todo;
|
||||
|
||||
override public string ToString()
|
||||
{
|
||||
return string.Format("{0}: {1}/{2}={3}", status, total, done, todo);
|
||||
}
|
||||
}
|
||||
|
||||
[SoapField]
|
||||
public struct ContentData
|
||||
{
|
||||
[SoapField(1)]
|
||||
public string synckey;
|
||||
|
||||
[SoapField(2)]
|
||||
public int type; // TODO: SyncType
|
||||
|
||||
[SoapField(3)]
|
||||
public string[] flags;
|
||||
|
||||
[SoapField(4)]
|
||||
public SyncData Sync;
|
||||
|
||||
public bool IsSyncing { get { return Sync != null; } }
|
||||
|
||||
[SoapField(5)]
|
||||
public string id; // TODO: backend folder id
|
||||
}
|
||||
|
||||
public struct Data2
|
||||
{
|
||||
public string deviceid;
|
||||
public string devicetype;
|
||||
public string domain;
|
||||
public string deviceuser;
|
||||
public string useragent;
|
||||
public DateTime firstsynctime;
|
||||
public string announcedasversion;
|
||||
public string hierarchyuuid;
|
||||
|
||||
public string asversion;
|
||||
public DateTime lastupdatetime;
|
||||
public string koeversion;
|
||||
public string koebuild;
|
||||
public DateTime koebuilddate;
|
||||
public string[] koecapabilities;
|
||||
public string koegabbackendfolderid;
|
||||
|
||||
public bool changed;
|
||||
public DateTime lastsynctime;
|
||||
public bool hasfolderidmapping;
|
||||
|
||||
public Dictionary<string, ContentData> contentdata;
|
||||
|
||||
// TODO: additionalfolders
|
||||
// TODO: hierarchycache
|
||||
// TODO: useragenthistory
|
||||
}
|
||||
|
||||
public struct Data
|
||||
{
|
||||
public Data2 data;
|
||||
public bool changed;
|
||||
}
|
||||
|
||||
private readonly Data _data;
|
||||
|
||||
public DeviceDetails(Data data)
|
||||
{
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
public Data SoapSerialize()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public Dictionary<string, ContentData> Content
|
||||
{
|
||||
get { return _data.data.contentdata; }
|
||||
}
|
||||
}
|
||||
|
||||
private class GetDeviceDetailsRequest : SoapRequest<DeviceDetails>
|
||||
{
|
||||
}
|
||||
|
||||
private void CheckSyncState(ZPushAccount account)
|
||||
{
|
||||
// TODO: we probably want one invocation for all accounts
|
||||
using (ZPushConnection connection = account.Connect())
|
||||
using (ZPushWebServiceDevice deviceService = connection.DeviceService)
|
||||
{
|
||||
// Fetch
|
||||
DeviceDetails details = deviceService.Execute(new GetDeviceDetailsRequest());
|
||||
|
||||
foreach(KeyValuePair<string, DeviceDetails.ContentData> cd in details.Content)
|
||||
Logger.Instance.Trace(this, "SYNC: {0}: {1}: {2} -- {3}", cd.Key, cd.Value.IsSyncing, cd.Value.Sync, cd.Value.synckey);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSyncState()
|
||||
|
@ -35,10 +35,10 @@ namespace Acacia.ZPush.API.SharedFolders
|
||||
/// </summary>
|
||||
public struct SoapData
|
||||
{
|
||||
public SyncId ServerId;
|
||||
public SyncId ParentId;
|
||||
public string DisplayName;
|
||||
public OutlookConstants.SyncType Type;
|
||||
public SyncId serverid;
|
||||
public SyncId parentid;
|
||||
public string displayname;
|
||||
public OutlookConstants.SyncType type;
|
||||
public BackendId BackendId;
|
||||
|
||||
// TODO: are there ever flags on available folders? They are sent by the server
|
||||
@ -71,12 +71,12 @@ namespace Acacia.ZPush.API.SharedFolders
|
||||
|
||||
#region Ids and properties
|
||||
|
||||
public SyncId ServerId { get { return _data.ServerId; } }
|
||||
public SyncId ParentId { get { return _data.ParentId; } }
|
||||
public SyncId ServerId { get { return _data.serverid; } }
|
||||
public SyncId ParentId { get { return _data.parentid; } }
|
||||
public BackendId ParentIdAsBackend { get { return Parent?.BackendId ?? BackendId.NONE; } }
|
||||
public BackendId BackendId { get { return _data.BackendId; } }
|
||||
|
||||
public string Name { get { return _data.DisplayName; } }
|
||||
public string Name { get { return _data.displayname; } }
|
||||
|
||||
public string DefaultName
|
||||
{
|
||||
@ -90,7 +90,7 @@ namespace Acacia.ZPush.API.SharedFolders
|
||||
}
|
||||
}
|
||||
|
||||
public OutlookConstants.SyncType Type { get { return _data.Type; } }
|
||||
public OutlookConstants.SyncType Type { get { return _data.type; } }
|
||||
|
||||
public GABUser Store { get; private set; }
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.ZPush.Connect.Soap
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies a Soap field id for a field. If used, the class must also be annotated with SoapField.
|
||||
/// </summary>
|
||||
public class SoapFieldAttribute : Attribute
|
||||
{
|
||||
public object FieldId { get; set; }
|
||||
|
||||
public SoapFieldAttribute(object fieldId = null)
|
||||
{
|
||||
this.FieldId = fieldId;
|
||||
}
|
||||
}
|
||||
}
|
@ -167,33 +167,38 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
return node.InnerText.ToLower().Equals("true");
|
||||
}
|
||||
}
|
||||
private class TypeHandlerInt : TypeHandler
|
||||
|
||||
abstract private class TypeHandlerIntegral : TypeHandler
|
||||
{
|
||||
public TypeHandlerIntegral(string xmlns, string name, Type baseType) : base(xmlns, name, baseType)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(string name, object value, StringBuilder s)
|
||||
{
|
||||
s.Append(string.Format("<{0} xsi:type=\"xsd:int\">{1}</{0}>", name, value));
|
||||
}
|
||||
|
||||
protected override object DeserializeContents(XmlNode node, Type expectedType)
|
||||
{
|
||||
long value = long.Parse(node.InnerText);
|
||||
if (expectedType == typeof(DateTime))
|
||||
{
|
||||
// TODO: make a util function for this?
|
||||
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
return origin.AddSeconds(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeHandlerInt : TypeHandlerIntegral
|
||||
{
|
||||
public TypeHandlerInt() : base(SoapConstants.XMLNS_XSD, null, typeof(int)) { }
|
||||
|
||||
public override void Serialize(string name, object value, StringBuilder s)
|
||||
{
|
||||
s.Append(string.Format("<{0} xsi:type=\"xsd:int\">{1}</{0}>", name, value));
|
||||
}
|
||||
|
||||
protected override object DeserializeContents(XmlNode node, Type expectedType)
|
||||
{
|
||||
return long.Parse(node.InnerText);
|
||||
}
|
||||
}
|
||||
private class TypeHandlerLong : TypeHandler
|
||||
private class TypeHandlerLong : TypeHandlerIntegral
|
||||
{
|
||||
public TypeHandlerLong() : base(SoapConstants.XMLNS_XSD, "int", typeof(long)) { }
|
||||
|
||||
public override void Serialize(string name, object value, StringBuilder s)
|
||||
{
|
||||
s.Append(string.Format("<{0} xsi:type=\"xsd:int\">{1}</{0}>", name, value));
|
||||
}
|
||||
|
||||
protected override object DeserializeContents(XmlNode node, Type expectedType)
|
||||
{
|
||||
return long.Parse(node.InnerText);
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeHandlerString : TypeHandler
|
||||
@ -221,18 +226,37 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
|
||||
protected override object DeserializeContents(XmlNode node, Type expectedType)
|
||||
{
|
||||
// Create a list instance
|
||||
if (expectedType == null)
|
||||
return null;
|
||||
|
||||
if (expectedType.IsArray)
|
||||
{
|
||||
// Decode into array
|
||||
Array array = Array.CreateInstance(expectedType.GetElementType(), node.ChildNodes.Count);
|
||||
int index = 0;
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
object element = DeserializeNode(child, expectedType.GetElementType());
|
||||
array.SetValue(element, index);
|
||||
++index;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Decode into list
|
||||
System.Collections.IList list = (System.Collections.IList)Activator.CreateInstance(expectedType);
|
||||
Type entryType = expectedType.GetGenericArguments()[0];
|
||||
Type elementType = expectedType.GetGenericArguments()[0];
|
||||
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
object element = DeserializeNode(child, entryType);
|
||||
object element = DeserializeNode(child, elementType);
|
||||
list.Add(element);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(string name, object value, StringBuilder s)
|
||||
{
|
||||
@ -260,6 +284,9 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
|
||||
protected override object DeserializeContents(XmlNode node, Type expectedType)
|
||||
{
|
||||
if (expectedType == null)
|
||||
return null;
|
||||
|
||||
// Determine if the expected type is an ISoapSerializable
|
||||
if (!typeof(ISoapSerializable<>).IsGenericAssignableFrom(expectedType))
|
||||
{
|
||||
@ -294,8 +321,9 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
object instance = Activator.CreateInstance(serializationType);
|
||||
foreach (FieldInfo field in serializationType.GetFields())
|
||||
{
|
||||
string key = field.GetCustomAttribute<SoapFieldAttribute>()?.FieldId?.ToString() ?? field.Name;
|
||||
object value = null;
|
||||
if (node.TryGetValue(field.Name.ToLower(), out value))
|
||||
if (node.TryGetValue(key, out value))
|
||||
{
|
||||
value = SoapConvert(field.FieldType, value);
|
||||
field.SetValue(instance, value);
|
||||
@ -352,11 +380,13 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
if (type == null)
|
||||
return null;
|
||||
|
||||
// Check if the field is a simple field name
|
||||
FieldInfo prop = type.GetField(field);
|
||||
if (prop == null)
|
||||
return null;
|
||||
if (prop == null && type.GetCustomAttribute<SoapFieldAttribute>() != null)
|
||||
// Check for an attriubte
|
||||
prop = type.GetFields().FirstOrDefault(f => f.GetCustomAttribute<SoapFieldAttribute>()?.FieldId?.ToString() == field);
|
||||
|
||||
return prop.FieldType;
|
||||
return prop?.FieldType;
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,7 +401,7 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
{
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
string key = child.Name.ToLower();
|
||||
string key = child.Name;
|
||||
object value = DeserializeNode(child, DetermineChildType(expectedType, key));
|
||||
dict.Add(key, value);
|
||||
}
|
||||
@ -396,7 +426,8 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
foreach (XmlNode child in node.ChildNodes)
|
||||
{
|
||||
string key = (string)DeserializeNode(child.SelectSingleNode("key"), typeof(string));
|
||||
object value = DeserializeNode(child.SelectSingleNode("value"), DetermineChildType(expectedType, key));
|
||||
Type childType = DetermineChildType(expectedType, key);
|
||||
object value = DeserializeNode(child.SelectSingleNode("value"), childType);
|
||||
dict.Add(key, value);
|
||||
}
|
||||
}
|
||||
@ -494,7 +525,7 @@ namespace Acacia.ZPush.Connect.Soap
|
||||
|
||||
XmlAttribute typeAttr = part.Attributes["type", SoapConstants.XMLNS_XSI];
|
||||
if (typeAttr == null)
|
||||
throw new Exception("Missing type");
|
||||
throw new Exception("Missing type: " + part.OuterXml);
|
||||
string value = typeAttr.Value;
|
||||
string[] parts = value.Split(new char[] { ':' }, 2);
|
||||
string fullName;
|
||||
|
@ -86,6 +86,7 @@ namespace Acacia.ZPush.Connect
|
||||
{
|
||||
SoapParameters parameters = new SoapParameters();
|
||||
parameters.Add("devid", _connection.Account.Account.DeviceId.ToLower());
|
||||
//parameters.Add("deviceId", _connection.Account.Account.DeviceId.ToLower());
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ namespace Acacia.ZPush
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
Logger.Instance.Trace(this, "Unwatching folder: {0}", _folder.Name);
|
||||
Logger.Instance.Trace(this, "Unwatching folder"); // Cannot log name, as folder is now invalid
|
||||
// The events need to be unhooked explicitly, otherwise we get double notifications if a folder is moved
|
||||
HookEvents(false);
|
||||
foreach (ZPushFolder child in _children.Values)
|
||||
|
Loading…
Reference in New Issue
Block a user