smon/trigger.go

211 lines
3.7 KiB
Go
Raw Permalink Normal View History

2024-04-29 08:36:13 +02:00
package main
import (
// External
we "git.gibonuddevalla.se/go/wrappederror"
"github.com/expr-lang/expr"
2024-05-01 10:02:33 +02:00
"github.com/lib/pq"
2024-04-29 08:36:13 +02:00
// Standard
"encoding/json"
"fmt"
"strings"
)
type Trigger struct {
ID int
Name string
SectionID int `db:"section_id"`
Expression string
Datapoints []string
}
func TriggersRetrieve() (areas []Area, err error) { // {{{
areas = []Area{}
row := service.Db.Conn.QueryRow(`
WITH section_triggers AS (
SELECT
s.id AS id,
s.area_id,
s.name AS name,
jsonb_agg(
to_jsonb(t.*)
) AS triggers
FROM section s
LEFT JOIN "trigger" t ON t.section_id = s.id
GROUP BY
s.id, s.name)
SELECT
jsonb_agg(jsonsections)
FROM (
SELECT
a.id,
a.name,
jsonb_agg(
to_jsonb(
s.*
)
) AS sections
FROM area a
LEFT JOIN section_triggers s ON s.area_id = a.id
GROUP BY
a.id, a.name
) jsonsections
`,
)
var jsonData []byte
err = row.Scan(&jsonData)
if err != nil {
err = we.Wrap(err)
return
}
if jsonData == nil {
return
}
2024-04-29 08:36:13 +02:00
err = json.Unmarshal(jsonData, &areas)
if err != nil {
err = we.Wrap(err)
return
}
return
} // }}}
2024-04-30 20:10:05 +02:00
func TriggersRetrieveByDatapoint(datapointName string) (triggers []Trigger, err error) { // {{{
triggers = []Trigger{}
row := service.Db.Conn.QueryRow(`
SELECT jsonb_agg(t.*)
FROM public."trigger" t
2024-04-30 20:10:05 +02:00
WHERE
datapoints @> $1
`,
fmt.Sprintf(`["%s"]`, datapointName),
)
var data []byte
err = row.Scan(&data)
2024-04-30 20:10:05 +02:00
if err != nil {
err = we.Wrap(err).WithData(datapointName)
return
}
err = json.Unmarshal(data, &triggers)
if err != nil {
err = we.Wrap(err).WithData(datapointName)
return
2024-04-30 20:10:05 +02:00
}
return
} // }}}
2024-04-29 08:36:13 +02:00
func TriggerRetrieve(id int) (trigger Trigger, err error) { // {{{
row := service.Db.Conn.QueryRow(`SELECT to_jsonb(t.*) FROM "trigger" t WHERE id=$1`, id)
var jsonData []byte
err = row.Scan(&jsonData)
if err != nil {
err = we.Wrap(err)
return
}
err = json.Unmarshal(jsonData, &trigger)
return
} // }}}
2024-04-30 20:10:05 +02:00
func (t *Trigger) Validate() (ok bool, err error) { // {{{
2024-04-29 08:36:13 +02:00
if strings.TrimSpace(t.Name) == "" {
err = fmt.Errorf("Name can't be empty")
return
}
if strings.TrimSpace(t.Expression) == "" {
err = fmt.Errorf("Expression can't be empty")
return
}
return true, nil
2024-04-30 20:10:05 +02:00
} // }}}
func (t *Trigger) Update() (err error) { // {{{
2024-04-29 08:36:13 +02:00
var ok bool
if ok, err = t.Validate(); !ok {
return
}
2024-05-01 10:02:33 +02:00
if t.Datapoints == nil {
t.Datapoints = []string{}
}
jsonDatapoints, _ := json.Marshal(t.Datapoints)
if t.ID == 0 {
_, err = service.Db.Conn.Exec(`
INSERT INTO "trigger"(name, section_id, expression, datapoints)
VALUES($1, $2, $3, $4)
`,
t.Name,
t.SectionID,
t.Expression,
jsonDatapoints,
)
} else {
_, err = service.Db.Conn.Exec(`
UPDATE "trigger"
SET
name=$2,
expression=$3,
datapoints=$4
WHERE
id=$1
`,
t.ID,
t.Name,
t.Expression,
jsonDatapoints,
)
}
if pqErr, ok := err.(*pq.Error); ok {
err = we.Wrap(err).WithData(
struct {
Trigger *Trigger
PostgresCode pq.ErrorCode
PostgresMsg string
}{
t,
pqErr.Code,
pqErr.Code.Name(),
})
} else if err != nil {
err = we.Wrap(err).WithData(t)
2024-04-29 08:36:13 +02:00
}
return
2024-04-30 20:10:05 +02:00
} // }}}
func (t *Trigger) Run() (output any, err error) { // {{{
datapoints := make(map[string]Datapoint)
for _, dpname := range t.Datapoints {
var dp Datapoint
dp, err = DatapointRetrieve(0, dpname)
if err != nil {
err = we.Wrap(err)
return
}
datapoints[dpname] = dp
}
2024-04-29 08:36:13 +02:00
env := make(map[string]any)
for dpName, dp := range datapoints {
env[dpName] = dp.LastDatapointValue.Value()
}
program, err := expr.Compile(t.Expression)
if err != nil {
return
}
output, err = expr.Run(program, env)
if err != nil {
return
}
return
2024-04-30 20:10:05 +02:00
} // }}}