You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

252 lines
5.5 KiB

package api
import (
"context"
"git.aiterp.net/lucifer/new-server/app/config"
"git.aiterp.net/lucifer/new-server/app/services/scene"
"git.aiterp.net/lucifer/new-server/models"
"github.com/gin-gonic/gin"
"golang.org/x/sync/errgroup"
"log"
"time"
)
func fetchDevices(ctx context.Context, fetchStr string) ([]models.Device, error) {
kind, value := models.ParseFetchString(fetchStr)
return config.DeviceRepository().FetchByReference(ctx, kind, value)
}
func Devices(r gin.IRoutes) {
r.GET("", handler(func(c *gin.Context) (interface{}, error) {
return config.DeviceRepository().FetchByReference(ctxOf(c), models.RKAll, "")
}))
r.GET("/:fetch", handler(func(c *gin.Context) (interface{}, error) {
return fetchDevices(ctxOf(c), c.Param("fetch"))
}))
r.PUT("", handler(func(c *gin.Context) (interface{}, error) {
var body []struct {
Fetch string `json:"fetch"`
SetState models.NewDeviceState `json:"setState"`
}
err := parseBody(c, &body)
if err != nil {
return nil, err
}
set := make(map[int]bool)
changed := make([]models.Device, 0, 64)
for _, job := range body {
devices, err := fetchDevices(ctxOf(c), job.Fetch)
if err != nil {
return nil, err
}
if len(devices) == 0 {
return []models.Device{}, nil
}
for i := range devices {
if set[devices[i].ID] {
continue
}
err := devices[i].SetState(job.SetState)
if err != nil {
return nil, err
}
_ = scene.GlobalManager().UpdateDevice(ctxOf(c), &devices[i], nil)
set[devices[i].ID] = true
changed = append(changed, devices[i])
}
}
config.PublishChannel <- scene.GlobalManager().FilterUnassigned(changed)
go func() {
for _, device := range changed {
err := config.DeviceRepository().Save(context.Background(), &device, models.SMState)
if err != nil {
log.Println("Failed to save device for state:", err)
continue
}
}
}()
return changed, nil
}))
r.PUT("/:fetch", handler(func(c *gin.Context) (interface{}, error) {
update := models.DeviceUpdate{}
err := parseBody(c, &update)
if err != nil {
return nil, err
}
devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
if err != nil {
return nil, err
}
if len(devices) == 0 {
return []models.Device{}, nil
}
for i := range devices {
devices[i].ApplyUpdate(update)
err := config.DeviceRepository().Save(context.Background(), &devices[i], models.SMProperties)
if err != nil {
log.Println("Failed to save device for state:", err)
continue
}
}
return devices, nil
}))
r.PUT("/:fetch/state", handler(func(c *gin.Context) (interface{}, error) {
state := models.NewDeviceState{}
err := parseBody(c, &state)
if err != nil {
return nil, err
}
devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
if err != nil {
return nil, err
}
if len(devices) == 0 {
return []models.Device{}, nil
}
for i := range devices {
err := devices[i].SetState(state)
if err != nil {
return nil, err
}
_ = scene.GlobalManager().UpdateDevice(ctxOf(c), &devices[i], nil)
}
config.PublishChannel <- scene.GlobalManager().FilterUnassigned(devices)
go func() {
for _, device := range devices {
err := config.DeviceRepository().Save(context.Background(), &device, models.SMState)
if err != nil {
log.Println("Failed to save device for state:", err)
continue
}
}
}()
return devices, nil
}))
r.PUT("/:fetch/tags", handler(func(c *gin.Context) (interface{}, error) {
var body struct {
Add []string `json:"add"`
Remove []string `json:"remove"`
}
err := parseBody(c, &body)
if err != nil {
return nil, err
}
devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
if err != nil {
return nil, err
}
if len(devices) == 0 {
return []models.Device{}, nil
}
for i := range devices {
device := &devices[i]
for _, tag := range body.Add {
found := false
for _, tag2 := range device.Tags {
if tag == tag2 {
found = true
break
}
}
if !found {
device.Tags = append(device.Tags, tag)
}
}
for _, tag := range body.Remove {
index := -1
for i, tag2 := range device.Tags {
if tag == tag2 {
index = i
}
}
if index == -1 {
continue
}
device.Tags = append(device.Tags[:index], device.Tags[index+1:]...)
}
err = config.DeviceRepository().Save(ctxOf(c), device, models.SMTags)
if err != nil {
return nil, err
}
}
return devices, nil
}))
r.PUT("/:fetch/scene", handler(func(c *gin.Context) (interface{}, error) {
var body models.DeviceSceneAssignment
err := parseBody(c, &body)
if err != nil {
return nil, err
}
devices, err := fetchDevices(ctxOf(c), c.Param("fetch"))
if err != nil {
return nil, err
}
if len(devices) == 0 {
return []models.Device{}, nil
}
assignedScene, err := config.SceneRepository().Find(ctxOf(c), body.SceneID)
if err != nil {
return nil, err
}
if body.DurationMS < 0 {
body.DurationMS = 0
}
body.StartTime = time.Now()
for i := range devices {
devices[i].SceneAssignments = []models.DeviceSceneAssignment{body}
err := scene.GlobalManager().UpdateDevice(ctxOf(c), &devices[i], assignedScene)
if err != nil {
return nil, err
}
}
eg := errgroup.Group{}
for i := range devices {
eg.Go(func() error {
return config.DeviceRepository().Save(ctxOf(c), &devices[i], 0)
})
}
err = eg.Wait()
if err != nil {
return nil, err
}
return devices, nil
}))
}