86 lines
2.3 KiB
Go
86 lines
2.3 KiB
Go
package db
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"crypto-miner-server/internal/models"
|
|
)
|
|
|
|
// AgentListFilter holds optional filters for paginated agent queries.
|
|
type AgentListFilter struct {
|
|
Limit int // 0 = no limit (return all matching rows)
|
|
Offset int
|
|
Status string // "online", "offline", or "" for any
|
|
Subnet string // e.g. "10.0.0.x" — matched against agents.ip prefix
|
|
}
|
|
|
|
// subnetToIPPrefix converts UI subnet labels to SQL LIKE patterns.
|
|
func subnetToIPPrefix(subnet string) string {
|
|
subnet = strings.TrimSpace(subnet)
|
|
if subnet == "" {
|
|
return ""
|
|
}
|
|
if strings.HasSuffix(subnet, ".x") {
|
|
return strings.TrimSuffix(subnet, ".x") + ".%"
|
|
}
|
|
if strings.HasSuffix(subnet, "%") {
|
|
return subnet
|
|
}
|
|
parts := strings.Split(subnet, ".")
|
|
if len(parts) >= 3 {
|
|
return fmt.Sprintf("%s.%s.%s.%%", parts[0], parts[1], parts[2])
|
|
}
|
|
return subnet + "%"
|
|
}
|
|
|
|
func (d *Database) agentListWhere(f AgentListFilter) (clause string, args []interface{}) {
|
|
var where []string
|
|
if f.Status != "" {
|
|
where = append(where, "status = ?")
|
|
args = append(args, f.Status)
|
|
}
|
|
if prefix := subnetToIPPrefix(f.Subnet); prefix != "" {
|
|
where = append(where, "ip LIKE ?")
|
|
args = append(args, prefix)
|
|
}
|
|
if len(where) == 0 {
|
|
return "", nil
|
|
}
|
|
return " WHERE " + strings.Join(where, " AND "), args
|
|
}
|
|
|
|
// ListAgentsFiltered returns agents matching optional status/subnet filters.
|
|
// When Limit > 0, results are paginated with Offset.
|
|
func (d *Database) ListAgentsFiltered(f AgentListFilter) ([]*models.Agent, error) {
|
|
where, args := d.agentListWhere(f)
|
|
query := `SELECT ` + agentSelectCols + ` FROM agents` + where + ` ORDER BY last_seen DESC`
|
|
if f.Limit > 0 {
|
|
query += ` LIMIT ? OFFSET ?`
|
|
args = append(args, f.Limit, f.Offset)
|
|
}
|
|
rows, err := d.Query(query, args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var agents []*models.Agent
|
|
for rows.Next() {
|
|
a, err := d.scanAgent(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
agents = append(agents, a)
|
|
}
|
|
return agents, rows.Err()
|
|
}
|
|
|
|
// CountAgentsFiltered returns the number of agents matching filter criteria (ignores Limit/Offset).
|
|
func (d *Database) CountAgentsFiltered(f AgentListFilter) (int, error) {
|
|
where, args := d.agentListWhere(f)
|
|
var n int
|
|
err := d.QueryRow(`SELECT COUNT(*) FROM agents`+where, args...).Scan(&n)
|
|
return n, err
|
|
}
|