Raghava Pulugu
DIAG: Add /diag/testdbwrite endpoint
f1ad7b6
Raw
History Blame Contribute Delete
8.1 kB
using Microsoft.Extensions.FileProviders;
using System.IO;
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using TelegramSaaS.Application;
using TelegramSaaS.Application.Common.Interfaces.Services;
using TelegramSaaS.Infrastructure;
using MongoDB.Driver;
using TelegramSaaS.Infrastructure.Persistence;
using Telegram.Bot;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddProvider(new InMemoryLoggerProvider());
// Add services to the container
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});
// Learn more about configuring OpenAPI
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApi();
// Register Clean Architecture layers
builder.Services.AddApplication();
builder.Services.AddInfrastructure(builder.Configuration);
var app = builder.Build();
// Ensure local storage folders are generated at startup
using (var scope = app.Services.CreateScope())
{
var storageService = scope.ServiceProvider.GetRequiredService<IStorageService>();
storageService.EnsureDirectoriesCreated();
}
// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
// Enable local static image file serving
var storagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "storage");
Directory.CreateDirectory(storagePath);
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(storagePath),
RequestPath = "/storage"
});
// HF Space handles HTTPS at the proxy level — no redirect needed
// app.UseHttpsRedirection();
app.MapControllers();
// Serve files dynamically from MongoDB
app.MapGet("/storage/{*path}", async (string path, MongoDbContext dbContext) =>
{
var cleanPath = path.Replace('\\', '/');
var fileCollection = dbContext.GetCollection<MongoFile>("Files");
var file = await fileCollection.Find(x => x.Id == cleanPath).FirstOrDefaultAsync();
if (file == null)
{
return Results.NotFound();
}
return Results.File(file.Content, file.ContentType);
});
// Simple health endpoint
app.MapGet("/health", () => Results.Ok(new { Status = "Healthy", Timestamp = DateTime.UtcNow }));
// Diagnostic endpoint — test Telegram API connectivity
app.MapGet("/diag", async (ITelegramBotClient botClient, IConfiguration configuration) =>
{
var results = new Dictionary<string, string>();
var rawToken = configuration["Telegram:BotToken"] ?? "";
var maskedToken = string.IsNullOrEmpty(rawToken) ? "empty" : (rawToken.Length > 10 ? $"{rawToken[..6]}...{rawToken[^6..]}" : "too short");
results["token_configured"] = maskedToken;
try
{
var me = await botClient.GetMe();
results["bot"] = $"@{me.Username} ({me.FirstName})";
results["telegram_api"] = "OK";
}
catch (Exception ex)
{
results["bot"] = "FAILED";
results["telegram_api"] = ex.Message;
}
try
{
var webhookInfo = await botClient.GetWebhookInfo();
results["webhook_url"] = webhookInfo.Url ?? "NOT SET";
results["webhook_pending"] = webhookInfo.PendingUpdateCount.ToString();
results["webhook_error"] = webhookInfo.LastErrorMessage ?? "none";
results["webhook_last_error_date"] = webhookInfo.LastErrorDate?.ToString() ?? "none";
}
catch (Exception ex)
{
results["webhook"] = $"FAILED: {ex.Message}";
}
return Results.Ok(results);
});
app.MapGet("/diag/db", async (MongoDbContext dbContext) =>
{
try
{
var usersCol = dbContext.GetCollection<TelegramSaaS.Domain.Entities.User>("Users");
var jobsCol = dbContext.GetCollection<TelegramSaaS.Domain.Entities.GenerationJob>("GenerationJobs");
var serversCol = dbContext.GetCollection<TelegramSaaS.Domain.Entities.GpuServer>("GpuServers");
var jobs = await jobsCol.Find(_ => true).SortByDescending(j => j.CreatedAt).Limit(10).ToListAsync();
var users = await usersCol.Find(_ => true).SortByDescending(u => u.CreatedAt).Limit(10).ToListAsync();
var servers = await serversCol.Find(_ => true).ToListAsync();
return Results.Ok(new
{
Status = "OK",
JobsCount = await jobsCol.CountDocumentsAsync(_ => true),
UsersCount = await usersCol.CountDocumentsAsync(_ => true),
Servers = servers,
RecentJobs = jobs,
RecentUsers = users
});
}
catch (Exception ex)
{
return Results.Problem(title: "Database Diagnostics Failed", detail: ex.ToString());
}
});
app.MapGet("/diag/testdbwrite", async (MongoDbContext dbContext) =>
{
try
{
var jobsCol = dbContext.GetCollection<TelegramSaaS.Domain.Entities.GenerationJob>("GenerationJobs");
var testJob = new TelegramSaaS.Domain.Entities.GenerationJob
{
UserId = "afe67ef9-82a3-4596-8b3c-4c7a319ce2e5",
Prompt = "Test database write",
Type = TelegramSaaS.Domain.Entities.JobType.TextToImage,
Status = TelegramSaaS.Domain.Entities.JobStatus.Pending,
CreditCost = 0,
CreatedAt = DateTime.UtcNow
};
await jobsCol.InsertOneAsync(testJob);
await jobsCol.DeleteOneAsync(j => j.Id == testJob.Id);
return Results.Ok(new { Status = "Success", Message = "Database write and delete completed successfully.", JobId = testJob.Id });
}
catch (Exception ex)
{
return Results.Problem(title: "Database Write Test Failed", detail: ex.ToString());
}
});
// Auto-register Telegram webhook on startup
_ = Task.Run(async () =>
{
try
{
await Task.Delay(3000); // Wait for server to fully start
using var scope = app.Services.CreateScope();
var botClient = scope.ServiceProvider.GetRequiredService<ITelegramBotClient>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
var baseUrl = app.Configuration["Storage:BaseUrl"] ?? "https://raghava0450-saluai.hf.space";
var webhookUrl = $"{baseUrl.TrimEnd('/')}/api/v1/telegram/webhook";
await botClient.SetWebhook(webhookUrl, dropPendingUpdates: true);
logger.LogInformation("✅ Telegram webhook set: {WebhookUrl}", webhookUrl);
}
catch (Exception ex)
{
try
{
using var scope = app.Services.CreateScope();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "❌ Failed to set webhook");
}
catch
{
Console.WriteLine($"❌ Failed to set webhook: {ex.Message}");
}
}
});
app.MapGet("/diag/logs", () => Results.Ok(InMemoryLogStore.Logs.ToList()));
app.Run();
public static class InMemoryLogStore
{
public static ConcurrentQueue<string> Logs { get; } = new();
public static void Add(string log)
{
Logs.Enqueue($"[{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}] {log}");
while (Logs.Count > 200)
{
Logs.TryDequeue(out _);
}
}
}
public class InMemoryLogger : ILogger
{
private readonly string _name;
public InMemoryLogger(string name)
{
_name = name;
}
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter)
{
var message = formatter(state, exception);
if (exception != null)
{
message += Environment.NewLine + exception.ToString();
}
InMemoryLogStore.Add($"[{logLevel}] [{_name}] {message}");
}
}
public class InMemoryLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new InMemoryLogger(categoryName);
}
public void Dispose() {}
}