-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathConnectionTracker.cs
More file actions
184 lines (165 loc) · 7.65 KB
/
ConnectionTracker.cs
File metadata and controls
184 lines (165 loc) · 7.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* By David Barrett, Microsoft Ltd. 2022. Use at your own risk. No warranties are given.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* */
using System;
using System.Linq;
using System.Text;
using Microsoft.Exchange.WebServices.Data;
namespace EWSStreamingNotificationSample
{
internal class ConnectionTracker
{
public string GroupName { get; internal set; }
public string AnchorMailbox { get; internal set; }
public string BackEndOverrideCookie { get; internal set; }
public StreamingSubscriptionConnection StreamingSubscriptionConnection { get; internal set; }
private ExchangeService _exchangeService;
/// <summary>
/// Lifetime for the streaming connection
/// </summary>
public static int ConnectionLifetime = 5;
/// <summary>
/// The number of open connections
/// </summary>
public static int TotalOpenConnections = 0;
public ConnectionTracker(string GroupName)
{
this.GroupName = GroupName;
}
public bool IsConnected
{
get
{
if (StreamingSubscriptionConnection != null)
return StreamingSubscriptionConnection.IsOpen;
return false;
}
}
public ExchangeService ExchangeService
{
get { return _exchangeService; }
}
public void SetBackendOverrideCookie(string cookieValue)
{
BackEndOverrideCookie = cookieValue;
}
/// <summary>
/// Adds the subscription to this connection
/// </summary>
/// <param name="subscriptionTracker">The SubscriptionTracker object containing the subscription information</param>
/// <returns>True if successful, otherwise false</returns>
public bool AddSubscription(SubscriptionTracker subscriptionTracker)
{
if (_exchangeService == null)
return false;
if (subscriptionTracker.Subscription == null)
{
Logger.DefaultLogger?.Log($"Add subscription failed (subscription not found): {subscriptionTracker.SMTPAddress}");
return false;
}
if (this.StreamingSubscriptionConnection == null)
{
// Ensure the connection lifetime is not longer than the OAuth access token validity period
//int lifeTime = (int)Utils.CredentialHandler.TimeUntilAccessTokenExpires().TotalMinutes;
//if (ConnectionLifetime<lifeTime)
// lifeTime = ConnectionLifetime;
//
// Turns out this is pointless as you can't set Lifetime on GetEvents with the EWS API, you can only set it when you first create the StreamingSubscriptionConnection.
// In practise it doesn't matter too much as an error will occur if the token expires, and renewal/reconnection will be triggered at that point.
// It would be neater if we could control lifetime on GetEvents and sync with OAuth token renewal, but that would require modification of the EWS API.
//
this.StreamingSubscriptionConnection = new StreamingSubscriptionConnection(_exchangeService, ConnectionLifetime);
StreamingSubscriptionConnection.OnDisconnect += StreamingSubscriptionConnection_OnDisconnect;
}
StreamingSubscriptionConnection.AddSubscription(subscriptionTracker.Subscription);
return true;
}
/// <summary>
/// Configure the supplied SubscriptionTracker (applies group AnchorMailbox)
/// </summary>
/// <param name="subscriptionTracker">The SubscriptionTracker to be configured</param>
public void ConfigureSubscription(SubscriptionTracker subscriptionTracker)
{
subscriptionTracker.Connection = this;
if (_exchangeService == null)
{
// This is the first subscription to be configured, and so becomes the anchor mailbox
if (String.IsNullOrEmpty(AnchorMailbox))
AnchorMailbox = subscriptionTracker.SMTPAddress;
if (String.IsNullOrEmpty(subscriptionTracker.AnchorMailbox))
subscriptionTracker.AnchorMailbox = AnchorMailbox;
_exchangeService = Utils.NewExchangeService(subscriptionTracker.SMTPAddress, subscriptionTracker.EwsUrl, subscriptionTracker.AnchorMailbox);
Logger.DefaultLogger?.Log($"ExchangeService created for {GroupName}, anchor mailbox {AnchorMailbox}");
}
if (String.IsNullOrEmpty(subscriptionTracker.AnchorMailbox))
subscriptionTracker.AnchorMailbox = AnchorMailbox;
if (!String.IsNullOrEmpty(BackEndOverrideCookie))
{
_exchangeService.CookieContainer.Add(_exchangeService.Url, new System.Net.Cookie("X-BackEndOverrideCookie", BackEndOverrideCookie));
}
}
private void StreamingSubscriptionConnection_OnDisconnect(object sender, SubscriptionErrorEventArgs args)
{
// Handle OnDisconnect event
TotalOpenConnections--;
StringBuilder log = new StringBuilder("OnDisconnect received");
try
{
// If Subscription is null, then the error applies to the whole connection (this is the usual case)
if (args.Subscription != null)
log.Append($" for {args.Subscription.Service.ImpersonatedUserId.Id}");
if (args.Exception != null)
log.Append($" with error {args.Exception.Message}");
}
catch { }
//Logger.DefaultLogger?.Log(log.ToString());
}
/// <summary>
/// Connect to the subscriptions and start receiving events
/// </summary>
public bool Connect()
{
if (_exchangeService == null || StreamingSubscriptionConnection == null || StreamingSubscriptionConnection.CurrentSubscriptions.Count()<1)
return false;
try
{
Utils.CredentialHandler?.ApplyCredentialsToExchangeService(_exchangeService);
Utils.SetClientRequestId(_exchangeService);
_exchangeService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, AnchorMailbox);
StreamingSubscriptionConnection.Open();
Logger.DefaultLogger?.Log($"Opened connection: {GroupName}");
TotalOpenConnections++;
return true;
}
catch (Exception ex)
{
Logger.DefaultLogger?.Log($"Failed to connect {GroupName}: {ex.Message}");
}
return false;
}
/// <summary>
/// Disconnect from subscriptions (stop receiving events)
/// </summary>
public void Disconnect()
{
if (!IsConnected)
return;
try
{
StreamingSubscriptionConnection.Close();
}
catch (Exception ex)
{
Logger.DefaultLogger?.Log($"Failed to close connection {GroupName}: {ex.Message}");
}
}
}
}