private void setupFileWithMetadata(DropboxFileInfo file, JToken metadata) { file.Provider = this; file.IsReadOnly = false; file.IsDirectory = (bool)metadata["is_dir"]; file.Size = (long)metadata["bytes"]; string hash = metadata.Value<string>("hash"); if (hash != null) file.Hash = hash; string path = (string)metadata["path"]; if (path == "/") file.Name = this.Name; else file.Name = path.Substring(path.LastIndexOf('/') + 1); }
private void addFile(string[] folders, JToken metadata) { DropboxFileInfo currentFile = _root; for(int i = 1; i < folders.Length; ++i) { string name = folders[i]; DFileInfo nextFile; if (!currentFile.Contents.TryGetValue(name, out nextFile)) { // There is a guarantee that if file/folder doesn't already exist, metadata for it will // arrive later. Thus all wrong assumptions made at this step (if any) will be corrected. nextFile = new DropboxFileInfo() { IsDirectory = true, Parent = currentFile }; currentFile.Contents.Add(name, nextFile); } currentFile = (DropboxFileInfo)nextFile; } setupFileWithMetadata(currentFile, metadata); }
public async Task<DFileInfo> CreateFolderAsync(DFileInfo destinationFolder, string name) { string nameKey = name.ToLowerInvariant(); if (destinationFolder.Contents.ContainsKey(nameKey)) throw new FileConflictException("Entry with name specified is already present."); var dParent = (DropboxFileInfo)destinationFolder; string path = concatenatePath(dParent.Path, name); var url = new ParamUrl(DropboxConfig.CreateFolderUrl); url.Add("root", DropboxConfig.AccessType); url.Add("path", path); var response = await queryServer(url).ConfigureAwait(false); var metadata = JObject.Parse(response); var newFolder = new DropboxFileInfo() { Parent = dParent }; setupFileWithMetadata(newFolder, metadata); dParent.Contents.Add(nameKey, newFolder); return newFolder; }
public async Task<DFileInfo> UploadFileAsync(DFileInfo destinationFolder, string name, Stream stream, CancellationToken cancellationToken, IProgress<int> progress, long fileSize) { var dDestFolder = (DropboxFileInfo)destinationFolder; string uploadId = null; using (stream) { if (progress != null) progress.Report(0); var buffer = new byte[DropboxConfig.ChunkSize]; long totalUploaded = 0, offset = 0; // Some data is read from the buffer until it is full and we // attempt to push it to the server until it acknowledges all of it. while (true) { int bytesRead = 0, bytesReadThisTime = 0; while (bytesRead < buffer.Length) { bytesReadThisTime = await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead).ConfigureAwait(false); bytesRead += bytesReadThisTime; if (bytesReadThisTime == 0) break; } if (bytesRead == 0) break; int relativeOffset = 0; // relativeOffset shows how many bytes server already accepted. while (relativeOffset < bytesRead) { cancellationToken.ThrowIfCancellationRequested(); var url = new ParamUrl(DropboxConfig.UploadUrl); url.Add("offset", (offset + relativeOffset).ToString()); if (uploadId != null) url.Add("upload_id", uploadId); var signedUrl = await signAsync(url).ConfigureAwait(false); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(signedUrl); request.Method = WebRequestMethods.Http.Put; request.ContentLength = bytesRead - relativeOffset; using (var requestStream = await request.GetRequestStreamAsync().ConfigureAwait(false)) { requestStream.Write(buffer, relativeOffset, bytesRead - relativeOffset); } JToken response; try { var webResponse = await request.GetResponseAsync().ConfigureAwait(false); StreamReader reader = new StreamReader(webResponse.GetResponseStream()); var jsonResult = reader.ReadToEnd(); reader.Close(); response = JToken.Parse(jsonResult); } catch (WebException e) { string message = e.ResponseString(); if (e.HttpStatusCode() == 400 && !string.IsNullOrEmpty(message)) { response = JToken.Parse(message); } else throw parseException(e); } uploadId = (string)response["upload_id"]; relativeOffset = (int)((long)response["offset"] - offset); totalUploaded = offset + relativeOffset; if (progress != null) progress.Report((int)(totalUploaded * 100 / fileSize)); } offset += bytesRead; } } var baseUrl = new StringBuilder(DropboxConfig.UploadFinishUrl); baseUrl.Append(DropboxConfig.AccessType); baseUrl.Append(concatenatePath(dDestFolder.Path, name)); var finalUrl = new ParamUrl(baseUrl.ToString()); finalUrl.Add("upload_id", uploadId); var finishResponse = await queryServer(finalUrl, WebRequestMethods.Http.Post).ConfigureAwait(false); DropboxFileInfo file = new DropboxFileInfo() { Parent = destinationFolder }; setupFileWithMetadata(file, JToken.Parse(finishResponse)); destinationFolder.Contents.Add(name.ToLowerInvariant(), file); return file; }
private async Task<DFileInfo> copyOperation(DropboxFileInfo file, DropboxFileInfo destFolder, bool move, string newName = null) { string nameKey = file.Name.ToLowerInvariant(); string newNameKey = (newName == null)? nameKey : newName.ToLowerInvariant(); // Storage provider should check possible file conflicts by itself, because // the outer system doesn't know how to access keys in dictionary correctly. if (destFolder.Contents.ContainsKey(newNameKey)) throw new FileConflictException("Entry with specified name is already present."); string path = concatenatePath(destFolder.Path, newName ?? file.Name); var url = new ParamUrl(move ? DropboxConfig.MoveUrl : DropboxConfig.CopyUrl); url.Add("root", DropboxConfig.AccessType); url.Add("from_path", percentEncoding(file.Path)); url.Add("to_path", percentEncoding(path)); var response = await queryServer(url).ConfigureAwait(false); var metadata = JObject.Parse(response); if (move) { file.Parent.Contents.Remove(nameKey); file.Parent = destFolder; setupFileWithMetadata(file, metadata); destFolder.Contents.Add(newNameKey, file); return file; } else { var newFile = (DropboxFileInfo)file.Clone(); newFile.Parent = destFolder; setupFileWithMetadata(newFile, metadata); destFolder.Contents.Add(newNameKey, newFile); return newFile; } }