From b27122de6c754bc3bac7489d2b41c0029b80243d Mon Sep 17 00:00:00 2001 From: eleith Date: Tue, 26 Aug 2025 21:39:25 +0000 Subject: [PATCH] feat: improve email sending, startup, and testing - Add a new test to ensure that all services are initialized correctly. - Add a new `preview-docker` target to the `Makefile` to make it easier to build and run the application in Docker. - Fix a bug that was causing the application to run twice when run in Docker. - Fix a bug that was preventing the digest from being run on startup. - Add logging to the `digestJob` to indicate the source of the job (startup or scheduler). - Fix a bug that was causing the `EmailTemplate` to be `nil`. - Rename `ProcessAndSendDigest` to `ProcessDigest` to more accurately reflect its function. - Make email sending conditional on SMTP configuration. - Add a concise log message for each digest produced, including entry count, output folder, and email sending status. --- Makefile | 3 ++ cmd/miniflux-digest/main.go | 37 ++++++++++++------------ cmd/miniflux-digest/main_test.go | 48 ++++++++++++++++++++++++++++++++ docker-compose.yml | 1 - internal/processor/processor.go | 4 --- internal/webserver/webserver.go | 11 ++------ 6 files changed, 72 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 1aa5c26..25a001f 100644 --- a/Makefile +++ b/Makefile @@ -32,3 +32,6 @@ vendor: go mod vendor all: ci build + +preview-docker: + @trap "exit 0" INT; docker compose up --build diff --git a/cmd/miniflux-digest/main.go b/cmd/miniflux-digest/main.go index 2909b85..f317456 100644 --- a/cmd/miniflux-digest/main.go +++ b/cmd/miniflux-digest/main.go @@ -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( diff --git a/cmd/miniflux-digest/main_test.go b/cmd/miniflux-digest/main_test.go index f681d45..f69162b 100644 --- a/cmd/miniflux-digest/main_test.go +++ b/cmd/miniflux-digest/main_test.go @@ -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") + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 0f618c6..cb8adfe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,4 +8,3 @@ services: - ./web/miniflux-archive:/app/web/miniflux-archive ports: - "3000:8080" - restart: unless-stopped diff --git a/internal/processor/processor.go b/internal/processor/processor.go index e885f47..4ce605b 100644 --- a/internal/processor/processor.go +++ b/internal/processor/processor.go @@ -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 { diff --git a/internal/webserver/webserver.go b/internal/webserver/webserver.go index e383f31..135cfd3 100644 --- a/internal/webserver/webserver.go +++ b/internal/webserver/webserver.go @@ -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 -} \ No newline at end of file +} -- 2.54.0