c38b7d4c78
Add database foundation for observability features: - event_log table with severity/source filtering and pagination - standalone_proxies table for user-created reverse proxies - stale_threshold_days setting (default 7 days) - Auto-persist warn/error events from event bus to database - SSE broadcast of persistent events for real-time UI updates - Frontend types and API functions for downstream UI phases
121 lines
4.1 KiB
Go
121 lines
4.1 KiB
Go
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// CreateStandaloneProxy inserts a new standalone proxy record.
|
|
func (s *Store) CreateStandaloneProxy(p StandaloneProxy) (StandaloneProxy, error) {
|
|
p.ID = uuid.New().String()
|
|
p.CreatedAt = Now()
|
|
p.UpdatedAt = p.CreatedAt
|
|
|
|
if p.HealthStatus == "" {
|
|
p.HealthStatus = "unknown"
|
|
}
|
|
|
|
_, err := s.db.Exec(
|
|
`INSERT INTO standalone_proxies (id, domain, destination_url, destination_port, ssl_certificate_id, npm_proxy_id, health_status, health_checked_at, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
p.ID, p.Domain, p.DestinationURL, p.DestinationPort, p.SSLCertificateID,
|
|
p.NpmProxyID, p.HealthStatus, p.HealthCheckedAt, p.CreatedAt, p.UpdatedAt,
|
|
)
|
|
if err != nil {
|
|
return StandaloneProxy{}, fmt.Errorf("insert standalone proxy: %w", err)
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// GetStandaloneProxy returns a standalone proxy by ID.
|
|
func (s *Store) GetStandaloneProxy(id string) (StandaloneProxy, error) {
|
|
var p StandaloneProxy
|
|
err := s.db.QueryRow(
|
|
`SELECT id, domain, destination_url, destination_port, ssl_certificate_id, npm_proxy_id, health_status, health_checked_at, created_at, updated_at
|
|
FROM standalone_proxies WHERE id = ?`, id,
|
|
).Scan(&p.ID, &p.Domain, &p.DestinationURL, &p.DestinationPort, &p.SSLCertificateID,
|
|
&p.NpmProxyID, &p.HealthStatus, &p.HealthCheckedAt, &p.CreatedAt, &p.UpdatedAt)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return StandaloneProxy{}, fmt.Errorf("standalone proxy %s: %w", id, ErrNotFound)
|
|
}
|
|
if err != nil {
|
|
return StandaloneProxy{}, fmt.Errorf("query standalone proxy: %w", err)
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// ListStandaloneProxies returns all standalone proxy records ordered by creation time.
|
|
func (s *Store) ListStandaloneProxies() ([]StandaloneProxy, error) {
|
|
rows, err := s.db.Query(
|
|
`SELECT id, domain, destination_url, destination_port, ssl_certificate_id, npm_proxy_id, health_status, health_checked_at, created_at, updated_at
|
|
FROM standalone_proxies ORDER BY created_at DESC`,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query standalone proxies: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
proxies := []StandaloneProxy{}
|
|
for rows.Next() {
|
|
var p StandaloneProxy
|
|
if err := rows.Scan(&p.ID, &p.Domain, &p.DestinationURL, &p.DestinationPort, &p.SSLCertificateID,
|
|
&p.NpmProxyID, &p.HealthStatus, &p.HealthCheckedAt, &p.CreatedAt, &p.UpdatedAt); err != nil {
|
|
return nil, fmt.Errorf("scan standalone proxy: %w", err)
|
|
}
|
|
proxies = append(proxies, p)
|
|
}
|
|
return proxies, rows.Err()
|
|
}
|
|
|
|
// UpdateStandaloneProxy updates an existing standalone proxy's mutable fields.
|
|
func (s *Store) UpdateStandaloneProxy(p StandaloneProxy) error {
|
|
p.UpdatedAt = Now()
|
|
result, err := s.db.Exec(
|
|
`UPDATE standalone_proxies SET domain=?, destination_url=?, destination_port=?, ssl_certificate_id=?, npm_proxy_id=?, health_status=?, health_checked_at=?, updated_at=?
|
|
WHERE id=?`,
|
|
p.Domain, p.DestinationURL, p.DestinationPort, p.SSLCertificateID,
|
|
p.NpmProxyID, p.HealthStatus, p.HealthCheckedAt, p.UpdatedAt, p.ID,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("update standalone proxy: %w", err)
|
|
}
|
|
n, _ := result.RowsAffected()
|
|
if n == 0 {
|
|
return fmt.Errorf("standalone proxy %s: %w", p.ID, ErrNotFound)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteStandaloneProxy removes a standalone proxy by ID.
|
|
func (s *Store) DeleteStandaloneProxy(id string) error {
|
|
result, err := s.db.Exec(`DELETE FROM standalone_proxies WHERE id = ?`, id)
|
|
if err != nil {
|
|
return fmt.Errorf("delete standalone proxy: %w", err)
|
|
}
|
|
n, _ := result.RowsAffected()
|
|
if n == 0 {
|
|
return fmt.Errorf("standalone proxy %s: %w", id, ErrNotFound)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateProxyHealth updates the health status and check timestamp for a standalone proxy.
|
|
func (s *Store) UpdateProxyHealth(id string, status string) error {
|
|
ts := Now()
|
|
result, err := s.db.Exec(
|
|
`UPDATE standalone_proxies SET health_status=?, health_checked_at=?, updated_at=? WHERE id=?`,
|
|
status, ts, ts, id,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("update proxy health: %w", err)
|
|
}
|
|
n, _ := result.RowsAffected()
|
|
if n == 0 {
|
|
return fmt.Errorf("standalone proxy %s: %w", id, ErrNotFound)
|
|
}
|
|
return nil
|
|
}
|