private async Task <WebItem> GetOrCreateFileAsync(StateSyncEntry entry, SyncGetEntryOptions options)
        {
            WebItem item;

            if (entry.Id == null)
            {
                // temporary files are used to move content
                if (!options.IsTemporary)
                {
                    return(null);
                }

                // get parent path;
                Guid parentId;
                var  parent = options.JobChange.Change.FilePathSegments.Parent;
                if (parent == null)
                {
                    // root
                    parentId = Guid.Empty;
                }
                else
                {
                    // check entry exists.
                    // it should since we init the endpoint synchronizer with UploadsWaitForParents = true
                    var parentEntry = EndPointSynchronizer.StateProvider.GetEntryByFilePath(options.JobChange.DestinationSynchronizer, parent.ToString());
                    parentId = ToId(parentEntry.Id);
                }

                item = await WebApi.GetChildAsync(parentId, entry.Name).ConfigureAwait(false);

                if (item != null)
                {
                    return(item);
                }

                Logger?.Log(TraceLevel.Warning, "Cannot find temp entry '" + entry.Name + "' with parent id '" + parentId + "'.");
                if (!options.CanCreate)
                {
                    return(null);
                }

                // create temp files as hidden files
                return(await WebApi.CreateAsync(parentId, entry.Name, FileAttributes.Hidden).ConfigureAwait(false));
            }

            item = await WebApi.GetAsync(ToId(entry.Id)).ConfigureAwait(false);

            if (item != null)
            {
                return(item);
            }

            Logger?.Log(TraceLevel.Warning, "Cannot find entry with id '" + entry.Id + "' name '" + entry.Name + "'.");
            if (!options.CanCreate)
            {
                return(null);
            }

            return(await CreateEntryAsync(entry).ConfigureAwait(false));
        }
Example #2
0
        private void OnWatcherEvent(object sender, LocalFileSystemWatcherEventArgs e)
        {
            // basic checks
            if (!IOUtilities.PathIsChildOrEqual(WebApi.LocalDirectory.FullName, e.Path))
            {
                return;
            }

            // skip some well known files (office, etc.)
            if (!ConsiderForRemote(Path.GetFileName(e.Path)))
            {
                return;
            }

            var isDir = IOUtilities.PathIsDirectory(e.Path);

            Server.Log(TraceLevel.Verbose, "Action:" + e.Action + " Get remote item for local: " + e.Path);
            var item = Server.GetRemoteItem(e.Path);

            if (item != null)
            {
                if (e.Action == WatcherChangeTypes.Deleted)
                {
                    // a delete in a local file doesn't mean a delete in the server
                    ShellUtilities.ChangeNotify(SHCNE.SHCNE_UPDATEITEM, 0, item.IdList);
                }
                else if (e.Action == WatcherChangeTypes.Changed)
                {
                    ShellUtilities.ChangeNotify(isDir ? SHCNE.SHCNE_UPDATEDIR : SHCNE.SHCNE_UPDATEITEM, 0, item.IdList);
                    if (!isDir)
                    {
                        SynchronizeFile(e.Path);
                    }
                }
                else if (e.Action == WatcherChangeTypes.Renamed)
                {
                    ShellUtilities.ChangeNotify(isDir ? SHCNE.SHCNE_RENAMEFOLDER : SHCNE.SHCNE_RENAMEITEM, 0, item.IdList);
                    if (!isDir)
                    {
                        SynchronizeFile(e.Path);
                    }
                }
                // else create do nothing
            }
            else // try parent
            {
                var parentPath = Path.GetDirectoryName(e.Path);
                item = Server.GetRemoteItem(parentPath);
                if (item != null)
                {
                    // new item creation in the local directories? could come from the "New ..." menu in virtual folder's context
                    // we don't use created just changed
                    if (e.Action != WatcherChangeTypes.Deleted && e.Action != WatcherChangeTypes.Created && item is IObjectWithApiItem owa)
                    {
                        var atts = IOUtilities.PathGetAttributes(e.Path);
                        if (atts.HasValue &&
                            !atts.Value.HasFlag(FileAttributes.Directory) &&
                            !atts.Value.HasFlag(FileAttributes.Hidden) &&
                            !atts.Value.HasFlag(FileAttributes.System))
                        {
                            WebApi.CreateAsync(owa.ApiItem.Id, e.Path, null, atts.Value);
                        }
                    }

                    ShellUtilities.ChangeNotify(SHCNE.SHCNE_UPDATEDIR, 0, item.IdList);
                }
            }
        }
 private static Task <WebItem> CreateEntryAsync(StateSyncEntry entry) => WebApi.CreateAsync(ToId(entry.ParentId), entry.Name, ToAttributes(entry));
Example #4
0
        protected override void OnMenuInvoke(ShellMenuInvokeEventArgs e)
        {
            if (e.Verb != null)
            {
                // user is using "New ..." menu in the Explorer command bar
                // note if the user is using the "New..." menu in the folder's Context menu, it will not get there but be handled by WebShellFolderServer's notifier creation handling
                if (e.Verb.EqualsIgnoreCase("NewFolder") || e.Verb.EqualsIgnoreCase("NewLink") || e.Verb.StartsWith("."))
                {
                    // come up with a new file name
                    // since we're virtual we use a temp path

                    // here, we use the Shell itself to come up with a new file name (roundtrip api)
                    // note this can be costy in terms of performance (server call, etc.)
                    // so, we could choose arbitrary name instead, or ask the server for a new name
                    var files   = new List <string>();
                    var folders = new List <string>();
                    foreach (var item in ApiItem.EnumerateChildren())
                    {
                        if (item.IsFolder)
                        {
                            folders.Add(IOUtilities.PathToValidFileName(item.Name));
                        }
                        else
                        {
                            files.Add(IOUtilities.PathToValidFileName(item.Name));
                        }
                    }

                    // use ShellBoost's utility classes
                    var options = new CreateNewItemOptions();
                    options.ExistingFileNames   = files;
                    options.ExistingFolderNames = folders;
                    var path = Menu.CreateNewItem(e.Verb, options, false);
                    if (path != null)
                    {
                        var name = ApiItem.GetNewName(Path.GetFileName(path));
                        if (IOUtilities.DirectoryExists(path))
                        {
                            WebApi.CreateAsync(ApiItem.Id, null, name, FileAttributes.Directory);
                        }
                        else
                        {
                            WebApi.CreateAsync(ApiItem.Id, path, name);
                        }

                        // cleanup temp files
                        IOUtilities.DirectoryDelete(options.TargetPath, true, false);
                    }
                    return;
                }
            }

            // copy & cut support
            if (e.Command == DFM_CMD.DFM_CMD_COPY || e.Command == DFM_CMD.DFM_CMD_MOVE)
            {
                // make sure items are present locally
                // note if the past action is too fast, items may not be here yet (user will have to press "Retry")
                foreach (var si in e.Items)
                {
                    if (si is not IObjectWithApiItem apiItem)
                    {
                        continue;
                    }

                    Task.Run(() => apiItem.ApiItem.EnsureLocalAsync(si.FileSystemPath));
                }
                return;
            }

            // note DFM_CMD_DELETE is unhandled here so will fallback in OnOperate RecycleItem / RemoveItem
            base.OnMenuInvoke(e);
        }