♻️ Move the chat part of the Sphere service to the Messager service

This commit is contained in:
2026-01-01 22:09:08 +08:00
parent c503083df7
commit ab37bbc7b0
50 changed files with 3042 additions and 611 deletions

View File

@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NodaTime;
using PollQuestionType = DysonNetwork.Shared.Models.PollQuestionType;
namespace DysonNetwork.Sphere.Poll;
@@ -14,7 +15,7 @@ namespace DysonNetwork.Sphere.Poll;
[Route("/api/polls")]
public class PollController(
AppDatabase db,
PollService polls,
Poll.PollService polls,
Publisher.PublisherService pub,
RemoteAccountService remoteAccountsHelper
) : ControllerBase

View File

@@ -0,0 +1,158 @@
using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Models;
using Grpc.Core;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;
using PollQuestionType = DysonNetwork.Shared.Proto.PollQuestionType;
namespace DysonNetwork.Sphere.Poll;
public class PollServiceGrpc(AppDatabase db, PollService ps) : Shared.Proto.PollService.PollServiceBase
{
public override async Task<Shared.Proto.Poll> GetPoll(GetPollRequest request, ServerCallContext context)
{
if (!Guid.TryParse(request.Id, out var id))
throw new RpcException(new Status(StatusCode.InvalidArgument, "invalid poll id"));
var poll = await db.Polls
.Include(p => p.Publisher)
.Include(p => p.Questions)
.FirstOrDefaultAsync(p => p.Id == id);
if (poll == null) throw new RpcException(new Status(StatusCode.NotFound, "poll not found"));
return poll.ToProtoValue();
}
public override async Task<GetPollBatchResponse> GetPollBatch(GetPollBatchRequest request,
ServerCallContext context)
{
var ids = request.Ids
.Where(s => !string.IsNullOrWhiteSpace(s) && Guid.TryParse(s, out _))
.Select(Guid.Parse)
.ToList();
if (ids.Count == 0) return new GetPollBatchResponse();
var polls = await db.Polls
.Include(p => p.Publisher)
.Include(p => p.Questions)
.Where(p => ids.Contains(p.Id))
.ToListAsync();
var resp = new GetPollBatchResponse();
resp.Polls.AddRange(polls.Select(p => p.ToProtoValue()));
return resp;
}
public override async Task<ListPollsResponse> ListPolls(ListPollsRequest request, ServerCallContext context)
{
var query = db.Polls
.Include(p => p.Publisher)
.Include(p => p.Questions)
.AsQueryable();
if (!string.IsNullOrWhiteSpace(request.PublisherId) && Guid.TryParse(request.PublisherId, out var pid))
query = query.Where(p => p.PublisherId == pid);
var totalSize = await query.CountAsync();
var pageSize = request.PageSize > 0 ? request.PageSize : 20;
var pageToken = request.PageToken;
var offset = string.IsNullOrEmpty(pageToken) ? 0 : int.Parse(pageToken);
IOrderedQueryable<SnPoll> orderedQuery;
if (!string.IsNullOrEmpty(request.OrderBy))
{
switch (request.OrderBy)
{
case "title":
orderedQuery = request.OrderDesc
? query.OrderByDescending(q => q.Title ?? string.Empty)
: query.OrderBy(q => q.Title ?? string.Empty);
break;
case "ended_at":
orderedQuery = request.OrderDesc
? query.OrderByDescending(q => q.EndedAt)
: query.OrderBy(q => q.EndedAt);
break;
default:
orderedQuery = request.OrderDesc
? query.OrderByDescending(q => q.CreatedAt)
: query.OrderBy(q => q.CreatedAt);
break;
}
}
else
{
orderedQuery = request.OrderDesc
? query.OrderByDescending(q => q.CreatedAt)
: query.OrderBy(q => q.CreatedAt);
}
var polls = await orderedQuery
.Skip(offset)
.Take(pageSize)
.ToListAsync();
var nextToken = offset + pageSize < totalSize ? (offset + pageSize).ToString() : string.Empty;
var resp = new ListPollsResponse();
resp.Polls.AddRange(polls.Select(p => p.ToProtoValue()));
resp.NextPageToken = nextToken;
resp.TotalSize = totalSize;
return resp;
}
public override async Task<PollAnswer> GetPollAnswer(GetPollAnswerRequest request, ServerCallContext context)
{
if (!Guid.TryParse(request.PollId, out var pollId))
throw new RpcException(new Status(StatusCode.InvalidArgument, "invalid poll id"));
if (!Guid.TryParse(request.AccountId, out var accountId))
throw new RpcException(new Status(StatusCode.InvalidArgument, "invalid account id"));
var answer = await ps.GetPollAnswer(pollId, accountId);
if (answer == null)
throw new RpcException(new Status(StatusCode.NotFound, "answer not found"));
return answer.ToProtoValue();
}
public override async Task<GetPollStatsResponse> GetPollStats(GetPollStatsRequest request, ServerCallContext context)
{
if (!Guid.TryParse(request.PollId, out var pollId))
throw new RpcException(new Status(StatusCode.InvalidArgument, "invalid poll id"));
var stats = await ps.GetPollStats(pollId);
var resp = new GetPollStatsResponse();
foreach (var stat in stats)
{
var statsJson = JsonSerializer.Serialize(stat.Value);
resp.Stats[stat.Key.ToString()] = statsJson;
}
return resp;
}
public override async Task<GetPollQuestionStatsResponse> GetPollQuestionStats(GetPollQuestionStatsRequest request,
ServerCallContext context)
{
if (!Guid.TryParse(request.QuestionId, out var questionId))
throw new RpcException(new Status(StatusCode.InvalidArgument, "invalid question id"));
var stats = await ps.GetPollQuestionStats(questionId);
var resp = new GetPollQuestionStatsResponse();
foreach (var stat in stats)
{
resp.Stats[stat.Key] = stat.Value;
}
return resp;
}
}