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)); }
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));
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); }