mirror of
https://github.com/Xevion/go-ha.git
synced 2025-12-06 17:15:14 -06:00
feat: new schedule triggering, new builder pattern in internal
This commit is contained in:
114
internal/scheduling/builder.go
Normal file
114
internal/scheduling/builder.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package scheduling
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Xevion/go-ha/types"
|
||||
)
|
||||
|
||||
type DailyScheduleBuilder struct {
|
||||
errors []error
|
||||
hashes map[uint64]bool
|
||||
triggers []Trigger
|
||||
}
|
||||
|
||||
func NewSchedule() *DailyScheduleBuilder {
|
||||
return &DailyScheduleBuilder{
|
||||
hashes: make(map[uint64]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// tryAddTrigger adds a trigger to the builder if it is not already present.
|
||||
// If the trigger is already present, an error will be added to the builder's errors.
|
||||
// It will return the builder for chaining.
|
||||
func (b *DailyScheduleBuilder) tryAddTrigger(trigger Trigger) *DailyScheduleBuilder {
|
||||
hash := trigger.Hash()
|
||||
if _, ok := b.hashes[hash]; ok {
|
||||
b.errors = append(b.errors, fmt.Errorf("duplicate trigger: %v", trigger))
|
||||
return b
|
||||
}
|
||||
|
||||
b.triggers = append(b.triggers, trigger)
|
||||
b.hashes[hash] = true
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *DailyScheduleBuilder) onSun(sunset bool, offset ...types.DurationString) *DailyScheduleBuilder {
|
||||
if len(offset) == 0 {
|
||||
b.errors = append(b.errors, fmt.Errorf("no offset provided for sun"))
|
||||
return b
|
||||
}
|
||||
|
||||
offsetDuration, err := time.ParseDuration(string(offset[0]))
|
||||
if err != nil {
|
||||
b.errors = append(b.errors, err)
|
||||
return b
|
||||
}
|
||||
|
||||
return b.tryAddTrigger(&SunTrigger{
|
||||
sunset: sunset,
|
||||
offset: &offsetDuration,
|
||||
})
|
||||
}
|
||||
|
||||
// OnSunrise adds a trigger for sunrise with an optional offset.
|
||||
// Only the first offset is considered.
|
||||
// You can call this multiple times to add multiple triggers for sunrise with different offsets.
|
||||
func (b *DailyScheduleBuilder) OnSunrise(offset ...types.DurationString) *DailyScheduleBuilder {
|
||||
return b.onSun(false, offset...)
|
||||
}
|
||||
|
||||
// OnSunset adds a trigger for sunset with an optional offset.
|
||||
// Only the first offset is considered.
|
||||
func (b *DailyScheduleBuilder) OnSunset(offset ...types.DurationString) *DailyScheduleBuilder {
|
||||
return b.onSun(true, offset...)
|
||||
}
|
||||
|
||||
// OnFixedTime adds a trigger for a fixed time each day.
|
||||
// The time is in the local timezone.
|
||||
// This will error if the integer values are not in the range 0-23 for the hour and 0-59 for the minute.
|
||||
func (b *DailyScheduleBuilder) OnFixedTime(hour, minute int) *DailyScheduleBuilder {
|
||||
errored := false
|
||||
if hour < 0 || hour > 23 {
|
||||
b.errors = append(b.errors, fmt.Errorf("hour must be between 0 and 23"))
|
||||
errored = true
|
||||
}
|
||||
|
||||
if minute < 0 || minute > 59 {
|
||||
b.errors = append(b.errors, fmt.Errorf("minute must be between 0 and 59"))
|
||||
errored = true
|
||||
}
|
||||
|
||||
if errored {
|
||||
return b
|
||||
}
|
||||
|
||||
return b.tryAddTrigger(&FixedTimeTrigger{
|
||||
Hour: hour,
|
||||
Minute: minute,
|
||||
})
|
||||
}
|
||||
|
||||
// Build returns a Trigger that will trigger at the configured times.
|
||||
// It will return an error if any errors occurred during configuration.
|
||||
func (b *DailyScheduleBuilder) Build() (Trigger, error) {
|
||||
// If there are no triggers, add an error.
|
||||
if len(b.triggers) == 0 {
|
||||
b.errors = append(b.errors, fmt.Errorf("no triggers provided"))
|
||||
}
|
||||
|
||||
// If there are errors, return an error.
|
||||
if len(b.errors) > 0 {
|
||||
return nil, fmt.Errorf("errors occurred: %v", b.errors)
|
||||
}
|
||||
|
||||
// If there is only one trigger, return it.
|
||||
if len(b.triggers) == 1 {
|
||||
return b.triggers[0], nil
|
||||
}
|
||||
|
||||
// Otherwise, return a composite schedule that combines all the triggers.
|
||||
return &CompositeDailySchedule{triggers: b.triggers}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user