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;
            }
        }
Exemple #3
0
        /// <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);
        }
Exemple #4
0
        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);
                    }
                }
            }
        }
Exemple #5
0
        /// <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);
            }
        }
Exemple #6
0
        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));
            }
        }
Exemple #7
0
        /// <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);
        }
Exemple #8
0
        /// <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);
        }
Exemple #9
0
        /// <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;
            }
        }
Exemple #10
0
        /// <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;
            }
        }
Exemple #11
0
        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);
            }
        }
Exemple #12
0
        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);
 }
Exemple #15
0
 /// <summary>
 /// Handle the upload completion
 /// </summary>
 protected abstract Task OnUploadCompleted(FileCompleteContext ctx);