code guidelines
This commit is contained in:
106
src/Yavsc/Services/DiskUsageTracker.cs
Normal file
106
src/Yavsc/Services/DiskUsageTracker.cs
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Yavsc;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Services;
|
||||
|
||||
|
||||
public class DiskUsageTracker : IDiskUsageTracker
|
||||
{
|
||||
public class DUTInfo
|
||||
{
|
||||
public DUTInfo()
|
||||
{
|
||||
Creation = DateTime.Now;
|
||||
}
|
||||
public long Usage { get; set; }
|
||||
public long Quota { get; set; }
|
||||
public readonly DateTime Creation;
|
||||
}
|
||||
|
||||
readonly Dictionary<string, DUTInfo> DiskUsage;
|
||||
readonly ApplicationDbContext context;
|
||||
readonly int ulistLength;
|
||||
public DiskUsageTracker(IOptions<SiteSettings> options, ApplicationDbContext context)
|
||||
{
|
||||
ulistLength = options.Value.DUUserListLen;
|
||||
DiskUsage = new Dictionary<string, DUTInfo>();
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
readonly static object userInfoLock = new object();
|
||||
|
||||
DUTInfo GetInfo(string username)
|
||||
{
|
||||
lock (userInfoLock)
|
||||
{
|
||||
if (!DiskUsage.ContainsKey(username))
|
||||
{
|
||||
var user = context.Users.SingleOrDefault(u => u.UserName == username);
|
||||
if (user == null) throw new Exception($"Not an user : {username}");
|
||||
DUTInfo usage = new DUTInfo
|
||||
{
|
||||
Usage = user.DiskUsage,
|
||||
Quota = user.DiskQuota
|
||||
};
|
||||
DiskUsage.Add(username, usage);
|
||||
if (DiskUsage.Count > ulistLength)
|
||||
{
|
||||
// remove the oldest
|
||||
var oldestts = DateTime.Now;
|
||||
DUTInfo oinfo = null;
|
||||
string ouname = null;
|
||||
foreach (var diskusage in DiskUsage)
|
||||
{
|
||||
if (oldestts > usage.Creation)
|
||||
{
|
||||
oldestts = diskusage.Value.Creation;
|
||||
ouname = diskusage.Key;
|
||||
oinfo = diskusage.Value;
|
||||
}
|
||||
}
|
||||
var ouser = context.Users.SingleOrDefault(u => u.UserName == ouname);
|
||||
ouser.DiskUsage = oinfo.Usage;
|
||||
context.SaveChanges();
|
||||
DiskUsage.Remove(ouname);
|
||||
}
|
||||
return usage;
|
||||
}
|
||||
return DiskUsage[username];
|
||||
}
|
||||
}
|
||||
public bool GetSpace(string userName, long space)
|
||||
{
|
||||
var info = GetInfo(userName);
|
||||
if (info.Quota < info.Usage + space) return false;
|
||||
info.Usage += space;
|
||||
#pragma warning disable CS4014
|
||||
SaveUserUsage(userName,info.Usage);
|
||||
#pragma warning restore CS4014
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Release(string userName, long space)
|
||||
{
|
||||
var info = GetInfo(userName);
|
||||
info.Usage -= space;
|
||||
#pragma warning disable CS4014
|
||||
SaveUserUsage(userName,info.Usage);
|
||||
#pragma warning restore CS4014
|
||||
}
|
||||
|
||||
async Task SaveUserUsage(string username, long usage)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var ouser = context.Users.SingleOrDefault(u => u.UserName == username);
|
||||
ouser.DiskUsage = usage;
|
||||
context.SaveChanges();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -4,6 +4,9 @@ using System.Security.Principal;
|
||||
using System.Security.Claims;
|
||||
using Yavsc.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using System.IO;
|
||||
using rules;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
@ -12,10 +15,20 @@ namespace Yavsc.Services
|
||||
readonly ApplicationDbContext _dbContext;
|
||||
readonly ILogger _logger;
|
||||
|
||||
public FileSystemAuthManager(ApplicationDbContext dbContext, ILoggerFactory loggerFactory)
|
||||
readonly SiteSettings SiteSettings;
|
||||
|
||||
readonly string aclfileName;
|
||||
|
||||
readonly RuleSetParser ruleSetParser;
|
||||
|
||||
public FileSystemAuthManager(ApplicationDbContext dbContext, ILoggerFactory loggerFactory,
|
||||
IOptions<SiteSettings> sitesOptions)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_logger = loggerFactory.CreateLogger<FileSystemAuthManager>();
|
||||
SiteSettings = sitesOptions.Value;
|
||||
aclfileName = SiteSettings.AccessListFileName;
|
||||
ruleSetParser = new RuleSetParser(true);
|
||||
}
|
||||
|
||||
public FileAccessRight GetFilePathAccess(ClaimsPrincipal user, string normalizedFullPath)
|
||||
@ -25,38 +38,45 @@ namespace Yavsc.Services
|
||||
var parts = normalizedFullPath.Split('/');
|
||||
|
||||
// below 4 parts, no file name.
|
||||
if (parts.Length<4) return FileAccessRight.None;
|
||||
|
||||
var filePath = string.Join("/",parts.Skip(3));
|
||||
if (parts.Length < 4) return FileAccessRight.None;
|
||||
|
||||
var fileDir = string.Join("/", parts.Take(parts.Length - 1));
|
||||
|
||||
var firstFileNamePart = parts[3];
|
||||
if (firstFileNamePart == "pub")
|
||||
{
|
||||
_logger.LogInformation("Serving public file.");
|
||||
return FileAccessRight.Read;
|
||||
}
|
||||
if (firstFileNamePart == "pub")
|
||||
{
|
||||
_logger.LogInformation("Serving public file.");
|
||||
return FileAccessRight.Read;
|
||||
}
|
||||
|
||||
var funame = parts[2];
|
||||
_logger.LogInformation($"{normalizedFullPath} from {funame}");
|
||||
|
||||
if (funame == user?.GetUserName())
|
||||
{
|
||||
_logger.LogInformation("Serving file to owner.");
|
||||
return FileAccessRight.Read | FileAccessRight.Write;
|
||||
}
|
||||
_logger.LogInformation($"Accessing {normalizedFullPath} from {funame}");
|
||||
|
||||
if (funame == user?.GetUserName())
|
||||
{
|
||||
_logger.LogInformation("Serving file to owner.");
|
||||
return FileAccessRight.Read | FileAccessRight.Write;
|
||||
}
|
||||
var aclfi = new FileInfo(Path.Combine(Environment.CurrentDirectory, fileDir, aclfileName));
|
||||
// TODO default user scoped file access policy
|
||||
if (!aclfi.Exists) return FileAccessRight.Read;
|
||||
ruleSetParser.Reset();
|
||||
ruleSetParser.ParseFile(aclfi.FullName);
|
||||
if (ruleSetParser.Rules.Allow(user.GetUserName()))
|
||||
return FileAccessRight.Read;
|
||||
|
||||
var ucl = user.Claims.Where(c => c.Type == YavscClaimTypes.CircleMembership).Select(c => long.Parse(c.Value)).Distinct().ToArray();
|
||||
|
||||
|
||||
var uclString = string.Join(",", ucl);
|
||||
_logger.LogInformation($"{uclString} ");
|
||||
foreach (
|
||||
var cid in ucl
|
||||
) {
|
||||
var ok = _dbContext.CircleAuthorizationToFile.Any(a => a.CircleId == cid && a.FullPath == filePath);
|
||||
)
|
||||
{
|
||||
var ok = _dbContext.CircleAuthorizationToFile.Any(a => a.CircleId == cid && a.FullPath == fileDir);
|
||||
if (ok) return FileAccessRight.Read;
|
||||
}
|
||||
|
||||
|
||||
return FileAccessRight.None;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@ namespace Yavsc.Services
|
||||
readonly IHubContext _hubContext;
|
||||
private readonly ILogger _logger;
|
||||
readonly ApplicationDbContext _dbContext;
|
||||
public PathString LiveCastingPath { get; set; } = Constants.LivePath;
|
||||
|
||||
|
||||
public ConcurrentDictionary<string, LiveCastHandler> Casters { get; } = new ConcurrentDictionary<string, LiveCastHandler>();
|
||||
@ -38,23 +37,12 @@ namespace Yavsc.Services
|
||||
_logger = loggerFactory.CreateLogger<LiveProcessor>();
|
||||
}
|
||||
|
||||
public async Task<bool> AcceptStream(HttpContext context)
|
||||
public async Task<bool> AcceptStream(HttpContext context, ApplicationUser user, string destDir, string fileName)
|
||||
{
|
||||
// TODO defer request handling
|
||||
var liveId = long.Parse(context.Request.Path.Value.Substring(LiveCastingPath.Value.Length + 1));
|
||||
var userId = context.User.GetUserId();
|
||||
var user = await _dbContext.Users.FirstAsync(u => u.Id == userId);
|
||||
var uname = user.UserName;
|
||||
var flow = _dbContext.LiveFlow.Include(f => f.Owner).SingleOrDefault(f => (f.OwnerId == userId && f.Id == liveId));
|
||||
if (flow == null)
|
||||
{
|
||||
_logger.LogWarning("Aborting. Flow info was not found.");
|
||||
context.Response.StatusCode = 400;
|
||||
return false;
|
||||
}
|
||||
_logger.LogInformation("flow : " + flow.Title + " for " + uname);
|
||||
|
||||
|
||||
|
||||
string uname = user.UserName;
|
||||
LiveCastHandler liveHandler = null;
|
||||
if (Casters.ContainsKey(uname))
|
||||
{
|
||||
@ -100,35 +88,15 @@ namespace Yavsc.Services
|
||||
|
||||
_logger.LogInformation($"Received bytes : {received.Count}");
|
||||
_logger.LogInformation($"Is the end : {received.EndOfMessage}");
|
||||
const string livePath = "live";
|
||||
|
||||
|
||||
string destDir = context.User.InitPostToFileSystem(livePath);
|
||||
_logger.LogInformation($"Saving flow to {destDir}");
|
||||
|
||||
string fileName = flow.GetFileName();
|
||||
FileInfo destFileInfo = new FileInfo(Path.Combine(destDir, fileName));
|
||||
// this should end :-)
|
||||
while (destFileInfo.Exists)
|
||||
{
|
||||
flow.SequenceNumber++;
|
||||
fileName = flow.GetFileName();
|
||||
destFileInfo = new FileInfo(Path.Combine(destDir, fileName));
|
||||
}
|
||||
|
||||
var fsInputQueue = new Queue<ArraySegment<byte>>();
|
||||
|
||||
bool endOfInput = false;
|
||||
fsInputQueue.Enqueue(sBuffer);
|
||||
var taskWritingToFs = liveHandler.ReceiveUserFile(user, _logger, destDir, fsInputQueue, fileName, flow.MediaType, () => endOfInput);
|
||||
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
|
||||
|
||||
hubContext.Clients.All.addPublicStream(new PublicStreamInfo
|
||||
{
|
||||
id = flow.Id,
|
||||
sender = flow.Owner.UserName,
|
||||
title = flow.Title,
|
||||
url = flow.GetFileUrl(),
|
||||
mediaType = flow.MediaType
|
||||
}, $"{flow.Owner.UserName} is starting a stream!");
|
||||
var taskWritingToFs = liveHandler.ReceiveUserFile(user, _logger, destDir, fsInputQueue, fileName, () => endOfInput);
|
||||
|
||||
|
||||
Stack<string> ToClose = new Stack<string>();
|
||||
|
||||
@ -136,7 +104,6 @@ namespace Yavsc.Services
|
||||
{
|
||||
do
|
||||
{
|
||||
|
||||
_logger.LogInformation($"Echoing {received.Count} bytes received in a {received.MessageType} message; Fin={received.EndOfMessage}");
|
||||
// Echo anything we receive
|
||||
// and send to all listner found
|
||||
|
Reference in New Issue
Block a user