Esempio n. 1
0
        public async Task <IFileSystemInfo> MoveToAsync(SqlItem item, Guid newParentId, MoveOptions options = null)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (item.Id == Guid.Empty)
            {
                throw new UnauthorizedAccessException();
            }

            options ??= new MoveOptions();
            if (options.Copy)
            {
                return(await CopyToAsync(item, newParentId).ConfigureAwait(false));
            }

            Log("New Parent: " + newParentId + " item: " + item.Id + " '" + item.Name + "'");

            var oldParent = item.Parent;
            var sql       = "UPDATE Item SET ParentId = @parentId WHERE Id = @id";
            await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, sql, new { id = item.Id, parentId = newParentId }, Logger).ConfigureAwait(false);

            var newItem = await GetItemAsync(item.Id).ConfigureAwait(false);

            if (oldParent != null)
            {
                AddEvent(oldParent.Id, oldParent.ParentId, WatcherChangeTypes.Changed);
            }
            AddEvent(newItem.ParentId, (newItem.Parent?.ParentId).GetValueOrDefault(), WatcherChangeTypes.Changed);
            return(newItem);
        }
        public async Task WriteAsync(SqlItem item, Stream stream)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (item.Id == Guid.Empty)
            {
                throw new UnauthorizedAccessException();
            }

            Log("Item : " + item.Id + " '" + item.Name + " stream: " + stream);

            if (stream == null)
            {
                await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, "UPDATE Item SET Data = NULL WHERE Id = @id", new { id = item.Id }, Logger).ConfigureAwait(false);
            }
            else
            {
                await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, "UPDATE Item SET Data = @data WHERE Id = @id", new { id = item.Id, data = stream }, Logger).ConfigureAwait(false);
            }

            if (!IsTempFile(item.Name))
            {
                AddEvent(item.Id, item.ParentId, WatcherChangeTypes.Changed);
            }
        }
Esempio n. 3
0
        public async Task <int> ClearOldChanges(DateTime startTime)
        {
            var sql   = "DELETE FROM Change WHERE CreationTimeUtc < @startTime";
            var count = await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, sql, new { startTime = startTime.ToUniversalTime() }, Logger).ConfigureAwait(false);

            Log("Deleted:" + count);
            return(count);
        }
        public async Task <int> ClearOldTempFiles(DateTime startTime)
        {
            // these are files that were uploaded but never finished for some reason
            var sql   = "DELETE FROM Item WHERE Name LIKE @temp AND CreationTimeUtc < @startTime";
            var count = await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, sql, new { temp = Core.Synchronization.ContentMover.DefaultTemporaryEntryMarker + "%", startTime = startTime.ToUniversalTime() }, Logger).ConfigureAwait(false);

            Log("Deleted:" + count);
            return(count);
        }
        public void Initialize(Action <WebFolderOptions> setupAction, IFileSystemEvents events, IDictionary <string, string> properties)
        {
            if (properties == null)
            {
                throw new ArgumentNullException(nameof(properties));
            }

            if (events == null)
            {
                throw new ArgumentNullException(nameof(events));
            }

            var cnx = properties.GetNullifiedValue(nameof(ConnectionString));

            if (string.IsNullOrWhiteSpace(cnx))
            {
                throw new WebFolderException("0001: Configuration is missing parameter '" + nameof(ConnectionString) + "'.");
            }

            Events           = events;
            ConnectionString = cnx;
            UniqueId         = Conversions.ComputeGuidHash(ConnectionString);
            setupAction?.Invoke(Options);

            Task.Run(async() =>
            {
                // create tables
                await SqlExtensions.CreateTableAsync(ConnectionString, "Item", "Id uniqueidentifier NOT NULL, ParentId uniqueidentifier NOT NULL, Name nvarchar(260) NOT NULL, LastAccessTimeUtc datetime2 NOT NULL, CreationTimeUtc datetime2 NOT NULL, LastWriteTimeUtc datetime2 NOT NULL, Attributes int NOT NULL, Data varbinary(max) CONSTRAINT PK_Item PRIMARY KEY NONCLUSTERED (Id)").ConfigureAwait(false);
                await SqlExtensions.CreateTableAsync(ConnectionString, "Change", "Id uniqueidentifier NOT NULL, ItemId uniqueidentifier NOT NULL, ParentId uniqueidentifier NOT NULL, Type int NOT NULL, CreationTimeUtc datetime2 NOT NULL, OldName nvarchar(260) CONSTRAINT PK_Change PRIMARY KEY NONCLUSTERED (Id)").ConfigureAwait(false);

                // add indices
                await SqlExtensions.CreateIndexAsync(ConnectionString, "IX_Parent", "CREATE NONCLUSTERED INDEX IX_Parent ON Item(ParentId)").ConfigureAwait(false);
                await SqlExtensions.CreateIndexAsync(ConnectionString, "IX_ParentIdName", "CREATE UNIQUE NONCLUSTERED INDEX IX_ParentIdName ON Item(ParentId, Name)").ConfigureAwait(false);
                await SqlExtensions.CreateIndexAsync(ConnectionString, "IX_ChangeCreationTimeUtc", "CREATE CLUSTERED INDEX IX_ChangeCreationTimeUtc ON Change(CreationTimeUtc)").ConfigureAwait(false);

                // ensure root exists
                // we don't use ms
                var now = DateTime.UtcNow.RemoveMilliseconds();
                await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, "IF (NOT EXISTS(SELECT * FROM Item WHERE Id = '00000000-0000-0000-0000-000000000000')) INSERT INTO Item (Id, ParentId, Name, LastAccessTimeUtc, CreationTimeUtc, LastWriteTimeUtc, Attributes) VALUES ('00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000000', '', @now, @now, @now, 16)", new { now }).ConfigureAwait(false);

                // clear old changes
                var max = Options.MaxChangesDays;
                if (max >= 0)
                {
                    var deleteStartTime = DateTime.Now.AddDays(-max);
                    await ClearOldChanges(max > 0 ? DateTime.Now.AddDays(-max) : DateTime.MaxValue).ConfigureAwait(false);
                }

                max = Options.MaxTempFilesDays;
                if (max >= 0)
                {
                    await ClearOldTempFiles(max > 0 ? DateTime.Now.AddDays(-max) : DateTime.MaxValue).ConfigureAwait(false);
                }
            }).Wait();
        }
        private async Task <SqlItem> CreateSqlItemAsync(SqlItem parentItem, string name, CreateOptions options = null)
        {
            if (parentItem == null)
            {
                throw new ArgumentNullException(nameof(parentItem));
            }

            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            Log("Parent: " + parentItem.Id + " '" + parentItem.Name + "' name: '" + name + "'");
            options ??= new CreateOptions();

            // if a race condition occurred, it may already exists
            var item = await GetSqlItemAsync(parentItem.Id, name).ConfigureAwait(false);

            if (item == null)
            {
                var id         = Guid.NewGuid();
                var parameters = new
                {
                    id,
                    parentId = parentItem.Id,
                    name,
                    attributes = options.Attributes,
                    now        = DateTime.UtcNow.RemoveMilliseconds()
                };

                await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, "INSERT INTO Item (Id, ParentId, Name, LastAccessTimeUtc, CreationTimeUtc, LastWriteTimeUtc, Attributes) VALUES (@id, @parentId, @name, @now, @now, @now, @attributes)", parameters, Logger).ConfigureAwait(false);

                item = await GetSqlItemAsync(id).ConfigureAwait(false);
            }

            if (!item.IsFolder && options.InputStream != null)
            {
                await WriteAsync(item, options.InputStream).ConfigureAwait(false);

                // refresh
                item = await GetSqlItemAsync(item.Id).ConfigureAwait(false);
            }

            if (!IsTempFile(name))
            {
                AddEvent(item.Id, item.ParentId, WatcherChangeTypes.Created);
                AddEvent(item.ParentId, (item.Parent?.ParentId).GetValueOrDefault(), WatcherChangeTypes.Changed);
            }
            return(item);
        }
        public async Task <bool> DeleteAsync(SqlItem item, DeleteOptions options = null)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (item.Id == Guid.Empty)
            {
                throw new UnauthorizedAccessException();
            }

            Log("Item : " + item.Id + " '" + item.Name);

            string sql;

            if (!item.IsFolder)
            {
                sql = "DELETE FROM Item WHERE Id = @id";
            }
            else // deleting a folder is always recursive
            {
                sql = @"
WITH ItemHierarchy (Id)  
AS  
(  
	SELECT Id FROM Item WHERE Id = @id
	UNION ALL
	SELECT i.Id FROM Item i INNER JOIN ItemHierarchy h ON i.ParentId = h.Id AND i.ParentId <> '00000000-0000-0000-0000-000000000000'
)  
DELETE Item FROM ItemHierarchy JOIN Item ON Item.Id = ItemHierarchy.Id";
            }

            var parent  = item.Parent; // get parent before delete
            var deleted = await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, sql, new { id = item.Id }, Logger).ConfigureAwait(false) != 0;

            if (deleted)
            {
                if (!IsTempFile(item.Name))
                {
                    AddEvent(item.Id, item.ParentId, WatcherChangeTypes.Deleted);
                    if (parent != null)
                    {
                        AddEvent(parent.Id, parent.ParentId, WatcherChangeTypes.Changed);
                    }
                }
            }
            return(deleted);
        }
Esempio n. 8
0
        public void SendEvents()
        {
            var events = Interlocked.Exchange(ref _events, new ConcurrentDictionary <string, Event>());

            Task.Run(async() =>
            {
                foreach (var evt in events.Values.OrderBy(v => v.CreationTimeUtc))
                {
                    if (evt.OldName == null)
                    {
                        await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, "INSERT INTO Change (Id, ItemId, ParentId, Type, CreationTimeUtc) VALUES (@id, @itemId, @parentId, @type, @creationTimeUtc)", new { id = evt.Id, itemId = evt.ItemId, parentId = evt.ParentId, type = evt.Type, creationTimeUtc = evt.CreationTimeUtc }).ConfigureAwait(false);
                    }
                    else
                    {
                        await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, "INSERT INTO Change (Id, ItemId, ParentId, Type, CreationTimeUtc, OldName) VALUES (@id, @itemId, @parentId, @type, @creationTimeUtc, @oldName)", new { id = evt.Id, itemId = evt.ItemId, parentId = evt.ParentId, type = evt.Type, creationTimeUtc = evt.CreationTimeUtc, oldName = evt.OldName }).ConfigureAwait(false);
                    }

                    Events.Change(evt);
                }
            });
        }
Esempio n. 9
0
        public async Task <IFileSystemInfo> UpdateAsync(SqlItem item, UpdateOptions options)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (item.Id == Guid.Empty)
            {
                throw new UnauthorizedAccessException();
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            Log("Item : " + item.Id + " '" + item.Name + "' attributes: " + item.Attributes);

            var sql        = "UPDATE Item SET ";
            var parameters = new Dictionary <string, object>();

            parameters["id"] = item.Id;

            var    sets    = new List <string>();
            string newName = null;
            var    changed = false;

            if (options.Name != null && options.Name != item.Name)
            {
                newName = options.Name;
                if (options.EnsureUniqueName && item.Parent is SqlItem parent)
                {
                    newName = await GetNewChildNameAsync(parent, newName).ConfigureAwait(false);
                }

                parameters["name"] = newName;
                sets.Add("Name = @name");
            }

            if (options.CreationTimeUtc.HasValue)
            {
                parameters["creationTimeUtc"] = options.CreationTimeUtc.Value.RemoveMilliseconds();
                sets.Add("CreationTimeUtc = @creationTimeUtc");
                changed = true;
            }

            if (options.LastAccessTimeUtc.HasValue)
            {
                parameters["lastAccessTimeUtc"] = options.LastAccessTimeUtc.Value.RemoveMilliseconds();
                sets.Add("LastAccessTimeUtc = @lastAccessTimeUtc");
                changed = true;
            }

            if (options.LastWriteTimeUtc.HasValue)
            {
                parameters["lastWriteTimeUtc"] = options.LastWriteTimeUtc.Value.RemoveMilliseconds();
                sets.Add("LastWriteTimeUtc = @lastWriteTimeUtc");
                changed = true;
            }

            if (options.Attributes.HasValue)
            {
                parameters["attributes"] = (int)options.Attributes.Value;
                sets.Add("Attributes = @attributes");
                changed = true;
            }

            if (sets.Count == 0) // nothing to do
            {
                return(item);
            }

            sql += string.Join(", ", sets) + " WHERE Id = @id";
            await SqlExtensions.ExecuteNonQueryAsync(ConnectionString, sql, parameters, Logger).ConfigureAwait(false);

            var newItem = await GetItemAsync(item.Id).ConfigureAwait(false);

            if (newName != null)
            {
                AddEvent(newItem.Id, newItem.ParentId, WatcherChangeTypes.Renamed, newName);
            }

            if (changed)
            {
                AddEvent(newItem.Id, newItem.ParentId, WatcherChangeTypes.Changed);
            }
            AddEvent(newItem.ParentId, (newItem.Parent?.ParentId).GetValueOrDefault(), WatcherChangeTypes.Changed);
            return(newItem);
        }