feat: improve email sending, startup, and testing #52

Merged
eleith merged 1 commits from gemini/fix/email-and-startup-issues into main 2025-08-26 21:59:42 +00:00
6 changed files with 72 additions and 32 deletions

No files matched your search

+3
View File
@@ -32,3 +32,6 @@ vendor:
go mod vendor
all: ci build
preview-docker:
@trap "exit 0" INT; docker compose up --build
+18 -19
View File
@@ -19,11 +19,12 @@ import (
)
const (
JitterSeconds = 30
ArchiveCleanupDays = 21
JitterSeconds = 30
ArchiveCleanupDays = 21
)
func digestJob(application *app.App) {
func digestJob(application *app.App, source string) {
log.Printf("Starting digest job from source: %s", source)
overviewFile, groupedEntryFiles, data, err := processor.ProcessDigest(application)
if err != nil {
log.Printf("Error processing digest: %v", err)
@@ -37,22 +38,30 @@ func digestJob(application *app.App) {
}
}
log.Printf("Digest produced at %s: entries=%d, folder=%s, email_sent=%t",
log.Printf("Digest produced at %s: entries=%d, folder=%s, email_sent=%t, source=%s",
data.GeneratedDate.Format(time.RFC3339),
len(data.Entries),
overviewFile.Name(),
emailSent,
source,
)
}
func registerDigestJob(application *app.App, scheduler gocron.Scheduler) {
_, err := scheduler.NewJob(gocron.CronJob(application.Config.Digest.Schedule, true), gocron.NewTask(func() {
digestJob(application)
}))
_, err := scheduler.NewJob(
gocron.CronJob(application.Config.Digest.Schedule, true),
gocron.NewTask(func() {
digestJob(application, "scheduler")
}),
)
if err != nil {
log.Fatalf("Error creating job: %v", err)
}
if application.Config.Digest.RunOnStartup {
go digestJob(application, "startup")
}
}
func registerArchiveCleanupJob(application *app.App, scheduler gocron.Scheduler) {
@@ -82,23 +91,13 @@ func main() {
log.Fatalf("Error creating scheduler: %v", err)
}
defer func() {
if err := scheduler.Shutdown(); err != nil {
log.Printf("Error stopping scheduler: %v", err)
}
}()
scheduler.Start()
registerDigestJob(application, scheduler)
registerArchiveCleanupJob(application, scheduler)
if application.Config.Digest.RunOnStartup {
go digestJob(application)
}
go webserver.ListenAndServe(webserver.ArchiveBasePath, webserver.Port)
scheduler.Start()
select {}
}
@@ -113,7 +112,7 @@ func initServices(cfg *config.Config) (*app.App, error) {
}
archiveSvc := archive.NewArchiveService(webserver.ArchiveBasePath, templates.ArchiveTemplate, templates.OverviewTemplate)
emailSvc := &email.EmailServiceImpl{}
emailSvc := &email.EmailServiceImpl{EmailTemplate: templates.EmailTemplate}
digestService := digest.NewDigestService(llmService)
application := app.NewApp(
+48
View File
@@ -8,6 +8,8 @@ import (
"path/filepath"
"testing"
"miniflux-digest/internal/config"
"miniflux-digest/internal/email"
"miniflux-digest/internal/webserver"
)
@@ -226,3 +228,49 @@ func TestInitScheduler(t *testing.T) {
t.Fatal("initScheduler() returned a nil scheduler")
}
}
func TestInitServices(t *testing.T) {
cfg := &config.Config{
Miniflux: config.ConfigMiniflux{
Host: "http://localhost",
ApiToken: "test",
},
AI: config.ConfigAI{
ApiKey: "test",
},
}
app, err := initServices(cfg)
if err != nil {
t.Fatalf("initServices returned an unexpected error: %v", err)
}
if app.ArchiveService == nil {
t.Error("ArchiveService should not be nil")
}
if app.EmailService == nil {
t.Error("EmailService should not be nil")
}
if app.MinifluxClientService == nil {
t.Error("MinifluxClientService should not be nil")
}
if app.DigestService == nil {
t.Error("DigestService should not be nil")
}
if app.LLMService == nil {
t.Error("LLMService should not be nil")
}
emailServiceImpl, ok := app.EmailService.(*email.EmailServiceImpl)
if !ok {
t.Fatal("EmailService is not of type *email.EmailServiceImpl")
}
if emailServiceImpl.EmailTemplate == nil {
t.Error("EmailTemplate should not be nil")
}
}
-1
View File
@@ -8,4 +8,3 @@ services:
- ./web/miniflux-archive:/app/web/miniflux-archive
ports:
- "3000:8080"
restart: unless-stopped
-4
View File
@@ -11,16 +11,12 @@ import (
)
func ProcessDigest(application *app.App) (*os.File, []*os.File, *models.OverviewTemplateData, error) {
log.Println("Starting to process digest...")
entries, err := application.MinifluxClientService.GetAllUnreadEntries()
if err != nil {
log.Printf("Error getting all unread entries: %v", err)
return nil, nil, nil, err
}
log.Printf("Found %d unread entries", len(entries))
icons := make(map[int64]*models.FeedIcon)
for _, entry := range entries {
if _, ok := icons[entry.FeedID]; !ok {
+3 -8
View File
@@ -63,19 +63,14 @@ func SetupServer(archiveBasePath string) *http.ServeMux {
return mux
}
func StartServer(port string, handler http.Handler) {
log.Printf("Internal web server starting on port %s", port)
if err := http.ListenAndServe(port, handler); err != nil {
log.Fatalf("Internal web server failed to start: %v", err)
}
}
func ListenAndServe(archiveBasePath string, port string) *http.ServeMux {
mux := SetupServer(archiveBasePath)
log.Printf("Internal web server starting on port %s", port)
if err := http.ListenAndServe(port, mux); err != nil {
log.Fatalf("Internal web server failed to start: %v", err)
}
return mux
}
}