X-Git-Url: https://code.grnet.gr/git/pithos-ms-client/blobdiff_plain/23821bd23b21cdb88e0820134753ddc5572d661d..0f369429e94e6c8128658b8f45447abbb0b0a5ca:/trunk/Pithos.Core/PithosMonitor.cs diff --git a/trunk/Pithos.Core/PithosMonitor.cs b/trunk/Pithos.Core/PithosMonitor.cs index d0a302e..7ca5a30 100644 --- a/trunk/Pithos.Core/PithosMonitor.cs +++ b/trunk/Pithos.Core/PithosMonitor.cs @@ -1,22 +1,55 @@ +#region +/* ----------------------------------------------------------------------- + * + * + * 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. + * + * ----------------------------------------------------------------------- + */ +#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.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; @@ -25,30 +58,65 @@ namespace Pithos.Core [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 IPithosSettings Settings{get;set;} + private IStatusKeeper _statusKeeper; + [Import] - public IStatusKeeper StatusKeeper { get; set; } + public IStatusKeeper StatusKeeper + { + get { return _statusKeeper; } + set + { + _statusKeeper = value; + FileAgent.StatusKeeper = value; + } + } + + + private IPithosWorkflow _workflow; [Import] - public IPithosWorkflow Workflow { get; set; } + public IPithosWorkflow Workflow + { + get { return _workflow; } + set + { + _workflow = value; + FileAgent.Workflow = value; + } + } public ICloudClient CloudClient { get; set; } public IStatusNotification StatusNotification { get; set; } + //[Import] + public FileAgent FileAgent { get; private set; } + + private WorkflowAgent _workflowAgent; + [Import] - public FileAgent FileAgent { get; set; } + public WorkflowAgent WorkflowAgent + { + get { return _workflowAgent; } + set + { + _workflowAgent = value; + FileAgent.WorkflowAgent = value; + } + } [Import] - public WorkflowAgent WorkflowAgent { get; set; } - + public NetworkAgent NetworkAgent { get; set; } [Import] - public NetworkAgent NetworkAgent { get; set; } + public PollAgent PollAgent { get; set; } public string UserName { get; set; } private string _apiKey; @@ -66,7 +134,8 @@ namespace Pithos.Core private AccountInfo _accountInfo; - private static readonly ILog Log = LogManager.GetLogger(typeof(PithosMonitor)); + + public bool Pause @@ -75,16 +144,6 @@ namespace Pithos.Core set { FileAgent.Pause = value; - if (value) - { - StatusKeeper.SetPithosStatus(PithosStatus.SyncPaused); - StatusNotification.NotifyChange("Paused"); - } - else - { - StatusKeeper.SetPithosStatus(PithosStatus.InSynch); - StatusNotification.NotifyChange("Synchronizing"); - } } } @@ -103,7 +162,10 @@ namespace Pithos.Core CancellationTokenSource _cancellationSource; - + public PithosMonitor() + { + FileAgent = new FileAgent(); + } private bool _started; public void Start() @@ -121,6 +183,8 @@ namespace Pithos.Core //TODO; Warn user? return; + WorkflowAgent.StatusNotification = StatusNotification; + StatusNotification.NotifyChange("Starting"); if (_started) { @@ -128,15 +192,13 @@ namespace Pithos.Core return; } _cancellationSource = new CancellationTokenSource(); - - CloudClient=new CloudFilesClient(UserName,ApiKey); - var proxyUri = ProxyFromSettings(); - CloudClient.Proxy = proxyUri; - 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; @@ -157,11 +219,16 @@ namespace Pithos.Core 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().Select(url => new Uri(url)).ToArray(); + + SetSelectivePaths(selectiveUrls,null,null); + StartWatcherAgent(); StartNetworkAgent(); - - StartWorkflowAgent(); + WorkflowAgent.RestartInterruptedFiles(_accountInfo); _started = true; } @@ -173,11 +240,11 @@ namespace Pithos.Core var pithosContainers = new List{ 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; @@ -188,33 +255,17 @@ namespace Pithos.Core public string AuthenticationUrl { get; set; } - private Uri ProxyFromSettings() - { - if (Settings.UseManualProxy) - { - var proxyUri = new UriBuilder - { - Host = Settings.ProxyServer, - Port = Settings.ProxyPort - }; - if (Settings.ProxyAuthentication) - { - proxyUri.UserName = Settings.ProxyUsername; - proxyUri.Password = Settings.ProxyPassword; - } - return proxyUri.Uri; - } - 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 = @@ -233,6 +284,7 @@ namespace Pithos.Core { Log.Info("[END]"); } + StatusNotification.SetPithosStatus(PithosStatus.LocalComplete,"Indexing Completed"); } } @@ -240,20 +292,21 @@ namespace Pithos.Core - private void StartWorkflowAgent() + /* private void StartWorkflowAgent() { + WorkflowAgent.StatusNotification = StatusNotification; - bool connected = NetworkListManager.IsConnectedToInternet; +/* //On Vista and up we can check for a network connection + bool connected=Environment.OSVersion.Version.Major < 6 || NetworkListManager.IsConnectedToInternet; //If we are not connected retry later if (!connected) { Task.Factory.StartNewDelayed(10000, StartWorkflowAgent); return; - } + }#1# try { - WorkflowAgent.StatusNotification = StatusNotification; WorkflowAgent.Start(); } catch (Exception) @@ -262,58 +315,26 @@ namespace Pithos.Core //Retry after a while Task.Factory.StartNewDelayed(10000, StartWorkflowAgent); } - } - - internal class LocalFileComparer:EqualityComparer - { - 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.ProcessRemoteFiles(); + 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"); @@ -340,7 +361,6 @@ namespace Pithos.Core Log.InfoFormat("Reset cache folder to hidden: {0}", folder); } } - return folder; } @@ -348,9 +368,14 @@ namespace Pithos.Core private void StartWatcherAgent() { - AgentLocator.Register(FileAgent,RootPath); + if (Log.IsDebugEnabled) + Log.DebugFormat("Start Folder Monitoring [{0}]",RootPath); + AgentLocator.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); @@ -363,9 +388,6 @@ namespace Pithos.Core if (FileAgent!=null) FileAgent.Stop(); FileAgent = null; - if (timer != null) - timer.Dispose(); - timer = null; } @@ -404,29 +426,58 @@ namespace Pithos.Core 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) + /// + /// Mark all unselected paths as Unversioned + /// + /// + private void UnversionSelectivePaths(List 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 GetRootFolders() + + /// + /// Return a list of absolute filepaths from a list of Uris + /// + /// + /// + private List UrisToFilePaths(IEnumerable 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(); + + 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)) @@ -450,7 +501,7 @@ namespace Pithos.Core //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 @@ -465,7 +516,7 @@ namespace Pithos.Core } else { - accountName = this.UserName; + accountName = UserName; container = parts[0]; relativeUrl = String.Join("/", parts.Splice(1)); } @@ -496,7 +547,7 @@ namespace Pithos.Core //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 @@ -523,12 +574,4 @@ namespace Pithos.Core }); } } - - - public interface IStatusNotification - { - void NotifyChange(string status,TraceLevel level=TraceLevel.Info); - void NotifyChangedFile(string filePath); - void NotifyAccount(AccountInfo policy); - } }