mirror of
https://github.com/chylex/Discord-History-Tracker.git
synced 2025-04-14 07:37:13 +03:00
Show downloaded attachments when viewing via Open Viewer
This commit is contained in:
parent
739e87c5ab
commit
c94808a15f
@ -11,9 +11,11 @@ using Avalonia.Controls;
|
|||||||
using DHT.Desktop.Common;
|
using DHT.Desktop.Common;
|
||||||
using DHT.Desktop.Dialogs.Message;
|
using DHT.Desktop.Dialogs.Message;
|
||||||
using DHT.Desktop.Main.Controls;
|
using DHT.Desktop.Main.Controls;
|
||||||
|
using DHT.Desktop.Server;
|
||||||
using DHT.Server.Data.Filters;
|
using DHT.Server.Data.Filters;
|
||||||
using DHT.Server.Database;
|
using DHT.Server.Database;
|
||||||
using DHT.Server.Database.Export;
|
using DHT.Server.Database.Export;
|
||||||
|
using DHT.Server.Database.Export.Strategy;
|
||||||
using DHT.Utils.Models;
|
using DHT.Utils.Models;
|
||||||
using static DHT.Desktop.Program;
|
using static DHT.Desktop.Program;
|
||||||
|
|
||||||
@ -55,7 +57,7 @@ namespace DHT.Desktop.Main.Pages {
|
|||||||
HasFilters = FilterModel.HasAnyFilters;
|
HasFilters = FilterModel.HasAnyFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WriteViewerFile(string path) {
|
private async Task WriteViewerFile(string path, IViewerExportStrategy strategy) {
|
||||||
const string ArchiveTag = "/*[ARCHIVE]*/";
|
const string ArchiveTag = "/*[ARCHIVE]*/";
|
||||||
|
|
||||||
string indexFile = await Resources.ReadTextAsync("Viewer/index.html");
|
string indexFile = await Resources.ReadTextAsync("Viewer/index.html");
|
||||||
@ -68,7 +70,7 @@ namespace DHT.Desktop.Main.Pages {
|
|||||||
string jsonTempFile = path + ".tmp";
|
string jsonTempFile = path + ".tmp";
|
||||||
|
|
||||||
await using (var jsonStream = new FileStream(jsonTempFile, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) {
|
await using (var jsonStream = new FileStream(jsonTempFile, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) {
|
||||||
await ViewerJsonExport.Generate(jsonStream, db, FilterModel.CreateFilter());
|
await ViewerJsonExport.Generate(jsonStream, strategy, db, FilterModel.CreateFilter());
|
||||||
|
|
||||||
char[] jsonBuffer = new char[Math.Min(32768, jsonStream.Position)];
|
char[] jsonBuffer = new char[Math.Min(32768, jsonStream.Position)];
|
||||||
jsonStream.Position = 0;
|
jsonStream.Position = 0;
|
||||||
@ -106,7 +108,7 @@ namespace DHT.Desktop.Main.Pages {
|
|||||||
TemporaryFiles.Add(fullPath);
|
TemporaryFiles.Add(fullPath);
|
||||||
|
|
||||||
Directory.CreateDirectory(rootPath);
|
Directory.CreateDirectory(rootPath);
|
||||||
await WriteViewerFile(fullPath);
|
await WriteViewerFile(fullPath, new LiveViewerExportStrategy(ServerManager.Port, ServerManager.Token));
|
||||||
|
|
||||||
Process.Start(new ProcessStartInfo(fullPath) { UseShellExecute = true });
|
Process.Start(new ProcessStartInfo(fullPath) { UseShellExecute = true });
|
||||||
}
|
}
|
||||||
@ -126,7 +128,7 @@ namespace DHT.Desktop.Main.Pages {
|
|||||||
|
|
||||||
string? path = await dialog;
|
string? path = await dialog;
|
||||||
if (!string.IsNullOrEmpty(path)) {
|
if (!string.IsNullOrEmpty(path)) {
|
||||||
await WriteViewerFile(path);
|
await WriteViewerFile(path, StandaloneViewerExportStrategy.Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ const DISCORD = (function() {
|
|||||||
|
|
||||||
// noinspection HtmlUnknownTarget
|
// noinspection HtmlUnknownTarget
|
||||||
templateAttachmentDownload = new TEMPLATE([
|
templateAttachmentDownload = new TEMPLATE([
|
||||||
"<a href='{url}' class='embed download'>Download {filename}</a>"
|
"<a href='{url}' class='embed download'>Download {name}</a>"
|
||||||
].join(""));
|
].join(""));
|
||||||
|
|
||||||
// noinspection HtmlUnknownTarget
|
// noinspection HtmlUnknownTarget
|
||||||
@ -240,19 +240,11 @@ const DISCORD = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return value.map(attachment => {
|
return value.map(attachment => {
|
||||||
const url = DOM.tryParseUrl(attachment.url);
|
if (DISCORD.isImageAttachment(attachment) && SETTINGS.enableImagePreviews) {
|
||||||
|
|
||||||
if (url != null && isImageUrl(url) && SETTINGS.enableImagePreviews) {
|
|
||||||
return templateEmbedImage.apply({ url: attachment.url, src: attachment.url });
|
return templateEmbedImage.apply({ url: attachment.url, src: attachment.url });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const path = url == null ? attachment.url : url.pathname;
|
return templateAttachmentDownload.apply(attachment);
|
||||||
const sliced = path.split("/");
|
|
||||||
|
|
||||||
return templateAttachmentDownload.apply({
|
|
||||||
"url": attachment.url,
|
|
||||||
"filename": sliced[sliced.length - 1]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}).join("");
|
}).join("");
|
||||||
}
|
}
|
||||||
|
6
app/Server/Data/DownloadedAttachment.cs
Normal file
6
app/Server/Data/DownloadedAttachment.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace DHT.Server.Data {
|
||||||
|
public readonly struct DownloadedAttachment {
|
||||||
|
public string? Type { get; internal init; }
|
||||||
|
public byte[] Data { get; internal init; }
|
||||||
|
}
|
||||||
|
}
|
@ -63,6 +63,10 @@ namespace DHT.Server.Database {
|
|||||||
return download;
|
return download;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DownloadedAttachment? GetDownloadedAttachment(string url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddDownload(Data.Download download) {}
|
public void AddDownload(Data.Download download) {}
|
||||||
|
|
||||||
public void EnqueueDownloadItems(AttachmentFilter? filter = null) {}
|
public void EnqueueDownloadItems(AttachmentFilter? filter = null) {}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
using DHT.Server.Data;
|
||||||
|
|
||||||
|
namespace DHT.Server.Database.Export.Strategy {
|
||||||
|
public interface IViewerExportStrategy {
|
||||||
|
string GetAttachmentUrl(Attachment attachment);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using System.Net;
|
||||||
|
using DHT.Server.Data;
|
||||||
|
|
||||||
|
namespace DHT.Server.Database.Export.Strategy {
|
||||||
|
public sealed class LiveViewerExportStrategy : IViewerExportStrategy {
|
||||||
|
private readonly string safePort;
|
||||||
|
private readonly string safeToken;
|
||||||
|
|
||||||
|
public LiveViewerExportStrategy(ushort port, string token) {
|
||||||
|
this.safePort = port.ToString();
|
||||||
|
this.safeToken = WebUtility.UrlEncode(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetAttachmentUrl(Attachment attachment) {
|
||||||
|
return "http://127.0.0.1:" + safePort + "/get-attachment/" + WebUtility.UrlEncode(attachment.Url) + "?token=" + safeToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
using DHT.Server.Data;
|
||||||
|
|
||||||
|
namespace DHT.Server.Database.Export.Strategy {
|
||||||
|
public sealed class StandaloneViewerExportStrategy : IViewerExportStrategy {
|
||||||
|
public static StandaloneViewerExportStrategy Instance { get; } = new ();
|
||||||
|
|
||||||
|
private StandaloneViewerExportStrategy() {}
|
||||||
|
|
||||||
|
public string GetAttachmentUrl(Attachment attachment) {
|
||||||
|
return attachment.Url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -5,13 +6,14 @@ using System.Text.Json;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DHT.Server.Data;
|
using DHT.Server.Data;
|
||||||
using DHT.Server.Data.Filters;
|
using DHT.Server.Data.Filters;
|
||||||
|
using DHT.Server.Database.Export.Strategy;
|
||||||
using DHT.Utils.Logging;
|
using DHT.Utils.Logging;
|
||||||
|
|
||||||
namespace DHT.Server.Database.Export {
|
namespace DHT.Server.Database.Export {
|
||||||
public static class ViewerJsonExport {
|
public static class ViewerJsonExport {
|
||||||
private static readonly Log Log = Log.ForType(typeof(ViewerJsonExport));
|
private static readonly Log Log = Log.ForType(typeof(ViewerJsonExport));
|
||||||
|
|
||||||
public static async Task Generate(Stream stream, IDatabaseFile db, MessageFilter? filter = null) {
|
public static async Task Generate(Stream stream, IViewerExportStrategy strategy, IDatabaseFile db, MessageFilter? filter = null) {
|
||||||
var perf = Log.Start();
|
var perf = Log.Start();
|
||||||
|
|
||||||
var includedUserIds = new HashSet<ulong>();
|
var includedUserIds = new HashSet<ulong>();
|
||||||
@ -41,7 +43,7 @@ namespace DHT.Server.Database.Export {
|
|||||||
|
|
||||||
var value = new {
|
var value = new {
|
||||||
meta = new { users, userindex, servers, channels },
|
meta = new { users, userindex, servers, channels },
|
||||||
data = GenerateMessageList(includedMessages, userIndices)
|
data = GenerateMessageList(includedMessages, userIndices, strategy)
|
||||||
};
|
};
|
||||||
|
|
||||||
perf.Step("Generate value object");
|
perf.Step("Generate value object");
|
||||||
@ -138,7 +140,7 @@ namespace DHT.Server.Database.Export {
|
|||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object GenerateMessageList(List<Message> includedMessages, Dictionary<ulong, object> userIndices) {
|
private static object GenerateMessageList( List<Message> includedMessages, Dictionary<ulong, object> userIndices, IViewerExportStrategy strategy) {
|
||||||
var data = new Dictionary<string, Dictionary<string, object>>();
|
var data = new Dictionary<string, Dictionary<string, object>>();
|
||||||
|
|
||||||
foreach (var grouping in includedMessages.GroupBy(static message => message.Channel)) {
|
foreach (var grouping in includedMessages.GroupBy(static message => message.Channel)) {
|
||||||
@ -164,8 +166,9 @@ namespace DHT.Server.Database.Export {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!message.Attachments.IsEmpty) {
|
if (!message.Attachments.IsEmpty) {
|
||||||
obj["a"] = message.Attachments.Select(static attachment => new Dictionary<string, object> {
|
obj["a"] = message.Attachments.Select(attachment => new Dictionary<string, object> {
|
||||||
{ "url", attachment.Url }
|
{ "url", strategy.GetAttachmentUrl(attachment) },
|
||||||
|
{ "name", Uri.TryCreate(attachment.Url, UriKind.Absolute, out var uri) ? Path.GetFileName(uri.LocalPath) : attachment.Url }
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ namespace DHT.Server.Database {
|
|||||||
void AddDownload(Data.Download download);
|
void AddDownload(Data.Download download);
|
||||||
List<Data.Download> GetDownloadsWithoutData();
|
List<Data.Download> GetDownloadsWithoutData();
|
||||||
Data.Download GetDownloadWithData(Data.Download download);
|
Data.Download GetDownloadWithData(Data.Download download);
|
||||||
|
DownloadedAttachment? GetDownloadedAttachment(string url);
|
||||||
|
|
||||||
void EnqueueDownloadItems(AttachmentFilter? filter = null);
|
void EnqueueDownloadItems(AttachmentFilter? filter = null);
|
||||||
List<DownloadItem> GetEnqueuedDownloadItems(int count);
|
List<DownloadItem> GetEnqueuedDownloadItems(int count);
|
||||||
void RemoveDownloadItems(DownloadItemFilter? filter, FilterRemovalMode mode);
|
void RemoveDownloadItems(DownloadItemFilter? filter, FilterRemovalMode mode);
|
||||||
|
@ -470,6 +470,28 @@ LEFT JOIN replied_to rt ON m.message_id = rt.message_id" + filter.GenerateWhereC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DownloadedAttachment? GetDownloadedAttachment(string url) {
|
||||||
|
using var conn = pool.Take();
|
||||||
|
using var cmd = conn.Command(@"
|
||||||
|
SELECT a.type, d.blob FROM downloads d
|
||||||
|
LEFT JOIN attachments a ON d.url = a.url
|
||||||
|
WHERE d.url = :url AND d.status = :success AND d.blob IS NOT NULL");
|
||||||
|
|
||||||
|
cmd.AddAndSet(":url", SqliteType.Text, url);
|
||||||
|
cmd.AddAndSet(":success", SqliteType.Integer, (int) DownloadStatus.Success);
|
||||||
|
|
||||||
|
using var reader = cmd.ExecuteReader();
|
||||||
|
|
||||||
|
if (!reader.Read()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DownloadedAttachment {
|
||||||
|
Type = reader.IsDBNull(0) ? null : reader.GetString(0),
|
||||||
|
Data = (byte[]) reader["blob"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public void EnqueueDownloadItems(AttachmentFilter? filter = null) {
|
public void EnqueueDownloadItems(AttachmentFilter? filter = null) {
|
||||||
using var conn = pool.Take();
|
using var conn = pool.Take();
|
||||||
using var cmd = conn.Command("INSERT INTO downloads (url, status, size) SELECT a.url, :enqueued, MAX(a.size) FROM attachments a" + filter.GenerateWhereClause("a") + " GROUP BY a.url");
|
using var cmd = conn.Command("INSERT INTO downloads (url, status, size) SELECT a.url, :enqueued, MAX(a.size) FROM attachments a" + filter.GenerateWhereClause("a") + " GROUP BY a.url");
|
||||||
|
@ -8,6 +8,7 @@ using DHT.Utils.Http;
|
|||||||
using DHT.Utils.Logging;
|
using DHT.Utils.Logging;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Extensions;
|
using Microsoft.AspNetCore.Http.Extensions;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace DHT.Server.Endpoints {
|
namespace DHT.Server.Endpoints {
|
||||||
abstract class BaseEndpoint {
|
abstract class BaseEndpoint {
|
||||||
@ -21,26 +22,22 @@ namespace DHT.Server.Endpoints {
|
|||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(HttpContext ctx) {
|
private async Task Handle(HttpContext ctx, StringValues token) {
|
||||||
var request = ctx.Request;
|
var request = ctx.Request;
|
||||||
var response = ctx.Response;
|
var response = ctx.Response;
|
||||||
|
|
||||||
Log.Info("Request: " + request.GetDisplayUrl() + " (" + request.ContentLength + " B)");
|
Log.Info("Request: " + request.GetDisplayUrl() + " (" + request.ContentLength + " B)");
|
||||||
|
|
||||||
var requestToken = request.Headers["X-DHT-Token"];
|
if (token.Count != 1 || token[0] != parameters.Token) {
|
||||||
if (requestToken.Count != 1 || requestToken[0] != parameters.Token) {
|
Log.Error("Token: " + (token.Count == 1 ? token[0] : "<missing>"));
|
||||||
Log.Error("Token: " + (requestToken.Count == 1 ? requestToken[0] : "<missing>"));
|
|
||||||
response.StatusCode = (int) HttpStatusCode.Forbidden;
|
response.StatusCode = (int) HttpStatusCode.Forbidden;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var (statusCode, output) = await Respond(ctx);
|
response.StatusCode = (int) HttpStatusCode.OK;
|
||||||
response.StatusCode = (int) statusCode;
|
var output = await Respond(ctx);
|
||||||
|
await output.WriteTo(response);
|
||||||
if (output != null) {
|
|
||||||
await response.WriteAsJsonAsync(output);
|
|
||||||
}
|
|
||||||
} catch (HttpException e) {
|
} catch (HttpException e) {
|
||||||
Log.Error(e);
|
Log.Error(e);
|
||||||
response.StatusCode = (int) e.StatusCode;
|
response.StatusCode = (int) e.StatusCode;
|
||||||
@ -51,7 +48,15 @@ namespace DHT.Server.Endpoints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Task<(HttpStatusCode, object?)> Respond(HttpContext ctx);
|
public async Task HandleGet(HttpContext ctx) {
|
||||||
|
await Handle(ctx, ctx.Request.Query["token"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandlePost(HttpContext ctx) {
|
||||||
|
await Handle(ctx, ctx.Request.Headers["X-DHT-Token"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Task<IHttpOutput> Respond(HttpContext ctx);
|
||||||
|
|
||||||
protected static async Task<JsonElement> ReadJson(HttpContext ctx) {
|
protected static async Task<JsonElement> ReadJson(HttpContext ctx) {
|
||||||
return await ctx.Request.ReadFromJsonAsync<JsonElement?>() ?? throw new HttpException(HttpStatusCode.UnsupportedMediaType, "This endpoint only accepts JSON.");
|
return await ctx.Request.ReadFromJsonAsync<JsonElement?>() ?? throw new HttpException(HttpStatusCode.UnsupportedMediaType, "This endpoint only accepts JSON.");
|
||||||
|
25
app/Server/Endpoints/GetAttachmentEndpoint.cs
Normal file
25
app/Server/Endpoints/GetAttachmentEndpoint.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using DHT.Server.Data;
|
||||||
|
using DHT.Server.Database;
|
||||||
|
using DHT.Server.Service;
|
||||||
|
using DHT.Utils.Http;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace DHT.Server.Endpoints {
|
||||||
|
sealed class GetAttachmentEndpoint : BaseEndpoint {
|
||||||
|
public GetAttachmentEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {}
|
||||||
|
|
||||||
|
protected override Task<IHttpOutput> Respond(HttpContext ctx) {
|
||||||
|
string attachmentUrl = WebUtility.UrlDecode((string) ctx.Request.RouteValues["url"]!);
|
||||||
|
DownloadedAttachment? maybeDownloadedAttachment = Db.GetDownloadedAttachment(attachmentUrl);
|
||||||
|
|
||||||
|
if (maybeDownloadedAttachment is {} downloadedAttachment) {
|
||||||
|
return Task.FromResult<IHttpOutput>(new HttpOutput.File(downloadedAttachment.Type, downloadedAttachment.Data));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Task.FromResult<IHttpOutput>(new HttpOutput.Redirect(attachmentUrl, permanent: false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ namespace DHT.Server.Endpoints {
|
|||||||
sealed class TrackChannelEndpoint : BaseEndpoint {
|
sealed class TrackChannelEndpoint : BaseEndpoint {
|
||||||
public TrackChannelEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {}
|
public TrackChannelEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {}
|
||||||
|
|
||||||
protected override async Task<(HttpStatusCode, object?)> Respond(HttpContext ctx) {
|
protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
|
||||||
var root = await ReadJson(ctx);
|
var root = await ReadJson(ctx);
|
||||||
var server = ReadServer(root.RequireObject("server"), "server");
|
var server = ReadServer(root.RequireObject("server"), "server");
|
||||||
var channel = ReadChannel(root.RequireObject("channel"), "channel", server.Id);
|
var channel = ReadChannel(root.RequireObject("channel"), "channel", server.Id);
|
||||||
@ -19,7 +19,7 @@ namespace DHT.Server.Endpoints {
|
|||||||
Db.AddServer(server);
|
Db.AddServer(server);
|
||||||
Db.AddChannel(channel);
|
Db.AddChannel(channel);
|
||||||
|
|
||||||
return (HttpStatusCode.OK, null);
|
return HttpOutput.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Data.Server ReadServer(JsonElement json, string path) => new() {
|
private static Data.Server ReadServer(JsonElement json, string path) => new() {
|
||||||
|
@ -17,7 +17,7 @@ namespace DHT.Server.Endpoints {
|
|||||||
sealed class TrackMessagesEndpoint : BaseEndpoint {
|
sealed class TrackMessagesEndpoint : BaseEndpoint {
|
||||||
public TrackMessagesEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {}
|
public TrackMessagesEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {}
|
||||||
|
|
||||||
protected override async Task<(HttpStatusCode, object?)> Respond(HttpContext ctx) {
|
protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
|
||||||
var root = await ReadJson(ctx);
|
var root = await ReadJson(ctx);
|
||||||
|
|
||||||
if (root.ValueKind != JsonValueKind.Array) {
|
if (root.ValueKind != JsonValueKind.Array) {
|
||||||
@ -39,7 +39,7 @@ namespace DHT.Server.Endpoints {
|
|||||||
|
|
||||||
Db.AddMessages(messages);
|
Db.AddMessages(messages);
|
||||||
|
|
||||||
return (HttpStatusCode.OK, anyNewMessages ? 1 : 0);
|
return new HttpOutput.Json(anyNewMessages ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Message ReadMessage(JsonElement json, string path) => new() {
|
private static Message ReadMessage(JsonElement json, string path) => new() {
|
||||||
|
@ -11,7 +11,7 @@ namespace DHT.Server.Endpoints {
|
|||||||
sealed class TrackUsersEndpoint : BaseEndpoint {
|
sealed class TrackUsersEndpoint : BaseEndpoint {
|
||||||
public TrackUsersEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {}
|
public TrackUsersEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {}
|
||||||
|
|
||||||
protected override async Task<(HttpStatusCode, object?)> Respond(HttpContext ctx) {
|
protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
|
||||||
var root = await ReadJson(ctx);
|
var root = await ReadJson(ctx);
|
||||||
|
|
||||||
if (root.ValueKind != JsonValueKind.Array) {
|
if (root.ValueKind != JsonValueKind.Array) {
|
||||||
@ -27,7 +27,7 @@ namespace DHT.Server.Endpoints {
|
|||||||
|
|
||||||
Db.AddUsers(users);
|
Db.AddUsers(users);
|
||||||
|
|
||||||
return (HttpStatusCode.OK, null);
|
return HttpOutput.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static User ReadUser(JsonElement json, string path) => new() {
|
private static User ReadUser(JsonElement json, string path) => new() {
|
||||||
|
@ -34,13 +34,16 @@ namespace DHT.Server.Service {
|
|||||||
app.UseCors();
|
app.UseCors();
|
||||||
app.UseEndpoints(endpoints => {
|
app.UseEndpoints(endpoints => {
|
||||||
TrackChannelEndpoint trackChannel = new(db, parameters);
|
TrackChannelEndpoint trackChannel = new(db, parameters);
|
||||||
endpoints.MapPost("/track-channel", async context => await trackChannel.Handle(context));
|
endpoints.MapPost("/track-channel", async context => await trackChannel.HandlePost(context));
|
||||||
|
|
||||||
TrackUsersEndpoint trackUsers = new(db, parameters);
|
TrackUsersEndpoint trackUsers = new(db, parameters);
|
||||||
endpoints.MapPost("/track-users", async context => await trackUsers.Handle(context));
|
endpoints.MapPost("/track-users", async context => await trackUsers.HandlePost(context));
|
||||||
|
|
||||||
TrackMessagesEndpoint trackMessages = new(db, parameters);
|
TrackMessagesEndpoint trackMessages = new(db, parameters);
|
||||||
endpoints.MapPost("/track-messages", async context => await trackMessages.Handle(context));
|
endpoints.MapPost("/track-messages", async context => await trackMessages.HandlePost(context));
|
||||||
|
|
||||||
|
GetAttachmentEndpoint getAttachment = new(db, parameters);
|
||||||
|
endpoints.MapGet("/get-attachment/{url}", async context => await getAttachment.HandleGet(context));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
app/Utils/Http/HttpOutput.cs
Normal file
56
app/Utils/Http/HttpOutput.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace DHT.Utils.Http {
|
||||||
|
public static class HttpOutput {
|
||||||
|
public static IHttpOutput None { get; } = new NoneImpl();
|
||||||
|
|
||||||
|
private sealed class NoneImpl : IHttpOutput {
|
||||||
|
public Task WriteTo(HttpResponse response) {
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class Json : IHttpOutput {
|
||||||
|
private readonly object? obj;
|
||||||
|
|
||||||
|
public Json(object? obj) {
|
||||||
|
this.obj = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task WriteTo(HttpResponse response) {
|
||||||
|
return response.WriteAsJsonAsync(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class File : IHttpOutput {
|
||||||
|
private readonly string? contentType;
|
||||||
|
private readonly byte[] bytes;
|
||||||
|
|
||||||
|
public File(string? contentType, byte[] bytes) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task WriteTo(HttpResponse response) {
|
||||||
|
response.ContentType = contentType ?? string.Empty;
|
||||||
|
await response.Body.WriteAsync(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class Redirect : IHttpOutput {
|
||||||
|
private readonly string url;
|
||||||
|
private readonly bool permanent;
|
||||||
|
|
||||||
|
public Redirect(string url, bool permanent) {
|
||||||
|
this.url = url;
|
||||||
|
this.permanent = permanent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task WriteTo(HttpResponse response) {
|
||||||
|
response.Redirect(url, permanent);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
app/Utils/Http/IHttpOutput.cs
Normal file
8
app/Utils/Http/IHttpOutput.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace DHT.Utils.Http {
|
||||||
|
public interface IHttpOutput {
|
||||||
|
Task WriteTo(HttpResponse response);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,9 @@
|
|||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<DebugType>none</DebugType>
|
<DebugType>none</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="10.3.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="10.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user