diff --git a/app/api/devices.go b/app/api/devices.go index 275961f..4555772 100644 --- a/app/api/devices.go +++ b/app/api/devices.go @@ -80,7 +80,7 @@ func Devices(r gin.IRoutes) { go func() { for _, device := range changed { - err := config.DeviceRepository().Save(context.Background(), &device) + err := config.DeviceRepository().Save(context.Background(), &device, models.SMState) if err != nil { log.Println("Failed to save device for state:", err) continue @@ -109,7 +109,7 @@ func Devices(r gin.IRoutes) { for i := range devices { devices[i].ApplyUpdate(update) - err := config.DeviceRepository().Save(context.Background(), &devices[i]) + err := config.DeviceRepository().Save(context.Background(), &devices[i], models.SMProperties) if err != nil { log.Println("Failed to save device for state:", err) continue @@ -145,7 +145,7 @@ func Devices(r gin.IRoutes) { go func() { for _, device := range devices { - err := config.DeviceRepository().Save(context.Background(), &device) + err := config.DeviceRepository().Save(context.Background(), &device, models.SMState) if err != nil { log.Println("Failed to save device for state:", err) continue @@ -204,7 +204,7 @@ func Devices(r gin.IRoutes) { device.Tags = append(device.Tags[:index], device.Tags[index+1:]...) } - err = config.DeviceRepository().Save(ctxOf(c), device) + err = config.DeviceRepository().Save(ctxOf(c), device, models.SMTags) if err != nil { return nil, err } diff --git a/app/services/events.go b/app/services/events.go index b873924..c1bac4d 100644 --- a/app/services/events.go +++ b/app/services/events.go @@ -157,7 +157,7 @@ func handleEvent(event models.Event) (responses []models.Event) { wg.Add(1) go func(device models.Device) { - err := config.DeviceRepository().Save(context.Background(), &device) + err := config.DeviceRepository().Save(context.Background(), &device, models.SMState) if err != nil { log.Println("Failed to save device for state:", err) } diff --git a/app/services/synclights.go b/app/services/synclights.go index 1dc0cb2..11b9c80 100644 --- a/app/services/synclights.go +++ b/app/services/synclights.go @@ -66,7 +66,7 @@ func checkNewDevices() error { log.Println("Saving new device", driverDevice.InternalID) - err := config.DeviceRepository().Save(ctx, &driverDevice) + err := config.DeviceRepository().Save(ctx, &driverDevice, models.SMState|models.SMProperties|models.SMTags) if err != nil { log.Println("Failed to save device:", err) continue diff --git a/internal/mysql/devicerepo.go b/internal/mysql/devicerepo.go index e800ea5..1d6e373 100644 --- a/internal/mysql/devicerepo.go +++ b/internal/mysql/devicerepo.go @@ -117,7 +117,7 @@ func (r *DeviceRepo) FetchByReference(ctx context.Context, kind models.Reference return r.populate(ctx, records) } -func (r *DeviceRepo) Save(ctx context.Context, device *models.Device) error { +func (r *DeviceRepo) Save(ctx context.Context, device *models.Device, mode models.SaveMode) error { tx, err := r.DBX.Beginx() if err != nil { return dbErr(err) @@ -149,13 +149,18 @@ func (r *DeviceRepo) Save(ctx context.Context, device *models.Device) error { } // Let's just be lazy for now, optimize later if need be. - _, err = tx.ExecContext(ctx, "DELETE FROM device_tag WHERE device_id=?", record.ID) - if err != nil { - return dbErr(err) + if mode == 0 || mode&models.SMTags != 0 { + _, err = tx.ExecContext(ctx, "DELETE FROM device_tag WHERE device_id=?", record.ID) + if err != nil { + return dbErr(err) + } } - _, err = tx.ExecContext(ctx, "DELETE FROM device_property WHERE device_id=?", record.ID) - if err != nil { - return dbErr(err) + + if mode == 0 || mode&models.SMProperties != 0 { + _, err = tx.ExecContext(ctx, "DELETE FROM device_property WHERE device_id=?", record.ID) + if err != nil { + return dbErr(err) + } } } else { res, err := tx.NamedExecContext(ctx, ` @@ -175,51 +180,57 @@ func (r *DeviceRepo) Save(ctx context.Context, device *models.Device) error { device.ID = int(lastID) } - for _, tag := range device.Tags { - _, err := tx.ExecContext(ctx, "INSERT INTO device_tag (device_id, tag_name) VALUES (?, ?)", record.ID, tag) - if err != nil { - return dbErr(err) + if mode == 0 || mode&models.SMTags != 0 { + for _, tag := range device.Tags { + _, err := tx.ExecContext(ctx, "INSERT INTO device_tag (device_id, tag_name) VALUES (?, ?)", record.ID, tag) + if err != nil { + return dbErr(err) + } } } - for key, value := range device.UserProperties { - _, err := tx.ExecContext(ctx, "INSERT INTO device_property (device_id, prop_key, prop_value, is_user) VALUES (?, ?, ?, 1)", - record.ID, key, value, - ) - if err != nil { - return dbErr(err) + if mode == 0 || mode&models.SMProperties != 0 { + for key, value := range device.UserProperties { + _, err := tx.ExecContext(ctx, "INSERT INTO device_property (device_id, prop_key, prop_value, is_user) VALUES (?, ?, ?, 1)", + record.ID, key, value, + ) + if err != nil { + return dbErr(err) + } } - } - for key, value := range device.DriverProperties { - j, err := json.Marshal(value) - if err != nil { - // Eh, it'll get filled by the driver anyway - continue - } + for key, value := range device.DriverProperties { + j, err := json.Marshal(value) + if err != nil { + // Eh, it'll get filled by the driver anyway + continue + } - _, err = tx.ExecContext(ctx, "INSERT INTO device_property (device_id, prop_key, prop_value, is_user) VALUES (?, ?, ?, 0)", - record.ID, key, string(j), - ) - if err != nil { - // Return err here anyway, it might put the tx in a bad state to ignore it. - return dbErr(err) + _, err = tx.ExecContext(ctx, "INSERT INTO device_property (device_id, prop_key, prop_value, is_user) VALUES (?, ?, ?, 0)", + record.ID, key, string(j), + ) + if err != nil { + // Return err here anyway, it might put the tx in a bad state to ignore it. + return dbErr(err) + } } } - _, err = tx.NamedExecContext(ctx, ` + if mode == 0 || mode&models.SMState != 0 { + _, err = tx.NamedExecContext(ctx, ` REPLACE INTO device_state(device_id, hue, saturation, kelvin, power, intensity) VALUES (:device_id, :hue, :saturation, :kelvin, :power, :intensity) `, deviceStateRecord{ - DeviceID: record.ID, - Hue: device.State.Color.Hue, - Saturation: device.State.Color.Saturation, - Kelvin: device.State.Color.Kelvin, - Power: device.State.Power, - Intensity: device.State.Intensity, - }) - if err != nil { - return dbErr(err) + DeviceID: record.ID, + Hue: device.State.Color.Hue, + Saturation: device.State.Color.Saturation, + Kelvin: device.State.Color.Kelvin, + Power: device.State.Power, + Intensity: device.State.Intensity, + }) + if err != nil { + return dbErr(err) + } } return tx.Commit() diff --git a/models/device.go b/models/device.go index de51e88..e8e5146 100644 --- a/models/device.go +++ b/models/device.go @@ -20,8 +20,8 @@ type Device struct { } type DeviceUpdate struct { - Icon *string `json:"icon"` - Name *string `json:"name"` + Icon *string `json:"icon"` + Name *string `json:"name"` UserProperties map[string]*string `json:"userProperties"` } @@ -46,10 +46,18 @@ type NewDeviceState struct { type DeviceCapability string +type SaveMode int + +const ( + SMState SaveMode = 1 + SMProperties SaveMode = 2 + SMTags SaveMode = 4 +) + type DeviceRepository interface { Find(ctx context.Context, id int) (*Device, error) FetchByReference(ctx context.Context, kind ReferenceKind, value string) ([]Device, error) - Save(ctx context.Context, device *Device) error + Save(ctx context.Context, device *Device, mode SaveMode) error Delete(ctx context.Context, device *Device) error }