+#region
+/* -----------------------------------------------------------------------
+ * <copyright file="PithosMonitor.cs" company="GRNet">
+ *
+ * Copyright 2011-2012 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ * </copyright>
+ * -----------------------------------------------------------------------
+ */
+#endregion
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.Composition;
-using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
-using System.Net;
-using System.Net.NetworkInformation;
-using System.Security.Cryptography;
-using System.ServiceModel.Description;
-using System.Text;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
-using Castle.ActiveRecord.Queries;
-using Microsoft.WindowsAPICodePack.Net;
using Pithos.Core.Agents;
using Pithos.Interfaces;
-using System.ServiceModel;
using Pithos.Network;
using log4net;
[Export(typeof(PithosMonitor))]
public class PithosMonitor:IDisposable
{
+ private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
private int _blockSize;
private string _blockHash;
}
[Import]
- public NetworkAgent NetworkAgent { get; set; }
+ public NetworkAgent NetworkAgent { get; set; }
+ [Import]
+ public PollAgent PollAgent { get; set; }
public string UserName { get; set; }
private string _apiKey;
}
private AccountInfo _accountInfo;
-
-
- private static readonly ILog Log = LogManager.GetLogger(typeof(PithosMonitor));
+
+
public bool Pause
set
{
FileAgent.Pause = value;
- if (value)
- {
- StatusKeeper.SetPithosStatus(PithosStatus.SyncPaused);
- StatusNotification.NotifyChange("Paused");
- }
- else
- {
- StatusKeeper.SetPithosStatus(PithosStatus.InSynch);
- StatusNotification.NotifyChange("Synchronizing");
- }
}
}
public PithosMonitor()
{
FileAgent = new FileAgent();
-
}
private bool _started;
return;
}
_cancellationSource = new CancellationTokenSource();
-
-
- CloudClient=new CloudFilesClient(UserName,ApiKey);
- var proxy = ProxyFromSettings();
- CloudClient.Proxy = proxy;
- CloudClient.UsePithos = true;
- CloudClient.AuthenticationUrl = this.AuthenticationUrl;
- _accountInfo = CloudClient.Authenticate();
+ lock (this)
+ {
+ CloudClient = new CloudFilesClient(UserName, ApiKey)
+ {UsePithos = true, AuthenticationUrl = AuthenticationUrl};
+ _accountInfo = CloudClient.Authenticate();
+ }
_accountInfo.SiteUri = AuthenticationUrl;
_accountInfo.AccountPath = RootPath;
StatusKeeper.StartProcessing(_cancellationSource.Token);
IndexLocalFiles();
+ //Extract the URIs from the string collection
+ var settings = Settings.Accounts.First(s => s.AccountKey == _accountInfo.AccountKey );
+ var selectiveUrls=settings.SelectiveFolders.Cast<string>().Select(url => new Uri(url)).ToArray();
+
+ SetSelectivePaths(selectiveUrls,null,null);
+
StartWatcherAgent();
StartNetworkAgent();
var pithosContainers = new List<string>{ FolderConstants.TrashContainer,FolderConstants.PithosContainer};
foreach (var container in pithosContainers)
{
- var info=CloudClient.GetContainerInfo(this.UserName, container);
+ var info=CloudClient.GetContainerInfo(UserName, container);
if (info == ContainerInfo.Empty)
{
- CloudClient.CreateContainer(this.UserName, container);
- info = CloudClient.GetContainerInfo(this.UserName, container);
+ CloudClient.CreateContainer(UserName, container);
+ info = CloudClient.GetContainerInfo(UserName, container);
}
_blockSize = info.BlockSize;
_blockHash = info.BlockHash;
public string AuthenticationUrl { get; set; }
- private WebProxy ProxyFromSettings()
- {
- if (Settings.UseManualProxy)
- {
- var proxy = new WebProxy(Settings.ProxyServer, Settings.ProxyPort);
- //If the proxy requires specific authentication settings, use them
- if (Settings.ProxyAuthentication)
- {
- proxy.Credentials=new NetworkCredential(Settings.ProxyUsername,Settings.ProxyPassword,Settings.ProxyDomain);
- }
- //Otherwise, if there are generic authentication settings, use them
- if (!String.IsNullOrWhiteSpace(CredentialCache.DefaultNetworkCredentials.UserName))
- {
- proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
- }
- return proxy;
- }
- return null;
- }
-
private void IndexLocalFiles()
{
- StatusNotification.NotifyChange("Indexing Local Files",TraceLevel.Info);
- using (log4net.ThreadContext.Stacks["Monitor"].Push("Indexing local files"))
+ using (ThreadContext.Stacks["Operation"].Push("Indexing local files"))
{
- Log.Info("START");
+
try
{
+ //StatusNotification.NotifyChange("Indexing Local Files");
+ Log.Info("Start local indexing");
+ StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing,"Indexing Local Files");
+
var cachePath = Path.Combine(RootPath, FolderConstants.CacheFolder);
var directory = new DirectoryInfo(RootPath);
var files =
{
Log.Info("[END]");
}
+ StatusNotification.SetPithosStatus(PithosStatus.LocalComplete,"Indexing Completed");
}
}
}
}*/
- internal class LocalFileComparer:EqualityComparer<CloudAction>
- {
- public override bool Equals(CloudAction x, CloudAction y)
- {
- if (x.Action != y.Action)
- return false;
- if (x.LocalFile != null && y.LocalFile != null && !x.LocalFile.FullName.Equals(y.LocalFile.FullName))
- return false;
- if (x.CloudFile != null && y.CloudFile != null )
- {
- if (x.CloudFile.Hash == null & y.CloudFile.Hash != null)
- return false;
- if (x.CloudFile.Hash != null & y.CloudFile.Hash == null)
- return false;
- if (x.CloudFile.Hash == null & y.CloudFile.Hash == null)
- return (x.CloudFile.Name == y.CloudFile.Name);
- if (!x.CloudFile.Hash.Equals(y.CloudFile.Hash))
- return false;
- }
- if (x.CloudFile == null ^ y.CloudFile == null ||
- x.LocalFile == null ^ y.LocalFile == null)
- return false;
- return true;
- }
-
- public override int GetHashCode(CloudAction obj)
- {
- var hash1 = (obj.LocalFile == null) ? int.MaxValue : obj.LocalFile.FullName.GetHashCode();
- var hash2 = (obj.CloudFile == null) ? int.MaxValue : (obj.CloudFile.Hash ?? obj.CloudFile.Name??"").GetHashCode();
- var hash3 = obj.Action.GetHashCode();
- return hash1 ^ hash2 & hash3;
- }
- }
-
- private Timer timer;
private void StartNetworkAgent()
{
-
- NetworkAgent.AddAccount(_accountInfo);
-
NetworkAgent.StatusNotification = StatusNotification;
-
+
+ //TODO: The Network and Poll agents are not account specific
+ //They should be moved outside PithosMonitor
NetworkAgent.Start();
- NetworkAgent.PollRemoteFiles();
+ PollAgent.AddAccount(_accountInfo);
+
+ PollAgent.StatusNotification = StatusNotification;
+
+ PollAgent.PollRemoteFiles();
}
//Make sure a hidden cache folder exists to store partial downloads
- private static string CreateHiddenFolder(string rootPath, string folderName)
+ private static void CreateHiddenFolder(string rootPath, string folderName)
{
if (String.IsNullOrWhiteSpace(rootPath))
throw new ArgumentNullException("rootPath");
Log.InfoFormat("Reset cache folder to hidden: {0}", folder);
}
}
- return folder;
}
private void StartWatcherAgent()
{
- AgentLocator<FileAgent>.Register(FileAgent,RootPath);
+ if (Log.IsDebugEnabled)
+ Log.DebugFormat("Start Folder Monitoring [{0}]",RootPath);
+ AgentLocator<FileAgent>.Register(FileAgent,RootPath);
+
+ FileAgent.IdleTimeout = Settings.FileIdleTimeout;
FileAgent.StatusKeeper = StatusKeeper;
+ FileAgent.StatusNotification = StatusNotification;
FileAgent.Workflow = Workflow;
FileAgent.CachePath = Path.Combine(RootPath, FolderConstants.CacheFolder);
FileAgent.Start(_accountInfo, RootPath);
if (FileAgent!=null)
FileAgent.Stop();
FileAgent = null;
- if (timer != null)
- timer.Dispose();
- timer = null;
}
StatusKeeper.ChangeRoots(oldPath, newPath);
}
- public void AddSelectivePaths(string[] added)
+ public void SetSelectivePaths(Uri[] uris,Uri[] added, Uri[] removed)
{
- /* FileAgent.SelectivePaths.AddRange(added);
- NetworkAgent.SyncPaths(added);*/
+ //Convert the uris to paths
+ var selectivePaths = UrisToFilePaths(uris);
+
+ FileAgent.SelectivePaths=selectivePaths;
+ WorkflowAgent.SelectivePaths = selectivePaths;
+ PollAgent.SetSyncUris(_accountInfo.AccountKey,uris);
+
+ var removedPaths = UrisToFilePaths(removed);
+ UnversionSelectivePaths(removedPaths);
+
}
- public void RemoveSelectivePaths(string[] removed)
+ /// <summary>
+ /// Mark all unselected paths as Unversioned
+ /// </summary>
+ /// <param name="removed"></param>
+ private void UnversionSelectivePaths(List<string> removed)
{
- FileAgent.SelectivePaths.RemoveAll(removed.Contains);
- foreach (var removedPath in removed.Where(Directory.Exists))
- {
- Directory.Delete(removedPath,true);
- }
+ if (removed == null)
+ return;
+
+ //Ensure we remove any file state below the deleted folders
+ FileState.UnversionPaths(removed);
}
- public IEnumerable<string> GetRootFolders()
+
+ /// <summary>
+ /// Return a list of absolute filepaths from a list of Uris
+ /// </summary>
+ /// <param name="uris"></param>
+ /// <returns></returns>
+ private List<string> UrisToFilePaths(IEnumerable<Uri> uris)
{
- var dirs = from container in CloudClient.ListContainers(UserName)
- from dir in CloudClient.ListObjects(UserName, container.Name, "")
- select dir.Name;
- return dirs;
+ if (uris == null)
+ return new List<string>();
+
+ var own = (from uri in uris
+ where uri.ToString().StartsWith(_accountInfo.StorageUri.ToString())
+ let relativePath = _accountInfo.StorageUri.MakeRelativeUri(uri).RelativeUriToFilePath()
+ //Trim the account name
+ select Path.Combine(RootPath, relativePath.After(_accountInfo.UserName + '\\'))).ToList();
+ var others= (from uri in uris
+ where !uri.ToString().StartsWith(_accountInfo.StorageUri.ToString())
+ let relativePath = _accountInfo.StorageUri.MakeRelativeUri(uri).RelativeUriToFilePath()
+ //Trim the account name
+ select Path.Combine(RootPath,"others-shared", relativePath)).ToList();
+ return own.Union(others).ToList();
}
+
public ObjectInfo GetObjectInfo(string filePath)
{
if (String.IsNullOrWhiteSpace(filePath))
//Create the root URL for the target account
var oldName = UserName;
var absoluteUri = _accountInfo.StorageUri.AbsoluteUri;
- var nameIndex=absoluteUri.IndexOf(oldName);
+ var nameIndex=absoluteUri.IndexOf(oldName, StringComparison.Ordinal);
var root=absoluteUri.Substring(0, nameIndex);
accountInfo = new AccountInfo
}
else
{
- accountName = this.UserName;
+ accountName = UserName;
container = parts[0];
relativeUrl = String.Join("/", parts.Splice(1));
}
//Create the root URL for the target account
var oldName = UserName;
var absoluteUri = _accountInfo.StorageUri.AbsoluteUri;
- var nameIndex=absoluteUri.IndexOf(oldName);
+ var nameIndex=absoluteUri.IndexOf(oldName, StringComparison.Ordinal);
var root=absoluteUri.Substring(0, nameIndex);
accountInfo = new AccountInfo