diff --git a/AobaCore/AobaCore.csproj b/AobaCore/AobaCore.csproj
index 02d6c07..835ab6f 100644
--- a/AobaCore/AobaCore.csproj
+++ b/AobaCore/AobaCore.csproj
@@ -8,11 +8,10 @@
-
+
-
diff --git a/AobaCore/AobaService.cs b/AobaCore/AobaService.cs
index 51db6d2..30417e1 100644
--- a/AobaCore/AobaService.cs
+++ b/AobaCore/AobaService.cs
@@ -1,31 +1,76 @@
-using AobaV2.Models;
+using AobaCore.Models;
+
+using MaybeError.Errors;
using MongoDB.Bson;
using MongoDB.Driver;
+using MongoDB.Driver.GridFS;
namespace AobaCore;
public class AobaService(IMongoDatabase db)
{
private readonly IMongoCollection _media = db.GetCollection("media");
+ private readonly GridFSBucket _gridFs = new(db);
- public async Task GetMediaAsync(ObjectId id)
+ public async Task GetMediaAsync(ObjectId id, CancellationToken cancellationToken = default)
{
- return await _media.Find(m => m.Id == id).FirstOrDefaultAsync();
+ return await _media.Find(m => m.Id == id).FirstOrDefaultAsync(cancellationToken);
}
- public Task AddMediaAsync(Media media)
+ public Task AddMediaAsync(Media media, CancellationToken cancellationToken = default)
{
- return _media.InsertOneAsync(media);
+ return _media.InsertOneAsync(media, null, cancellationToken);
}
- public Task IncrementViewCountAsync(ObjectId id)
+ public Task IncrementViewCountAsync(ObjectId id, CancellationToken cancellationToken = default)
{
- return _media.UpdateOneAsync(m => m.Id == id, Builders.Update.Inc(m => m.ViewCount, 1));
+ return _media.UpdateOneAsync(m => m.Id == id, Builders.Update.Inc(m => m.ViewCount, 1), cancellationToken: cancellationToken);
}
- public Task IncrementFileViewCountAsync(ObjectId fileId)
+ public Task IncrementFileViewCountAsync(ObjectId fileId, CancellationToken cancellationToken = default)
{
- return _media.UpdateOneAsync(m => m.MediaId == fileId, Builders.Update.Inc(m => m.ViewCount, 1));
+ return _media.UpdateOneAsync(m => m.MediaId == fileId, Builders.Update.Inc(m => m.ViewCount, 1), cancellationToken: cancellationToken);
+ }
+
+
+ public async Task> UploadFileAsync(Stream data, string filename, ObjectId owner, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ var fileId = await _gridFs.UploadFromStreamAsync(filename, data, cancellationToken: cancellationToken);
+ var media = new Media(fileId, filename, owner);
+ await AddMediaAsync(media, cancellationToken);
+ return media;
+ }
+ catch (Exception ex)
+ {
+ return ex;
+ }
+ }
+
+ public async Task> GetFileStreamAsync(ObjectId id, bool seekable = false, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ return await _gridFs.OpenDownloadStreamAsync(id, new GridFSDownloadOptions { Seekable = seekable }, cancellationToken);
+ }
+ catch (GridFSException ex)
+ {
+ return ex;
+ }
+ }
+
+ public async Task DeleteFileAsync(ObjectId fileId, CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ await _gridFs.DeleteAsync(fileId, cancellationToken);
+ await _media.DeleteOneAsync(m => m.MediaId == fileId, cancellationToken);
+ }
+ catch (GridFSFileNotFoundException)
+ {
+ //ignore if file was not found
+ }
}
}
diff --git a/AobaCore/Extensions.cs b/AobaCore/Extensions.cs
index f04dd0c..405ea6d 100644
--- a/AobaCore/Extensions.cs
+++ b/AobaCore/Extensions.cs
@@ -23,7 +23,6 @@ public static class Extensions
services.AddSingleton(dbClient);
services.AddSingleton(db);
services.AddSingleton();
- services.AddSingleton();
return services;
}
}
diff --git a/AobaCore/MediaService.cs b/AobaCore/MediaService.cs
deleted file mode 100644
index 0573ba8..0000000
--- a/AobaCore/MediaService.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using AobaV2.Models;
-
-using MaybeError.Errors;
-
-using MongoDB.Bson;
-using MongoDB.Driver;
-using MongoDB.Driver.GridFS;
-
-
-namespace AobaCore;
-public class MediaService(IMongoDatabase db, AobaService aobaService)
-{
- private readonly GridFSBucket _gridFs = new(db);
-
- public async Task> UploadMediaAsync(Stream data, string filename, ObjectId owner, CancellationToken cancellationToken = default)
- {
- var fileId = await _gridFs.UploadFromStreamAsync(filename, data, cancellationToken: cancellationToken);
- var media = new Media(fileId, filename, owner);
- await aobaService.AddMediaAsync(media);
- return media;
- }
-
- public async Task>> GetMediaStreamAsync(ObjectId id, bool seekable = false)
- {
- try
- {
- return await _gridFs.OpenDownloadStreamAsync(id, new GridFSDownloadOptions { Seekable = seekable });
- }
- catch (GridFSException ex)
- {
- return new ExceptionError(ex);
- }
- }
-}
diff --git a/AobaCore/Models/Media.cs b/AobaCore/Models/Media.cs
index 0c140a6..5d178b5 100644
--- a/AobaCore/Models/Media.cs
+++ b/AobaCore/Models/Media.cs
@@ -1,7 +1,7 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
-namespace AobaV2.Models;
+namespace AobaCore.Models;
[BsonIgnoreExtraElements]
public class Media
diff --git a/AobaServer/AobaServer.csproj b/AobaServer/AobaServer.csproj
index 2e49415..ffcabe8 100644
--- a/AobaServer/AobaServer.csproj
+++ b/AobaServer/AobaServer.csproj
@@ -9,21 +9,29 @@
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
-
-
+
-
+
-
-
-
+
+
+
+
+
+
+
diff --git a/AobaServer/Controllers/MediaController.cs b/AobaServer/Controllers/MediaController.cs
index c1124e4..2d869b7 100644
--- a/AobaServer/Controllers/MediaController.cs
+++ b/AobaServer/Controllers/MediaController.cs
@@ -10,20 +10,24 @@ using MongoDB.Driver;
namespace AobaServer.Controllers;
[Route("/m")]
-public class MediaController(MediaService mediaService, AobaService aobaService, ILogger logger) : Controller
+public class MediaController(AobaService aobaService, ILogger logger) : Controller
{
[HttpGet("{id}")]
[ResponseCache(Duration = int.MaxValue)]
- public async Task MediaAsync(ObjectId id)
+ public async Task MediaAsync(ObjectId id, [FromServices] MongoClient client, CancellationToken cancellationToken)
{
- var file = await mediaService.GetMediaStreamAsync(id);
+ using var session = await client.StartSessionAsync(cancellationToken: cancellationToken);
+ session.StartTransaction();
+ var file = await aobaService.GetFileStreamAsync(id, cancellationToken: cancellationToken);
if (file.HasError)
{
+ await session.AbortTransactionAsync(cancellationToken: cancellationToken);
logger.LogError(file.Error.Exception, "Failed to load media stream");
return NotFound();
}
+ await session.CommitTransactionAsync(cancellationToken: cancellationToken);
var mime = MimeTypesMap.GetMimeType(file.Value.FileInfo.Filename);
- _ = aobaService.IncrementFileViewCountAsync(id);
+ _ = aobaService.IncrementFileViewCountAsync(id, cancellationToken);
return File(file, mime, true);
}
@@ -35,9 +39,9 @@ public class MediaController(MediaService mediaService, AobaService aobaService,
///
///
[HttpGet("/i/{id}/{*rest}")]
- public async Task LegacyRedirectAsync(ObjectId id, string rest, [FromServices] AobaService aoba)
+ public async Task LegacyRedirectAsync(ObjectId id, string rest, CancellationToken cancellationToken)
{
- var media = await aoba.GetMediaAsync(id);
+ var media = await aobaService.GetMediaAsync(id, cancellationToken);
if (media == null)
return NotFound();
return LocalRedirectPermanent($"/m/{media.MediaId}/{rest}");
diff --git a/AobaServer/Program.cs b/AobaServer/Program.cs
index 24205d5..1c4a5d3 100644
--- a/AobaServer/Program.cs
+++ b/AobaServer/Program.cs
@@ -4,6 +4,7 @@ using AobaServer;
using AobaServer.Auth;
using AobaServer.Middleware;
using AobaServer.Models;
+using AobaServer.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
@@ -16,6 +17,7 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(opt => opt.ModelBinderProviders.Add(new BsonIdModelBinderProvider()));
builder.Services.AddObersability(builder.Configuration);
+builder.Services.AddGrpc();
var authInfo = AuthInfo.LoadOrCreate("Auth.json", "aobaV2", "aoba");
builder.Services.AddSingleton(authInfo);
@@ -92,6 +94,9 @@ app.UseAuthorization();
app.MapControllers();
app.MapObserability();
+app.MapGrpcService();
+
+
app.Run();
diff --git a/AobaServer/Proto/Aoba.proto b/AobaServer/Proto/Aoba.proto
new file mode 100644
index 0000000..91e62ed
--- /dev/null
+++ b/AobaServer/Proto/Aoba.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+
+
+service AobaRPC {
+ rpc GetMedia (Id) returns (MediaModel);
+}
+
+message Id{
+ string idString = 1;
+}
+
+message MediaModel {
+ int32 version = 1;
+ Id id = 2;
+ string mediaId = 3;
+ string fileName = 4;
+ MediaType mediaType = 5;
+ string ext = 6;
+ int32 viewCount = 7;
+ Id owner = 8;
+}
+
+enum MediaType{
+ Image = 0;
+ Audio = 1;
+ Video = 2;
+ Text = 3;
+ Code = 4;
+ Raw = 5;
+}
\ No newline at end of file
diff --git a/AobaServer/Services/AobaRpcService.cs b/AobaServer/Services/AobaRpcService.cs
new file mode 100644
index 0000000..c915eff
--- /dev/null
+++ b/AobaServer/Services/AobaRpcService.cs
@@ -0,0 +1,13 @@
+using AobaCore;
+
+using Grpc.Core;
+
+namespace AobaServer.Services;
+
+public class AobaRpcService(AobaService aobaService) : AobaRPC.AobaRPCBase
+{
+ public override Task GetMedia(Id request, ServerCallContext context)
+ {
+ return base.GetMedia(request, context);
+ }
+}