Browse Source

Start work on /stop and /snooze

master
Remi Reuvekamp 5 years ago
parent
commit
500f45f42b
  1. 1
      .gitignore
  2. 69
      alarm/alarm.go
  3. 26
      alarm/behaviour.go
  4. 8
      alarm/behaviour_test.go
  5. 2
      alarm/cache.go
  6. 20
      handlers.go
  7. 2
      http.go
  8. 12
      main.go

1
.gitignore

@ -1 +1,2 @@
config.json
alarmd

69
alarm/alarm.go

@ -2,7 +2,6 @@ package alarm
import (
"encoding/json"
"errors"
"fmt"
"math"
"sync"
@ -23,6 +22,9 @@ type Config struct {
pendingAlarmsStops []chan struct{}
pendingAlarmsStopsMutex sync.Mutex
// The alarm currently going off. Nil is no alarm currently active/going-off.
activeAlarm *parsedAlarm
Deps BehItemDeps
}
@ -135,7 +137,7 @@ func (c *Config) Init() error {
}*/
if db.DateExpr == nil {
return errors.New("date expression is empty but 'always' is not set")
return fmt.Errorf("date expression is empty but 'always' is not set")
}
if _, ok := c.Behaviours[db.BehaviourName]; !ok {
@ -157,7 +159,7 @@ func (c *Config) Init() error {
}*/
if t.DateExpr == nil {
return errors.New("date expression is empty but 'always' is not set")
return fmt.Errorf("date expression is empty but 'always' is not set")
}
if _, err := time.ParseDuration(t.Time); err != nil {
@ -277,17 +279,28 @@ func (c *Config) RefreshPendingAlarms() error {
sub := pa.Time.Sub(time.Now())
paCopy := pa
go func() {
timer := time.NewTimer(sub)
select {
case <-stop:
timer.Stop()
case <-timer.C:
fmt.Println("Execute behaviour", pa.behaviour)
if c.activeAlarm != nil {
err := c.activeAlarm.behaviour.Stop()
if err != nil {
fmt.Println("Wut? Could not stop behaviour because another should activate:", err)
}
}
err := pa.behaviour.Execute()
if err != nil {
fmt.Println("Wut?", err)
return
}
c.activeAlarm = &paCopy
}
}()
@ -302,6 +315,54 @@ func (c *Config) RefreshPendingAlarms() error {
return nil
}
func (c *Config) Stop() error {
if c.activeAlarm == nil {
return fmt.Errorf("no alarm active")
}
defer func() {
c.activeAlarm = nil
}()
return c.activeAlarm.behaviour.Stop()
}
func (c *Config) Snooze() error {
if c.activeAlarm == nil {
return fmt.Errorf("no alarm active")
}
defer func() {
c.activeAlarm = nil
}()
snoozable, snoozeDur, err := c.activeAlarm.behaviour.Snooze()
if err != nil {
return err
}
if !snoozable {
return fmt.Errorf("not snoozable")
}
active := c.activeAlarm
done := make(chan struct{})
c.Cache.operations <- func(d *cacheData) {
defer close(done)
pa := d.parsedAlarms[active.Time.Format("20060102")][active.alarmID]
// Add snoozeDur to alarm's time in cache.
pa.Time = time.Now().Add(snoozeDur)
fmt.Println("New time", pa.Time)
d.parsedAlarms[active.Time.Format("20060102")][active.alarmID] = pa
}
<-done
return c.RefreshPendingAlarms()
}
// TODO: This function should be removed if proper default behaviour support has been added.
func (c *Config) TmpDefaultBehaviour() *behaviour {
var b *behaviour

26
alarm/behaviour.go

@ -25,9 +25,10 @@ type behaviour struct {
// Secondary behaviourItems which are activated in the background.
// (So not snoozable or stoppable. behaviourOptions don't have an effecet on
// them either.)
Before map[string]behaviourBackgroundItem // Before the alarm expires. Key is a duration.
After map[string]behaviourBackgroundItem // After the alarm expires. Key is a duration.
AfterRelative map[string]behaviourBackgroundItem // After the alarm is stopped. Key is a duration.
// Pointer because the 'stopCleanup' is set.
Before map[string]*behaviourBackgroundItem // Before the alarm expires. Key is a duration.
After map[string]*behaviourBackgroundItem // After the alarm expires. Key is a duration.
AfterRelative map[string]*behaviourBackgroundItem // After the alarm is stopped. Key is a duration.
deps BehItemDeps
}
@ -37,7 +38,8 @@ type BehaviourOptions struct {
AutoGoToPrev string // Automatically go to prev Item after duration.
// Is the alarm snoozable while this behaviour is active.
Snoozeable bool
// (Pointer so the user has to set it explicitly)
Snoozeable *bool
// Special behaviour when the alarm is snoozed when this item is active.
OnSnooze struct {
@ -98,7 +100,7 @@ type BehItemDeps struct {
type behaviourBackgroundItem AbstractBehaviourItem
// tm is the time at which the behaviour should be executed.
func (b behaviour) initBackgroundTimers(tm time.Time) []chan struct{} {
func (b *behaviour) initBackgroundTimers(tm time.Time) []chan struct{} {
stops := make([]chan struct{}, len(b.Before)+len(b.After))
var n int
@ -168,22 +170,22 @@ func (b behaviour) Execute() error {
}
func (b behaviour) Stop() error {
_, err := b.stop(false)
_, _, err := b.stop(false)
return err
}
func (b behaviour) Snooze() (bool, error) {
func (b behaviour) Snooze() (snoozeAble bool, snoozeDur time.Duration, err error) {
return b.stop(true)
}
// stop stops the executing of the behaviour.
func (b behaviour) stop(isSnooze bool) (bool, error) {
func (b behaviour) stop(isSnooze bool) (snoozable bool, snoozeDur time.Duration, err error) {
bi := b.Items[b.curItem]
// TODO: Maybe separate isCurrentlySnoozable func?
if isSnooze {
if !bi.Snoozeable {
return false, nil
if bi.Snoozeable != nil && *bi.Snoozeable == false {
return false, snoozeDur, nil
}
}
@ -219,10 +221,12 @@ func (b behaviour) stop(isSnooze bool) (bool, error) {
if err != nil {
fmt.Println("Wut", err)
}
} else {
snoozeDur = 5 * time.Second // TODO: Configurable duration, behaviour specific or alarm specific.
}
}
return true, nil
return true, snoozeDur, nil
}
func (bi AbstractBehaviourItem) stop() {

8
alarm/behaviour_test.go

@ -12,8 +12,8 @@ func TestBehaviourInitBackgroundTimers(t *testing.T) {
executed := make(chan int)
b := behaviour{
Before: make(map[string]behaviourBackgroundItem),
After: make(map[string]behaviourBackgroundItem),
Before: make(map[string]*behaviourBackgroundItem),
After: make(map[string]*behaviourBackgroundItem),
}
befores := map[string]int{
@ -24,7 +24,7 @@ func TestBehaviourInitBackgroundTimers(t *testing.T) {
for durStr, ms := range befores {
msCopy := ms
b.Before[durStr] = behaviourBackgroundItem{
b.Before[durStr] = &behaviourBackgroundItem{
executeFunc: func(_ AbstractBehaviourItem, _ BehItemDeps) error {
executed <- msCopy
return nil
@ -39,7 +39,7 @@ func TestBehaviourInitBackgroundTimers(t *testing.T) {
for durStr, ms := range afters {
msCopy := ms
b.After[durStr] = behaviourBackgroundItem{
b.After[durStr] = &behaviourBackgroundItem{
executeFunc: func(_ AbstractBehaviourItem, _ BehItemDeps) error {
executed <- msCopy
return nil

2
alarm/cache.go

@ -28,7 +28,7 @@ type cacheData struct {
type parsedAlarm struct {
// Disabled is true if this parsedAlarm should be considered deleted.
// (Usefull for config.parsedAlarms. If an itemi is removed from the slice,
// (Usefull for config.parsedAlarms. If an item would be removed from the slice,
// it will be re-added again by AlarmsFor.)
Disabled bool

20
handlers.go

@ -195,6 +195,26 @@ func handleExecute(e *env, w http.ResponseWriter, r *http.Request) error {
return nil
}
func handleStop(e *env, w http.ResponseWriter, _ *http.Request) error {
err := e.alarm.Stop()
if err != nil {
return err
}
writeSuccess(w)
return nil
}
func handleSnooze(e *env, w http.ResponseWriter, _ *http.Request) error {
err := e.alarm.Snooze()
if err != nil {
return err
}
writeSuccess(w)
return nil
}
// parseDuration converts the given string to an integer and creates a time.Duration
// set to that amount in seconds.
func parseDuration(durStr string) (dur time.Duration, err error) {

2
http.go

@ -23,7 +23,7 @@ type env struct {
speakc *speakc.Client
alarm alarm.Config
alarm *alarm.Config
}
// handler is a custom HTTP handler used in the application.

12
main.go

@ -61,7 +61,7 @@ func main() {
BaseURL: cfg.SpeakdBaseURL,
CallbackURL: cfg.SpeakdCallbackBaseURL + "/speakc-callback",
},
alarm: cfg.Alarm,
alarm: &cfg.Alarm,
}
// Set up the HTTP server.
@ -73,6 +73,8 @@ func main() {
mux.Handle("/action/disable", handle(e, handleDisable))
mux.Handle("/action/add", handle(e, handleAdd))
mux.Handle("/execute", handle(e, handleExecute))
mux.Handle("/stop", handle(e, handleStop))
mux.Handle("/snooze", handle(e, handleSnooze))
mux.Handle("/speakc-callback", e.speakc.CallbackHandler())
srv := &http.Server{
@ -86,12 +88,14 @@ func main() {
log.Fatal(srv.ListenAndServe())
// TODO: Check how the pointer st00fs is going for behaviours (starts in alarm).
/*
HTTP calls:
+ /speak-alarms
Speak every alarm for the next x seconds. Use alarmsFor.
"0: 3:00, behaviour 'night-behaviour'. 1: 7:30, behaviour 'school'"
+ /actions/change
+ /action/change
Change given alarm index (told by /speak-alarms) to the given time.
+ /action/delete
Remove alarm with given index.
@ -99,10 +103,10 @@ func main() {
Add alarm. Method of the cache? Index of alarm ID (index in Alarm.Alarms) use a negative number. Doesn't matter.
- /snooze
Snooze alarm currently active.
- /off
- /stop
Stop alarm currently active.
Optional:
- /execute
+ /execute
Execute behaviour of given alarm index. For testing.
*/
}

Loading…
Cancel
Save