A vibe coded tangled fork which supports pijul.
at sl/knotmirror 102 lines 2.3 kB view raw
1package db 2 3import ( 4 "context" 5 "database/sql" 6 "errors" 7 "fmt" 8 "log" 9 10 "tangled.org/core/knotmirror/models" 11) 12 13func UpsertHost(ctx context.Context, e *sql.DB, host *models.Host) error { 14 if _, err := e.ExecContext(ctx, 15 `insert into hosts (hostname, no_ssl, status, last_seq) 16 values ($1, $2, $3, $4) 17 on conflict(hostname) do update set 18 no_ssl = excluded.no_ssl, 19 status = excluded.status, 20 last_seq = excluded.last_seq 21 `, 22 host.Hostname, 23 host.NoSSL, 24 host.Status, 25 host.LastSeq, 26 ); err != nil { 27 return fmt.Errorf("upserting host: %w", err) 28 } 29 return nil 30} 31 32func GetHost(ctx context.Context, e *sql.DB, hostname string) (*models.Host, error) { 33 var host models.Host 34 if err := e.QueryRowContext(ctx, 35 `select hostname, no_ssl, status, last_seq 36 from hosts where hostname = $1`, 37 hostname, 38 ).Scan( 39 &host.Hostname, 40 &host.NoSSL, 41 &host.Status, 42 &host.LastSeq, 43 ); err != nil { 44 if errors.Is(err, sql.ErrNoRows) { 45 return nil, nil 46 } 47 return nil, err 48 } 49 return &host, nil 50} 51 52func StoreCursors(ctx context.Context, e *sql.DB, cursors []models.HostCursor) error { 53 tx, err := e.BeginTx(ctx, nil) 54 if err != nil { 55 return fmt.Errorf("starting transaction: %w", err) 56 } 57 defer tx.Rollback() 58 for _, cur := range cursors { 59 if cur.LastSeq <= 0 { 60 continue 61 } 62 if _, err := tx.ExecContext(ctx, 63 `update hosts set last_seq = $1 where hostname = $2`, 64 cur.LastSeq, 65 cur.Hostname, 66 ); err != nil { 67 log.Println("failed to persist host cursor", "host", cur.Hostname, "lastSeq", cur.LastSeq, "err", err) 68 } 69 } 70 return tx.Commit() 71} 72 73func ListHosts(ctx context.Context, e *sql.DB, status models.HostStatus) ([]models.Host, error) { 74 rows, err := e.QueryContext(ctx, 75 `select hostname, no_ssl, status, last_seq 76 from hosts 77 where status = $1`, 78 status, 79 ) 80 if err != nil { 81 return nil, fmt.Errorf("querying hosts: %w", err) 82 } 83 defer rows.Close() 84 85 var hosts []models.Host 86 for rows.Next() { 87 var host models.Host 88 if err := rows.Scan( 89 &host.Hostname, 90 &host.NoSSL, 91 &host.Status, 92 &host.LastSeq, 93 ); err != nil { 94 return nil, fmt.Errorf("scanning row: %w", err) 95 } 96 hosts = append(hosts, host) 97 } 98 if err := rows.Err(); err != nil { 99 return nil, fmt.Errorf("scanning rows: %w ", err) 100 } 101 return hosts, nil 102}