Add configurable report module composition
This commit is contained in:
@@ -2,7 +2,13 @@
|
||||
// precedence, and validation.
|
||||
package config
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type MissingSourcePolicy string
|
||||
type NotifyFailurePolicy string
|
||||
@@ -16,15 +22,16 @@ const (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
WeatherAPI WeatherAPIConfig `yaml:"weather_api"`
|
||||
Location LocationConfig `yaml:"location"`
|
||||
Secrets SecretsConfig `yaml:"secrets"`
|
||||
Notify NotifyConfig `yaml:"notify"`
|
||||
MissingSource MissingSourceConfig `yaml:"missing_source"`
|
||||
Scriptorium ScriptoriumConfig `yaml:"scriptorium"`
|
||||
Workspace WorkspaceConfig `yaml:"workspace"`
|
||||
Dayparts []DaypartConfig `yaml:"dayparts"`
|
||||
RecentChange RecentChangeConfig `yaml:"recent_change"`
|
||||
WeatherAPI WeatherAPIConfig `yaml:"weather_api"`
|
||||
Location LocationConfig `yaml:"location"`
|
||||
Secrets SecretsConfig `yaml:"secrets"`
|
||||
Notify NotifyConfig `yaml:"notify"`
|
||||
MissingSource MissingSourceConfig `yaml:"missing_source"`
|
||||
Scriptorium ScriptoriumConfig `yaml:"scriptorium"`
|
||||
Workspace WorkspaceConfig `yaml:"workspace"`
|
||||
Dayparts []DaypartConfig `yaml:"dayparts"`
|
||||
RecentChange RecentChangeConfig `yaml:"recent_change"`
|
||||
Reports map[string]ReportConfig `yaml:"reports"`
|
||||
}
|
||||
|
||||
type WeatherAPIConfig struct {
|
||||
@@ -96,3 +103,71 @@ type RecentChangeConfig struct {
|
||||
WindGustMilesPerHour int `yaml:"wind_gust_miles_per_hour"`
|
||||
PrecipTimingShiftMinutes int `yaml:"precip_timing_shift_minutes"`
|
||||
}
|
||||
|
||||
type ReportConfig struct {
|
||||
DeterministicModules []ModuleConfigItem `yaml:"deterministic_modules"`
|
||||
deterministicModulesSet bool
|
||||
}
|
||||
|
||||
type ModuleConfigItem struct {
|
||||
ID module.ID `yaml:"id"`
|
||||
Options any `yaml:"options,omitempty"`
|
||||
}
|
||||
|
||||
func (c *ReportConfig) UnmarshalYAML(value *yaml.Node) error {
|
||||
if value.Kind != yaml.MappingNode {
|
||||
return fmt.Errorf("report entry must be a mapping")
|
||||
}
|
||||
for i := 0; i < len(value.Content); i += 2 {
|
||||
key := value.Content[i].Value
|
||||
node := value.Content[i+1]
|
||||
switch key {
|
||||
case "deterministic_modules":
|
||||
if err := node.Decode(&c.DeterministicModules); err != nil {
|
||||
return err
|
||||
}
|
||||
c.deterministicModulesSet = true
|
||||
default:
|
||||
return fmt.Errorf("unknown report entry field %q", key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ModuleConfigItem) UnmarshalYAML(value *yaml.Node) error {
|
||||
switch value.Kind {
|
||||
case yaml.ScalarNode:
|
||||
if value.Value == "" {
|
||||
return fmt.Errorf("module id is required")
|
||||
}
|
||||
m.ID = module.ID(value.Value)
|
||||
return nil
|
||||
case yaml.MappingNode:
|
||||
var sawID bool
|
||||
for i := 0; i < len(value.Content); i += 2 {
|
||||
key := value.Content[i].Value
|
||||
node := value.Content[i+1]
|
||||
switch key {
|
||||
case "id":
|
||||
if err := node.Decode(&m.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
sawID = true
|
||||
case "options":
|
||||
var options any
|
||||
if err := node.Decode(&options); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Options = options
|
||||
default:
|
||||
return fmt.Errorf("unknown module entry field %q", key)
|
||||
}
|
||||
}
|
||||
if !sawID || m.ID == "" {
|
||||
return fmt.Errorf("module id is required")
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("module entry must be a string or mapping")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user