-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathBackgroundDifferenceLoader.cs
executable file
·278 lines (230 loc) · 9.99 KB
/
BackgroundDifferenceLoader.cs
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
//
// This is the source code of Telegram for Windows Phone v. 3.x.x.
// It is licensed under GNU GPL v. 2 or later.
// You should have received a copy of the license in this archive (see LICENSE).
//
// Copyright Evgeny Nadymov, 2013-present.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Windows.ApplicationModel.Background;
using Telegram.Api;
using Telegram.Api.Aggregator;
using Telegram.Api.Helpers;
using Telegram.Api.Extensions;
using Telegram.Api.Services;
using Telegram.Api.Services.Cache;
using Telegram.Api.Services.Connection;
using Telegram.Api.Services.DeviceInfo;
using Telegram.Api.Services.Updates;
using Telegram.Api.TL;
using Telegram.Api.Transport;
namespace TelegramClient.Tasks
{
public sealed class BackgroundDifferenceLoader : IBackgroundTask
{
private readonly Mutex _appOpenMutex = new Mutex(false, Constants.TelegramMessengerMutexName);
private static bool _logEnabled = true;
private static void Log(string message, Action callback = null)
{
if (!_logEnabled) return;
Telegram.Logs.Log.Write(string.Format("::BackgroundDifferenceLoader {0} {1}", _id, message), callback.SafeInvoke);
#if DEBUG
//PushUtils.AddToast("difference", string.Format("{0} {1}", _id, message), string.Empty, string.Empty, null, null);
#endif
}
private static readonly int _id = new Random().Next(999);
private TLInitConnection GetInitConnection()
{
return TLUtils.OpenObjectFromMTProtoFile<TLInitConnection>(_initConnectionSyncRoot, Constants.InitConnectionFileName) ??
new TLInitConnection
{
DeviceModel = new TLString("unknown"),
AppVersion = new TLString("background task"),
SystemVersion = new TLString("8.10.0.0")
};
}
public void Run(IBackgroundTaskInstance taskInstance)
{
Telegram.Logs.Log.WriteSync = true;
var stopwatch = Stopwatch.StartNew();
if (!_appOpenMutex.WaitOne(0))
{
Log("cancel");
return;
}
_appOpenMutex.ReleaseMutex();
var isAuthorized = SettingsHelper.GetValue<bool>(Constants.IsAuthorizedKey);
if (!isAuthorized)
{
Log("cancel isAuthorized=false");
}
var deferral = taskInstance.GetDeferral();
RunAsync(() =>
{
Log(string.Format("stop elapsed={0}", stopwatch.Elapsed));
deferral.Complete();
});
}
private readonly object _stateRoot = new object();
private readonly object _initConnectionSyncRoot = new object();
private void RunAsync(Action callback)
{
var deviceInfoService = new DeviceInfoService(GetInitConnection(), true, "BackgroundDifferenceLoader", _id);
var eventAggregator = new TelegramEventAggregator();
var cacheService = new InMemoryCacheService(eventAggregator);
var updatesService = new UpdatesService(cacheService, eventAggregator);
var transportService = new TransportService();
var connectionService = new ConnectionService(deviceInfoService);
var publicConfigService = new MockupPublicConfigService();
var manualResetEvent = new ManualResetEvent(false);
var mtProtoService = new MTProtoService(deviceInfoService, updatesService, cacheService, transportService, connectionService, publicConfigService);
mtProtoService.Initialized += (o, e) =>
{
var lastTime = TLUtils.OpenObjectFromMTProtoFile<TLInt>(_differenceTimeSyncRoot, Constants.DifferenceTimeFileName);
if (lastTime != null)
{
var now = TLUtils.DateToUniversalTimeTLInt(mtProtoService.ClientTicksDelta, DateTime.Now);
if (lastTime.Value + Constants.DifferenceMinInterval > now.Value)
{
manualResetEvent.Set();
return;
}
}
var clientState = TLUtils.OpenObjectFromMTProtoFile<TLState>(_stateRoot, Constants.StateFileName);
_results = TLUtils.OpenObjectFromMTProtoFile<TLVector<TLDifference>>(_differenceFileSyncRoot, Constants.DifferenceFileName) ?? new TLVector<TLDifference>();
var state = GetState(clientState, _results);
if (state != null)
{
GetDifferenceAsync(mtProtoService, state, () => manualResetEvent.Set());
}
else
{
manualResetEvent.Set();
}
};
mtProtoService.InitializationFailed += (o, e) =>
{
manualResetEvent.Set();
};
mtProtoService.Initialize();
#if DEBUG
manualResetEvent.WaitOne(15000);
#else
manualResetEvent.WaitOne(15000);
#endif
callback.SafeInvoke();
}
private static TLState GetState(TLState clientState, TLVector<TLDifference> results)
{
var state = clientState;
for (var i = 0; i < results.Count; i++)
{
var difference = results[i];
if (difference != null)
{
if (difference.State.Pts.Value < clientState.Pts.Value)
{
results.RemoveAt(i--);
continue;
}
if (difference.State.Pts.Value > state.Pts.Value)
{
state = difference.State;
}
}
}
return state;
}
private void GetDifferenceAsync(IMTProtoService mtProtoService, TLState state, Action callback)
{
Log(string.Format("get_diff [{0}]", state));
mtProtoService.GetDifferenceWithoutUpdatesAsync(state.Pts, state.Date, state.Qts,
result =>
{
var now = TLUtils.DateToUniversalTimeTLInt(mtProtoService.ClientTicksDelta, DateTime.Now);
TLUtils.SaveObjectToMTProtoFile(_differenceTimeSyncRoot, Constants.DifferenceTimeFileName, now);
var differenceEmpty = result as TLDifferenceEmpty;
if (differenceEmpty != null)
{
Log(string.Format("diff_empty date={0} seq={1}", differenceEmpty.Date, differenceEmpty.Seq));
//DeleteFile();
callback.SafeInvoke();
}
var difference = result as TLDifference;
if (difference != null)
{
SaveToFile(difference);
var differenceSlice = result as TLDifferenceSlice;
if (differenceSlice != null)
{
Log(string.Format("diff_slice [{0}]", differenceSlice.State));
GetDifferenceAsync(mtProtoService, differenceSlice.State, callback);
}
else
{
Log(string.Format("diff [{0}]", difference.State));
callback.SafeInvoke();
}
}
},
error =>
{
Log(string.Format("diff_error={0}\n{1}", error, error.Exception));
callback.SafeInvoke();
});
}
private readonly object _differenceFileSyncRoot = new object();
private readonly object _differenceTimeSyncRoot = new object();
private TLVector<TLDifference> _results;
private void SaveToFile(TLDifference result)
{
if (result == null) return;
AddResult(_results, result);
TLUtils.SaveObjectToMTProtoFile(_differenceFileSyncRoot, Constants.DifferenceFileName, _results);
}
private void AddResult(TLVector<TLDifference> results, TLDifference result)
{
if (results.Count > 0)
{
var firstResult = results.FirstOrDefault();
var usersCache = new Dictionary<int, TLUserBase>();
var chatsCache = new Dictionary<int, TLChatBase>();
foreach (var user in firstResult.Users)
{
usersCache[user.Index] = user;
}
foreach (var chat in firstResult.Chats)
{
chatsCache[chat.Index] = chat;
}
foreach (var user in result.Users)
{
usersCache[user.Index] = user;
}
foreach (var chat in result.Chats)
{
chatsCache[chat.Index] = chat;
}
result.Users = new TLVector<TLUserBase>();
result.Chats = new TLVector<TLChatBase>();
var users = new TLVector<TLUserBase>();
foreach (var user in usersCache.Values)
{
users.Add(user);
}
firstResult.Users = users;
var chats = new TLVector<TLChatBase>();
foreach (var chat in chatsCache.Values)
{
chats.Add(chat);
}
firstResult.Chats = chats;
}
_results.Add(result);
}
}
}