Files
weatherreporter/internal/app/app.go

154 lines
3.6 KiB
Go

// Package app owns application orchestration and top-level use cases.
package app
import (
"context"
"fmt"
"time"
"gitea.maximumdirect.net/eric/weatherreporter/internal/adapters/weatherapi"
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
"gitea.maximumdirect.net/eric/weatherreporter/internal/forecast"
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
)
type ReportKind string
const (
ReportDaily ReportKind = "daily"
ReportTomorrow ReportKind = "tomorrow"
ReportThreeDay ReportKind = "three-day"
ReportWeekend ReportKind = "weekend"
ReportStorm ReportKind = "storm"
)
type BatchKind string
const (
BatchMorning BatchKind = "morning"
BatchEvening BatchKind = "evening"
)
type GenerateRequest struct {
Config config.Config
Report ReportKind
OutputPath string
Date time.Time
StormStart time.Time
StormEnd time.Time
}
type BatchRequest struct {
Config config.Config
Batch BatchKind
}
type FetchBundleRequest struct {
Config config.Config
OutputPath string
}
func Generate(ctx context.Context, req GenerateRequest) error {
_ = ctx
if _, err := ResolveGenerate(req, time.Now()); err != nil {
return err
}
return fmt.Errorf("generate is not implemented")
}
func RunBatch(ctx context.Context, req BatchRequest) error {
_ = ctx
if _, err := ResolveBatch(req, time.Now()); err != nil {
return err
}
return fmt.Errorf("run is not implemented")
}
func ResolveGenerate(req GenerateRequest, now time.Time) (report.Resolved, error) {
location, err := timeutil.LoadLocation(req.Config.WeatherAPI.Timezone)
if err != nil {
return report.Resolved{}, err
}
id, err := reportIDForCommand(req.Report)
if err != nil {
return report.Resolved{}, err
}
return report.DefaultRegistry().Resolve(id, report.ResolveRequest{
Now: now,
Location: location,
Date: req.Date,
StormStart: req.StormStart,
StormEnd: req.StormEnd,
})
}
func ResolveBatch(req BatchRequest, now time.Time) ([]report.Resolved, error) {
location, err := timeutil.LoadLocation(req.Config.WeatherAPI.Timezone)
if err != nil {
return nil, err
}
batch, err := reportBatchForCommand(req.Batch)
if err != nil {
return nil, err
}
return report.DefaultRegistry().BatchReports(batch, report.ResolveRequest{
Now: now,
Location: location,
})
}
func reportIDForCommand(kind ReportKind) (report.ID, error) {
switch kind {
case ReportDaily:
return report.DailyToday, nil
case ReportTomorrow:
return report.DailyTomorrow, nil
case ReportThreeDay:
return report.ThreeDay, nil
case ReportWeekend:
return report.Weekend, nil
case ReportStorm:
return report.Storm, nil
default:
return "", fmt.Errorf("unknown report command %q", kind)
}
}
func reportBatchForCommand(kind BatchKind) (report.Batch, error) {
switch kind {
case BatchMorning:
return report.Morning, nil
case BatchEvening:
return report.Evening, nil
default:
return "", fmt.Errorf("unknown batch command %q", kind)
}
}
func FetchBundle(ctx context.Context, req FetchBundleRequest) (*forecast.Bundle, error) {
client, err := weatherapi.New(req.Config)
if err != nil {
return nil, err
}
bundle, err := client.FetchBundle(ctx)
if err != nil {
return nil, err
}
return bundle, nil
}
func FetchAndSaveBundle(ctx context.Context, req FetchBundleRequest) (*forecast.Bundle, error) {
if req.OutputPath == "" {
return nil, fmt.Errorf("output path is required")
}
bundle, err := FetchBundle(ctx, req)
if err != nil {
return nil, err
}
if err := weatherapi.SaveBundle(req.OutputPath, bundle); err != nil {
return nil, err
}
return bundle, nil
}