lampac/BaseModule/Controllers/StorageController.cs
2026-02-07 22:49:57 +02:00

318 lines
11 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Shared;
using Shared.Engine;
using Shared.Engine.Utilities;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using IO = System.IO;
namespace Lampac.Controllers
{
public class StorageController : BaseController
{
#region backup.js
[HttpGet]
[AllowAnonymous]
[Route("backup.js")]
[Route("backup/js/{token}")]
public ActionResult Backup(string token)
{
if (!AppInit.conf.storage.enable)
return Content(string.Empty, "application/javascript; charset=utf-8");
var sb = new StringBuilder(FileCache.ReadAllText("plugins/backup.js"));
sb.Replace("{localhost}", host)
.Replace("{token}", HttpUtility.UrlEncode(token));
return Content(sb.ToString(), "application/javascript; charset=utf-8");
}
#endregion
#region sync.js
[HttpGet]
[AllowAnonymous]
[Route("sync.js")]
[Route("sync/js/{token}")]
public ActionResult SyncJS(string token, bool lite)
{
if (!AppInit.conf.storage.enable)
return Content(string.Empty, "application/javascript; charset=utf-8");
StringBuilder sb;
if (lite || AppInit.conf.sync_user.version == 1)
{
sb = new StringBuilder(FileCache.ReadAllText($"plugins/{(lite ? "sync_lite" : "sync")}.js"));
}
else
{
sb = new StringBuilder(FileCache.ReadAllText("plugins/sync_v2/sync.js"));
}
sb.Replace("{sync-invc}", FileCache.ReadAllText("plugins/sync-invc.js"))
.Replace("{localhost}", host)
.Replace("{token}", HttpUtility.UrlEncode(token));
return Content(sb.ToString(), "application/javascript; charset=utf-8");
}
#endregion
#region Get
[HttpGet]
[Route("/storage/get")]
async public Task<ActionResult> Get(string path, string pathfile, bool responseInfo)
{
if (!AppInit.conf.storage.enable)
return ContentTo("{\"success\": false, \"msg\": \"disabled\"}");
string outFile = StorageManager.GetFilePath(path, false, requestInfo, pathfile);
if (outFile == null || !IO.File.Exists(outFile))
return ContentTo("{\"success\": false, \"msg\": \"outFile\"}");
var file = new FileInfo(outFile);
var fileInfo = new { file.Name, path = outFile, file.Length, changeTime = new DateTimeOffset(file.LastWriteTimeUtc).ToUnixTimeMilliseconds() };
if (responseInfo)
return Json(new { success = true, uid = requestInfo.user_uid, fileInfo });
string data;
if (AppInit.conf.storage.brotli)
{
data = await BrotliTo.DecompressAsync(outFile);
}
else
{
var semaphore = new SemaphorManager(outFile, TimeSpan.FromSeconds(20));
try
{
await semaphore.WaitAsync();
data = await IO.File.ReadAllTextAsync(outFile);
}
catch
{
HttpContext.Response.StatusCode = 503;
return ContentTo("{\"success\": false, \"msg\": \"fileLock\"}");
}
finally
{
semaphore.Release();
}
}
return Json(new { success = true, uid = requestInfo.user_uid, fileInfo, data });
}
#endregion
#region Set
[HttpPost]
[Route("/storage/set")]
async public Task<ActionResult> Set([FromQuery]string path, [FromQuery]string pathfile, [FromQuery]string connectionId, [FromQuery]string events)
{
if (!AppInit.conf.storage.enable)
return ContentTo("{\"success\": false, \"msg\": \"disabled\"}");
if (HttpContext.Request.ContentLength > AppInit.conf.storage.max_size)
return ContentTo("{\"success\": false, \"msg\": \"max_size\"}");
string outFile = StorageManager.GetFilePath(path, true, requestInfo, pathfile);
if (outFile == null)
return ContentTo("{\"success\": false, \"msg\": \"outFile\"}");
using (var memoryStream = PoolInvk.msm.GetStream())
{
try
{
await HttpContext.Request.Body.CopyToAsync(memoryStream);
memoryStream.Position = 0;
}
catch
{
HttpContext.Response.StatusCode = 503;
return ContentTo("{\"success\": false, \"msg\": \"Request.Body.CopyToAsync\"}");
}
if (AppInit.conf.storage.brotli)
{
await BrotliTo.CompressAsync(outFile, memoryStream);
}
else
{
var semaphore = new SemaphorManager(outFile, TimeSpan.FromSeconds(20));
try
{
await semaphore.WaitAsync();
using (var fileStream = new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None, PoolInvk.bufferSize))
{
await memoryStream.CopyToAsync(fileStream, PoolInvk.bufferSize);
}
}
catch
{
HttpContext.Response.StatusCode = 503;
return ContentTo("{\"success\": false, \"msg\": \"fileLock\"}");
}
finally
{
semaphore.Release();
}
}
}
#region events
if (!string.IsNullOrEmpty(events))
{
try
{
var json = JsonConvert.DeserializeObject<JObject>(CrypTo.DecodeBase64(events));
_ = Shared.Startup.WS.EventsAsync(json.Value<string>("connectionId"), requestInfo.user_uid, json.Value<string>("name"), json.Value<string>("data")).ConfigureAwait(false);
_ = Shared.Startup.Nws.EventsAsync(json.Value<string>("connectionId"), requestInfo.user_uid, json.Value<string>("name"), json.Value<string>("data")).ConfigureAwait(false);
}
catch { }
}
else
{
string edata = JsonConvertPool.SerializeObject(new { path, pathfile });
_ = Shared.Startup.Nws.EventsAsync(connectionId, requestInfo.user_uid, "storage", edata).ConfigureAwait(false);
}
#endregion
var inf = new FileInfo(outFile);
return Json(new
{
success = true,
uid = requestInfo.user_uid,
fileInfo = new { inf.Name, path = outFile, inf.Length, changeTime = new DateTimeOffset(inf.LastWriteTimeUtc).ToUnixTimeMilliseconds() }
});
}
#endregion
#region TempGet
[HttpGet]
[Route("/storage/temp/{key}")]
async public Task<ActionResult> TempGet(string key, bool responseInfo)
{
if (!AppInit.conf.storage.enable)
return ContentTo("{\"success\": false, \"msg\": \"disabled\"}");
string outFile = StorageManager.GetFilePath("temp", false, key);
if (outFile == null || !IO.File.Exists(outFile))
return ContentTo("{\"success\": false, \"msg\": \"outFile\"}");
var file = new FileInfo(outFile);
var fileInfo = new { file.Name, path = outFile, file.Length, changeTime = new DateTimeOffset(file.LastWriteTimeUtc).ToUnixTimeMilliseconds() };
if (responseInfo)
return Json(new { success = true, uid = requestInfo.user_uid, fileInfo });
string data;
if (AppInit.conf.storage.brotli)
{
data = await BrotliTo.DecompressAsync(outFile);
}
else
{
var semaphore = new SemaphorManager(outFile, TimeSpan.FromSeconds(20));
try
{
await semaphore.WaitAsync();
data = await IO.File.ReadAllTextAsync(outFile);
}
catch
{
HttpContext.Response.StatusCode = 503;
return ContentTo("{\"success\": false, \"msg\": \"fileLock\"}");
}
finally
{
semaphore.Release();
}
}
return Json(new { success = true, uid = requestInfo.user_uid, fileInfo, data });
}
#endregion
#region TempSet
[HttpPost]
[Route("/storage/temp/{key}")]
async public Task<ActionResult> TempSet(string key)
{
if (!AppInit.conf.storage.enable)
return ContentTo("{\"success\": false, \"msg\": \"disabled\"}");
if (HttpContext.Request.ContentLength > AppInit.conf.storage.max_size)
return ContentTo("{\"success\": false, \"msg\": \"max_size\"}");
string outFile = StorageManager.GetFilePath("temp", true, key);
if (outFile == null)
return ContentTo("{\"success\": false, \"msg\": \"outFile\"}");
using (var memoryStream = PoolInvk.msm.GetStream())
{
try
{
await HttpContext.Request.Body.CopyToAsync(memoryStream);
memoryStream.Position = 0;
}
catch
{
HttpContext.Response.StatusCode = 503;
return ContentTo("{\"success\": false, \"msg\": \"Request.Body.CopyToAsync\"}");
}
if (AppInit.conf.storage.brotli)
{
await BrotliTo.CompressAsync(outFile, memoryStream);
}
else
{
var semaphore = new SemaphorManager(outFile, TimeSpan.FromSeconds(20));
try
{
await semaphore.WaitAsync();
using (var fileStream = new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None, PoolInvk.bufferSize))
await memoryStream.CopyToAsync(fileStream, PoolInvk.bufferSize);
}
catch
{
HttpContext.Response.StatusCode = 503;
return ContentTo("{\"success\": false, \"msg\": \"fileLock\"}");
}
finally
{
semaphore.Release();
}
}
}
var inf = new FileInfo(outFile);
return Json(new
{
success = true,
uid = requestInfo.user_uid,
fileInfo = new { inf.Name, path = outFile, inf.Length, changeTime = new DateTimeOffset(inf.LastWriteTimeUtc).ToUnixTimeMilliseconds() }
});
}
#endregion
}
}