[feat] Partially implemented transmission system
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -57,3 +57,4 @@ nunit-*.xml
|
||||
*.db
|
||||
|
||||
appsettings.json
|
||||
appsettings.Development.json
|
||||
95
.idea/.idea.Abyss/.idea/workspace.xml
generated
95
.idea/.idea.Abyss/.idea/workspace.xml
generated
@@ -10,10 +10,24 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="bf317275-3039-49bb-a475-725a800a0cce" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Components/Controllers/Task/TaskController.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Components/Tools/TemporaryDB.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Chip.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Comment.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Task.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/TaskCreation.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/Abyss/Model/Video.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss.sln.DotSettings.user" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss.sln.DotSettings.user" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Controllers/Media/VideoController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Controllers/Media/VideoController.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Services/ResourceService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Services/ResourceService.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Services/UserService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Services/UserService.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Components/Static/Helpers.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Static/Helpers.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Program.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/Properties/launchSettings.json" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Properties/launchSettings.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Abyss/appsettings.Development.json" beforeDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -27,27 +41,36 @@
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="HighlightingSettingsPerFile">
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/011a191356a243438f987de3ec3d6c6230800/04/8419ff35/ServiceProvider.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/457530be4752476295767457c3639889d1a000/4c/4b962087/Monitor.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/5df2accb46d040ccbbbe8331bf4d24b61daa00/df/93debd37/ControllerBase.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/7598e47d5cdf4107ba88f8220720fdc89000/a6/79d67871/xxHash128.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/f09ccaeb94c34c2299acd3efee0facee1a400/81/137b58b4/Key.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Controllers/AbyssController.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="mock:///home/acite/embd/WebProjects/Abyss/Abyss/Components/Controllers/Media/VideoController.cs" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///home/acite/embd/WebProjects/Abyss/Abyss/Components/Controllers/Media/VideoController.cs" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Controllers/Security/UserController.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Controllers/Task/TaskController.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Services/ConfigureService.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Services/ResourceService.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Services/UserService.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="mock:///home/acite/embd/WebProjects/Abyss/Abyss/Components/Services/UserService.cs" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///home/acite/embd/WebProjects/Abyss/Abyss/Components/Services/UserService.cs" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Static/Helpers.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Components/Tools/TemporaryDB.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/ChallengeResponse.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Chip.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Comment.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/ResourceAttribute.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Task.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/TaskCreation.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/User.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/UserCreating.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/Abyss/Model/Video.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/AbyssCli/Program.cs" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file:///usr/lib/dotnet/sdk/9.0.109/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.targets" root0="FORCE_HIGHLIGHTING" />
|
||||
</component>
|
||||
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
|
||||
<component name="ProblemsViewState">
|
||||
<option name="selectedTabId" value="CurrentFile" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 3
|
||||
}</component>
|
||||
@@ -56,31 +79,31 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
".NET Launch Settings Profile.Abyss: http.executor": "Run",
|
||||
".NET Launch Settings Profile.Abyss: https.executor": "Run",
|
||||
".NET Project.AbyssCli.executor": "Run",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"Publish to folder.Publish Abyss to folder x86.executor": "Run",
|
||||
"Publish to folder.Publish Abyss to folder.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"XThreadsFramesViewSplitterKey": "0.30266345",
|
||||
"git-widget-placeholder": "main",
|
||||
"last_opened_file_path": "/opt/security/https/server",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
".NET Launch Settings Profile.Abyss: http.executor": "Run",
|
||||
".NET Launch Settings Profile.Abyss: https.executor": "Debug",
|
||||
".NET Project.AbyssCli.executor": "Run",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"Publish to folder.Publish Abyss to folder x86.executor": "Run",
|
||||
"Publish to folder.Publish Abyss to folder.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"XThreadsFramesViewSplitterKey": "0.30266345",
|
||||
"git-widget-placeholder": "dev-task",
|
||||
"last_opened_file_path": "/home/acite/embd/WebProjects/Abyss/.gitignore",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
<component name="RunManager" selected="Publish to folder.Publish Abyss to folder x86">
|
||||
}]]></component>
|
||||
<component name="RunManager" selected=".NET Launch Settings Profile.Abyss: https">
|
||||
<configuration name="Publish Abyss to folder x86" type="DotNetFolderPublish" factoryName="Publish to folder">
|
||||
<riderPublish configuration="Release" platform="Any CPU" produce_single_file="true" ready_to_run="true" self_contained="true" target_folder="/opt/security/https/server" target_framework="net9.0" uuid_high="3690631506471504162" uuid_low="-4858628519588143325">
|
||||
<runtimes>
|
||||
@@ -174,7 +197,8 @@
|
||||
<workItem from="1756121403390" duration="7316000" />
|
||||
<workItem from="1756145197559" duration="780000" />
|
||||
<workItem from="1756205686118" duration="5398000" />
|
||||
<workItem from="1756277940361" duration="862000" />
|
||||
<workItem from="1756277940361" duration="1097000" />
|
||||
<workItem from="1756293105406" duration="17059000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
@@ -224,6 +248,19 @@
|
||||
<properties exception="System.Threading.ThreadAbortException" breakIfHandledByOtherCode="false" displayValue="System.Threading.ThreadAbortException" />
|
||||
<option name="timeStamp" value="3" />
|
||||
</breakpoint>
|
||||
<line-breakpoint enabled="true" type="DotNet Breakpoints">
|
||||
<url>file://$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs</url>
|
||||
<line>60</line>
|
||||
<properties documentPath="$PROJECT_DIR$/Abyss/Components/Services/TaskService.cs" containingFunctionPresentation="Method 'CreateVideoTask'">
|
||||
<startOffsets>
|
||||
<option value="2099" />
|
||||
</startOffsets>
|
||||
<endOffsets>
|
||||
<option value="2163" />
|
||||
</endOffsets>
|
||||
</properties>
|
||||
<option name="timeStamp" value="13" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AControllerBase_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5df2accb46d040ccbbbe8331bf4d24b61daa00_003Fdf_003F93debd37_003FControllerBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKey_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ff09ccaeb94c34c2299acd3efee0facee1a400_003F81_003F137b58b4_003FKey_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMonitor_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F457530be4752476295767457c3639889d1a000_003F4c_003F4b962087_003FMonitor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AServiceProvider_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F011a191356a243438f987de3ec3d6c6230800_003F04_003F8419ff35_003FServiceProvider_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AxxHash128_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7598e47d5cdf4107ba88f8220720fdc89000_003Fa6_003F79d67871_003FxxHash128_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
@@ -93,16 +93,5 @@ public class VideoController(ILogger<VideoController> logger, ResourceService rs
|
||||
return PhysicalFile(d, "video/mp4", enableRangeProcessing: true);
|
||||
}
|
||||
|
||||
[HttpGet("{klass}/{id}/nv")]
|
||||
public async Task<IActionResult> Nv(string klass, string id, string token)
|
||||
{
|
||||
var d = Helpers.SafePathCombine(VideoFolder, [klass, id, "video.a.mp4"]);
|
||||
if (d == null) return StatusCode(403, new { message = "403 Denied" });
|
||||
|
||||
var r = await rs.Get(d, token, Ip);
|
||||
if (!r) return StatusCode(403, new { message = "403 Denied" });
|
||||
return PhysicalFile(d, "video/mp4", enableRangeProcessing: true);
|
||||
}
|
||||
|
||||
private string Ip => HttpContext.Connection.RemoteIpAddress?.ToString() ?? "127.0.0.1";
|
||||
}
|
||||
60
Abyss/Components/Controllers/Task/TaskController.cs
Normal file
60
Abyss/Components/Controllers/Task/TaskController.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Abyss.Components.Services;
|
||||
using Abyss.Components.Static;
|
||||
using Abyss.Model;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Abyss.Components.Controllers.Task;
|
||||
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class TaskController(ILogger<TaskController> logger, ConfigureService config, TaskService taskService) : Controller
|
||||
{
|
||||
public readonly string TaskFolder = Path.Combine(config.MediaRoot, "Tasks");
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Query(string token)
|
||||
{
|
||||
// If the token is invalid, an empty list will be returned, which is part of the design
|
||||
return Json(await taskService.Query(token, Ip));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(string token, [FromBody] TaskCreation creation)
|
||||
{
|
||||
var r = await taskService.Create(token, Ip, creation);
|
||||
if(r == null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
return Ok(JsonConvert.SerializeObject(r, Formatting.Indented));
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetTask(string id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[HttpPatch("{id}")]
|
||||
public async Task<IActionResult> PutChip(string id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[HttpPost("{id}")]
|
||||
public async Task<IActionResult> VerifyChip(string id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> DeleteTask(string id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string Ip => HttpContext.Connection.RemoteIpAddress?.ToString() ?? "127.0.0.1";
|
||||
}
|
||||
@@ -39,6 +39,11 @@ public class ResourceService
|
||||
|
||||
_database = new SQLiteAsyncConnection(config.RaDatabase, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create);
|
||||
_database.CreateTableAsync<ResourceAttribute>().Wait();
|
||||
|
||||
var tasksPath = Helpers.SafePathCombine(_config.MediaRoot, "Tasks");
|
||||
if(tasksPath != null)
|
||||
InsertRaRow(tasksPath, "root", "rw,r-,r-", true).Wait();
|
||||
|
||||
}
|
||||
|
||||
// Create UID only for resources, without considering advanced hash security such as adding salt
|
||||
@@ -335,4 +340,34 @@ public class ResourceService
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> InsertRaRow(string fullPath, string owner, string permission, bool update = false)
|
||||
{
|
||||
if (!PermissionRegex.IsMatch(permission))
|
||||
{
|
||||
_logger.LogError($"Invalid permission format: {permission}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var path = Path.GetRelativePath(_config.MediaRoot, fullPath);
|
||||
|
||||
if (update)
|
||||
return await _database.InsertOrReplaceAsync(new ResourceAttribute()
|
||||
{
|
||||
Uid = Uid(path),
|
||||
Name = path,
|
||||
Owner = owner,
|
||||
Permission = permission,
|
||||
}) == 1;
|
||||
else
|
||||
{
|
||||
return await _database.InsertAsync(new ResourceAttribute()
|
||||
{
|
||||
Uid = Uid(path),
|
||||
Name = path,
|
||||
Owner = owner,
|
||||
Permission = permission,
|
||||
}) == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
247
Abyss/Components/Services/TaskService.cs
Normal file
247
Abyss/Components/Services/TaskService.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
using Abyss.Components.Static;
|
||||
using Abyss.Model;
|
||||
using Newtonsoft.Json;
|
||||
using SQLite;
|
||||
using Task = Abyss.Model.Task;
|
||||
|
||||
namespace Abyss.Components.Services;
|
||||
|
||||
|
||||
|
||||
public class TaskService(ILogger<TaskService> logger, ConfigureService config, ResourceService rs, UserService user)
|
||||
{
|
||||
public readonly string TaskFolder = Path.Combine(config.MediaRoot, "Tasks");
|
||||
public readonly string VideoFolder = Path.Combine(config.MediaRoot, "Videos");
|
||||
|
||||
private const ulong MaxChunkSize = 20 * 1024 * 1024;
|
||||
|
||||
public async Task<List<String>> Query(string token, string ip)
|
||||
{
|
||||
var r = await rs.Query(TaskFolder, token, ip);
|
||||
var u = user.Validate(token, ip);
|
||||
|
||||
List<string> s = new();
|
||||
foreach (var i in r ?? [])
|
||||
{
|
||||
var p = Helpers.SafePathCombine(TaskFolder, [i, "task.json"]);
|
||||
var c = JsonConvert.DeserializeObject<Model.Task>(await System.IO.File.ReadAllTextAsync(p ?? ""));
|
||||
|
||||
if(c?.Owner == u) s.Add(i);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public async Task<TaskCreationResponse?> Create(string token, string ip, TaskCreation creation)
|
||||
{
|
||||
if(creation.Name.Length > 64 || creation.Klass.Length > 16 || creation.Size > 10UL * 1024UL * 1024UL * 1024UL || creation.Author.Length > 32)
|
||||
return null;
|
||||
if(creation.Name == "" || creation.Klass == "")
|
||||
return null;
|
||||
if(!IsFileNameSafe(creation.Klass))
|
||||
return null;
|
||||
if (GetAvailableFreeSpace(TaskFolder) - (long)creation.Size < 10 * 1024L * 1024L * 1024L)
|
||||
{ // Reserve 10GB of space
|
||||
return null;
|
||||
}
|
||||
|
||||
switch ((TaskType)creation.Type)
|
||||
{
|
||||
case TaskType.Image:
|
||||
return await CreateImageTask(token, ip, creation);
|
||||
case TaskType.Video:
|
||||
return await CreateVideoTask(token, ip, creation);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<TaskCreationResponse?> CreateVideoTask(string token, string ip, TaskCreation creation)
|
||||
{
|
||||
if(!await rs.Valid(VideoFolder, token, OperationType.Write, ip))
|
||||
return null;
|
||||
var u = user.Validate(token, ip);
|
||||
if(u == null)
|
||||
return null;
|
||||
|
||||
var r = new TaskCreationResponse()
|
||||
{
|
||||
Id = GenerateUniqueId(TaskFolder),
|
||||
Chips = SliceFile(creation.Size)
|
||||
};
|
||||
|
||||
Directory.CreateDirectory(Path.Combine(TaskFolder, r.Id.ToString()));
|
||||
Directory.CreateDirectory(Path.Combine(TaskFolder, r.Id.ToString(), "gallery"));
|
||||
// It shouldn't be a problem to spell it directly like this, as all the parameters are generated by myself
|
||||
|
||||
Task v = new Task()
|
||||
{
|
||||
Name = creation.Name,
|
||||
Owner = u,
|
||||
Class = creation.Klass,
|
||||
Id = r.Id,
|
||||
Type = TaskType.Video
|
||||
};
|
||||
|
||||
await System.IO.File.WriteAllTextAsync(
|
||||
Path.Combine(TaskFolder, r.Id.ToString(), "task.json"),
|
||||
JsonConvert.SerializeObject(v, Formatting.Indented));
|
||||
|
||||
using (var connection = new SQLiteConnection(Path.Combine(TaskFolder, r.Id.ToString(), "task.db")))
|
||||
{
|
||||
connection.CreateTable<Chip>();
|
||||
connection.InsertAll(r.Chips.Select(x => new Chip()
|
||||
{
|
||||
Addr = x.Addr,
|
||||
Hash = "",
|
||||
Id = x.Id,
|
||||
Size = x.Size,
|
||||
State = ChipState.Created
|
||||
}));
|
||||
connection.Close();
|
||||
}
|
||||
|
||||
CreateEmptyFile(Path.Combine(TaskFolder, r.Id.ToString(), "video.mp4"), (long)creation.Size);
|
||||
return r;
|
||||
}
|
||||
|
||||
private async Task<TaskCreationResponse?> CreateImageTask(string token, string ip, TaskCreation creation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static uint GenerateUniqueId(string parentDirectory)
|
||||
{
|
||||
string[] directories = Directory.GetDirectories(parentDirectory);
|
||||
HashSet<uint> existingIds = new HashSet<uint>();
|
||||
|
||||
foreach (string dirPath in directories)
|
||||
{
|
||||
string dirName = new DirectoryInfo(dirPath).Name;
|
||||
if (uint.TryParse(dirName, out uint id))
|
||||
{
|
||||
if (id != 0)
|
||||
{
|
||||
existingIds.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint newId = 1;
|
||||
while (existingIds.Contains(newId))
|
||||
{
|
||||
newId++;
|
||||
if (newId == uint.MaxValue)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return newId;
|
||||
}
|
||||
|
||||
public static List<ChipDesc> SliceFile(ulong fileSize)
|
||||
{
|
||||
var tasks = new List<ChipDesc>();
|
||||
if (fileSize == 0)
|
||||
{
|
||||
return tasks;
|
||||
}
|
||||
|
||||
ulong remainingSize = fileSize;
|
||||
ulong currentAddr = 0;
|
||||
uint id = 0;
|
||||
|
||||
while (remainingSize > 0)
|
||||
{
|
||||
ulong chunkSize = remainingSize > MaxChunkSize ? MaxChunkSize : remainingSize;
|
||||
|
||||
tasks.Add(new ChipDesc
|
||||
{
|
||||
Id = id,
|
||||
Addr = currentAddr,
|
||||
Size = chunkSize
|
||||
});
|
||||
|
||||
currentAddr += chunkSize;
|
||||
remainingSize -= chunkSize;
|
||||
id++;
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public static bool IsFileNameSafe(string fileName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileName.Contains(Path.DirectorySeparatorChar) ||
|
||||
fileName.Contains(Path.AltDirectorySeparatorChar))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char[] invalidChars = Path.GetInvalidFileNameChars();
|
||||
if (fileName.Any(c => invalidChars.Contains(c)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] reservedNames = {
|
||||
"CON", "PRN", "AUX", "NUL",
|
||||
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
|
||||
};
|
||||
string nameWithoutExtension = Path.GetFileNameWithoutExtension(fileName).ToUpperInvariant();
|
||||
if (reservedNames.Contains(nameWithoutExtension))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void CreateEmptyFile(string filePath, long sizeInBytes)
|
||||
{
|
||||
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
fs.SetLength(sizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static long GetAvailableFreeSpace(string directoryPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(directoryPath))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
string rootPath = Path.GetPathRoot(directoryPath) ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(rootPath))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
DriveInfo driveInfo = new DriveInfo(rootPath);
|
||||
|
||||
if (driveInfo.IsReady)
|
||||
{
|
||||
return driveInfo.AvailableFreeSpace;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Abyss.Model;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NSec.Cryptography;
|
||||
using SQLite;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Abyss.Components.Services;
|
||||
|
||||
@@ -27,6 +28,8 @@ public class UserService
|
||||
_database.CreateTableAsync<User>().Wait();
|
||||
var rootUser = _database.Table<User>().Where(x => x.Name == "root").FirstOrDefaultAsync().Result;
|
||||
|
||||
_cache.Set("acite", $"acite@127.0.0.1", DateTimeOffset.Now.AddDays(1));
|
||||
|
||||
if (rootUser == null)
|
||||
{
|
||||
var key = GenerateKeyPair();
|
||||
|
||||
@@ -67,7 +67,6 @@ public static class StringArrayExtensions
|
||||
{
|
||||
public static string[] SortLikeWindows(this string[] array)
|
||||
{
|
||||
if (array == null) return null;
|
||||
if (array.Length == 0) return array;
|
||||
|
||||
Array.Sort(array, new WindowsFileNameComparer());
|
||||
@@ -76,7 +75,6 @@ public static class StringArrayExtensions
|
||||
|
||||
public static string[] SortLikeWindowsDescending(this string[] array)
|
||||
{
|
||||
if (array == null) return null;
|
||||
if (array.Length == 0) return array;
|
||||
|
||||
Array.Sort(array, new WindowsFileNameComparerDescending());
|
||||
@@ -85,14 +83,14 @@ public static class StringArrayExtensions
|
||||
|
||||
public static void SortLikeWindowsInPlace(this string[] array)
|
||||
{
|
||||
if (array == null || array.Length == 0) return;
|
||||
if (array.Length == 0) return;
|
||||
|
||||
Array.Sort(array, new WindowsFileNameComparer());
|
||||
}
|
||||
|
||||
public static void SortLikeWindowsDescendingInPlace(this string[] array)
|
||||
{
|
||||
if (array == null || array.Length == 0) return;
|
||||
if (array.Length == 0) return;
|
||||
|
||||
Array.Sort(array, new WindowsFileNameComparerDescending());
|
||||
}
|
||||
@@ -100,8 +98,8 @@ public static class StringArrayExtensions
|
||||
|
||||
public class WindowsFileNameComparer : IComparer<string>
|
||||
{
|
||||
private static readonly Regex _regex = new Regex(@"(\d+|\D+)", RegexOptions.Compiled);
|
||||
private static readonly CompareInfo _compareInfo = CultureInfo.InvariantCulture.CompareInfo;
|
||||
private static readonly Regex Regex = new Regex(@"(\d+|\D+)", RegexOptions.Compiled);
|
||||
private static readonly CompareInfo CompareInfo = CultureInfo.InvariantCulture.CompareInfo;
|
||||
|
||||
public int Compare(string? x, string? y)
|
||||
{
|
||||
@@ -110,8 +108,8 @@ public class WindowsFileNameComparer : IComparer<string>
|
||||
if (y == null) return 1;
|
||||
if (ReferenceEquals(x, y)) return 0;
|
||||
|
||||
var partsX = _regex.Matches(x);
|
||||
var partsY = _regex.Matches(y);
|
||||
var partsX = Regex.Matches(x);
|
||||
var partsY = Regex.Matches(y);
|
||||
|
||||
int minLength = Math.Min(partsX.Count, partsY.Count);
|
||||
|
||||
@@ -130,7 +128,7 @@ public class WindowsFileNameComparer : IComparer<string>
|
||||
int comparison;
|
||||
if (ContainsChinese(partX) || ContainsChinese(partY))
|
||||
{
|
||||
comparison = _compareInfo.Compare(partX, partY, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);
|
||||
comparison = CompareInfo.Compare(partX, partY, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -161,20 +159,20 @@ public class WindowsFileNameComparer : IComparer<string>
|
||||
|
||||
public class WindowsFileNameComparerDescending : IComparer<string>
|
||||
{
|
||||
private static readonly WindowsFileNameComparer _ascendingComparer = new WindowsFileNameComparer();
|
||||
private static readonly WindowsFileNameComparer AscendingComparer = new WindowsFileNameComparer();
|
||||
|
||||
public int Compare(string x, string y)
|
||||
public int Compare(string? x, string? y)
|
||||
{
|
||||
return _ascendingComparer.Compare(y, x);
|
||||
return AscendingComparer.Compare(y, x);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringNaturalCompare
|
||||
{
|
||||
private static readonly WindowsFileNameComparer _comparer = new WindowsFileNameComparer();
|
||||
private static readonly WindowsFileNameComparer Comparer = new WindowsFileNameComparer();
|
||||
|
||||
public static int Compare(string x, string y)
|
||||
{
|
||||
return _comparer.Compare(x, y);
|
||||
return Comparer.Compare(x, y);
|
||||
}
|
||||
}
|
||||
6
Abyss/Components/Tools/TemporaryDB.cs
Normal file
6
Abyss/Components/Tools/TemporaryDB.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Abyss.Components.Tools;
|
||||
|
||||
public class TemporaryDB
|
||||
{
|
||||
|
||||
}
|
||||
17
Abyss/Model/Chip.cs
Normal file
17
Abyss/Model/Chip.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Abyss.Model;
|
||||
|
||||
public enum ChipState
|
||||
{
|
||||
Created,
|
||||
Uploaded,
|
||||
Verified
|
||||
}
|
||||
|
||||
public class Chip
|
||||
{
|
||||
public uint Id { get; set; }
|
||||
public ulong Addr { get; set; }
|
||||
public ulong Size { get; set; }
|
||||
public string Hash { get; set; } = "";
|
||||
public ChipState State { get; set; }
|
||||
}
|
||||
7
Abyss/Model/Comment.cs
Normal file
7
Abyss/Model/Comment.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Abyss.Model;
|
||||
|
||||
public class Comment
|
||||
{
|
||||
public string username = "";
|
||||
public string text = "";
|
||||
}
|
||||
16
Abyss/Model/Task.cs
Normal file
16
Abyss/Model/Task.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Abyss.Model;
|
||||
|
||||
public enum TaskType
|
||||
{
|
||||
Video = 1,
|
||||
Image = 2,
|
||||
}
|
||||
|
||||
public class Task
|
||||
{
|
||||
public uint Id;
|
||||
public string Owner = "";
|
||||
public string Class = "";
|
||||
public string Name = "";
|
||||
public TaskType Type;
|
||||
}
|
||||
23
Abyss/Model/TaskCreation.cs
Normal file
23
Abyss/Model/TaskCreation.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Abyss.Model;
|
||||
|
||||
public class TaskCreation
|
||||
{
|
||||
public int Type { get; set; }
|
||||
public ulong Size { get; set; }
|
||||
public string Klass { get; set; } = "";
|
||||
public string Name { get; set; } = "";
|
||||
public string Author { get; set; } = "";
|
||||
}
|
||||
|
||||
public class ChipDesc
|
||||
{
|
||||
public uint Id;
|
||||
public ulong Addr;
|
||||
public ulong Size;
|
||||
}
|
||||
|
||||
public class TaskCreationResponse // As Array
|
||||
{
|
||||
public uint Id;
|
||||
public List<ChipDesc> Chips = new();
|
||||
}
|
||||
12
Abyss/Model/Video.cs
Normal file
12
Abyss/Model/Video.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Abyss.Model;
|
||||
|
||||
public class Video
|
||||
{
|
||||
public string name;
|
||||
public ulong duration;
|
||||
public List<string> gallery = new();
|
||||
public List<Comment> comment = new();
|
||||
public bool star;
|
||||
public uint like;
|
||||
public string author;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading.RateLimiting;
|
||||
using Abyss.Components.Controllers.Task;
|
||||
using Abyss.Components.Services;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
|
||||
@@ -17,6 +18,8 @@ public class Program
|
||||
builder.Services.AddSingleton<ConfigureService>();
|
||||
builder.Services.AddSingleton<UserService>();
|
||||
builder.Services.AddSingleton<ResourceService>();
|
||||
builder.Services.AddSingleton<TaskController>();
|
||||
builder.Services.AddSingleton<TaskService>();
|
||||
|
||||
builder.Services.AddRateLimiter(options =>
|
||||
{
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:7013;http://localhost:5198",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"MEDIA_ROOT" : "/storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user