root / trunk / Pithos.Core / PithosMonitor.cs @ 8f44fd3a
History | View | Annotate | Download (19.8 kB)
1 | 255f5f86 | Panagiotis Kanavos | #region |
---|---|---|---|
2 | 255f5f86 | Panagiotis Kanavos | /* ----------------------------------------------------------------------- |
3 | 255f5f86 | Panagiotis Kanavos | * <copyright file="PithosMonitor.cs" company="GRNet"> |
4 | 255f5f86 | Panagiotis Kanavos | * |
5 | 255f5f86 | Panagiotis Kanavos | * Copyright 2011-2012 GRNET S.A. All rights reserved. |
6 | 255f5f86 | Panagiotis Kanavos | * |
7 | 255f5f86 | Panagiotis Kanavos | * Redistribution and use in source and binary forms, with or |
8 | 255f5f86 | Panagiotis Kanavos | * without modification, are permitted provided that the following |
9 | 255f5f86 | Panagiotis Kanavos | * conditions are met: |
10 | 255f5f86 | Panagiotis Kanavos | * |
11 | 255f5f86 | Panagiotis Kanavos | * 1. Redistributions of source code must retain the above |
12 | 255f5f86 | Panagiotis Kanavos | * copyright notice, this list of conditions and the following |
13 | 255f5f86 | Panagiotis Kanavos | * disclaimer. |
14 | 255f5f86 | Panagiotis Kanavos | * |
15 | 255f5f86 | Panagiotis Kanavos | * 2. Redistributions in binary form must reproduce the above |
16 | 255f5f86 | Panagiotis Kanavos | * copyright notice, this list of conditions and the following |
17 | 255f5f86 | Panagiotis Kanavos | * disclaimer in the documentation and/or other materials |
18 | 255f5f86 | Panagiotis Kanavos | * provided with the distribution. |
19 | 255f5f86 | Panagiotis Kanavos | * |
20 | 255f5f86 | Panagiotis Kanavos | * |
21 | 255f5f86 | Panagiotis Kanavos | * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
22 | 255f5f86 | Panagiotis Kanavos | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
23 | 255f5f86 | Panagiotis Kanavos | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | 255f5f86 | Panagiotis Kanavos | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
25 | 255f5f86 | Panagiotis Kanavos | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 | 255f5f86 | Panagiotis Kanavos | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
27 | 255f5f86 | Panagiotis Kanavos | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
28 | 255f5f86 | Panagiotis Kanavos | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
29 | 255f5f86 | Panagiotis Kanavos | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | 255f5f86 | Panagiotis Kanavos | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
31 | 255f5f86 | Panagiotis Kanavos | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | 255f5f86 | Panagiotis Kanavos | * POSSIBILITY OF SUCH DAMAGE. |
33 | 255f5f86 | Panagiotis Kanavos | * |
34 | 255f5f86 | Panagiotis Kanavos | * The views and conclusions contained in the software and |
35 | 255f5f86 | Panagiotis Kanavos | * documentation are those of the authors and should not be |
36 | 255f5f86 | Panagiotis Kanavos | * interpreted as representing official policies, either expressed |
37 | 255f5f86 | Panagiotis Kanavos | * or implied, of GRNET S.A. |
38 | 255f5f86 | Panagiotis Kanavos | * </copyright> |
39 | 255f5f86 | Panagiotis Kanavos | * ----------------------------------------------------------------------- |
40 | 255f5f86 | Panagiotis Kanavos | */ |
41 | 255f5f86 | Panagiotis Kanavos | #endregion |
42 | d78cbf09 | Panagiotis Kanavos | using System; |
43 | d78cbf09 | Panagiotis Kanavos | using System.Collections.Generic; |
44 | d78cbf09 | Panagiotis Kanavos | using System.ComponentModel.Composition; |
45 | d78cbf09 | Panagiotis Kanavos | using System.Diagnostics.Contracts; |
46 | d78cbf09 | Panagiotis Kanavos | using System.IO; |
47 | d78cbf09 | Panagiotis Kanavos | using System.Linq; |
48 | db8a9589 | Panagiotis Kanavos | using System.Reflection; |
49 | d78cbf09 | Panagiotis Kanavos | using System.Threading; |
50 | d78cbf09 | Panagiotis Kanavos | using System.Threading.Tasks; |
51 | 9c4346c9 | Panagiotis Kanavos | using Pithos.Core.Agents; |
52 | d78cbf09 | Panagiotis Kanavos | using Pithos.Interfaces; |
53 | 5ce54458 | Panagiotis Kanavos | using Pithos.Network; |
54 | 5120f3cb | Panagiotis Kanavos | using log4net; |
55 | d78cbf09 | Panagiotis Kanavos | |
56 | d78cbf09 | Panagiotis Kanavos | namespace Pithos.Core |
57 | d78cbf09 | Panagiotis Kanavos | { |
58 | d78cbf09 | Panagiotis Kanavos | [Export(typeof(PithosMonitor))] |
59 | d78cbf09 | Panagiotis Kanavos | public class PithosMonitor:IDisposable |
60 | d78cbf09 | Panagiotis Kanavos | { |
61 | db8a9589 | Panagiotis Kanavos | private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
62 | db8a9589 | Panagiotis Kanavos | |
63 | 5ce54458 | Panagiotis Kanavos | private int _blockSize; |
64 | 5ce54458 | Panagiotis Kanavos | private string _blockHash; |
65 | 5ce54458 | Panagiotis Kanavos | |
66 | d78cbf09 | Panagiotis Kanavos | [Import] |
67 | d78cbf09 | Panagiotis Kanavos | public IPithosSettings Settings{get;set;} |
68 | d78cbf09 | Panagiotis Kanavos | |
69 | 4ec636f6 | Panagiotis Kanavos | private IStatusKeeper _statusKeeper; |
70 | 4ec636f6 | Panagiotis Kanavos | |
71 | d78cbf09 | Panagiotis Kanavos | [Import] |
72 | 4ec636f6 | Panagiotis Kanavos | public IStatusKeeper StatusKeeper |
73 | 4ec636f6 | Panagiotis Kanavos | { |
74 | 4ec636f6 | Panagiotis Kanavos | get { return _statusKeeper; } |
75 | 4ec636f6 | Panagiotis Kanavos | set |
76 | 4ec636f6 | Panagiotis Kanavos | { |
77 | 4ec636f6 | Panagiotis Kanavos | _statusKeeper = value; |
78 | 4ec636f6 | Panagiotis Kanavos | FileAgent.StatusKeeper = value; |
79 | 4ec636f6 | Panagiotis Kanavos | } |
80 | 4ec636f6 | Panagiotis Kanavos | } |
81 | 4ec636f6 | Panagiotis Kanavos | |
82 | 4ec636f6 | Panagiotis Kanavos | |
83 | 4ec636f6 | Panagiotis Kanavos | private IPithosWorkflow _workflow; |
84 | d78cbf09 | Panagiotis Kanavos | |
85 | d78cbf09 | Panagiotis Kanavos | [Import] |
86 | 4ec636f6 | Panagiotis Kanavos | public IPithosWorkflow Workflow |
87 | 4ec636f6 | Panagiotis Kanavos | { |
88 | 4ec636f6 | Panagiotis Kanavos | get { return _workflow; } |
89 | 4ec636f6 | Panagiotis Kanavos | set |
90 | 4ec636f6 | Panagiotis Kanavos | { |
91 | 4ec636f6 | Panagiotis Kanavos | _workflow = value; |
92 | 4ec636f6 | Panagiotis Kanavos | FileAgent.Workflow = value; |
93 | 4ec636f6 | Panagiotis Kanavos | } |
94 | 4ec636f6 | Panagiotis Kanavos | } |
95 | d78cbf09 | Panagiotis Kanavos | |
96 | d78cbf09 | Panagiotis Kanavos | public ICloudClient CloudClient { get; set; } |
97 | d78cbf09 | Panagiotis Kanavos | |
98 | 0c02aa65 | Panagiotis Kanavos | public IStatusNotification StatusNotification { get; set; } |
99 | 0c02aa65 | Panagiotis Kanavos | |
100 | 4ec636f6 | Panagiotis Kanavos | //[Import] |
101 | 4ec636f6 | Panagiotis Kanavos | public FileAgent FileAgent { get; private set; } |
102 | 4ec636f6 | Panagiotis Kanavos | |
103 | 4ec636f6 | Panagiotis Kanavos | private WorkflowAgent _workflowAgent; |
104 | 4ec636f6 | Panagiotis Kanavos | |
105 | 9c4346c9 | Panagiotis Kanavos | [Import] |
106 | 4ec636f6 | Panagiotis Kanavos | public WorkflowAgent WorkflowAgent |
107 | 4ec636f6 | Panagiotis Kanavos | { |
108 | 4ec636f6 | Panagiotis Kanavos | get { return _workflowAgent; } |
109 | 4ec636f6 | Panagiotis Kanavos | set |
110 | 4ec636f6 | Panagiotis Kanavos | { |
111 | 4ec636f6 | Panagiotis Kanavos | _workflowAgent = value; |
112 | 4ec636f6 | Panagiotis Kanavos | FileAgent.WorkflowAgent = value; |
113 | 4ec636f6 | Panagiotis Kanavos | } |
114 | 4ec636f6 | Panagiotis Kanavos | } |
115 | 9c4346c9 | Panagiotis Kanavos | |
116 | 9c4346c9 | Panagiotis Kanavos | [Import] |
117 | aa7ac00e | Panagiotis Kanavos | public NetworkAgent NetworkAgent { get; set; } |
118 | aa7ac00e | Panagiotis Kanavos | [Import] |
119 | aa7ac00e | Panagiotis Kanavos | public PollAgent PollAgent { get; set; } |
120 | 9c4346c9 | Panagiotis Kanavos | |
121 | 0eea575a | Panagiotis Kanavos | public string UserName { get; set; } |
122 | c92e02f3 | Panagiotis Kanavos | private string _apiKey; |
123 | c92e02f3 | Panagiotis Kanavos | public string ApiKey |
124 | c92e02f3 | Panagiotis Kanavos | { |
125 | c92e02f3 | Panagiotis Kanavos | get { return _apiKey; } |
126 | c92e02f3 | Panagiotis Kanavos | set |
127 | c92e02f3 | Panagiotis Kanavos | { |
128 | c92e02f3 | Panagiotis Kanavos | _apiKey = value; |
129 | c92e02f3 | Panagiotis Kanavos | if (_accountInfo != null) |
130 | c92e02f3 | Panagiotis Kanavos | _accountInfo.Token = value; |
131 | c92e02f3 | Panagiotis Kanavos | } |
132 | c92e02f3 | Panagiotis Kanavos | } |
133 | 0eea575a | Panagiotis Kanavos | |
134 | 0bd56b7c | Panagiotis Kanavos | private AccountInfo _accountInfo; |
135 | c53aa229 | Panagiotis Kanavos | |
136 | eeee29e3 | Panagiotis Kanavos | |
137 | db8a9589 | Panagiotis Kanavos | |
138 | db8a9589 | Panagiotis Kanavos | |
139 | 5120f3cb | Panagiotis Kanavos | |
140 | d78cbf09 | Panagiotis Kanavos | |
141 | d78cbf09 | Panagiotis Kanavos | public bool Pause |
142 | d78cbf09 | Panagiotis Kanavos | { |
143 | 5ce54458 | Panagiotis Kanavos | get { return FileAgent.Pause; } |
144 | d78cbf09 | Panagiotis Kanavos | set |
145 | d78cbf09 | Panagiotis Kanavos | { |
146 | 5ce54458 | Panagiotis Kanavos | FileAgent.Pause = value; |
147 | d78cbf09 | Panagiotis Kanavos | } |
148 | d78cbf09 | Panagiotis Kanavos | } |
149 | d78cbf09 | Panagiotis Kanavos | |
150 | c28a075a | Panagiotis Kanavos | private string _rootPath; |
151 | c28a075a | Panagiotis Kanavos | public string RootPath |
152 | c28a075a | Panagiotis Kanavos | { |
153 | c28a075a | Panagiotis Kanavos | get { return _rootPath; } |
154 | 7e26c075 | Panagiotis Kanavos | set |
155 | c28a075a | Panagiotis Kanavos | { |
156 | 7e26c075 | Panagiotis Kanavos | _rootPath = String.IsNullOrWhiteSpace(value) |
157 | 7e26c075 | Panagiotis Kanavos | ? String.Empty |
158 | 7e26c075 | Panagiotis Kanavos | : value.ToLower(); |
159 | c28a075a | Panagiotis Kanavos | } |
160 | c28a075a | Panagiotis Kanavos | } |
161 | 0eea575a | Panagiotis Kanavos | |
162 | d78cbf09 | Panagiotis Kanavos | |
163 | d78cbf09 | Panagiotis Kanavos | CancellationTokenSource _cancellationSource; |
164 | d78cbf09 | Panagiotis Kanavos | |
165 | 4ec636f6 | Panagiotis Kanavos | public PithosMonitor() |
166 | 4ec636f6 | Panagiotis Kanavos | { |
167 | 5d7b20e8 | Panagiotis Kanavos | FileAgent = new FileAgent(); |
168 | 4ec636f6 | Panagiotis Kanavos | } |
169 | 7e26c075 | Panagiotis Kanavos | private bool _started; |
170 | d78cbf09 | Panagiotis Kanavos | |
171 | d78cbf09 | Panagiotis Kanavos | public void Start() |
172 | c53aa229 | Panagiotis Kanavos | { |
173 | c53aa229 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(ApiKey)) |
174 | c53aa229 | Panagiotis Kanavos | throw new InvalidOperationException("The ApiKey is empty"); |
175 | c53aa229 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(UserName)) |
176 | c53aa229 | Panagiotis Kanavos | throw new InvalidOperationException("The UserName is empty"); |
177 | c53aa229 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(AuthenticationUrl)) |
178 | c53aa229 | Panagiotis Kanavos | throw new InvalidOperationException("The Authentication url is empty"); |
179 | c53aa229 | Panagiotis Kanavos | Contract.EndContractBlock(); |
180 | c53aa229 | Panagiotis Kanavos | |
181 | 437abfca | Panagiotis Kanavos | //If the account doesn't have a valid path, don't start monitoring but don't throw either |
182 | 437abfca | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(RootPath)) |
183 | 437abfca | Panagiotis Kanavos | //TODO; Warn user? |
184 | 437abfca | Panagiotis Kanavos | return; |
185 | 437abfca | Panagiotis Kanavos | |
186 | 70f12b36 | Panagiotis Kanavos | WorkflowAgent.StatusNotification = StatusNotification; |
187 | 70f12b36 | Panagiotis Kanavos | |
188 | 0c02aa65 | Panagiotis Kanavos | StatusNotification.NotifyChange("Starting"); |
189 | 7e26c075 | Panagiotis Kanavos | if (_started) |
190 | d78cbf09 | Panagiotis Kanavos | { |
191 | d78cbf09 | Panagiotis Kanavos | if (!_cancellationSource.IsCancellationRequested) |
192 | d78cbf09 | Panagiotis Kanavos | return; |
193 | d78cbf09 | Panagiotis Kanavos | } |
194 | 29672672 | Panagiotis Kanavos | _cancellationSource = new CancellationTokenSource(); |
195 | d78cbf09 | Panagiotis Kanavos | |
196 | 8f44fd3a | pkanavos | lock (this) |
197 | 8f44fd3a | pkanavos | { |
198 | 8f44fd3a | pkanavos | CloudClient = new CloudFilesClient(UserName, ApiKey) |
199 | 8f44fd3a | pkanavos | {UsePithos = true, AuthenticationUrl = AuthenticationUrl}; |
200 | 8f44fd3a | pkanavos | _accountInfo = CloudClient.Authenticate(); |
201 | 8f44fd3a | pkanavos | } |
202 | 23821bd2 | Panagiotis Kanavos | _accountInfo.SiteUri = AuthenticationUrl; |
203 | c53aa229 | Panagiotis Kanavos | _accountInfo.AccountPath = RootPath; |
204 | c53aa229 | Panagiotis Kanavos | |
205 | 5750d7cc | Panagiotis Kanavos | |
206 | 5750d7cc | Panagiotis Kanavos | var pithosFolder = Path.Combine(RootPath, FolderConstants.PithosContainer); |
207 | 5750d7cc | Panagiotis Kanavos | if (!Directory.Exists(pithosFolder)) |
208 | 5750d7cc | Panagiotis Kanavos | Directory.CreateDirectory(pithosFolder); |
209 | 77e10b4f | Panagiotis Kanavos | //Create the cache folder and ensure it is hidden |
210 | 77e10b4f | Panagiotis Kanavos | CreateHiddenFolder(RootPath, FolderConstants.CacheFolder); |
211 | 77e10b4f | Panagiotis Kanavos | |
212 | 0bd56b7c | Panagiotis Kanavos | var policy=CloudClient.GetAccountPolicies(_accountInfo); |
213 | c53aa229 | Panagiotis Kanavos | |
214 | 0bd56b7c | Panagiotis Kanavos | StatusNotification.NotifyAccount(policy); |
215 | 3c43ec9b | Panagiotis Kanavos | EnsurePithosContainers(); |
216 | 9c4346c9 | Panagiotis Kanavos | |
217 | 5ce54458 | Panagiotis Kanavos | StatusKeeper.BlockHash = _blockHash; |
218 | 5ce54458 | Panagiotis Kanavos | StatusKeeper.BlockSize = _blockSize; |
219 | 9c4346c9 | Panagiotis Kanavos | |
220 | 3c43ec9b | Panagiotis Kanavos | StatusKeeper.StartProcessing(_cancellationSource.Token); |
221 | c28a075a | Panagiotis Kanavos | IndexLocalFiles(); |
222 | 759bd3c4 | Panagiotis Kanavos | //Extract the URIs from the string collection |
223 | ebc37b0d | pkanavos | var settings = Settings.Accounts.First(s => s.AccountKey == _accountInfo.AccountKey ); |
224 | fec5da06 | Panagiotis Kanavos | var selectiveUrls=settings.SelectiveFolders.Cast<string>().Select(url => new Uri(url)).ToArray(); |
225 | 759bd3c4 | Panagiotis Kanavos | |
226 | 759bd3c4 | Panagiotis Kanavos | SetSelectivePaths(selectiveUrls,null,null); |
227 | 759bd3c4 | Panagiotis Kanavos | |
228 | c28a075a | Panagiotis Kanavos | StartWatcherAgent(); |
229 | c53aa229 | Panagiotis Kanavos | |
230 | c53aa229 | Panagiotis Kanavos | StartNetworkAgent(); |
231 | 70f12b36 | Panagiotis Kanavos | |
232 | c92e02f3 | Panagiotis Kanavos | WorkflowAgent.RestartInterruptedFiles(_accountInfo); |
233 | c92e02f3 | Panagiotis Kanavos | _started = true; |
234 | 29672672 | Panagiotis Kanavos | } |
235 | 29672672 | Panagiotis Kanavos | |
236 | 3c43ec9b | Panagiotis Kanavos | private void EnsurePithosContainers() |
237 | 3c43ec9b | Panagiotis Kanavos | { |
238 | 3c43ec9b | Panagiotis Kanavos | |
239 | cfed7823 | Panagiotis Kanavos | //Create the two default containers if they are missing |
240 | c53aa229 | Panagiotis Kanavos | var pithosContainers = new List<string>{ FolderConstants.TrashContainer,FolderConstants.PithosContainer}; |
241 | 3c43ec9b | Panagiotis Kanavos | foreach (var container in pithosContainers) |
242 | cfed7823 | Panagiotis Kanavos | { |
243 | c636df1f | Panagiotis Kanavos | var info=CloudClient.GetContainerInfo(UserName, container); |
244 | 5ce54458 | Panagiotis Kanavos | if (info == ContainerInfo.Empty) |
245 | 5ce54458 | Panagiotis Kanavos | { |
246 | c636df1f | Panagiotis Kanavos | CloudClient.CreateContainer(UserName, container); |
247 | c636df1f | Panagiotis Kanavos | info = CloudClient.GetContainerInfo(UserName, container); |
248 | 5ce54458 | Panagiotis Kanavos | } |
249 | 5ce54458 | Panagiotis Kanavos | _blockSize = info.BlockSize; |
250 | 5ce54458 | Panagiotis Kanavos | _blockHash = info.BlockHash; |
251 | c53aa229 | Panagiotis Kanavos | _accountInfo.BlockSize = _blockSize; |
252 | c53aa229 | Panagiotis Kanavos | _accountInfo.BlockHash = _blockHash; |
253 | 3c43ec9b | Panagiotis Kanavos | } |
254 | 3c43ec9b | Panagiotis Kanavos | } |
255 | 3c43ec9b | Panagiotis Kanavos | |
256 | 79736291 | Panagiotis Kanavos | public string AuthenticationUrl { get; set; } |
257 | 79736291 | Panagiotis Kanavos | |
258 | c28a075a | Panagiotis Kanavos | private void IndexLocalFiles() |
259 | b5061ac8 | Panagiotis Kanavos | { |
260 | 6bcdd8e2 | Panagiotis Kanavos | using (ThreadContext.Stacks["Operation"].Push("Indexing local files")) |
261 | b5061ac8 | Panagiotis Kanavos | { |
262 | 174bbb6e | Panagiotis Kanavos | |
263 | 5120f3cb | Panagiotis Kanavos | try |
264 | 5120f3cb | Panagiotis Kanavos | { |
265 | 174bbb6e | Panagiotis Kanavos | //StatusNotification.NotifyChange("Indexing Local Files"); |
266 | 174bbb6e | Panagiotis Kanavos | Log.Info("Start local indexing"); |
267 | 174bbb6e | Panagiotis Kanavos | StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing,"Indexing Local Files"); |
268 | 174bbb6e | Panagiotis Kanavos | |
269 | 77e10b4f | Panagiotis Kanavos | var cachePath = Path.Combine(RootPath, FolderConstants.CacheFolder); |
270 | c28a075a | Panagiotis Kanavos | var directory = new DirectoryInfo(RootPath); |
271 | 5120f3cb | Panagiotis Kanavos | var files = |
272 | 5120f3cb | Panagiotis Kanavos | from file in directory.EnumerateFiles("*", SearchOption.AllDirectories) |
273 | 77e10b4f | Panagiotis Kanavos | where !file.FullName.StartsWith(cachePath, StringComparison.InvariantCultureIgnoreCase) && |
274 | 5120f3cb | Panagiotis Kanavos | !file.Extension.Equals("ignore", StringComparison.InvariantCultureIgnoreCase) |
275 | 5120f3cb | Panagiotis Kanavos | select file; |
276 | 5120f3cb | Panagiotis Kanavos | StatusKeeper.ProcessExistingFiles(files); |
277 | 5120f3cb | Panagiotis Kanavos | |
278 | 5120f3cb | Panagiotis Kanavos | } |
279 | 5120f3cb | Panagiotis Kanavos | catch (Exception exc) |
280 | 5120f3cb | Panagiotis Kanavos | { |
281 | 5120f3cb | Panagiotis Kanavos | Log.Error("[ERROR]", exc); |
282 | 5120f3cb | Panagiotis Kanavos | } |
283 | 5120f3cb | Panagiotis Kanavos | finally |
284 | 5120f3cb | Panagiotis Kanavos | { |
285 | 5120f3cb | Panagiotis Kanavos | Log.Info("[END]"); |
286 | 5120f3cb | Panagiotis Kanavos | } |
287 | 174bbb6e | Panagiotis Kanavos | StatusNotification.SetPithosStatus(PithosStatus.LocalComplete,"Indexing Completed"); |
288 | b5061ac8 | Panagiotis Kanavos | } |
289 | b5061ac8 | Panagiotis Kanavos | } |
290 | b5061ac8 | Panagiotis Kanavos | |
291 | 9c4346c9 | Panagiotis Kanavos | |
292 | c53aa229 | Panagiotis Kanavos | |
293 | eeee29e3 | Panagiotis Kanavos | |
294 | eeee29e3 | Panagiotis Kanavos | |
295 | 70f12b36 | Panagiotis Kanavos | /* private void StartWorkflowAgent() |
296 | 29672672 | Panagiotis Kanavos | { |
297 | 65282d58 | Panagiotis Kanavos | WorkflowAgent.StatusNotification = StatusNotification; |
298 | 65282d58 | Panagiotis Kanavos | |
299 | 65282d58 | Panagiotis Kanavos | /* //On Vista and up we can check for a network connection |
300 | 56b53955 | Panagiotis Kanavos | bool connected=Environment.OSVersion.Version.Major < 6 || NetworkListManager.IsConnectedToInternet; |
301 | 29672672 | Panagiotis Kanavos | //If we are not connected retry later |
302 | 29672672 | Panagiotis Kanavos | if (!connected) |
303 | 29672672 | Panagiotis Kanavos | { |
304 | 9c4346c9 | Panagiotis Kanavos | Task.Factory.StartNewDelayed(10000, StartWorkflowAgent); |
305 | 29672672 | Panagiotis Kanavos | return; |
306 | 70f12b36 | Panagiotis Kanavos | }#1# |
307 | 29672672 | Panagiotis Kanavos | |
308 | 29672672 | Panagiotis Kanavos | try |
309 | 29672672 | Panagiotis Kanavos | { |
310 | 9c4346c9 | Panagiotis Kanavos | WorkflowAgent.Start(); |
311 | 29672672 | Panagiotis Kanavos | } |
312 | 29672672 | Panagiotis Kanavos | catch (Exception) |
313 | 29672672 | Panagiotis Kanavos | { |
314 | 29672672 | Panagiotis Kanavos | //Faild to authenticate due to network or account error |
315 | 29672672 | Panagiotis Kanavos | //Retry after a while |
316 | 9c4346c9 | Panagiotis Kanavos | Task.Factory.StartNewDelayed(10000, StartWorkflowAgent); |
317 | 29672672 | Panagiotis Kanavos | } |
318 | 70f12b36 | Panagiotis Kanavos | }*/ |
319 | d78cbf09 | Panagiotis Kanavos | |
320 | 174bbb6e | Panagiotis Kanavos | |
321 | c53aa229 | Panagiotis Kanavos | private void StartNetworkAgent() |
322 | d78cbf09 | Panagiotis Kanavos | { |
323 | 9c4346c9 | Panagiotis Kanavos | NetworkAgent.StatusNotification = StatusNotification; |
324 | 174bbb6e | Panagiotis Kanavos | |
325 | 174bbb6e | Panagiotis Kanavos | //TODO: The Network and Poll agents are not account specific |
326 | 174bbb6e | Panagiotis Kanavos | //They should be moved outside PithosMonitor |
327 | c53aa229 | Panagiotis Kanavos | NetworkAgent.Start(); |
328 | d78cbf09 | Panagiotis Kanavos | |
329 | fec5da06 | Panagiotis Kanavos | PollAgent.AddAccount(_accountInfo); |
330 | fec5da06 | Panagiotis Kanavos | |
331 | aa7ac00e | Panagiotis Kanavos | PollAgent.StatusNotification = StatusNotification; |
332 | aa7ac00e | Panagiotis Kanavos | |
333 | aa7ac00e | Panagiotis Kanavos | PollAgent.PollRemoteFiles(); |
334 | d78cbf09 | Panagiotis Kanavos | } |
335 | d78cbf09 | Panagiotis Kanavos | |
336 | 77e10b4f | Panagiotis Kanavos | //Make sure a hidden cache folder exists to store partial downloads |
337 | c636df1f | Panagiotis Kanavos | private static void CreateHiddenFolder(string rootPath, string folderName) |
338 | 5ce54458 | Panagiotis Kanavos | { |
339 | 5ce54458 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(rootPath)) |
340 | 5ce54458 | Panagiotis Kanavos | throw new ArgumentNullException("rootPath"); |
341 | 5ce54458 | Panagiotis Kanavos | if (!Path.IsPathRooted(rootPath)) |
342 | 5ce54458 | Panagiotis Kanavos | throw new ArgumentException("rootPath"); |
343 | 5ce54458 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(folderName)) |
344 | 5ce54458 | Panagiotis Kanavos | throw new ArgumentNullException("folderName"); |
345 | 5ce54458 | Panagiotis Kanavos | Contract.EndContractBlock(); |
346 | 5ce54458 | Panagiotis Kanavos | |
347 | 5ce54458 | Panagiotis Kanavos | var folder = Path.Combine(rootPath, folderName); |
348 | 5ce54458 | Panagiotis Kanavos | if (!Directory.Exists(folder)) |
349 | 5ce54458 | Panagiotis Kanavos | { |
350 | 5ce54458 | Panagiotis Kanavos | var info = Directory.CreateDirectory(folder); |
351 | 5ce54458 | Panagiotis Kanavos | info.Attributes |= FileAttributes.Hidden; |
352 | 5ce54458 | Panagiotis Kanavos | |
353 | 77e10b4f | Panagiotis Kanavos | Log.InfoFormat("Created cache Folder: {0}", folder); |
354 | 77e10b4f | Panagiotis Kanavos | } |
355 | 77e10b4f | Panagiotis Kanavos | else |
356 | 77e10b4f | Panagiotis Kanavos | { |
357 | 77e10b4f | Panagiotis Kanavos | var info = new DirectoryInfo(folder); |
358 | 77e10b4f | Panagiotis Kanavos | if ((info.Attributes & FileAttributes.Hidden) == 0) |
359 | 77e10b4f | Panagiotis Kanavos | { |
360 | 77e10b4f | Panagiotis Kanavos | info.Attributes |= FileAttributes.Hidden; |
361 | 77e10b4f | Panagiotis Kanavos | Log.InfoFormat("Reset cache folder to hidden: {0}", folder); |
362 | 77e10b4f | Panagiotis Kanavos | } |
363 | 5ce54458 | Panagiotis Kanavos | } |
364 | 5ce54458 | Panagiotis Kanavos | } |
365 | 5ce54458 | Panagiotis Kanavos | |
366 | b5061ac8 | Panagiotis Kanavos | |
367 | d78cbf09 | Panagiotis Kanavos | |
368 | d78cbf09 | Panagiotis Kanavos | |
369 | c28a075a | Panagiotis Kanavos | private void StartWatcherAgent() |
370 | d78cbf09 | Panagiotis Kanavos | { |
371 | 174bbb6e | Panagiotis Kanavos | if (Log.IsDebugEnabled) |
372 | 174bbb6e | Panagiotis Kanavos | Log.DebugFormat("Start Folder Monitoring [{0}]",RootPath); |
373 | 174bbb6e | Panagiotis Kanavos | |
374 | c28a075a | Panagiotis Kanavos | AgentLocator<FileAgent>.Register(FileAgent,RootPath); |
375 | 5d7b20e8 | Panagiotis Kanavos | |
376 | 5d7b20e8 | Panagiotis Kanavos | FileAgent.IdleTimeout = Settings.FileIdleTimeout; |
377 | 5ce54458 | Panagiotis Kanavos | FileAgent.StatusKeeper = StatusKeeper; |
378 | 174bbb6e | Panagiotis Kanavos | FileAgent.StatusNotification = StatusNotification; |
379 | 5ce54458 | Panagiotis Kanavos | FileAgent.Workflow = Workflow; |
380 | 77e10b4f | Panagiotis Kanavos | FileAgent.CachePath = Path.Combine(RootPath, FolderConstants.CacheFolder); |
381 | c28a075a | Panagiotis Kanavos | FileAgent.Start(_accountInfo, RootPath); |
382 | d78cbf09 | Panagiotis Kanavos | } |
383 | d78cbf09 | Panagiotis Kanavos | |
384 | d78cbf09 | Panagiotis Kanavos | public void Stop() |
385 | c28a075a | Panagiotis Kanavos | { |
386 | c28a075a | Panagiotis Kanavos | AgentLocator<FileAgent>.Remove(RootPath); |
387 | c28a075a | Panagiotis Kanavos | |
388 | c53aa229 | Panagiotis Kanavos | if (FileAgent!=null) |
389 | c53aa229 | Panagiotis Kanavos | FileAgent.Stop(); |
390 | c53aa229 | Panagiotis Kanavos | FileAgent = null; |
391 | d78cbf09 | Panagiotis Kanavos | } |
392 | d78cbf09 | Panagiotis Kanavos | |
393 | eeee29e3 | Panagiotis Kanavos | |
394 | d78cbf09 | Panagiotis Kanavos | ~PithosMonitor() |
395 | d78cbf09 | Panagiotis Kanavos | { |
396 | d78cbf09 | Panagiotis Kanavos | Dispose(false); |
397 | d78cbf09 | Panagiotis Kanavos | } |
398 | d78cbf09 | Panagiotis Kanavos | |
399 | d78cbf09 | Panagiotis Kanavos | public void Dispose() |
400 | d78cbf09 | Panagiotis Kanavos | { |
401 | d78cbf09 | Panagiotis Kanavos | Dispose(true); |
402 | d78cbf09 | Panagiotis Kanavos | GC.SuppressFinalize(this); |
403 | d78cbf09 | Panagiotis Kanavos | } |
404 | d78cbf09 | Panagiotis Kanavos | |
405 | d78cbf09 | Panagiotis Kanavos | protected virtual void Dispose(bool disposing) |
406 | d78cbf09 | Panagiotis Kanavos | { |
407 | d78cbf09 | Panagiotis Kanavos | if (disposing) |
408 | d78cbf09 | Panagiotis Kanavos | { |
409 | d78cbf09 | Panagiotis Kanavos | Stop(); |
410 | d78cbf09 | Panagiotis Kanavos | } |
411 | d78cbf09 | Panagiotis Kanavos | } |
412 | d78cbf09 | Panagiotis Kanavos | |
413 | d78cbf09 | Panagiotis Kanavos | |
414 | 5120f3cb | Panagiotis Kanavos | public void MoveFileStates(string oldPath, string newPath) |
415 | 5120f3cb | Panagiotis Kanavos | { |
416 | 5120f3cb | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(oldPath)) |
417 | 5120f3cb | Panagiotis Kanavos | throw new ArgumentNullException("oldPath"); |
418 | 5120f3cb | Panagiotis Kanavos | if (!Path.IsPathRooted(oldPath)) |
419 | 5120f3cb | Panagiotis Kanavos | throw new ArgumentException("oldPath must be an absolute path","oldPath"); |
420 | 5120f3cb | Panagiotis Kanavos | if (string.IsNullOrWhiteSpace(newPath)) |
421 | 5120f3cb | Panagiotis Kanavos | throw new ArgumentNullException("newPath"); |
422 | 5120f3cb | Panagiotis Kanavos | if (!Path.IsPathRooted(newPath)) |
423 | 5120f3cb | Panagiotis Kanavos | throw new ArgumentException("newPath must be an absolute path","newPath"); |
424 | 5120f3cb | Panagiotis Kanavos | Contract.EndContractBlock(); |
425 | 5120f3cb | Panagiotis Kanavos | |
426 | 5120f3cb | Panagiotis Kanavos | StatusKeeper.ChangeRoots(oldPath, newPath); |
427 | 5120f3cb | Panagiotis Kanavos | } |
428 | d3a13891 | Panagiotis Kanavos | |
429 | fec5da06 | Panagiotis Kanavos | public void SetSelectivePaths(Uri[] uris,Uri[] added, Uri[] removed) |
430 | d3a13891 | Panagiotis Kanavos | { |
431 | 759bd3c4 | Panagiotis Kanavos | //Convert the uris to paths |
432 | fec5da06 | Panagiotis Kanavos | var selectivePaths = UrisToFilePaths(uris); |
433 | fec5da06 | Panagiotis Kanavos | |
434 | fec5da06 | Panagiotis Kanavos | FileAgent.SelectivePaths=selectivePaths; |
435 | 8f44fd3a | pkanavos | WorkflowAgent.SelectivePaths = selectivePaths; |
436 | ebc37b0d | pkanavos | PollAgent.SetSyncUris(_accountInfo.AccountKey,uris); |
437 | 4147814e | Panagiotis Kanavos | |
438 | fec5da06 | Panagiotis Kanavos | var removedPaths = UrisToFilePaths(removed); |
439 | 4147814e | Panagiotis Kanavos | UnversionSelectivePaths(removedPaths); |
440 | 4147814e | Panagiotis Kanavos | |
441 | 4147814e | Panagiotis Kanavos | } |
442 | 4147814e | Panagiotis Kanavos | |
443 | 4147814e | Panagiotis Kanavos | /// <summary> |
444 | 4147814e | Panagiotis Kanavos | /// Mark all unselected paths as Unversioned |
445 | 4147814e | Panagiotis Kanavos | /// </summary> |
446 | 4147814e | Panagiotis Kanavos | /// <param name="removed"></param> |
447 | 4147814e | Panagiotis Kanavos | private void UnversionSelectivePaths(List<string> removed) |
448 | 4147814e | Panagiotis Kanavos | { |
449 | 4147814e | Panagiotis Kanavos | if (removed == null) |
450 | 4147814e | Panagiotis Kanavos | return; |
451 | fec5da06 | Panagiotis Kanavos | |
452 | 4147814e | Panagiotis Kanavos | //Ensure we remove any file state below the deleted folders |
453 | 4147814e | Panagiotis Kanavos | FileState.UnversionPaths(removed); |
454 | fec5da06 | Panagiotis Kanavos | } |
455 | fec5da06 | Panagiotis Kanavos | |
456 | 4147814e | Panagiotis Kanavos | |
457 | fec5da06 | Panagiotis Kanavos | /// <summary> |
458 | fec5da06 | Panagiotis Kanavos | /// Return a list of absolute filepaths from a list of Uris |
459 | fec5da06 | Panagiotis Kanavos | /// </summary> |
460 | fec5da06 | Panagiotis Kanavos | /// <param name="uris"></param> |
461 | fec5da06 | Panagiotis Kanavos | /// <returns></returns> |
462 | fec5da06 | Panagiotis Kanavos | private List<string> UrisToFilePaths(IEnumerable<Uri> uris) |
463 | fec5da06 | Panagiotis Kanavos | { |
464 | fec5da06 | Panagiotis Kanavos | if (uris == null) |
465 | fec5da06 | Panagiotis Kanavos | return new List<string>(); |
466 | fec5da06 | Panagiotis Kanavos | |
467 | 97d149c1 | pkanavos | var own = (from uri in uris |
468 | 97d149c1 | pkanavos | where uri.ToString().StartsWith(_accountInfo.StorageUri.ToString()) |
469 | 97d149c1 | pkanavos | let relativePath = _accountInfo.StorageUri.MakeRelativeUri(uri).RelativeUriToFilePath() |
470 | 97d149c1 | pkanavos | //Trim the account name |
471 | 97d149c1 | pkanavos | select Path.Combine(RootPath, relativePath.After(_accountInfo.UserName + '\\'))).ToList(); |
472 | 97d149c1 | pkanavos | var others= (from uri in uris |
473 | 97d149c1 | pkanavos | where !uri.ToString().StartsWith(_accountInfo.StorageUri.ToString()) |
474 | 97d149c1 | pkanavos | let relativePath = _accountInfo.StorageUri.MakeRelativeUri(uri).RelativeUriToFilePath() |
475 | 97d149c1 | pkanavos | //Trim the account name |
476 | 97d149c1 | pkanavos | select Path.Combine(RootPath,"others-shared", relativePath)).ToList(); |
477 | 97d149c1 | pkanavos | return own.Union(others).ToList(); |
478 | d3a13891 | Panagiotis Kanavos | } |
479 | d3a13891 | Panagiotis Kanavos | |
480 | 7b0a5fec | Panagiotis Kanavos | |
481 | 7b0a5fec | Panagiotis Kanavos | public ObjectInfo GetObjectInfo(string filePath) |
482 | 7b0a5fec | Panagiotis Kanavos | { |
483 | 7b0a5fec | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(filePath)) |
484 | 7b0a5fec | Panagiotis Kanavos | throw new ArgumentNullException("filePath"); |
485 | 7b0a5fec | Panagiotis Kanavos | Contract.EndContractBlock(); |
486 | 7b0a5fec | Panagiotis Kanavos | |
487 | 7b0a5fec | Panagiotis Kanavos | var file=new FileInfo(filePath); |
488 | 7b0a5fec | Panagiotis Kanavos | string relativeUrl;//=file.AsRelativeUrlTo(this.RootPath); |
489 | 7b0a5fec | Panagiotis Kanavos | var relativePath = file.AsRelativeTo(RootPath); |
490 | 7b0a5fec | Panagiotis Kanavos | |
491 | 7b0a5fec | Panagiotis Kanavos | string accountName,container; |
492 | 7b0a5fec | Panagiotis Kanavos | |
493 | 7b0a5fec | Panagiotis Kanavos | var parts=relativePath.Split('\\'); |
494 | 7b0a5fec | Panagiotis Kanavos | |
495 | 7b0a5fec | Panagiotis Kanavos | var accountInfo = _accountInfo; |
496 | 7b0a5fec | Panagiotis Kanavos | if (relativePath.StartsWith(FolderConstants.OthersFolder)) |
497 | 7b0a5fec | Panagiotis Kanavos | { |
498 | 7b0a5fec | Panagiotis Kanavos | accountName = parts[1]; |
499 | 7b0a5fec | Panagiotis Kanavos | container = parts[2]; |
500 | 7b0a5fec | Panagiotis Kanavos | relativeUrl = String.Join("/", parts.Splice(3)); |
501 | 7b0a5fec | Panagiotis Kanavos | //Create the root URL for the target account |
502 | 7b0a5fec | Panagiotis Kanavos | var oldName = UserName; |
503 | 7b0a5fec | Panagiotis Kanavos | var absoluteUri = _accountInfo.StorageUri.AbsoluteUri; |
504 | c636df1f | Panagiotis Kanavos | var nameIndex=absoluteUri.IndexOf(oldName, StringComparison.Ordinal); |
505 | 7b0a5fec | Panagiotis Kanavos | var root=absoluteUri.Substring(0, nameIndex); |
506 | 7b0a5fec | Panagiotis Kanavos | |
507 | 7b0a5fec | Panagiotis Kanavos | accountInfo = new AccountInfo |
508 | 7b0a5fec | Panagiotis Kanavos | { |
509 | 7b0a5fec | Panagiotis Kanavos | UserName = accountName, |
510 | 7b0a5fec | Panagiotis Kanavos | AccountPath = Path.Combine(accountInfo.AccountPath, parts[0], parts[1]), |
511 | 7b0a5fec | Panagiotis Kanavos | StorageUri = new Uri(root + accountName), |
512 | 7b0a5fec | Panagiotis Kanavos | BlockHash=accountInfo.BlockHash, |
513 | 7b0a5fec | Panagiotis Kanavos | BlockSize=accountInfo.BlockSize, |
514 | 7b0a5fec | Panagiotis Kanavos | Token=accountInfo.Token |
515 | 7b0a5fec | Panagiotis Kanavos | }; |
516 | 7b0a5fec | Panagiotis Kanavos | } |
517 | 7b0a5fec | Panagiotis Kanavos | else |
518 | 7b0a5fec | Panagiotis Kanavos | { |
519 | c636df1f | Panagiotis Kanavos | accountName = UserName; |
520 | 7b0a5fec | Panagiotis Kanavos | container = parts[0]; |
521 | 7b0a5fec | Panagiotis Kanavos | relativeUrl = String.Join("/", parts.Splice(1)); |
522 | 7b0a5fec | Panagiotis Kanavos | } |
523 | 42800be8 | Panagiotis Kanavos | |
524 | 7b0a5fec | Panagiotis Kanavos | var client = new CloudFilesClient(accountInfo); |
525 | 7b0a5fec | Panagiotis Kanavos | var objectInfo=client.GetObjectInfo(accountName, container, relativeUrl); |
526 | 7b0a5fec | Panagiotis Kanavos | return objectInfo; |
527 | 7b0a5fec | Panagiotis Kanavos | } |
528 | 42800be8 | Panagiotis Kanavos | |
529 | c92e02f3 | Panagiotis Kanavos | public Task<ContainerInfo> GetContainerInfo(string filePath) |
530 | 42800be8 | Panagiotis Kanavos | { |
531 | 42800be8 | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(filePath)) |
532 | 42800be8 | Panagiotis Kanavos | throw new ArgumentNullException("filePath"); |
533 | 42800be8 | Panagiotis Kanavos | Contract.EndContractBlock(); |
534 | 42800be8 | Panagiotis Kanavos | |
535 | 42800be8 | Panagiotis Kanavos | var file=new FileInfo(filePath); |
536 | 42800be8 | Panagiotis Kanavos | var relativePath = file.AsRelativeTo(RootPath); |
537 | 42800be8 | Panagiotis Kanavos | |
538 | 42800be8 | Panagiotis Kanavos | string accountName,container; |
539 | 42800be8 | Panagiotis Kanavos | |
540 | 42800be8 | Panagiotis Kanavos | var parts=relativePath.Split('\\'); |
541 | 42800be8 | Panagiotis Kanavos | |
542 | 42800be8 | Panagiotis Kanavos | var accountInfo = _accountInfo; |
543 | 42800be8 | Panagiotis Kanavos | if (relativePath.StartsWith(FolderConstants.OthersFolder)) |
544 | 42800be8 | Panagiotis Kanavos | { |
545 | 42800be8 | Panagiotis Kanavos | accountName = parts[1]; |
546 | 42800be8 | Panagiotis Kanavos | container = parts[2]; |
547 | 42800be8 | Panagiotis Kanavos | //Create the root URL for the target account |
548 | 42800be8 | Panagiotis Kanavos | var oldName = UserName; |
549 | 42800be8 | Panagiotis Kanavos | var absoluteUri = _accountInfo.StorageUri.AbsoluteUri; |
550 | c636df1f | Panagiotis Kanavos | var nameIndex=absoluteUri.IndexOf(oldName, StringComparison.Ordinal); |
551 | 42800be8 | Panagiotis Kanavos | var root=absoluteUri.Substring(0, nameIndex); |
552 | 42800be8 | Panagiotis Kanavos | |
553 | 42800be8 | Panagiotis Kanavos | accountInfo = new AccountInfo |
554 | 42800be8 | Panagiotis Kanavos | { |
555 | 42800be8 | Panagiotis Kanavos | UserName = accountName, |
556 | 42800be8 | Panagiotis Kanavos | AccountPath = Path.Combine(accountInfo.AccountPath, parts[0], parts[1]), |
557 | 42800be8 | Panagiotis Kanavos | StorageUri = new Uri(root + accountName), |
558 | 42800be8 | Panagiotis Kanavos | BlockHash=accountInfo.BlockHash, |
559 | 42800be8 | Panagiotis Kanavos | BlockSize=accountInfo.BlockSize, |
560 | 42800be8 | Panagiotis Kanavos | Token=accountInfo.Token |
561 | 42800be8 | Panagiotis Kanavos | }; |
562 | 42800be8 | Panagiotis Kanavos | } |
563 | 42800be8 | Panagiotis Kanavos | else |
564 | 42800be8 | Panagiotis Kanavos | { |
565 | 42800be8 | Panagiotis Kanavos | accountName = UserName; |
566 | 42800be8 | Panagiotis Kanavos | container = parts[0]; |
567 | 42800be8 | Panagiotis Kanavos | } |
568 | c92e02f3 | Panagiotis Kanavos | |
569 | c92e02f3 | Panagiotis Kanavos | return Task.Factory.StartNew(() => |
570 | c92e02f3 | Panagiotis Kanavos | { |
571 | c92e02f3 | Panagiotis Kanavos | var client = new CloudFilesClient(accountInfo); |
572 | c92e02f3 | Panagiotis Kanavos | var containerInfo = client.GetContainerInfo(accountName, container); |
573 | c92e02f3 | Panagiotis Kanavos | return containerInfo; |
574 | c92e02f3 | Panagiotis Kanavos | }); |
575 | 42800be8 | Panagiotis Kanavos | } |
576 | d78cbf09 | Panagiotis Kanavos | } |
577 | d78cbf09 | Panagiotis Kanavos | } |