继续更新 update 门户站点界面和功能
build-winui / winui (push) Has been cancelled

This commit is contained in:
QWQLwToo
2026-06-26 20:17:34 +08:00
parent f525e5f3ba
commit 2513eb2903
68 changed files with 5586 additions and 3195 deletions
@@ -0,0 +1,132 @@
package db
import (
"database/sql"
"errors"
)
func (s *Store) UpsertSource(item Source) (Source, error) {
now := Now()
if item.SourceID == "" {
item.SourceID = item.CategoryID + "-" + item.Name
}
if item.Method == "" {
item.Method = "GET"
}
item.ProxyMode = normalizeProxyMode(firstNonEmpty(item.ProxyMode, "client_direct"), item.CategoryID, item.Name, item.APIURL)
if item.URLTemplate == "" {
item.URLTemplate = item.APIURL
}
if item.TimeoutMS <= 0 {
item.TimeoutMS = 8000
}
if item.RetryCount <= 0 {
item.RetryCount = 1
}
if item.CacheSeconds <= 0 {
item.CacheSeconds = item.CheckIntervalSec
}
if item.CacheSeconds <= 0 {
item.CacheSeconds = 300
}
if item.CheckIntervalSec <= 0 {
item.CheckIntervalSec = item.CacheSeconds
}
if item.SupportedFormats == "" {
item.SupportedFormats = "[]"
}
if item.LastStatus == "" {
item.LastStatus = "unknown"
}
if item.CategoryID == "" {
item.CategoryID = "custom"
}
if item.CategoryName == "" {
item.CategoryName = item.CategoryID
}
_, _ = s.exec(`INSERT INTO source_categories (category_id, name, enabled, ui_config, created_at, updated_at)
VALUES (?, ?, 1, '{}', ?, ?)
ON CONFLICT (category_id) DO UPDATE SET name = excluded.name, updated_at = excluded.updated_at`,
item.CategoryID, item.CategoryName, now, now)
conn, d := s.active()
query := d.upsert("source_endpoints",
[]string{"category_id", "category_name", "source_id", "name", "description", "method", "api_url", "url_template", "thumbnail_url", "proxy_mode", "timeout_ms", "retry_count", "cache_seconds", "check_interval_sec", "enabled", "client_visible", "supported_formats", "last_status", "last_latency_ms", "last_checked_at", "last_error", "consecutive_failure", "created_at", "updated_at"},
[]string{"source_id"})
if _, err := conn.Exec(d.rebind(query), item.CategoryID, item.CategoryName, item.SourceID, item.Name, item.Description, item.Method, item.APIURL, item.URLTemplate, item.ThumbnailURL,
item.ProxyMode, item.TimeoutMS, item.RetryCount, item.CacheSeconds, item.CheckIntervalSec, boolInt(item.Enabled), boolInt(item.ClientVisible), item.SupportedFormats,
item.LastStatus, item.LastLatencyMS, item.LastCheckedAt, item.LastError, item.ConsecutiveFailure, firstNonEmpty(item.CreatedAt, now), now); err != nil {
s.markFailover(err)
return Source{}, err
}
return s.GetSourceBySourceID(item.SourceID)
}
func (s *Store) GetSourceBySourceID(sourceID string) (Source, error) {
item, err := scanSourceRow(s.queryRow(sourceSelectSQL()+` WHERE source_id = ?`, sourceID))
if errors.Is(err, sql.ErrNoRows) {
return Source{}, errors.New("source not found")
}
return item, err
}
func (s *Store) ListSources(includeHidden bool) ([]Source, error) {
where := ""
args := []any{}
if !includeHidden {
where = " WHERE enabled = 1 AND client_visible = 1"
}
rows, err := s.query(sourceSelectSQL()+where+` ORDER BY category_id ASC, name ASC`, args...)
if err != nil {
return nil, err
}
defer rows.Close()
items := []Source{}
for rows.Next() {
item, err := scanSourceRowsCurrent(rows)
if err != nil {
return nil, err
}
items = append(items, item)
}
return items, rows.Err()
}
func (s *Store) CountSources() (int, error) {
var count int
err := s.queryRow(`SELECT COUNT(*) FROM source_endpoints`).Scan(&count)
return count, err
}
func (s *Store) DeleteSource(sourceID string) error {
_, err := s.exec(`DELETE FROM source_endpoints WHERE source_id = ?`, sourceID)
return err
}
func (s *Store) RecordSourceCheck(sourceDBID int64, status string, latency int, message string) error {
now := Now()
_, err := s.exec(`INSERT INTO endpoint_health_checks (source_db_id, status, latency_ms, error, checked_at) VALUES (?, ?, ?, ?, ?)`,
sourceDBID, status, latency, sanitize(message), now)
if err != nil {
return err
}
if status == "ok" {
_, err = s.exec(`UPDATE source_endpoints SET last_status = ?, last_latency_ms = ?, last_checked_at = ?, last_error = '', consecutive_failure = 0, updated_at = ? WHERE id = ?`,
status, latency, now, now, sourceDBID)
} else if status == "redirected" {
_, err = s.exec(`UPDATE source_endpoints SET last_status = ?, last_latency_ms = ?, last_checked_at = ?, last_error = ?, consecutive_failure = 0, updated_at = ? WHERE id = ?`,
status, latency, now, sanitize(message), now, sourceDBID)
} else {
_, err = s.exec(`UPDATE source_endpoints SET last_status = ?, last_latency_ms = ?, last_checked_at = ?, last_error = ?, consecutive_failure = consecutive_failure + 1, updated_at = ? WHERE id = ?`,
status, latency, now, sanitize(message), now, sourceDBID)
}
return err
}
func (s *Store) RecordSourceCall(call SourceCall) error {
if call.CreatedAt == "" {
call.CreatedAt = Now()
}
_, err := s.exec(`INSERT INTO endpoint_call_logs (source_id, status, latency_ms, error, client, created_at) VALUES (?, ?, ?, ?, ?, ?)`,
sanitize(call.SourceID), sanitize(call.Status), call.LatencyMS, sanitize(call.Error), sanitize(call.Client), call.CreatedAt)
return err
}