/// <summary> /// Upload file stream to the server /// </summary> /// <param name="apiSession">api session</param> /// <param name="inputStream">stream for read from</param> /// <param name="fileName">file name</param> /// <param name="fileSize">file size in bytes</param> /// <param name="destFolderPath">destination folder like /path/to/folder </param> /// <param name="cancellationToken">cancellation tokern</param> /// <param name="overwriteFileifExists"></param> /// <returns></returns> public async Task UploadFileAsync(ApiSession apiSession, Stream inputStream, string fileName, long fileSize, string destFolderPath, CancellationToken cancellationToken, bool overwriteFileifExists = false) { if (apiSession == null) { throw new ArgumentNullException(nameof(apiSession)); } try { var spaceName = apiSession.SpaceName; string boundary = "EasyMorphCommandClient--------" + Guid.NewGuid().ToString("N"); string url = UrlHelper.JoinUrl("space", spaceName, "files", destFolderPath); using (var content = new MultipartFormDataContent(boundary)) { var downloadProgress = new FileProgress(fileName, fileSize); downloadProgress.StateChanged += DownloadProgress_StateChanged; using (cancellationToken.Register(() => downloadProgress.ChangeState(FileProgressState.Cancelled))) { using (var streamContent = new ProgressStreamContent(inputStream, downloadProgress)) { content.Add(streamContent, "files", Path.GetFileName(fileName)); var requestMessage = BuildHttpRequestMessage(overwriteFileifExists ? HttpMethod.Put : HttpMethod.Post, url, content, apiSession); using (requestMessage) { using (var response = await GetHttpClient().SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) { await HandleResponse(response); } } } } } } catch (Exception ex) when(ex.InnerException != null && ex.InnerException is WebException) { var einner = ex.InnerException as WebException; if (einner.Status == WebExceptionStatus.ConnectionClosed) { throw new MorphApiNotFoundException("Specified folder not found"); } } }
/// <summary> /// Download file from server /// </summary> /// <param name="apiSession">api session</param> /// <param name="remoteFilePath"> Path to the remote file. Like /some/folder/file.txt </param> /// <param name="handleFile">delegate to check file info before accessing to the file stream</param> /// <param name="streamToWriteTo">stream for writing. Writing will be executed only if handleFile delegate returns true</param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task DownloadFileAsync(ApiSession apiSession, string remoteFilePath, Func <DownloadFileInfo, bool> handleFile, Stream streamToWriteTo, CancellationToken cancellationToken) { if (apiSession == null) { throw new ArgumentNullException(nameof(apiSession)); } var spaceName = apiSession.SpaceName; var nvc = new NameValueCollection(); nvc.Add("_", DateTime.Now.Ticks.ToString()); var url = UrlHelper.JoinUrl("space", spaceName, "files", remoteFilePath) + nvc.ToQueryString(); // it's necessary to add HttpCompletionOption.ResponseHeadersRead to disable caching using (HttpResponseMessage response = await GetHttpClient() .SendAsync(BuildHttpRequestMessage(HttpMethod.Get, url, null, apiSession), HttpCompletionOption.ResponseHeadersRead, cancellationToken)) if (response.IsSuccessStatusCode) { using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync()) { var contentDisposition = response.Content.Headers.ContentDisposition; DownloadFileInfo dfi = null; if (contentDisposition != null) { dfi = new DownloadFileInfo { // need to fix double quotes, that may come from server response // FileNameStar contains file name encoded in UTF8 FileName = (contentDisposition.FileNameStar ?? contentDisposition.FileName).TrimStart('\"').TrimEnd('\"') }; } var contentLength = response.Content.Headers.ContentLength; var fileProgress = new FileProgress(dfi.FileName, contentLength.Value); fileProgress.StateChanged += DownloadProgress_StateChanged; var bufferSize = 4096; if (handleFile(dfi)) { var buffer = new byte[bufferSize]; var size = contentLength.Value; var processed = 0; var lastUpdate = DateTime.MinValue; fileProgress.ChangeState(FileProgressState.Starting); while (true) { // cancel download if cancellation token triggered if (cancellationToken.IsCancellationRequested) { fileProgress.ChangeState(FileProgressState.Cancelled); throw new OperationCanceledException(); } var length = await streamToReadFrom.ReadAsync(buffer, 0, buffer.Length); if (length <= 0) { break; } await streamToWriteTo.WriteAsync(buffer, 0, length); processed += length; if (DateTime.Now - lastUpdate > TimeSpan.FromMilliseconds(250)) { fileProgress.SetProcessedBytes(processed); fileProgress.ChangeState(FileProgressState.Processing); lastUpdate = DateTime.Now; } } fileProgress.ChangeState(FileProgressState.Finishing); } } } else { // TODO: check await HandleErrorResponse(response); } }