private static Task RunOnUploadComplete(ContextAdapter context, long fileOffset, long bytesWritten) { if (context.Configuration.OnUploadCompleteAsync == null && context.Configuration.Events?.OnFileCompleteAsync == null) { return(Task.FromResult(0)); } return(RunOnUploadCompleteLocal()); async Task RunOnUploadCompleteLocal() { if (await IsPartialUpload(context)) { return; } var fileId = context.GetFileId(); var fileUploadLength = await context.Configuration.Store.GetUploadLengthAsync(fileId, context.CancellationToken); var fileIsComplete = fileOffset + bytesWritten == fileUploadLength; if (fileIsComplete) { if (context.Configuration.OnUploadCompleteAsync != null) { await context.Configuration.OnUploadCompleteAsync(fileId, context.Configuration.Store, context.CancellationToken); } if (context.Configuration.Events?.OnFileCompleteAsync != null) { await context.Configuration.Events.OnFileCompleteAsync(FileCompleteContext.Create(context)); } } } }
/// <summary> /// Handle the upload completion /// </summary> protected override async Task OnUploadCompleted(FileCompleteContext ctx) { try { // Get the connected client var gUserResponse = await _fileMngClient.GetUserAsync(new gUserRequest()); if (gUserResponse == null) { _logger.LogError("Unknown error occured while requesting user info"); ctx.HttpContext.Response.StatusCode = 400; return; } if (gUserResponse.Status.Status != Protos.RequestStatus.Success) { _logger.LogError(gUserResponse.Status.Message); ctx.HttpContext.Response.StatusCode = 400; return; } // Move files to user's folder MoveFilesToFolder(ctx, gUserResponse.User); // Update db string avatarUrl = await RequestUpdateDb(ctx, gUserResponse.User); // Attach avatar info to header, because tus send 204 (no response body is allowed) ctx.HttpContext.Response.Headers.Add("upload-data", Helpers.JsonSerialize(new { AvatarUrl = avatarUrl })); } catch (Exception _ex) { _logger.LogError(_ex.Message); ctx.HttpContext.Response.StatusCode = 500; throw _ex; } }
/// <summary> /// Persist the uploaded file data to db /// </summary> private async Task <gFileItem> PersistMetaData(FileCompleteContext ctx) { var gUserResponse = await _fileMngClient.GetUserAsync(new gUserRequest()); if (gUserResponse == null) { _logger.LogError("Unknown error occured while requesting user info"); ctx.HttpContext.Response.StatusCode = 400; return(null); } if (gUserResponse.Status.Status != Protos.RequestStatus.Success) { _logger.LogError(gUserResponse.Status.Message); ctx.HttpContext.Response.StatusCode = 400; return(null); } ITusFile file = await((ITusReadableStore)ctx.Store).GetFileAsync(ctx.FileId, ctx.CancellationToken); var metadata = await file.GetMetadataAsync(ctx.CancellationToken); gFileItem fileitem = new gFileItem() { Id = Helpers.GenerateUniqueId(), TusId = ctx.FileId, UserId = gUserResponse.User.Id, Size = uint.Parse(new FileInfo(Path.Combine(_uploadOpts.CurrentValue.UploadPath, file.Id)).Length.ToString()), Name = metadata["name"].GetString(Encoding.UTF8), MimeType = metadata["contentType"].GetString(Encoding.UTF8), // file with no folderid is placed in the virtual root folder FolderId = metadata["folderId"].GetString(Encoding.UTF8) == "root" ? null : metadata["folderId"].GetString(Encoding.UTF8), Extension = Helpers.GetFileExtension(metadata["contentType"].GetString(Encoding.UTF8)) ?? string.Empty, StorageServerId = metadata["serverId"].GetString(Encoding.UTF8), CreatedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)), LastModified = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc)), Status = Protos.ItemStatus.Visible }; // send the uploaded file info to the main app gFileItemResponse response = await _fileMngClient.SaveFileAsync(new gFileItemRequest() { FileItem = fileitem }); if (response == null) { _logger.LogError("No response has been received from the server.", ErrorOrigin.Server); return(null); } if (response.Status.Status != Protos.RequestStatus.Success) { _logger.LogError("An error has been returned from server call: " + response.Status.Message); return(null); } return(response.FileItem); }
public static async Task ProcessUploadTus(FileCompleteContext arg) { CommonController.LogDebug("Begin processing upload"); var context = arg.HttpContext; var headers = context.Request.Headers; if (Enum.TryParse <UploadFileType>(headers["type"].ToString(), out var type)) { if (Guid.TryParse(headers["guid"], out var guid)) { var newFilename = headers["filename"]; //NOTE(Simon): Check if provided filename is a guid if (!String.IsNullOrEmpty(newFilename)) { CommonController.LogDebug("Upload has correct headers"); var path = Path.Combine(baseFilePath, guid.ToString()); var tusFilePath = Path.Combine(path, arg.FileId); string newFilePath; switch (type) { case UploadFileType.Video: case UploadFileType.Meta: case UploadFileType.Tags: case UploadFileType.Chapters: newFilePath = Path.Combine(path, newFilename); break; case UploadFileType.Extra: newFilePath = Path.Combine(path, "extra", newFilename); break; case UploadFileType.Miniature: newFilePath = Path.Combine(path, "areaMiniatures", newFilename); break; default: await CommonController.WriteError(context, "Unknown file type", StatusCodes.Status400BadRequest); return; } CommonController.LogDebug($"Creating directory for {newFilePath} and moving uploaded file there"); Directory.CreateDirectory(Path.GetDirectoryName(newFilePath)); File.Move(tusFilePath, newFilePath, true); await((ITusTerminationStore)arg.Store).DeleteFileAsync(arg.FileId, arg.CancellationToken); } else { await CommonController.WriteError(arg.HttpContext, "The project being uploaded is corrupted", StatusCodes.Status400BadRequest); } } } }
/// <summary> /// Moves the uploaded files (the actual file and it's metadata) to the user folder /// tus protocol puts the uploaded files into the store, XtraUpload move those files to the user directory /// </summary> private void MoveFilesToFolder(FileCompleteContext ctx, gFileItem fileItem) { string userFolder = Path.Combine(_uploadOpts.CurrentValue.UploadPath, fileItem.UserId); string destFolder = Path.Combine(userFolder, fileItem.Id); string newFileFullPath = Path.Combine(destFolder, fileItem.Id); // Create user root directory if (!Directory.Exists(userFolder)) { Directory.CreateDirectory(userFolder); } // Create a new directory inside the user root dir if (!Directory.Exists(destFolder)) { Directory.CreateDirectory(destFolder); } // move all files to the destination folder DirectoryInfo directoryInfo = new DirectoryInfo(_uploadOpts.CurrentValue.UploadPath); foreach (FileInfo file in directoryInfo.GetFiles(ctx.FileId + "*")) { // Exemple of file names generated by tus are (...69375.metadata, ...69375.uploadlength ...) string[] subNames = file.Name.Split('.'); string subName = subNames.Count() == 2 ? '.' + subNames[1] : string.Empty; File.Move(file.FullName, newFileFullPath + subName); } // Create thumbnails for img file (less than 15mb) if (fileItem.MimeType.StartsWith("image") && fileItem.Size < (1024L * 1024L * 15)) { // Todo: move the process of cropping images to a job using FileStream smallThumboutStream = new FileStream(newFileFullPath + ".smallthumb.png", FileMode.Create); using Image image = Image.Load(File.ReadAllBytes(newFileFullPath), out IImageFormat format); if (image.Width >= 800 || image.Height >= 800) { int width = 960, height = 640; int aspectRatio = image.Width / image.Height; if (aspectRatio == 0) { height = 960; width = 640; } using FileStream mediumThumboutStream = new FileStream(newFileFullPath + ".mediumthumb.png", FileMode.Create); Image mediumthumbnail = image.Clone(i => i.Resize(width, height).Crop(new Rectangle(0, 0, width, height))); mediumthumbnail.Save(mediumThumboutStream, format); } Image smallthumbnail = image.Clone(i => i.Resize(128, 128).Crop(new Rectangle(0, 0, 128, 128))); smallthumbnail.Save(smallThumboutStream, format); } }
private static async Task HandleOnFileComplete(ContextAdapter context, CancellationToken cancellationToken, string fileId) { if (context.Configuration.OnUploadCompleteAsync != null) { await context.Configuration.OnUploadCompleteAsync(fileId, context.Configuration.Store, cancellationToken); } if (context.Configuration.Events?.OnFileCompleteAsync != null) { await context.Configuration.Events.OnFileCompleteAsync(FileCompleteContext.Create(context, ctx => ctx.FileId = fileId)); } }
/// <summary> /// Moves the uploaded files to the avatar folder /// tus protocol puts the uploaded files into the store, XtraUpload move those files to the user directory /// </summary> private async Task <gUser> MoveFilesToFolder(FileCompleteContext ctx) { var gUserResponse = await _fileMngClient.GetUserAsync(new gUserRequest()); if (gUserResponse == null) { _logger.LogError("Unknown error occured while requesting user info"); return(null); } if (gUserResponse.Status.Status != Protos.RequestStatus.Success) { _logger.LogError(gUserResponse.Status.Message); return(null); } string userFolder = Path.Combine(_uploadOpts.CurrentValue.UploadPath, gUserResponse.User.Id); string avatarFolder = Path.Combine(userFolder, "avatar"); // Create user root directory if (!Directory.Exists(userFolder)) { Directory.CreateDirectory(userFolder); } // Creat avatar directory if (!Directory.Exists(avatarFolder)) { Directory.CreateDirectory(avatarFolder); } // move avatar to the avatar folder DirectoryInfo directoryInfo = new DirectoryInfo(_uploadOpts.CurrentValue.UploadPath); foreach (FileInfo file in directoryInfo.GetFiles(ctx.FileId + "*")) { // Exemple of file names generated by tus are (...69375.metadata, ...69375.uploadlength ...) string[] subNames = file.Name.Split('.'); string subName = subNames.Count() == 2 ? '.' + subNames[1] : "orig.avatar.png"; File.Move(file.FullName, Path.Combine(avatarFolder, subName), true); } // crop image string avatarPath = Path.Combine(avatarFolder, "orig.avatar.png"); using FileStream smallavatar = new FileStream(Path.Combine(avatarFolder, "avatar.png"), FileMode.Create); using Image image = Image.Load(File.ReadAllBytes(avatarPath), out IImageFormat format); Image smallthumbnail = image.Clone(i => i.Resize(128, 128).Crop(new Rectangle(0, 0, 128, 128))); smallthumbnail.Save(smallavatar, format); return(gUserResponse.User); }
/// <summary> /// Update db /// </summary> private async Task <string> RequestUpdateDb(FileCompleteContext ctx, gUser user) { var avatarUrl = ctx.HttpContext.Request.Scheme + "://" + ctx.HttpContext.Request.Host.Value + "/api/file/avatar/" + user.Id; var response = await _fileMngClient.SaveAvatarAsync(new gSaveAvatarRequest() { AvatarUrl = avatarUrl }); if (response == null) { _logger.LogError("Unknown error occured while requesting user info"); } if (response.Status.Status != Protos.RequestStatus.Success) { _logger.LogError(response.Status.Message); } return(avatarUrl); }
/// <summary> /// Handle the upload completion /// </summary> protected override async Task OnUploadCompleted(FileCompleteContext ctx) { try { gUser user = await MoveFilesToFolder(ctx); // Update db string avatarUrl = await RequestUpdateDb(ctx, user); // Attach avatar info to header, because tus send 204 (no response body is allowed) ctx.HttpContext.Response.Headers.Add("upload-data", Helpers.JsonSerialize(new { AvatarUrl = avatarUrl })); } catch (Exception _ex) { _logger.LogError(_ex.Message); throw _ex; } }
/// <summary> /// Handle the upload completion /// </summary> protected override async Task OnUploadCompleted(FileCompleteContext ctx) { try { gFileItem file = await PersistMetaData(ctx); if (file != null) { MoveFilesToFolder(ctx, file); // Attach file info to header, because tus send 204 (no response body is allowed) ctx.HttpContext.Response.Headers.Add("upload-data", Helpers.JsonSerialize(file)); } } catch (Exception _ex) { _logger.LogError(_ex.Message); throw _ex; } }
internal static async Task NotifyFileComplete(ContextAdapter context, Action <FileCompleteContext> configure = null) { #pragma warning disable CS0618 // Type or member is obsolete if (context.Configuration.OnUploadCompleteAsync == null && context.Configuration.Events?.OnFileCompleteAsync == null) { return; } var eventContext = FileCompleteContext.Create(context, configure); if (context.Configuration.OnUploadCompleteAsync != null) { await context.Configuration.OnUploadCompleteAsync.Invoke(eventContext.FileId, eventContext.Store, eventContext.CancellationToken); } #pragma warning restore CS0618 // Type or member is obsolete if (context.Configuration.Events?.OnFileCompleteAsync != null) { await context.Configuration.Events.OnFileCompleteAsync(eventContext); } }
public async Task OnFileCompleteAsync(FileCompleteContext context) { ITusFile file = await context.GetFileAsync(); _logger.LogInformation($"Fileupload completed: ${file.Id}"); var metadata = await file.GetMetadataAsync(context.CancellationToken); var metadataInString = ""; foreach (var item in metadata) { if (metadataInString.Length != 0) { metadataInString += ", "; } metadataInString += $"\"{item.Key}:{item.Value.GetString(Encoding.UTF8)}\""; } _logger.LogInformation($"Fileupload completed: {metadataInString}"); await DoSomeProcessing(file, metadata); await Task.CompletedTask; }
/// <summary> /// Moves the uploaded files to the avatar folder /// tus protocol puts the uploaded files into the store, XtraUpload move those files to the user directory /// </summary> private void MoveFilesToFolder(FileCompleteContext ctx, gUser user) { string userFolder = Path.Combine(_uploadOpts.CurrentValue.UploadPath, user.Id); string avatarFolder = Path.Combine(userFolder, "avatar"); // Create user root directory if (!Directory.Exists(userFolder)) { Directory.CreateDirectory(userFolder); } // Creat avatar directory if (!Directory.Exists(avatarFolder)) { Directory.CreateDirectory(avatarFolder); } // move avatar to the avatar folder DirectoryInfo directoryInfo = new DirectoryInfo(_uploadOpts.CurrentValue.UploadPath); foreach (FileInfo file in directoryInfo.GetFiles(ctx.FileId + "*")) { // Exemple of file names generated by tus are (...69375.metadata, ...69375.uploadlength ...) string[] subNames = file.Name.Split('.'); string subName = subNames.Count() == 2 ? '.' + subNames[1] : "orig.avatar.png"; File.Move(file.FullName, Path.Combine(avatarFolder, subName), true); } // crop image string avatarPath = Path.Combine(avatarFolder, "orig.avatar.png"); using FileStream smallavatar = new FileStream(Path.Combine(avatarFolder, "avatar.png"), FileMode.Create); using Image image = Image.Load(File.ReadAllBytes(avatarPath), out IImageFormat format); using Image smallthumbnail = image.Clone(i => i.Resize(128, 128).Crop(new Rectangle(0, 0, 128, 128))); smallthumbnail.Save(smallavatar, format); return; }
public Task HandleFileComplete(FileCompleteContext context) { return(Task.CompletedTask); }
/// <summary> /// Handle the upload completion /// </summary> protected abstract Task OnUploadCompleted(FileCompleteContext ctx);