feat(api): add news to /api/meta response
This commit is contained in:
parent
31b6ac2cac
commit
5c57b75335
6 changed files with 147 additions and 5 deletions
97
Catalogger.Backend/Services/NewsService.cs
Normal file
97
Catalogger.Backend/Services/NewsService.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (C) 2021-present sam (starshines.gay)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Catalogger.Backend.Extensions;
|
||||
using NodaTime;
|
||||
using NodaTime.Extensions;
|
||||
using Remora.Discord.API;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
|
||||
namespace Catalogger.Backend.Services;
|
||||
|
||||
public class NewsService(
|
||||
Config config,
|
||||
ILogger logger,
|
||||
IDiscordRestChannelAPI channelApi,
|
||||
IClock clock
|
||||
)
|
||||
{
|
||||
private static readonly Duration MaxNewsAge = Duration.FromDays(90); // 3 months
|
||||
private static readonly Duration ExpiresAfter = Duration.FromHours(1);
|
||||
|
||||
private readonly ILogger _logger = logger.ForContext<NewsService>();
|
||||
private List<IMessage>? _messages;
|
||||
private readonly SemaphoreSlim _lock = new(1);
|
||||
private bool _isExpired => clock.GetCurrentInstant() > clock.GetCurrentInstant() + ExpiresAfter;
|
||||
|
||||
public async Task<IEnumerable<NewsMessage>> GetNewsAsync()
|
||||
{
|
||||
if (_messages != null && !_isExpired)
|
||||
return _messages.Select(FormatIMessage);
|
||||
|
||||
var messages = await GetRawNewsAsync();
|
||||
return messages.Select(FormatIMessage);
|
||||
}
|
||||
|
||||
public void AddMessage(IMessage message) =>
|
||||
_messages = _messages?.Take(4).Prepend(message).ToList();
|
||||
|
||||
private async Task<List<IMessage>> GetRawNewsAsync()
|
||||
{
|
||||
await _lock.WaitAsync();
|
||||
try
|
||||
{
|
||||
if (config.Web.NewsChannel == null)
|
||||
return [];
|
||||
|
||||
_logger.Information("Fetching news from channel {ChannelId}", config.Web.NewsChannel);
|
||||
|
||||
var res = await channelApi.GetChannelMessagesAsync(
|
||||
DiscordSnowflake.New(config.Web.NewsChannel.Value),
|
||||
limit: 5
|
||||
);
|
||||
if (res.IsSuccess)
|
||||
return _messages = res
|
||||
.Entity.Where(m =>
|
||||
m.ID.Timestamp.ToInstant() > clock.GetCurrentInstant() - MaxNewsAge
|
||||
)
|
||||
.ToList();
|
||||
|
||||
return [];
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public record NewsMessage(
|
||||
string Author,
|
||||
string Content,
|
||||
IEnumerable<string> AttachmentUrls,
|
||||
DateTimeOffset PostedAt,
|
||||
DateTimeOffset? EditedAt
|
||||
);
|
||||
|
||||
private NewsMessage FormatIMessage(IMessage msg) =>
|
||||
new(
|
||||
msg.Author.Tag(),
|
||||
msg.Content,
|
||||
msg.Attachments.Select(a => a.Url),
|
||||
msg.ID.Timestamp,
|
||||
msg.EditedTimestamp
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue