7 Commits

18 changed files with 130 additions and 183 deletions

View File

41
app.go
View File

@@ -13,9 +13,10 @@ import (
"github.com/gorilla/websocket"
sunriseLib "github.com/nathan-osman/go-sunrise"
"github.com/Workiva/go-datastructures/queue"
"github.com/Xevion/gome-assistant/internal"
"github.com/Xevion/gome-assistant/internal/http"
pq "github.com/Xevion/gome-assistant/internal/priority_queue"
"github.com/Xevion/gome-assistant/internal/parse"
ws "github.com/Xevion/gome-assistant/internal/websocket"
)
@@ -34,13 +35,27 @@ type App struct {
service *Service
state *StateImpl
schedules pq.PriorityQueue
intervals pq.PriorityQueue
schedules *queue.PriorityQueue
intervals *queue.PriorityQueue
entityListeners map[string][]*EntityListener
entityListenersId int64
eventListeners map[string][]*EventListener
}
type Item struct {
Value interface{}
Priority float64
}
func (mi Item) Compare(other queue.Item) int {
if mi.Priority > other.(Item).Priority {
return 1
} else if mi.Priority == other.(Item).Priority {
return 0
}
return -1
}
// DurationString represents a duration, such as "2s" or "24h".
// See https://pkg.go.dev/time#ParseDuration for all valid time units.
type DurationString string
@@ -178,8 +193,8 @@ func NewApp(request NewAppRequest) (*App, error) {
httpClient: httpClient,
service: service,
state: state,
schedules: pq.New(),
intervals: pq.New(),
schedules: queue.NewPriorityQueue(100, false),
intervals: queue.NewPriorityQueue(100, false),
entityListeners: map[string][]*EntityListener{},
eventListeners: map[string][]*EventListener{},
}, nil
@@ -232,7 +247,7 @@ func (a *App) RegisterSchedules(schedules ...DailySchedule) {
// realStartTime already set for sunset/sunrise
if s.isSunrise || s.isSunset {
s.nextRunTime = getNextSunRiseOrSet(a, s.isSunrise, s.sunOffset).Carbon2Time()
a.schedules.Insert(s, float64(s.nextRunTime.Unix()))
a.schedules.Put()
continue
}
@@ -245,7 +260,10 @@ func (a *App) RegisterSchedules(schedules ...DailySchedule) {
}
s.nextRunTime = startTime.Carbon2Time()
a.schedules.Insert(s, float64(startTime.Carbon2Time().Unix()))
a.schedules.Put(Item{
Value: s,
Priority: float64(startTime.Carbon2Time().Unix()),
})
}
}
@@ -256,12 +274,15 @@ func (a *App) RegisterIntervals(intervals ...Interval) {
panic(ErrInvalidArgs)
}
i.nextRunTime = internal.ParseTime(string(i.startTime)).Carbon2Time()
i.nextRunTime = parse.ParseTime(string(i.startTime)).Carbon2Time()
now := time.Now()
for i.nextRunTime.Before(now) {
i.nextRunTime = i.nextRunTime.Add(i.frequency)
}
a.intervals.Insert(i, float64(i.nextRunTime.Unix()))
a.intervals.Put(Item{
Value: i,
Priority: float64(i.nextRunTime.Unix()),
})
}
}
@@ -349,7 +370,7 @@ func (a *App) Start() {
go runIntervals(a)
// subscribe to state_changed events
id := internal.GetId()
id := internal.NextId()
ws.SubscribeToStateChangedEvents(id, a.wsWriter, a.ctx)
a.entityListenersId = id

View File

@@ -4,6 +4,7 @@ import (
"time"
"github.com/Xevion/gome-assistant/internal"
"github.com/Xevion/gome-assistant/internal/parse"
"github.com/golang-module/carbon"
)
@@ -16,8 +17,8 @@ func checkWithinTimeRange(startTime, endTime string) conditionCheck {
// if betweenStart and betweenEnd both set, first account for midnight
// overlap, then check if between those times.
if startTime != "" && endTime != "" {
parsedStart := internal.ParseTime(startTime)
parsedEnd := internal.ParseTime(endTime)
parsedStart := parse.ParseTime(startTime)
parsedEnd := parse.ParseTime(endTime)
// check for midnight overlap
if parsedEnd.Lt(parsedStart) { // example turn on night lights when motion from 23:00 to 07:00
@@ -34,9 +35,9 @@ func checkWithinTimeRange(startTime, endTime string) conditionCheck {
}
// otherwise just check individual before/after
} else if startTime != "" && internal.ParseTime(startTime).IsFuture() {
} else if startTime != "" && parse.ParseTime(startTime).IsFuture() {
cc.fail = true
} else if endTime != "" && internal.ParseTime(endTime).IsPast() {
} else if endTime != "" && parse.ParseTime(endTime).IsPast() {
cc.fail = true
}
return cc
@@ -168,7 +169,7 @@ func checkStartEndTime(s TimeString, isStart bool) conditionCheck {
}
now := time.Now()
parsedTime := internal.ParseTime(string(s)).Carbon2Time()
parsedTime := parse.ParseTime(string(s)).Carbon2Time()
if isStart {
if parsedTime.After(now) {
cc.fail = true

View File

@@ -8,6 +8,7 @@ import (
"github.com/golang-module/carbon"
"github.com/Xevion/gome-assistant/internal"
"github.com/Xevion/gome-assistant/internal/parse"
)
type EntityListener struct {
@@ -127,13 +128,13 @@ func (b elBuilder3) ToState(s string) elBuilder3 {
}
func (b elBuilder3) Duration(s DurationString) elBuilder3 {
d := internal.ParseDuration(string(s))
d := parse.ParseDuration(string(s))
b.entityListener.delay = d
return b
}
func (b elBuilder3) Throttle(s DurationString) elBuilder3 {
d := internal.ParseDuration(string(s))
d := parse.ParseDuration(string(s))
b.entityListener.throttle = d
return b
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/golang-module/carbon"
"github.com/Xevion/gome-assistant/internal"
"github.com/Xevion/gome-assistant/internal/parse"
ws "github.com/Xevion/gome-assistant/internal/websocket"
)
@@ -80,7 +81,7 @@ func (b eventListenerBuilder3) OnlyBefore(end string) eventListenerBuilder3 {
}
func (b eventListenerBuilder3) Throttle(s DurationString) eventListenerBuilder3 {
d := internal.ParseDuration(string(s))
d := parse.ParseDuration(string(s))
b.eventListener.throttle = d
return b
}

View File

3
go.mod
View File

@@ -3,10 +3,11 @@ module github.com/Xevion/gome-assistant
go 1.21
require (
github.com/Workiva/go-datastructures v1.1.5
github.com/golang-module/carbon v1.7.1
github.com/gorilla/websocket v1.5.0
github.com/nathan-osman/go-sunrise v1.1.0
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.10.0
gopkg.in/yaml.v3 v3.0.1
)

24
go.sum
View File

@@ -1,4 +1,6 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Workiva/go-datastructures v1.1.5 h1:5YfhQ4ry7bZc2Mc7R0YZyYwpf5c6t1cEFvdAhd6Mkf4=
github.com/Workiva/go-datastructures v1.1.5/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
@@ -41,6 +43,7 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/nathan-osman/go-sunrise v1.1.0 h1:ZqZmtmtzs8Os/DGQYi0YMHpuUqR/iRoJK+wDO0wTCw8=
github.com/nathan-osman/go-sunrise v1.1.0/go.mod h1:RcWqhT+5ShCZDev79GuWLayetpJp78RSjSWxiDowmlM=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -64,23 +67,40 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -70,34 +70,3 @@ func get(url, token string) ([]byte, error) {
return body, nil
}
// func post(url string, token string, data any) ([]byte, error) {
// postBody, err := json.Marshal(data)
// if err != nil {
// return nil, err
// }
// req, err := http.NewRequest("GET", url, bytes.NewBuffer(postBody))
// if err != nil {
// return nil, errors.New("Error building post request: " + err.Error())
// }
// req.Header.Add("Authorization", "Bearer "+token)
// client := &http.Client{}
// resp, err := client.Do(req)
// if err != nil {
// return nil, errors.New("Error in post response: " + err.Error())
// }
// defer resp.Body.Close()
// if resp.StatusCode == 401 {
// panic("ERROR: Auth token is invalid. Please double check it or create a new token in your Home Assistant profile")
// }
// body, err := io.ReadAll(resp.Body)
// if err != nil {
// panic(err)
// }
// return body, nil
// }

28
internal/misc.go Normal file
View File

@@ -0,0 +1,28 @@
package internal
import (
"reflect"
"runtime"
"sync/atomic"
)
type EnabledDisabledInfo struct {
Entity string
State string
RunOnError bool
}
var (
id atomic.Int64 // default value is 0
)
// NextId returns a unique integer (for the given process), often used for providing a uniquely identifiable
// id for a request. This function is thread-safe.
func NextId() int64 {
return id.Add(1)
}
// GetFunctionName returns the name of the function that the interface is a pointer to.
func GetFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

View File

@@ -1,28 +1,13 @@
package internal
package parse
import (
"fmt"
"log/slog"
"reflect"
"runtime"
"time"
"github.com/golang-module/carbon"
)
type EnabledDisabledInfo struct {
Entity string
State string
RunOnError bool
}
var id int64 = 0
func GetId() int64 {
id += 1
return id
}
// Parses a HH:MM string.
func ParseTime(s string) carbon.Carbon {
t, err := time.Parse("15:04", s)
@@ -43,7 +28,3 @@ func ParseDuration(s string) time.Duration {
}
return d
}
func GetFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

View File

@@ -1,87 +0,0 @@
package priority_queue
import (
"container/heap"
"errors"
)
// PriorityQueue represents the queue
type PriorityQueue struct {
itemHeap *itemHeap
lookup map[interface{}]*item
}
// New initializes an empty priority queue.
func New() PriorityQueue {
return PriorityQueue{
itemHeap: &itemHeap{},
lookup: make(map[interface{}]*item),
}
}
// Len returns the number of elements in the queue.
func (p *PriorityQueue) Len() int {
return p.itemHeap.Len()
}
// Insert inserts a new element into the queue. No action is performed on duplicate elements.
func (p *PriorityQueue) Insert(v interface{ Hash() string }, priority float64) {
_, ok := p.lookup[v.Hash()]
if ok {
return
}
newItem := &item{
value: v,
priority: priority,
}
heap.Push(p.itemHeap, newItem)
p.lookup[v.Hash()] = newItem
}
// Pop removes the element with the highest priority from the queue and returns it.
// In case of an empty queue, an error is returned.
func (p *PriorityQueue) Pop() (interface{}, error) {
if len(*p.itemHeap) == 0 {
return nil, errors.New("empty queue")
}
item := heap.Pop(p.itemHeap).(*item)
delete(p.lookup, item.value.(interface{ Hash() string }).Hash())
return item.value, nil
}
type itemHeap []*item
type item struct {
value interface{}
priority float64
index int
}
func (ih *itemHeap) Len() int {
return len(*ih)
}
func (ih *itemHeap) Less(i, j int) bool {
return (*ih)[i].priority < (*ih)[j].priority
}
func (ih *itemHeap) Swap(i, j int) {
(*ih)[i], (*ih)[j] = (*ih)[j], (*ih)[i]
(*ih)[i].index = i
(*ih)[j].index = j
}
func (ih *itemHeap) Push(x interface{}) {
it := x.(*item)
it.index = len(*ih)
*ih = append(*ih, it)
}
func (ih *itemHeap) Pop() interface{} {
old := *ih
item := old[len(old)-1]
*ih = old[0 : len(old)-1]
return item
}

View File

@@ -23,7 +23,7 @@ type FireEventRequest struct {
// as `event_data`.
func (e Event) Fire(eventType string, eventData ...map[string]any) error {
req := FireEventRequest{
Id: internal.GetId(),
Id: internal.NextId(),
Type: "fire_event",
}

View File

@@ -45,13 +45,15 @@ type BaseServiceRequest struct {
}
func NewBaseServiceRequest(entityId string) BaseServiceRequest {
id := internal.GetId()
bsr := BaseServiceRequest{
id := internal.NextId()
request := BaseServiceRequest{
Id: id,
RequestType: "call_service",
}
if entityId != "" {
bsr.Target.EntityId = entityId
request.Target.EntityId = entityId
}
return bsr
return request
}

View File

@@ -16,7 +16,7 @@ import (
"github.com/gorilla/websocket"
i "github.com/Xevion/gome-assistant/internal"
"github.com/Xevion/gome-assistant/internal"
)
var ErrInvalidToken = errors.New("invalid authentication token")
@@ -47,7 +47,9 @@ func ReadMessage(conn *websocket.Conn) ([]byte, error) {
}
func ConnectionFromUri(baseURL *url.URL, authToken string) (*websocket.Conn, context.Context, context.CancelFunc, error) {
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3)
// Create a short timeout context for the connection only
connCtx, connCtxCancel := context.WithTimeout(context.Background(), time.Second*3)
defer connCtxCancel() // Always cancel the connection context when we're done
// Shallow copy the URL to avoid modifying the original
urlWebsockets := *baseURL
@@ -61,9 +63,8 @@ func ConnectionFromUri(baseURL *url.URL, authToken string) (*websocket.Conn, con
// Init websocket connection
dialer := websocket.DefaultDialer
conn, _, err := dialer.DialContext(ctx, urlWebsockets.String(), nil)
conn, _, err := dialer.DialContext(connCtx, urlWebsockets.String(), nil)
if err != nil {
ctxCancel()
slog.Error("Failed to connect to websocket. Check URI\n", "url", urlWebsockets)
return nil, nil, nil, err
}
@@ -71,28 +72,28 @@ func ConnectionFromUri(baseURL *url.URL, authToken string) (*websocket.Conn, con
// Read auth_required message
_, err = ReadMessage(conn)
if err != nil {
ctxCancel()
slog.Error("Unknown error creating websocket client\n")
return nil, nil, nil, err
}
// Send auth message
err = SendAuthMessage(conn, ctx, authToken)
err = SendAuthMessage(conn, connCtx, authToken)
if err != nil {
ctxCancel()
slog.Error("Unknown error creating websocket client\n")
return nil, nil, nil, err
}
// Verify auth message was successful
err = VerifyAuthResponse(conn, ctx)
err = VerifyAuthResponse(conn, connCtx)
if err != nil {
ctxCancel()
slog.Error("Auth token is invalid. Please double check it or create a new token in your Home Assistant profile\n")
return nil, nil, nil, err
}
return conn, ctx, ctxCancel, nil
// Create a new background context for the application lifecycle (no timeout)
appCtx, appCtxCancel := context.WithCancel(context.Background())
return conn, appCtx, appCtxCancel, nil
}
func SendAuthMessage(conn *websocket.Conn, ctx context.Context, token string) error {
@@ -139,7 +140,7 @@ func SubscribeToStateChangedEvents(id int64, conn *WebsocketWriter, ctx context.
func SubscribeToEventType(eventType string, conn *WebsocketWriter, ctx context.Context, id ...int64) {
var finalId int64
if len(id) == 0 {
finalId = i.GetId()
finalId = internal.NextId()
} else {
finalId = id[0]
}

View File

@@ -6,6 +6,7 @@ import (
"time"
"github.com/Xevion/gome-assistant/internal"
"github.com/Xevion/gome-assistant/internal/parse"
)
type IntervalCallback func(*Service, State)
@@ -80,7 +81,7 @@ func (ib intervalBuilder) Call(callback IntervalCallback) intervalBuilderCall {
// Takes a DurationString ("2h", "5m", etc) to set the frequency of the interval.
func (ib intervalBuilderCall) Every(s DurationString) intervalBuilderEnd {
d := internal.ParseDuration(string(s))
d := parse.ParseDuration(string(s))
ib.interval.frequency = d
return intervalBuilderEnd(ib)
}
@@ -206,12 +207,15 @@ func (i Interval) maybeRunCallback(a *App) {
}
func popInterval(a *App) Interval {
i, _ := a.intervals.Pop()
return i.(Interval)
i, _ := a.intervals.Get(1)
return i[0].(Item).Value.(Interval)
}
func requeueInterval(a *App, i Interval) {
i.nextRunTime = i.nextRunTime.Add(i.frequency)
a.intervals.Insert(i, float64(i.nextRunTime.Unix()))
a.intervals.Put(Item{
Value: i,
Priority: float64(i.nextRunTime.Unix()),
})
}

View File

@@ -6,6 +6,7 @@ import (
"time"
"github.com/Xevion/gome-assistant/internal"
"github.com/Xevion/gome-assistant/internal/parse"
"github.com/golang-module/carbon"
)
@@ -75,7 +76,7 @@ func (sb scheduleBuilder) Call(callback ScheduleCallback) scheduleBuilderCall {
// At takes a string in 24hr format time like "15:30".
func (sb scheduleBuilderCall) At(s string) scheduleBuilderEnd {
t := internal.ParseTime(s)
t := parse.ParseTime(s)
sb.schedule.hour = t.Hour()
sb.schedule.minute = t.Minute()
return scheduleBuilderEnd(sb)
@@ -208,8 +209,8 @@ func (s DailySchedule) maybeRunCallback(a *App) {
}
func popSchedule(a *App) DailySchedule {
_sched, _ := a.schedules.Pop()
return _sched.(DailySchedule)
_sched, _ := a.schedules.Get(1)
return _sched[0].(Item).Value.(DailySchedule)
}
func requeueSchedule(a *App, s DailySchedule) {
@@ -227,5 +228,8 @@ func requeueSchedule(a *App, s DailySchedule) {
s.nextRunTime = carbon.Time2Carbon(s.nextRunTime).AddDay().Carbon2Time()
}
a.schedules.Insert(s, float64(s.nextRunTime.Unix()))
a.schedules.Put(Item{
Value: s,
Priority: float64(s.nextRunTime.Unix()),
})
}