97 lines
3.2 KiB
Go
97 lines
3.2 KiB
Go
package data
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"kra/internal/conf"
|
|
|
|
"google.golang.org/protobuf/encoding/protojson"
|
|
"google.golang.org/protobuf/proto"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
const integrationKindWebSocket = "websocket"
|
|
|
|
// saveWebSocketIntegrationConfig persists the Melody settings in the shared
|
|
// integration table. It intentionally lives separately from storage/payment
|
|
// persistence so adding another transport does not expand their API surface.
|
|
func saveWebSocketIntegrationConfig(db *gorm.DB, config *conf.AdminBackend_WebSocket) error {
|
|
if config == nil {
|
|
config = &conf.AdminBackend_WebSocket{}
|
|
}
|
|
raw, err := protojson.MarshalOptions{UseProtoNames: true, EmitDefaultValues: true}.Marshal(config)
|
|
if err != nil {
|
|
return fmt.Errorf("encode websocket integration configuration: %w", err)
|
|
}
|
|
clean := db.Session(&gorm.Session{NewDB: true})
|
|
var current integrationConfigPO
|
|
err = clean.Where("kind = ? AND provider = ?", integrationKindWebSocket, "melody").First(¤t).Error
|
|
switch {
|
|
case errors.Is(err, gorm.ErrRecordNotFound):
|
|
return clean.Create(&integrationConfigPO{Kind: integrationKindWebSocket, Provider: "melody", Enabled: config.Enabled, Config: string(raw)}).Error
|
|
case err != nil:
|
|
return err
|
|
default:
|
|
return clean.Model(¤t).Updates(map[string]any{"enabled": config.Enabled, "config": string(raw)}).Error
|
|
}
|
|
}
|
|
|
|
func loadWebSocketIntegrationConfig(db *gorm.DB) (*conf.AdminBackend_WebSocket, bool, error) {
|
|
var row integrationConfigPO
|
|
err := db.Session(&gorm.Session{NewDB: true}).Where("kind = ? AND provider = ?", integrationKindWebSocket, "melody").First(&row).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, false, nil
|
|
}
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if !json.Valid([]byte(row.Config)) {
|
|
return nil, false, errors.New("invalid websocket integration configuration")
|
|
}
|
|
config := &conf.AdminBackend_WebSocket{}
|
|
if err = (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal([]byte(row.Config), config); err != nil {
|
|
return nil, false, fmt.Errorf("decode websocket integration configuration: %w", err)
|
|
}
|
|
config.Enabled = row.Enabled
|
|
return config, true, nil
|
|
}
|
|
|
|
func resolveWebSocketIntegrationConfig(db *gorm.DB, legacy *conf.AdminBackend_WebSocket) (*conf.AdminBackend_WebSocket, error) {
|
|
clean := db.Session(&gorm.Session{NewDB: true})
|
|
if !clean.Migrator().HasTable(&integrationConfigPO{}) {
|
|
if legacy == nil {
|
|
return &conf.AdminBackend_WebSocket{}, nil
|
|
}
|
|
return proto.Clone(legacy).(*conf.AdminBackend_WebSocket), nil
|
|
}
|
|
config, found, err := loadWebSocketIntegrationConfig(clean)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if found {
|
|
return config, nil
|
|
}
|
|
if legacy == nil {
|
|
legacy = &conf.AdminBackend_WebSocket{}
|
|
}
|
|
if err = saveWebSocketIntegrationConfig(clean, legacy); err != nil {
|
|
return nil, err
|
|
}
|
|
config, _, err = loadWebSocketIntegrationConfig(clean)
|
|
return config, err
|
|
}
|
|
|
|
func (d *Data) PersistWebSocketConfig(ctx context.Context, config *conf.AdminBackend_WebSocket) error {
|
|
if !d.databaseReady.Load() {
|
|
return errors.New("database is not initialized")
|
|
}
|
|
db := d.gormDB.WithContext(ctx)
|
|
if !db.Migrator().HasTable(&integrationConfigPO{}) {
|
|
return errors.New("integration configuration table does not exist")
|
|
}
|
|
return saveWebSocketIntegrationConfig(db, config)
|
|
}
|