Files
Playa/hosts/Volcanic.AgenticCore.Telegram/Scheduling/CalendarScriptEnvironment.cs
EugeneTes 0cb791d529 fix(telegram): break the DI cycle through CalendarScriptEnvironment
ChatRegistry -> JobScheduler -> IScriptEnvironment -> ChatRegistry made the host
fail at startup. CalendarScriptEnvironment now takes TelegramOptions and computes
the workspace with the new static ChatRegistry.WorkspaceFor(options, chatId).
2026-10-02 08:45:48 +00:00

30 lines
1.7 KiB
C#

using System.Globalization;
using Volcanic.AgenticCore.Extensions.GoogleCalendar;
using Volcanic.AgenticCore.Extensions.Scheduler;
using Volcanic.AgenticCore.Telegram.Chats;
namespace Volcanic.AgenticCore.Telegram.Scheduling;
/// <summary>
/// Gives a chat's watcher scripts <c>GOOGLE_ACCESS_TOKEN</c>: an access token for that chat's calendar, valid for the
/// run's timeout plus a minute (as far as Google's one-hour lifetime allows). The bot refreshes it; the refresh token
/// and the client secret never reach the script. A chat without a connected calendar gets nothing.
/// Takes <see cref="TelegramOptions"/>, not <see cref="ChatRegistry"/>: the registry depends on the scheduler, which
/// depends on this.
/// </summary>
public sealed class CalendarScriptEnvironment(TelegramOptions options, GoogleCalendarOptions calendar) : IScriptEnvironment
{
public const string AccessTokenVariable = "GOOGLE_ACCESS_TOKEN";
private static readonly TimeSpan Margin = TimeSpan.FromMinutes(1);
private static readonly IReadOnlyDictionary<string, string> None = new Dictionary<string, string>();
public async Task<IReadOnlyDictionary<string, string>> ForRunAsync(string target, TimeSpan timeout, CancellationToken cancellationToken)
{
if (!long.TryParse(target, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var chatId)) return None;
var token = await (calendar.Connections ?? GoogleCalendarConnections.Shared)
.TryGetAccessTokenAsync(calendar, ChatRegistry.ScopeFor(chatId), ChatRegistry.WorkspaceFor(options, chatId), timeout + Margin, cancellationToken)
.ConfigureAwait(false);
return token is null ? None : new Dictionary<string, string> { [AccessTokenVariable] = token };
}
}