feat(models): widen Site struct and DB schema for ping, port, dns, group monitor types
Add Hostname, Port, Timeout, Method, Description, ParentID, AcceptedCodes, DNSResolveType, DNSServer, and IgnoreTLS fields. Refactor AddSite/UpdateSite to accept models.Site instead of individual params. Includes DB migrations for existing databases, per-monitor timeout/TLS in the engine, new type options in TUI forms, and TYPE column in the sites table.
This commit is contained in:
+11
-8
@@ -4,6 +4,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go-upkeep/internal/cluster"
|
"go-upkeep/internal/cluster"
|
||||||
|
"go-upkeep/internal/models"
|
||||||
"go-upkeep/internal/monitor"
|
"go-upkeep/internal/monitor"
|
||||||
"go-upkeep/internal/server"
|
"go-upkeep/internal/server"
|
||||||
"go-upkeep/internal/store"
|
"go-upkeep/internal/store"
|
||||||
@@ -166,14 +167,16 @@ func seedDemoData(s store.Store) {
|
|||||||
alertID = alerts[0].ID
|
alertID = alerts[0].ID
|
||||||
}
|
}
|
||||||
|
|
||||||
s.AddSite("Google", "https://www.google.com", "http", 30, alertID, true, 14, 2)
|
s.AddSite(models.Site{Name: "Google", URL: "https://www.google.com", Type: "http", Interval: 30, AlertID: alertID, CheckSSL: true, ExpiryThreshold: 14, MaxRetries: 2})
|
||||||
s.AddSite("GitHub", "https://github.com", "http", 30, alertID, true, 7, 3)
|
s.AddSite(models.Site{Name: "GitHub", URL: "https://github.com", Type: "http", Interval: 30, AlertID: alertID, CheckSSL: true, ExpiryThreshold: 7, MaxRetries: 3})
|
||||||
s.AddSite("Cloudflare DNS", "https://1.1.1.1", "http", 60, alertID, false, 7, 1)
|
s.AddSite(models.Site{Name: "Cloudflare DNS", URL: "https://1.1.1.1", Type: "http", Interval: 60, AlertID: alertID, ExpiryThreshold: 7, MaxRetries: 1})
|
||||||
s.AddSite("JSON Placeholder", "https://jsonplaceholder.typicode.com/posts/1", "http", 45, alertID, false, 7, 2)
|
s.AddSite(models.Site{Name: "JSON Placeholder", URL: "https://jsonplaceholder.typicode.com/posts/1", Type: "http", Interval: 45, AlertID: alertID, ExpiryThreshold: 7, MaxRetries: 2})
|
||||||
s.AddSite("Nonexistent Site", "https://this-domain-does-not-exist-12345.com", "http", 30, alertID, false, 7, 3)
|
s.AddSite(models.Site{Name: "Nonexistent Site", URL: "https://this-domain-does-not-exist-12345.com", Type: "http", Interval: 30, AlertID: alertID, ExpiryThreshold: 7, MaxRetries: 3})
|
||||||
s.AddSite("Bad Port", "https://localhost:19999", "http", 30, 0, false, 7, 1)
|
s.AddSite(models.Site{Name: "Bad Port", URL: "https://localhost:19999", Type: "http", Interval: 30, ExpiryThreshold: 7, MaxRetries: 1})
|
||||||
s.AddSite("Backup Cron", "", "push", 300, alertID, false, 7, 0)
|
s.AddSite(models.Site{Name: "Backup Cron", Type: "push", Interval: 300, AlertID: alertID, ExpiryThreshold: 7})
|
||||||
s.AddSite("DB Healthcheck", "", "push", 120, alertID, false, 7, 0)
|
s.AddSite(models.Site{Name: "DB Healthcheck", Type: "push", Interval: 120, AlertID: alertID, ExpiryThreshold: 7})
|
||||||
|
s.AddSite(models.Site{Name: "Gateway", Type: "ping", Interval: 30, AlertID: alertID, Hostname: "10.0.0.1", Timeout: 5, ExpiryThreshold: 7})
|
||||||
|
s.AddSite(models.Site{Name: "SSH Server", Type: "port", Interval: 60, AlertID: alertID, Hostname: "10.0.0.1", Port: 22, Timeout: 5, ExpiryThreshold: 7})
|
||||||
}
|
}
|
||||||
|
|
||||||
func isKeyAllowed(incomingKey ssh.PublicKey) bool {
|
func isKeyAllowed(incomingKey ssh.PublicKey) bool {
|
||||||
|
|||||||
+21
-11
@@ -6,23 +6,33 @@ type Site struct {
|
|||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
URL string
|
URL string
|
||||||
Type string // "http" or "push"
|
Type string // "http", "push", "ping", "port", "dns", "group"
|
||||||
Token string // Secure Token
|
Token string
|
||||||
Interval int
|
Interval int
|
||||||
AlertID int
|
AlertID int
|
||||||
CheckSSL bool
|
CheckSSL bool
|
||||||
ExpiryThreshold int
|
ExpiryThreshold int
|
||||||
|
|
||||||
MaxRetries int
|
MaxRetries int
|
||||||
FailureCount int
|
|
||||||
|
|
||||||
Status string
|
Hostname string
|
||||||
StatusCode int
|
Port int
|
||||||
Latency time.Duration
|
Timeout int
|
||||||
CertExpiry time.Time
|
Method string
|
||||||
HasSSL bool
|
Description string
|
||||||
LastCheck time.Time
|
ParentID int
|
||||||
SentSSLWarning bool
|
AcceptedCodes string
|
||||||
|
DNSResolveType string
|
||||||
|
DNSServer string
|
||||||
|
IgnoreTLS bool
|
||||||
|
|
||||||
|
FailureCount int
|
||||||
|
Status string
|
||||||
|
StatusCode int
|
||||||
|
Latency time.Duration
|
||||||
|
CertExpiry time.Time
|
||||||
|
HasSSL bool
|
||||||
|
LastCheck time.Time
|
||||||
|
SentSSLWarning bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlertConfig struct {
|
type AlertConfig struct {
|
||||||
|
|||||||
+34
-14
@@ -135,19 +135,29 @@ func StartEngine() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateSiteConfig(id int, name, url, sType string, interval, alertID int, checkSSL bool, threshold, retries int) {
|
func UpdateSiteConfig(site models.Site) {
|
||||||
Mutex.Lock()
|
Mutex.Lock()
|
||||||
defer Mutex.Unlock()
|
defer Mutex.Unlock()
|
||||||
if s, ok := LiveState[id]; ok {
|
if s, ok := LiveState[site.ID]; ok {
|
||||||
s.Name = name
|
s.Name = site.Name
|
||||||
s.URL = url
|
s.URL = site.URL
|
||||||
s.Type = sType
|
s.Type = site.Type
|
||||||
s.Interval = interval
|
s.Interval = site.Interval
|
||||||
s.AlertID = alertID
|
s.AlertID = site.AlertID
|
||||||
s.CheckSSL = checkSSL
|
s.CheckSSL = site.CheckSSL
|
||||||
s.ExpiryThreshold = threshold
|
s.ExpiryThreshold = site.ExpiryThreshold
|
||||||
s.MaxRetries = retries
|
s.MaxRetries = site.MaxRetries
|
||||||
LiveState[id] = s
|
s.Hostname = site.Hostname
|
||||||
|
s.Port = site.Port
|
||||||
|
s.Timeout = site.Timeout
|
||||||
|
s.Method = site.Method
|
||||||
|
s.Description = site.Description
|
||||||
|
s.ParentID = site.ParentID
|
||||||
|
s.AcceptedCodes = site.AcceptedCodes
|
||||||
|
s.DNSResolveType = site.DNSResolveType
|
||||||
|
s.DNSServer = site.DNSServer
|
||||||
|
s.IgnoreTLS = site.IgnoreTLS
|
||||||
|
LiveState[site.ID] = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,10 +204,15 @@ func checkByID(id int) {
|
|||||||
if !exists {
|
if !exists {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if site.Type == "http" {
|
switch site.Type {
|
||||||
|
case "http":
|
||||||
checkHTTP(site)
|
checkHTTP(site)
|
||||||
} else {
|
case "push":
|
||||||
checkPush(site)
|
checkPush(site)
|
||||||
|
case "ping", "port", "dns":
|
||||||
|
AddLog(fmt.Sprintf("Monitor '%s' type '%s' not yet implemented", site.Name, site.Type))
|
||||||
|
case "group":
|
||||||
|
// groups don't perform checks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +229,12 @@ func checkPush(site models.Site) {
|
|||||||
|
|
||||||
func checkHTTP(site models.Site) {
|
func checkHTTP(site models.Site) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
client := &http.Client{Timeout: 5 * time.Second, Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}}}
|
timeout := time.Duration(site.Timeout) * time.Second
|
||||||
|
if timeout <= 0 {
|
||||||
|
timeout = 5 * time.Second
|
||||||
|
}
|
||||||
|
skipTLS := insecureSkipVerify || site.IgnoreTLS
|
||||||
|
client := &http.Client{Timeout: timeout, Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: skipTLS}}}
|
||||||
resp, err := client.Get(site.URL)
|
resp, err := client.Get(site.URL)
|
||||||
latency := time.Since(start)
|
latency := time.Since(start)
|
||||||
|
|
||||||
|
|||||||
+45
-12
@@ -37,7 +37,17 @@ func (p *PostgresStore) Init() error {
|
|||||||
alert_id INTEGER,
|
alert_id INTEGER,
|
||||||
check_ssl BOOLEAN DEFAULT FALSE,
|
check_ssl BOOLEAN DEFAULT FALSE,
|
||||||
threshold INTEGER DEFAULT 7,
|
threshold INTEGER DEFAULT 7,
|
||||||
max_retries INTEGER DEFAULT 0
|
max_retries INTEGER DEFAULT 0,
|
||||||
|
hostname TEXT DEFAULT '',
|
||||||
|
port INTEGER DEFAULT 0,
|
||||||
|
timeout INTEGER DEFAULT 0,
|
||||||
|
method TEXT DEFAULT 'GET',
|
||||||
|
description TEXT DEFAULT '',
|
||||||
|
parent_id INTEGER DEFAULT 0,
|
||||||
|
accepted_codes TEXT DEFAULT '200-299',
|
||||||
|
dns_resolve_type TEXT DEFAULT '',
|
||||||
|
dns_server TEXT DEFAULT '',
|
||||||
|
ignore_tls BOOLEAN DEFAULT FALSE
|
||||||
);`,
|
);`,
|
||||||
`CREATE TABLE IF NOT EXISTS users (
|
`CREATE TABLE IF NOT EXISTS users (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
@@ -51,12 +61,29 @@ func (p *PostgresStore) Init() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
migrations := []string{
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS hostname TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS port INTEGER DEFAULT 0",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS timeout INTEGER DEFAULT 0",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS method TEXT DEFAULT 'GET'",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS description TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS parent_id INTEGER DEFAULT 0",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS accepted_codes TEXT DEFAULT '200-299'",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns_resolve_type TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS dns_server TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN IF NOT EXISTS ignore_tls BOOLEAN DEFAULT FALSE",
|
||||||
|
}
|
||||||
|
for _, m := range migrations {
|
||||||
|
p.db.Exec(m)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... [CRUD Methods are identical to Phase 4, keeping them concise here] ...
|
// ... [CRUD Methods are identical to Phase 4, keeping them concise here] ...
|
||||||
func (p *PostgresStore) GetSites() []models.Site {
|
func (p *PostgresStore) GetSites() []models.Site {
|
||||||
rows, err := p.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries FROM sites")
|
rows, err := p.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries, COALESCE(hostname, ''), COALESCE(port, 0), COALESCE(timeout, 0), COALESCE(method, 'GET'), COALESCE(description, ''), COALESCE(parent_id, 0), COALESCE(accepted_codes, '200-299'), COALESCE(dns_resolve_type, ''), COALESCE(dns_server, ''), COALESCE(ignore_tls, FALSE) FROM sites")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []models.Site{}
|
return []models.Site{}
|
||||||
}
|
}
|
||||||
@@ -64,25 +91,30 @@ func (p *PostgresStore) GetSites() []models.Site {
|
|||||||
var sites []models.Site
|
var sites []models.Site
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var s models.Site
|
var s models.Site
|
||||||
rows.Scan(&s.ID, &s.Name, &s.URL, &s.Type, &s.Token, &s.Interval, &s.AlertID, &s.CheckSSL, &s.ExpiryThreshold, &s.MaxRetries)
|
rows.Scan(&s.ID, &s.Name, &s.URL, &s.Type, &s.Token, &s.Interval, &s.AlertID, &s.CheckSSL, &s.ExpiryThreshold, &s.MaxRetries,
|
||||||
|
&s.Hostname, &s.Port, &s.Timeout, &s.Method, &s.Description, &s.ParentID, &s.AcceptedCodes, &s.DNSResolveType, &s.DNSServer, &s.IgnoreTLS)
|
||||||
sites = append(sites, s)
|
sites = append(sites, s)
|
||||||
}
|
}
|
||||||
return sites
|
return sites
|
||||||
}
|
}
|
||||||
func (p *PostgresStore) AddSite(name, url, sType string, interval, alertID int, checkSSL bool, threshold, retries int) {
|
func (p *PostgresStore) AddSite(site models.Site) {
|
||||||
token := ""
|
token := ""
|
||||||
if sType == "push" {
|
if site.Type == "push" {
|
||||||
token = generateToken()
|
token = generateToken()
|
||||||
}
|
}
|
||||||
p.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", name, url, sType, token, interval, alertID, checkSSL, threshold, retries)
|
p.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)",
|
||||||
|
site.Name, site.URL, site.Type, token, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
|
||||||
|
site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS)
|
||||||
}
|
}
|
||||||
func (p *PostgresStore) UpdateSite(id int, name, url, sType string, interval, alertID int, checkSSL bool, threshold, retries int) {
|
func (p *PostgresStore) UpdateSite(site models.Site) {
|
||||||
var existingToken string
|
var existingToken string
|
||||||
p.db.QueryRow("SELECT token FROM sites WHERE id=$1", id).Scan(&existingToken)
|
p.db.QueryRow("SELECT token FROM sites WHERE id=$1", site.ID).Scan(&existingToken)
|
||||||
if sType == "push" && existingToken == "" {
|
if site.Type == "push" && existingToken == "" {
|
||||||
existingToken = generateToken()
|
existingToken = generateToken()
|
||||||
}
|
}
|
||||||
p.db.Exec("UPDATE sites SET name=$1, url=$2, type=$3, token=$4, interval=$5, alert_id=$6, check_ssl=$7, threshold=$8, max_retries=$9 WHERE id=$10", name, url, sType, existingToken, interval, alertID, checkSSL, threshold, retries, id)
|
p.db.Exec("UPDATE sites SET name=$1, url=$2, type=$3, token=$4, interval=$5, alert_id=$6, check_ssl=$7, threshold=$8, max_retries=$9, hostname=$10, port=$11, timeout=$12, method=$13, description=$14, parent_id=$15, accepted_codes=$16, dns_resolve_type=$17, dns_server=$18, ignore_tls=$19 WHERE id=$20",
|
||||||
|
site.Name, site.URL, site.Type, existingToken, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
|
||||||
|
site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.ID)
|
||||||
}
|
}
|
||||||
func (p *PostgresStore) DeleteSite(id int) { p.db.Exec("DELETE FROM sites WHERE id=$1", id) }
|
func (p *PostgresStore) DeleteSite(id int) { p.db.Exec("DELETE FROM sites WHERE id=$1", id) }
|
||||||
func (p *PostgresStore) GetAllAlerts() []models.AlertConfig {
|
func (p *PostgresStore) GetAllAlerts() []models.AlertConfig {
|
||||||
@@ -175,8 +207,9 @@ func (p *PostgresStore) ImportData(data models.Backup) error {
|
|||||||
tx.Exec("INSERT INTO alerts (id, name, type, settings) VALUES ($1, $2, $3, $4)", a.ID, a.Name, a.Type, string(jsonBytes))
|
tx.Exec("INSERT INTO alerts (id, name, type, settings) VALUES ($1, $2, $3, $4)", a.ID, a.Name, a.Type, string(jsonBytes))
|
||||||
}
|
}
|
||||||
for _, st := range data.Sites {
|
for _, st := range data.Sites {
|
||||||
tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)",
|
||||||
st.ID, st.Name, st.URL, st.Type, st.Token, st.Interval, st.AlertID, st.CheckSSL, st.ExpiryThreshold, st.MaxRetries)
|
st.ID, st.Name, st.URL, st.Type, st.Token, st.Interval, st.AlertID, st.CheckSSL, st.ExpiryThreshold, st.MaxRetries,
|
||||||
|
st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.Exec("SELECT setval('sites_id_seq', (SELECT MAX(id) FROM sites))")
|
tx.Exec("SELECT setval('sites_id_seq', (SELECT MAX(id) FROM sites))")
|
||||||
|
|||||||
+48
-13
@@ -39,7 +39,17 @@ func (s *SQLiteStore) Init() error {
|
|||||||
alert_id INTEGER,
|
alert_id INTEGER,
|
||||||
check_ssl BOOLEAN DEFAULT 0,
|
check_ssl BOOLEAN DEFAULT 0,
|
||||||
threshold INTEGER DEFAULT 7,
|
threshold INTEGER DEFAULT 7,
|
||||||
max_retries INTEGER DEFAULT 0
|
max_retries INTEGER DEFAULT 0,
|
||||||
|
hostname TEXT DEFAULT '',
|
||||||
|
port INTEGER DEFAULT 0,
|
||||||
|
timeout INTEGER DEFAULT 0,
|
||||||
|
method TEXT DEFAULT 'GET',
|
||||||
|
description TEXT DEFAULT '',
|
||||||
|
parent_id INTEGER DEFAULT 0,
|
||||||
|
accepted_codes TEXT DEFAULT '200-299',
|
||||||
|
dns_resolve_type TEXT DEFAULT '',
|
||||||
|
dns_server TEXT DEFAULT '',
|
||||||
|
ignore_tls BOOLEAN DEFAULT 0
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -48,7 +58,27 @@ func (s *SQLiteStore) Init() error {
|
|||||||
role TEXT DEFAULT 'user'
|
role TEXT DEFAULT 'user'
|
||||||
);`
|
);`
|
||||||
_, err = s.db.Exec(createTables)
|
_, err = s.db.Exec(createTables)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
migrations := []string{
|
||||||
|
"ALTER TABLE sites ADD COLUMN hostname TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN port INTEGER DEFAULT 0",
|
||||||
|
"ALTER TABLE sites ADD COLUMN timeout INTEGER DEFAULT 0",
|
||||||
|
"ALTER TABLE sites ADD COLUMN method TEXT DEFAULT 'GET'",
|
||||||
|
"ALTER TABLE sites ADD COLUMN description TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN parent_id INTEGER DEFAULT 0",
|
||||||
|
"ALTER TABLE sites ADD COLUMN accepted_codes TEXT DEFAULT '200-299'",
|
||||||
|
"ALTER TABLE sites ADD COLUMN dns_resolve_type TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN dns_server TEXT DEFAULT ''",
|
||||||
|
"ALTER TABLE sites ADD COLUMN ignore_tls BOOLEAN DEFAULT 0",
|
||||||
|
}
|
||||||
|
for _, m := range migrations {
|
||||||
|
s.db.Exec(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateToken() string {
|
func generateToken() string {
|
||||||
@@ -60,7 +90,7 @@ func generateToken() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLiteStore) GetSites() []models.Site {
|
func (s *SQLiteStore) GetSites() []models.Site {
|
||||||
rows, err := s.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries FROM sites")
|
rows, err := s.db.Query("SELECT id, COALESCE(name, url), url, COALESCE(type, 'http'), COALESCE(token, ''), interval, alert_id, check_ssl, threshold, max_retries, COALESCE(hostname, ''), COALESCE(port, 0), COALESCE(timeout, 0), COALESCE(method, 'GET'), COALESCE(description, ''), COALESCE(parent_id, 0), COALESCE(accepted_codes, '200-299'), COALESCE(dns_resolve_type, ''), COALESCE(dns_server, ''), COALESCE(ignore_tls, 0) FROM sites")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []models.Site{}
|
return []models.Site{}
|
||||||
}
|
}
|
||||||
@@ -68,25 +98,29 @@ func (s *SQLiteStore) GetSites() []models.Site {
|
|||||||
var sites []models.Site
|
var sites []models.Site
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var st models.Site
|
var st models.Site
|
||||||
rows.Scan(&st.ID, &st.Name, &st.URL, &st.Type, &st.Token, &st.Interval, &st.AlertID, &st.CheckSSL, &st.ExpiryThreshold, &st.MaxRetries)
|
rows.Scan(&st.ID, &st.Name, &st.URL, &st.Type, &st.Token, &st.Interval, &st.AlertID, &st.CheckSSL, &st.ExpiryThreshold, &st.MaxRetries, &st.Hostname, &st.Port, &st.Timeout, &st.Method, &st.Description, &st.ParentID, &st.AcceptedCodes, &st.DNSResolveType, &st.DNSServer, &st.IgnoreTLS)
|
||||||
sites = append(sites, st)
|
sites = append(sites, st)
|
||||||
}
|
}
|
||||||
return sites
|
return sites
|
||||||
}
|
}
|
||||||
func (s *SQLiteStore) AddSite(name, url, sType string, interval, alertID int, checkSSL bool, threshold, retries int) {
|
func (s *SQLiteStore) AddSite(site models.Site) {
|
||||||
token := ""
|
token := ""
|
||||||
if sType == "push" {
|
if site.Type == "push" {
|
||||||
token = generateToken()
|
token = generateToken()
|
||||||
}
|
}
|
||||||
s.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", name, url, sType, token, interval, alertID, checkSSL, threshold, retries)
|
s.db.Exec("INSERT INTO sites (name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
site.Name, site.URL, site.Type, token, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
|
||||||
|
site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS)
|
||||||
}
|
}
|
||||||
func (s *SQLiteStore) UpdateSite(id int, name, url, sType string, interval, alertID int, checkSSL bool, threshold, retries int) {
|
func (s *SQLiteStore) UpdateSite(site models.Site) {
|
||||||
var existingToken string
|
var existingToken string
|
||||||
s.db.QueryRow("SELECT token FROM sites WHERE id=?", id).Scan(&existingToken)
|
s.db.QueryRow("SELECT token FROM sites WHERE id=?", site.ID).Scan(&existingToken)
|
||||||
if sType == "push" && existingToken == "" {
|
if site.Type == "push" && existingToken == "" {
|
||||||
existingToken = generateToken()
|
existingToken = generateToken()
|
||||||
}
|
}
|
||||||
s.db.Exec("UPDATE sites SET name=?, url=?, type=?, token=?, interval=?, alert_id=?, check_ssl=?, threshold=?, max_retries=? WHERE id=?", name, url, sType, existingToken, interval, alertID, checkSSL, threshold, retries, id)
|
s.db.Exec("UPDATE sites SET name=?, url=?, type=?, token=?, interval=?, alert_id=?, check_ssl=?, threshold=?, max_retries=?, hostname=?, port=?, timeout=?, method=?, description=?, parent_id=?, accepted_codes=?, dns_resolve_type=?, dns_server=?, ignore_tls=? WHERE id=?",
|
||||||
|
site.Name, site.URL, site.Type, existingToken, site.Interval, site.AlertID, site.CheckSSL, site.ExpiryThreshold, site.MaxRetries,
|
||||||
|
site.Hostname, site.Port, site.Timeout, site.Method, site.Description, site.ParentID, site.AcceptedCodes, site.DNSResolveType, site.DNSServer, site.IgnoreTLS, site.ID)
|
||||||
}
|
}
|
||||||
func (s *SQLiteStore) DeleteSite(id int) {
|
func (s *SQLiteStore) DeleteSite(id int) {
|
||||||
s.db.Exec("DELETE FROM sites WHERE id=?", id)
|
s.db.Exec("DELETE FROM sites WHERE id=?", id)
|
||||||
@@ -198,8 +232,9 @@ func (s *SQLiteStore) ImportData(data models.Backup) error {
|
|||||||
tx.Exec("INSERT INTO alerts (id, name, type, settings) VALUES (?, ?, ?, ?)", a.ID, a.Name, a.Type, string(jsonBytes))
|
tx.Exec("INSERT INTO alerts (id, name, type, settings) VALUES (?, ?, ?, ?)", a.ID, a.Name, a.Type, string(jsonBytes))
|
||||||
}
|
}
|
||||||
for _, st := range data.Sites {
|
for _, st := range data.Sites {
|
||||||
tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
tx.Exec("INSERT INTO sites (id, name, url, type, token, interval, alert_id, check_ssl, threshold, max_retries, hostname, port, timeout, method, description, parent_id, accepted_codes, dns_resolve_type, dns_server, ignore_tls) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
st.ID, st.Name, st.URL, st.Type, st.Token, st.Interval, st.AlertID, st.CheckSSL, st.ExpiryThreshold, st.MaxRetries)
|
st.ID, st.Name, st.URL, st.Type, st.Token, st.Interval, st.AlertID, st.CheckSSL, st.ExpiryThreshold, st.MaxRetries,
|
||||||
|
st.Hostname, st.Port, st.Timeout, st.Method, st.Description, st.ParentID, st.AcceptedCodes, st.DNSResolveType, st.DNSServer, st.IgnoreTLS)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ type Store interface {
|
|||||||
|
|
||||||
// Sites
|
// Sites
|
||||||
GetSites() []models.Site
|
GetSites() []models.Site
|
||||||
AddSite(name, url, sType string, interval, alertID int, checkSSL bool, threshold, retries int)
|
AddSite(site models.Site)
|
||||||
UpdateSite(id int, name, url, sType string, interval, alertID int, checkSSL bool, threshold, retries int)
|
UpdateSite(site models.Site)
|
||||||
DeleteSite(id int)
|
DeleteSite(id int)
|
||||||
|
|
||||||
// Alerts
|
// Alerts
|
||||||
|
|||||||
+68
-14
@@ -35,18 +35,23 @@ var (
|
|||||||
siteBorderStyle = lipgloss.NewStyle().
|
siteBorderStyle = lipgloss.NewStyle().
|
||||||
Foreground(lipgloss.Color("#444"))
|
Foreground(lipgloss.Color("#444"))
|
||||||
|
|
||||||
siteColWidths = []int{4, 16, 8, 9, 8, 22, 10, 6}
|
siteColWidths = []int{4, 14, 6, 8, 9, 8, 20, 10, 6}
|
||||||
)
|
)
|
||||||
|
|
||||||
type siteFormData struct {
|
type siteFormData struct {
|
||||||
Name string
|
Name string
|
||||||
SiteType string
|
SiteType string
|
||||||
URL string
|
URL string
|
||||||
Interval string
|
Interval string
|
||||||
AlertID string
|
AlertID string
|
||||||
CheckSSL bool
|
CheckSSL bool
|
||||||
Threshold string
|
Threshold string
|
||||||
Retries string
|
Retries string
|
||||||
|
Hostname string
|
||||||
|
Port string
|
||||||
|
Timeout string
|
||||||
|
Description string
|
||||||
|
IgnoreTLS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func latencySparkline(latencies []time.Duration, width int) string {
|
func latencySparkline(latencies []time.Duration, width int) string {
|
||||||
@@ -229,7 +234,8 @@ func (m Model) viewSitesTab() string {
|
|||||||
|
|
||||||
rows = append(rows, []string{
|
rows = append(rows, []string{
|
||||||
strconv.Itoa(site.ID),
|
strconv.Itoa(site.ID),
|
||||||
m.zones.Mark(fmt.Sprintf("site-%d", i), limitStr(site.Name, 15)),
|
m.zones.Mark(fmt.Sprintf("site-%d", i), limitStr(site.Name, 13)),
|
||||||
|
site.Type,
|
||||||
fmtStatus(site.Status),
|
fmtStatus(site.Status),
|
||||||
fmtLatency(site.Latency),
|
fmtLatency(site.Latency),
|
||||||
fmtUptime(hist.TotalChecks, hist.UpChecks),
|
fmtUptime(hist.TotalChecks, hist.UpChecks),
|
||||||
@@ -242,7 +248,7 @@ func (m Model) viewSitesTab() string {
|
|||||||
t := table.New().
|
t := table.New().
|
||||||
Border(lipgloss.RoundedBorder()).
|
Border(lipgloss.RoundedBorder()).
|
||||||
BorderStyle(siteBorderStyle).
|
BorderStyle(siteBorderStyle).
|
||||||
Headers("ID", "NAME", "STATUS", "LATENCY", "UPTIME", "HISTORY", "SSL", "RETRY").
|
Headers("ID", "NAME", "TYPE", "STATUS", "LATENCY", "UPTIME", "HISTORY", "SSL", "RETRY").
|
||||||
Rows(rows...).
|
Rows(rows...).
|
||||||
StyleFunc(func(row, col int) lipgloss.Style {
|
StyleFunc(func(row, col int) lipgloss.Style {
|
||||||
if row == table.HeaderRow {
|
if row == table.HeaderRow {
|
||||||
@@ -271,6 +277,8 @@ func (m *Model) initSiteHuhForm() tea.Cmd {
|
|||||||
Interval: "60",
|
Interval: "60",
|
||||||
Threshold: "7",
|
Threshold: "7",
|
||||||
Retries: "0",
|
Retries: "0",
|
||||||
|
Timeout: "5",
|
||||||
|
Port: "0",
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.editID > 0 {
|
if m.editID > 0 {
|
||||||
@@ -284,6 +292,11 @@ func (m *Model) initSiteHuhForm() tea.Cmd {
|
|||||||
m.siteFormData.CheckSSL = site.CheckSSL
|
m.siteFormData.CheckSSL = site.CheckSSL
|
||||||
m.siteFormData.Threshold = strconv.Itoa(site.ExpiryThreshold)
|
m.siteFormData.Threshold = strconv.Itoa(site.ExpiryThreshold)
|
||||||
m.siteFormData.Retries = strconv.Itoa(site.MaxRetries)
|
m.siteFormData.Retries = strconv.Itoa(site.MaxRetries)
|
||||||
|
m.siteFormData.Hostname = site.Hostname
|
||||||
|
m.siteFormData.Port = strconv.Itoa(site.Port)
|
||||||
|
m.siteFormData.Timeout = strconv.Itoa(site.Timeout)
|
||||||
|
m.siteFormData.Description = site.Description
|
||||||
|
m.siteFormData.IgnoreTLS = site.IgnoreTLS
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,6 +327,10 @@ func (m *Model) initSiteHuhForm() tea.Cmd {
|
|||||||
Options(
|
Options(
|
||||||
huh.NewOption("HTTP/HTTPS", "http"),
|
huh.NewOption("HTTP/HTTPS", "http"),
|
||||||
huh.NewOption("Push / Heartbeat", "push"),
|
huh.NewOption("Push / Heartbeat", "push"),
|
||||||
|
huh.NewOption("Ping (ICMP)", "ping"),
|
||||||
|
huh.NewOption("TCP Port", "port"),
|
||||||
|
huh.NewOption("DNS", "dns"),
|
||||||
|
huh.NewOption("Group", "group"),
|
||||||
).Value(&m.siteFormData.SiteType),
|
).Value(&m.siteFormData.SiteType),
|
||||||
huh.NewInput().Title("URL").
|
huh.NewInput().Title("URL").
|
||||||
Placeholder("https://example.com").
|
Placeholder("https://example.com").
|
||||||
@@ -345,6 +362,22 @@ func (m *Model) initSiteHuhForm() tea.Cmd {
|
|||||||
Options(alertOpts...).
|
Options(alertOpts...).
|
||||||
Value(&m.siteFormData.AlertID),
|
Value(&m.siteFormData.AlertID),
|
||||||
).Title("Monitor Settings"),
|
).Title("Monitor Settings"),
|
||||||
|
huh.NewGroup(
|
||||||
|
huh.NewInput().Title("Hostname / IP").
|
||||||
|
Placeholder("10.0.0.1").
|
||||||
|
Description("Target for ping/port/DNS monitors").
|
||||||
|
Value(&m.siteFormData.Hostname),
|
||||||
|
huh.NewInput().Title("Port").
|
||||||
|
Placeholder("0").
|
||||||
|
Description("Target port for TCP port monitors").
|
||||||
|
Value(&m.siteFormData.Port),
|
||||||
|
huh.NewInput().Title("Timeout (seconds)").
|
||||||
|
Placeholder("5").
|
||||||
|
Value(&m.siteFormData.Timeout),
|
||||||
|
huh.NewInput().Title("Description").
|
||||||
|
Placeholder("Optional description").
|
||||||
|
Value(&m.siteFormData.Description),
|
||||||
|
).Title("Connection"),
|
||||||
huh.NewGroup(
|
huh.NewGroup(
|
||||||
huh.NewConfirm().Title("Monitor SSL Certificate?").
|
huh.NewConfirm().Title("Monitor SSL Certificate?").
|
||||||
Value(&m.siteFormData.CheckSSL),
|
Value(&m.siteFormData.CheckSSL),
|
||||||
@@ -354,6 +387,8 @@ func (m *Model) initSiteHuhForm() tea.Cmd {
|
|||||||
huh.NewInput().Title("Max Retries Before Alert").
|
huh.NewInput().Title("Max Retries Before Alert").
|
||||||
Placeholder("0").
|
Placeholder("0").
|
||||||
Value(&m.siteFormData.Retries),
|
Value(&m.siteFormData.Retries),
|
||||||
|
huh.NewConfirm().Title("Ignore TLS Errors?").
|
||||||
|
Value(&m.siteFormData.IgnoreTLS),
|
||||||
).Title("Advanced"),
|
).Title("Advanced"),
|
||||||
).WithTheme(huh.ThemeDracula())
|
).WithTheme(huh.ThemeDracula())
|
||||||
|
|
||||||
@@ -366,6 +401,8 @@ func (m *Model) submitSiteForm() {
|
|||||||
alertID, _ := strconv.Atoi(d.AlertID)
|
alertID, _ := strconv.Atoi(d.AlertID)
|
||||||
threshold, _ := strconv.Atoi(d.Threshold)
|
threshold, _ := strconv.Atoi(d.Threshold)
|
||||||
retries, _ := strconv.Atoi(d.Retries)
|
retries, _ := strconv.Atoi(d.Retries)
|
||||||
|
port, _ := strconv.Atoi(d.Port)
|
||||||
|
timeout, _ := strconv.Atoi(d.Timeout)
|
||||||
if interval < 1 {
|
if interval < 1 {
|
||||||
interval = 60
|
interval = 60
|
||||||
}
|
}
|
||||||
@@ -373,11 +410,28 @@ func (m *Model) submitSiteForm() {
|
|||||||
threshold = 7
|
threshold = 7
|
||||||
}
|
}
|
||||||
|
|
||||||
|
site := models.Site{
|
||||||
|
ID: m.editID,
|
||||||
|
Name: d.Name,
|
||||||
|
URL: d.URL,
|
||||||
|
Type: d.SiteType,
|
||||||
|
Interval: interval,
|
||||||
|
AlertID: alertID,
|
||||||
|
CheckSSL: d.CheckSSL,
|
||||||
|
ExpiryThreshold: threshold,
|
||||||
|
MaxRetries: retries,
|
||||||
|
Hostname: d.Hostname,
|
||||||
|
Port: port,
|
||||||
|
Timeout: timeout,
|
||||||
|
Description: d.Description,
|
||||||
|
IgnoreTLS: d.IgnoreTLS,
|
||||||
|
}
|
||||||
|
|
||||||
if m.editID > 0 {
|
if m.editID > 0 {
|
||||||
store.Get().UpdateSite(m.editID, d.Name, d.URL, d.SiteType, interval, alertID, d.CheckSSL, threshold, retries)
|
store.Get().UpdateSite(site)
|
||||||
monitor.UpdateSiteConfig(m.editID, d.Name, d.URL, d.SiteType, interval, alertID, d.CheckSSL, threshold, retries)
|
monitor.UpdateSiteConfig(site)
|
||||||
} else {
|
} else {
|
||||||
store.Get().AddSite(d.Name, d.URL, d.SiteType, interval, alertID, d.CheckSSL, threshold, retries)
|
store.Get().AddSite(site)
|
||||||
}
|
}
|
||||||
m.state = stateDashboard
|
m.state = stateDashboard
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user