281 lines
12 KiB
C#

using System.Linq;
using System.Threading.Tasks;
using gehGassi.Core.Interfaces;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Primitives;
namespace gehGassi.Web.Controllers
{
/// <summary>
/// Controller für die Rückgabe von Dateien, Bilder usw.
/// </summary>
[Route("File")]
public class FileController : Controller
{
private readonly IFileService _fileService;
private readonly IFileShareService _fileShareService;
private readonly IWebHostEnvironment _webHostEnvironment;
/// <summary>
/// Erstellt eine Instanz
/// </summary>
/// <param name="fileService">Instanz eines IFileService</param>
/// <param name="fileShareService">Instnanz eines IFileShareService</param>
/// <param name="webHostEnvironment">Instanz eines IWebHostEnvironment</param>
public FileController(IFileService fileService, IFileShareService fileShareService, IWebHostEnvironment webHostEnvironment)
{
_fileService = fileService;
_fileShareService = fileShareService;
_webHostEnvironment = webHostEnvironment;
}
/// <summary>
/// Gibt eine Datei zurück
/// </summary>
/// <param name="container">Container</param>
/// <param name="filename">Dateiname inkl. Pfad (relativ)</param>
/// <returns>Datei oder notFound</returns>
[HttpGet("{container}/{*filename}")]
[ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "container", "filename" }, Location = ResponseCacheLocation.Any)]
//[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public async Task<IActionResult> GetFile(string container, string filename)
{
if (!string.IsNullOrWhiteSpace(container) && !string.IsNullOrWhiteSpace(filename))
{
var file = await _fileService.GetAsync(container, filename);
var flatFilename = _fileService.GetFlatFilename(filename);
if (file != null)
{
return File(file, GetMimeMapping(flatFilename));
}
}
return NotFound();
}
/// <summary>
/// Gibt eine Datei zurück
/// </summary>
/// <param name="container">Container</param>
/// <param name="filename">Dateiname inkl. Pfad (relativ)</param>
/// <returns>Datei oder notFound</returns>
[HttpGet("uncached/{container}/{*filename}")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public async Task<IActionResult> GetFileUncached(string container, string filename)
{
var file = await _fileService.GetAsync(container, filename);
var flatFilename = _fileService.GetFlatFilename(filename);
if (file != null)
{
return File(file, GetMimeMapping(flatFilename));
}
return NotFound();
}
/// <summary>
/// Gibt eine Datei zurück
/// </summary>
/// <param name="share">Share des Mandanten</param>
/// <param name="path">Dateiname inkl. Pfad (relativ)</param>
/// <returns>Datei oder notFound</returns>
[ApiExplorerSettings(IgnoreApi = true)]
[Route("~/Browser/", Name = "Browser")]
[HttpGet("share/{share}/{*path}")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Browser(string share, string path)
{
path = path.TrimStart('/');
var file = _fileShareService.Get(share, path);
var flatFilename = path.Split('/').Last();
if (file != null)
{
return File(file, GetMimeMapping(flatFilename));
}
return NotFound();
}
/// <summary>
/// Gibt ein Icon für eine Datei-Extension zurück
/// </summary>
/// <param name="ext">Extenstion der Datei</param>
/// <returns>Datei oder notFound</returns>
[HttpGet("extension/{*ext}")]
[ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "ext" }, Location = ResponseCacheLocation.Any)]
//[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Extension(string ext)
{
if (ext.Contains('.'))
ext = ext.Replace(".", "");
var imageUrl = "/images/FileExtensions/_blank.png";
if (!string.IsNullOrEmpty(ext))
{
imageUrl = "/images/FileExtensions/" + ext + ".png";
var absolutePath = _webHostEnvironment.WebRootPath + imageUrl;
if (!System.IO.File.Exists(absolutePath))
{
imageUrl = "/images/FileExtensions/_blank.png";
}
}
var file = System.IO.File.ReadAllBytes(_webHostEnvironment.WebRootPath + imageUrl);
return File(file, GetMimeMapping(imageUrl));
}
/// <summary>
/// Gibt eine Datei zurück
/// </summary>
/// <param name="share">Share des Mandanten</param>
/// <param name="path">Dateiname inkl. Pfad (relativ)</param>
/// <returns>Datei oder notFound</returns>
[Route("/scorm/{share}/{*path}", Name = "Scorm")]
[HttpGet]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult GetScorm(string share, string path)
{
if (User.Identity.IsAuthenticated)
{
path = path.TrimStart('/');
var rangeHeader = Request.Headers["Range"];
if (rangeHeader.Count == 0)
{
var fileStream = _fileShareService.GetStream(share, path);
var flatFilename = path.Split('/').Last();
if (fileStream != null)
{
return File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true);
}
}
else
{
var info = _fileShareService.GetFileInfo(share, path);
if (info != null)
{
var totalLength = info.Size;
long start = 0;
long end = 0;
start = GetRangeStartAndEnd(rangeHeader, start, totalLength, ref end);
long chunkSize = (end - start) + 1;
var flatFilename = path.Split('/').Last();
var fileStream = _fileShareService.GetStream(share, path, start, end);
if (fileStream != null)
{
var result = File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true);
HttpContext.Response.Headers.ContentLength = chunkSize;
HttpContext.Response.Headers.ContentType = GetMimeMapping(flatFilename);
HttpContext.Response.Headers.ContentRange = $"bytes {start}-{end}/{totalLength}";
HttpContext.Response.Headers.AcceptRanges = "bytes";
HttpContext.Response.StatusCode = 206;
return result;
//return new FileStreamResult(fileStream, GetMimeMapping(flatFilename));
}
}
}
}
return NotFound();
}
/// <summary>
/// Gibt eine Video-Datei zurück
/// </summary>
/// <param name="share">Share des Mandanten</param>
/// <param name="path">Dateiname inkl. Pfad (relativ)</param>
/// <returns>Datei oder notFound</returns>
[Route("/video/{share}/{*path}", Name = "Video")]
[HttpGet]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult GetVideo(string share, string path)
{
if (User.Identity.IsAuthenticated)
{
path = path.TrimStart('/');
var rangeHeader = Request.Headers["Range"];
if (rangeHeader.Count == 0)
{
var fileStream = _fileShareService.GetStream(share, path);
var flatFilename = path.Split('/').Last();
if (fileStream != null)
{
return File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true);
}
}
else
{
var info = _fileShareService.GetFileInfo(share, path);
if (info != null)
{
var totalLength = info.Size;
long start = 0;
long end = 0;
start = GetRangeStartAndEnd(rangeHeader, start, totalLength, ref end);
long chunkSize = (end - start) + 1;
var flatFilename = path.Split('/').Last();
var fileStream = _fileShareService.GetStream(share, path, start, end);
if (fileStream != null)
{
var result = File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true);
HttpContext.Response.Headers.ContentLength = chunkSize;
HttpContext.Response.Headers.ContentType = GetMimeMapping(flatFilename);
HttpContext.Response.Headers.ContentRange = $"bytes {start}-{end}/{totalLength}";
HttpContext.Response.Headers.AcceptRanges = "bytes";
HttpContext.Response.StatusCode = 206;
return result;
//return new FileStreamResult(fileStream, GetMimeMapping(flatFilename));
}
}
}
}
return NotFound();
}
private static long GetRangeStartAndEnd(StringValues rangeHeader, long start, long totalLength, ref long end)
{
var headerContent = rangeHeader[0];
if (headerContent.StartsWith("bytes="))
{
headerContent = headerContent.Replace("bytes=", "");
if (headerContent.EndsWith("-"))
{
headerContent = headerContent.Replace("-", "");
start = long.Parse(headerContent);
end = totalLength - 1;
}
else
{
var parts = headerContent.Split("-");
start = long.Parse(parts[0]);
end = long.Parse(parts[1]);
}
}
return start;
}
/// <summary>
/// Gibt den Mimetype einer Datei zurück
/// </summary>
/// <param name="fileName">Dateiname</param>
/// <returns>Mimetype</returns>
private string GetMimeMapping(string fileName)
{
new FileExtensionContentTypeProvider().TryGetContentType(fileName, out var contentType);
return contentType ?? "application/octet-stream";
}
}
}