scripting system, hue fixes and such
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE TABLE script (
|
||||
name VARCHAR(255) NOT NULL PRIMARY KEY,
|
||||
data JSON NOT NULL
|
||||
);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE IF EXISTS script;
|
||||
-- +goose StatementEnd
|
||||
@@ -0,0 +1,15 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE TABLE script_variable (
|
||||
scope VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (scope, name)
|
||||
)
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
DROP TABLE IF EXISTS script_variable;
|
||||
-- +goose StatementEnd
|
||||
@@ -63,6 +63,12 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
||||
if q.listDeviceInfosStmt, err = db.PrepareContext(ctx, listDeviceInfos); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ListDeviceInfos: %w", err)
|
||||
}
|
||||
if q.listScriptVariablesStmt, err = db.PrepareContext(ctx, listScriptVariables); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ListScriptVariables: %w", err)
|
||||
}
|
||||
if q.listScriptsStmt, err = db.PrepareContext(ctx, listScripts); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ListScripts: %w", err)
|
||||
}
|
||||
if q.replaceDeviceAssignmentStmt, err = db.PrepareContext(ctx, replaceDeviceAssignment); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ReplaceDeviceAssignment: %w", err)
|
||||
}
|
||||
@@ -72,6 +78,12 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
||||
if q.replaceDeviceInfoStmt, err = db.PrepareContext(ctx, replaceDeviceInfo); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query ReplaceDeviceInfo: %w", err)
|
||||
}
|
||||
if q.saveScriptStmt, err = db.PrepareContext(ctx, saveScript); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query SaveScript: %w", err)
|
||||
}
|
||||
if q.updateScriptVariablesStmt, err = db.PrepareContext(ctx, updateScriptVariables); err != nil {
|
||||
return nil, fmt.Errorf("error preparing query UpdateScriptVariables: %w", err)
|
||||
}
|
||||
return &q, nil
|
||||
}
|
||||
|
||||
@@ -142,6 +154,16 @@ func (q *Queries) Close() error {
|
||||
err = fmt.Errorf("error closing listDeviceInfosStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.listScriptVariablesStmt != nil {
|
||||
if cerr := q.listScriptVariablesStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing listScriptVariablesStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.listScriptsStmt != nil {
|
||||
if cerr := q.listScriptsStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing listScriptsStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.replaceDeviceAssignmentStmt != nil {
|
||||
if cerr := q.replaceDeviceAssignmentStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing replaceDeviceAssignmentStmt: %w", cerr)
|
||||
@@ -157,6 +179,16 @@ func (q *Queries) Close() error {
|
||||
err = fmt.Errorf("error closing replaceDeviceInfoStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.saveScriptStmt != nil {
|
||||
if cerr := q.saveScriptStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing saveScriptStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
if q.updateScriptVariablesStmt != nil {
|
||||
if cerr := q.updateScriptVariablesStmt.Close(); cerr != nil {
|
||||
err = fmt.Errorf("error closing updateScriptVariablesStmt: %w", cerr)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -209,9 +241,13 @@ type Queries struct {
|
||||
listDeviceAssignmentsStmt *sql.Stmt
|
||||
listDeviceAuthStmt *sql.Stmt
|
||||
listDeviceInfosStmt *sql.Stmt
|
||||
listScriptVariablesStmt *sql.Stmt
|
||||
listScriptsStmt *sql.Stmt
|
||||
replaceDeviceAssignmentStmt *sql.Stmt
|
||||
replaceDeviceAuthStmt *sql.Stmt
|
||||
replaceDeviceInfoStmt *sql.Stmt
|
||||
saveScriptStmt *sql.Stmt
|
||||
updateScriptVariablesStmt *sql.Stmt
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
@@ -231,8 +267,12 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
listDeviceAssignmentsStmt: q.listDeviceAssignmentsStmt,
|
||||
listDeviceAuthStmt: q.listDeviceAuthStmt,
|
||||
listDeviceInfosStmt: q.listDeviceInfosStmt,
|
||||
listScriptVariablesStmt: q.listScriptVariablesStmt,
|
||||
listScriptsStmt: q.listScriptsStmt,
|
||||
replaceDeviceAssignmentStmt: q.replaceDeviceAssignmentStmt,
|
||||
replaceDeviceAuthStmt: q.replaceDeviceAuthStmt,
|
||||
replaceDeviceInfoStmt: q.replaceDeviceInfoStmt,
|
||||
saveScriptStmt: q.saveScriptStmt,
|
||||
updateScriptVariablesStmt: q.updateScriptVariablesStmt,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,3 +34,14 @@ type DeviceInfo struct {
|
||||
Kind string
|
||||
Data json.RawMessage
|
||||
}
|
||||
|
||||
type Script struct {
|
||||
Name string
|
||||
Data json.RawMessage
|
||||
}
|
||||
|
||||
type ScriptVariable struct {
|
||||
Scope string
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.13.0
|
||||
// source: script.sql
|
||||
|
||||
package mysqlgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
const listScriptVariables = `-- name: ListScriptVariables :many
|
||||
SELECT scope, name, value FROM script_variable
|
||||
`
|
||||
|
||||
func (q *Queries) ListScriptVariables(ctx context.Context) ([]ScriptVariable, error) {
|
||||
rows, err := q.query(ctx, q.listScriptVariablesStmt, listScriptVariables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []ScriptVariable{}
|
||||
for rows.Next() {
|
||||
var i ScriptVariable
|
||||
if err := rows.Scan(&i.Scope, &i.Name, &i.Value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listScripts = `-- name: ListScripts :many
|
||||
SELECT name, data FROM script
|
||||
`
|
||||
|
||||
func (q *Queries) ListScripts(ctx context.Context) ([]Script, error) {
|
||||
rows, err := q.query(ctx, q.listScriptsStmt, listScripts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []Script{}
|
||||
for rows.Next() {
|
||||
var i Script
|
||||
if err := rows.Scan(&i.Name, &i.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const saveScript = `-- name: SaveScript :exec
|
||||
REPLACE INTO script (name, data) VALUES (?, ?)
|
||||
`
|
||||
|
||||
type SaveScriptParams struct {
|
||||
Name string
|
||||
Data json.RawMessage
|
||||
}
|
||||
|
||||
func (q *Queries) SaveScript(ctx context.Context, arg SaveScriptParams) error {
|
||||
_, err := q.exec(ctx, q.saveScriptStmt, saveScript, arg.Name, arg.Data)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateScriptVariables = `-- name: UpdateScriptVariables :exec
|
||||
REPLACE INTO script_variable (scope, name, value) VALUES (?, ?, ?)
|
||||
`
|
||||
|
||||
type UpdateScriptVariablesParams struct {
|
||||
Scope string
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateScriptVariables(ctx context.Context, arg UpdateScriptVariablesParams) error {
|
||||
_, err := q.exec(ctx, q.updateScriptVariablesStmt, updateScriptVariables, arg.Scope, arg.Name, arg.Value)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
-- name: ListScripts :many
|
||||
SELECT * FROM script;
|
||||
|
||||
-- name: SaveScript :exec
|
||||
REPLACE INTO script (name, data) VALUES (?, ?);
|
||||
|
||||
-- name: ListScriptVariables :many
|
||||
SELECT * FROM script_variable;
|
||||
|
||||
-- name: UpdateScriptVariables :exec
|
||||
REPLACE INTO script_variable (scope, name, value) VALUES (?, ?, ?);
|
||||
@@ -11,13 +11,16 @@ import (
|
||||
"git.aiterp.net/lucifer3/server/events"
|
||||
"git.aiterp.net/lucifer3/server/internal/gentools"
|
||||
"git.aiterp.net/lucifer3/server/services/mysqldb/mysqlgen"
|
||||
"git.aiterp.net/lucifer3/server/services/script"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
type database struct {
|
||||
db *sql.DB
|
||||
db *sql.DB
|
||||
scriptVariables map[string]string
|
||||
}
|
||||
|
||||
func (d *database) Active() bool {
|
||||
@@ -26,7 +29,7 @@ func (d *database) Active() bool {
|
||||
|
||||
func (d *database) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
|
||||
q := mysqlgen.New(d.db)
|
||||
timeout, cancel := context.WithTimeout(context.Background(), time.Second/2)
|
||||
timeout, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
|
||||
switch event := event.(type) {
|
||||
@@ -119,6 +122,58 @@ func (d *database) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
|
||||
})
|
||||
}
|
||||
|
||||
scripts, err := q.ListScripts(timeout)
|
||||
if err != nil {
|
||||
bus.RunEvent(events.Log{
|
||||
Level: "error",
|
||||
Code: "database_could_not_list_scripts",
|
||||
Message: "Database could not list scripts: " + err.Error(),
|
||||
})
|
||||
}
|
||||
for _, scr := range scripts {
|
||||
var lines []script.Line
|
||||
err := json.Unmarshal(scr.Data, &lines)
|
||||
if err != nil {
|
||||
bus.RunEvent(events.Log{
|
||||
Level: "error",
|
||||
Code: "database_could_not_read_script",
|
||||
Message: "Database could not read script: " + err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
bus.RunCommand(script.UpdateScript{
|
||||
Name: scr.Name,
|
||||
Lines: lines,
|
||||
})
|
||||
}
|
||||
|
||||
scriptVariables, err := q.ListScriptVariables(timeout)
|
||||
if err != nil {
|
||||
bus.RunEvent(events.Log{
|
||||
Level: "error",
|
||||
Code: "database_could_not_list_script_variables",
|
||||
Message: "Database could not list script variables: " + err.Error(),
|
||||
})
|
||||
}
|
||||
for _, variable := range scriptVariables {
|
||||
d.scriptVariables[variable.Scope+"::"+variable.Name] = variable.Value
|
||||
|
||||
cmd := script.SetVariable{
|
||||
Key: variable.Name,
|
||||
Value: variable.Value,
|
||||
}
|
||||
|
||||
scopeKind, scopeValue, _ := strings.Cut(variable.Scope, ":")
|
||||
switch scopeKind {
|
||||
case "devices":
|
||||
cmd.Devices = strings.Split(scopeValue, ";")
|
||||
case "match":
|
||||
cmd.Match = gentools.Ptr(scopeValue)
|
||||
}
|
||||
|
||||
bus.RunCommand(cmd)
|
||||
}
|
||||
|
||||
case events.DeviceAccepted:
|
||||
if event.Extras == nil {
|
||||
event.Extras = map[string]string{}
|
||||
@@ -298,7 +353,43 @@ func (d *database) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *database) HandleCommand(*lucifer3.EventBus, lucifer3.Command) {}
|
||||
func (d *database) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command) {
|
||||
q := mysqlgen.New(d.db)
|
||||
timeout, cancel := context.WithTimeout(context.Background(), time.Second/2)
|
||||
defer cancel()
|
||||
|
||||
switch command := command.(type) {
|
||||
case script.SetVariable:
|
||||
scopeName := "global"
|
||||
if command.Match != nil {
|
||||
scopeName = "match:" + *command.Match
|
||||
} else if command.Devices != nil {
|
||||
scopeName = "devices:" + strings.Join(command.Devices, ";")
|
||||
}
|
||||
|
||||
if d.scriptVariables[scopeName+"::"+command.Key] != command.Value {
|
||||
_ = q.UpdateScriptVariables(timeout, mysqlgen.UpdateScriptVariablesParams{
|
||||
Scope: scopeName,
|
||||
Name: command.Key,
|
||||
Value: command.Value,
|
||||
})
|
||||
}
|
||||
case script.UpdateScript:
|
||||
j, _ := json.Marshal(command.Lines)
|
||||
|
||||
err := q.SaveScript(timeout, mysqlgen.SaveScriptParams{
|
||||
Name: command.Name,
|
||||
Data: j,
|
||||
})
|
||||
if err != nil {
|
||||
bus.RunEvent(events.Log{
|
||||
Level: "error",
|
||||
Code: "database_could_not_save_script",
|
||||
Message: "Failed to save script: " + err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Connect(host string, port int, username, password, dbname string) (lucifer3.ActiveService, error) {
|
||||
db, err := sql.Open("mysql", fmt.Sprintf(
|
||||
@@ -317,5 +408,5 @@ func Connect(host string, port int, username, password, dbname string) (lucifer3
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &database{db: db}, nil
|
||||
return &database{db: db, scriptVariables: make(map[string]string)}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user