package models import ( "database/sql" "time" ) type Machine struct { ID int64 `db:"id" json:"id"` Name string `db:"name" json:"name"` Host string `db:"host" json:"host"` Port int `db:"port" json:"port"` SSHUser string `db:"ssh_user" json:"ssh_user"` SSHKeyID *int64 `db:"ssh_key_id" json:"ssh_key_id"` MACAddress *string `db:"mac_address" json:"mac_address"` WoLEnabled bool `db:"wol_enabled" json:"wol_enabled"` BroadcastAddr *string `db:"broadcast_addr" json:"broadcast_addr"` WakeTimeoutSeconds int `db:"wake_timeout_seconds" json:"wake_timeout_seconds"` WakeCheckIntervalSeconds int `db:"wake_check_interval_seconds" json:"wake_check_interval_seconds"` FingerprintConfirmed bool `db:"fingerprint_confirmed" json:"fingerprint_confirmed"` HostKeyFingerprint *string `db:"host_key_fingerprint" json:"host_key_fingerprint"` Status string `db:"status" json:"status"` LastSeenAt *time.Time `db:"last_seen_at" json:"last_seen_at"` CreatedAt time.Time `db:"created_at" json:"created_at"` ShutdownCommand string `db:"shutdown_command" json:"shutdown_command"` } type MachineRepository struct { db *sql.DB } func NewMachineRepository(db *sql.DB) *MachineRepository { return &MachineRepository{db: db} } func (r *MachineRepository) Create(m *Machine) (int64, error) { res, err := r.db.Exec(` INSERT INTO machines (name, host, port, ssh_user, ssh_key_id, mac_address, wol_enabled, broadcast_addr, wake_timeout_seconds, wake_check_interval_seconds, fingerprint_confirmed, host_key_fingerprint, status, shutdown_command) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, m.Name, m.Host, m.Port, m.SSHUser, m.SSHKeyID, m.MACAddress, boolToInt(m.WoLEnabled), m.BroadcastAddr, m.WakeTimeoutSeconds, m.WakeCheckIntervalSeconds, boolToInt(m.FingerprintConfirmed), m.HostKeyFingerprint, m.Status, m.ShutdownCommand, ) if err != nil { return 0, err } return res.LastInsertId() } func (r *MachineRepository) GetAll() ([]Machine, error) { rows, err := r.db.Query(` SELECT id, name, host, port, ssh_user, ssh_key_id, mac_address, wol_enabled, broadcast_addr, wake_timeout_seconds, wake_check_interval_seconds, fingerprint_confirmed, host_key_fingerprint, status, last_seen_at, created_at, shutdown_command FROM machines ORDER BY name`) if err != nil { return nil, err } defer rows.Close() var ms []Machine for rows.Next() { var m Machine var mac, bcast sql.NullString var keyID sql.NullInt64 var lastSeen sql.NullTime var hostKeyFP sql.NullString err := rows.Scan(&m.ID, &m.Name, &m.Host, &m.Port, &m.SSHUser, &keyID, &mac, &m.WoLEnabled, &bcast, &m.WakeTimeoutSeconds, &m.WakeCheckIntervalSeconds, &m.FingerprintConfirmed, &hostKeyFP, &m.Status, &lastSeen, &m.CreatedAt, &m.ShutdownCommand) if err != nil { return nil, err } if keyID.Valid { v := keyID.Int64 m.SSHKeyID = &v } if mac.Valid { m.MACAddress = &mac.String } if bcast.Valid { m.BroadcastAddr = &bcast.String } if hostKeyFP.Valid { m.HostKeyFingerprint = &hostKeyFP.String } if lastSeen.Valid { m.LastSeenAt = &lastSeen.Time } ms = append(ms, m) } return ms, rows.Err() } func (r *MachineRepository) GetByID(id int64) (*Machine, error) { var m Machine var mac, bcast sql.NullString var keyID sql.NullInt64 var lastSeen sql.NullTime var hostKeyFP sql.NullString err := r.db.QueryRow(` SELECT id, name, host, port, ssh_user, ssh_key_id, mac_address, wol_enabled, broadcast_addr, wake_timeout_seconds, wake_check_interval_seconds, fingerprint_confirmed, host_key_fingerprint, status, last_seen_at, created_at, shutdown_command FROM machines WHERE id = ?`, id).Scan( &m.ID, &m.Name, &m.Host, &m.Port, &m.SSHUser, &keyID, &mac, &m.WoLEnabled, &bcast, &m.WakeTimeoutSeconds, &m.WakeCheckIntervalSeconds, &m.FingerprintConfirmed, &hostKeyFP, &m.Status, &lastSeen, &m.CreatedAt, &m.ShutdownCommand) if err != nil { return nil, err } if keyID.Valid { v := keyID.Int64 m.SSHKeyID = &v } if mac.Valid { m.MACAddress = &mac.String } if bcast.Valid { m.BroadcastAddr = &bcast.String } if hostKeyFP.Valid { m.HostKeyFingerprint = &hostKeyFP.String } if lastSeen.Valid { m.LastSeenAt = &lastSeen.Time } return &m, nil } func (r *MachineRepository) Update(m *Machine) error { _, err := r.db.Exec(` UPDATE machines SET name=?, host=?, port=?, ssh_user=?, ssh_key_id=?, mac_address=?, wol_enabled=?, broadcast_addr=?, wake_timeout_seconds=?, wake_check_interval_seconds=?, fingerprint_confirmed=?, host_key_fingerprint=?, status=?, last_seen_at=?, shutdown_command=? WHERE id=?`, m.Name, m.Host, m.Port, m.SSHUser, m.SSHKeyID, m.MACAddress, boolToInt(m.WoLEnabled), m.BroadcastAddr, m.WakeTimeoutSeconds, m.WakeCheckIntervalSeconds, boolToInt(m.FingerprintConfirmed), m.HostKeyFingerprint, m.Status, m.LastSeenAt, m.ShutdownCommand, m.ID, ) return err } func (r *MachineRepository) Delete(id int64) error { _, err := r.db.Exec("DELETE FROM machines WHERE id = ?", id) return err } func (r *MachineRepository) UpdateFingerprint(id int64, confirmed bool, fingerprint string) error { _, err := r.db.Exec( "UPDATE machines SET fingerprint_confirmed = ?, host_key_fingerprint = ? WHERE id = ?", boolToInt(confirmed), fingerprint, id, ) return err } func (r *MachineRepository) UpdateStatus(id int64, status string) error { _, err := r.db.Exec( "UPDATE machines SET status = ?, last_seen_at = CURRENT_TIMESTAMP WHERE id = ?", status, id, ) return err } func boolToInt(b bool) int { if b { return 1 } return 0 } func intToBool(i int) bool { return i != 0 }