Monorepo for Tangled tangled.org
6

Configure Feed

Select the types of activity you want to include in your feed.

1package db 2 3import ( 4 "database/sql" 5 "log/slog" 6 "strconv" 7 "time" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 "tangled.org/core/api/tangled" 11) 12 13type PublicKey struct { 14 Did syntax.DID 15 Rkey syntax.RecordKey 16 tangled.PublicKey 17} 18 19func (d *DB) UpsertPublicKey(pk PublicKey) error { 20 tx, err := d.db.Begin() 21 if err != nil { 22 return err 23 } 24 defer tx.Rollback() 25 26 if pk.Rkey != "" { 27 if _, err := tx.Exec(`delete from public_keys where did = ? and rkey = ?`, pk.Did, pk.Rkey); err != nil { 28 return err 29 } 30 } 31 32 if err := insertPublicKey(tx, d.logger, pk); err != nil { 33 return err 34 } 35 36 return tx.Commit() 37} 38 39func insertPublicKey(tx *sql.Tx, logger *slog.Logger, pk PublicKey) error { 40 if pk.Key == "" { 41 logger.Warn("skipping public key with empty key value", "did", pk.Did, "rkey", pk.Rkey) 42 return nil 43 } 44 45 if pk.CreatedAt == "" { 46 pk.CreatedAt = time.Now().Format(time.RFC3339) 47 } 48 49 res, err := tx.Exec( 50 `insert or ignore into public_keys (did, key, rkey, created) values (?, ?, ?, ?)`, 51 pk.Did, pk.Key, pk.Rkey, pk.CreatedAt, 52 ) 53 if err != nil { 54 return err 55 } 56 57 if rows, err := res.RowsAffected(); err == nil && rows == 0 { 58 logger.Warn("public key not stored, already registered to another did", "did", pk.Did, "rkey", pk.Rkey) 59 } 60 61 return nil 62} 63 64func (d *DB) DeletePublicKeyByRkey(did syntax.DID, rkey syntax.RecordKey) error { 65 if rkey == "" { 66 return nil 67 } 68 69 query := `delete from public_keys where did = ? and rkey = ?` 70 _, err := d.db.Exec(query, did, rkey) 71 return err 72} 73 74func (d *DB) ReplacePublicKeys(did syntax.DID, keys []PublicKey) error { 75 tx, err := d.db.Begin() 76 if err != nil { 77 return err 78 } 79 defer tx.Rollback() 80 81 if _, err := tx.Exec(`delete from public_keys where did = ?`, did); err != nil { 82 return err 83 } 84 85 if err := insertPublicKeys(tx, d.logger, keys); err != nil { 86 return err 87 } 88 89 return tx.Commit() 90} 91 92func insertPublicKeys(tx *sql.Tx, logger *slog.Logger, keys []PublicKey) error { 93 if len(keys) == 0 { 94 return nil 95 } 96 97 if err := insertPublicKey(tx, logger, keys[0]); err != nil { 98 return err 99 } 100 101 return insertPublicKeys(tx, logger, keys[1:]) 102} 103 104func (pk *PublicKey) JSON() map[string]any { 105 return map[string]any{ 106 "did": pk.Did, 107 "key": pk.Key, 108 "createdAt": pk.CreatedAt, 109 } 110} 111 112func (d *DB) GetAllPublicKeys() ([]PublicKey, error) { 113 var keys []PublicKey 114 115 rows, err := d.db.Query(`select key, did, created from public_keys`) 116 if err != nil { 117 return nil, err 118 } 119 defer rows.Close() 120 121 for rows.Next() { 122 var publicKey PublicKey 123 if err := rows.Scan(&publicKey.Key, &publicKey.Did, &publicKey.CreatedAt); err != nil { 124 return nil, err 125 } 126 keys = append(keys, publicKey) 127 } 128 129 if err := rows.Err(); err != nil { 130 return nil, err 131 } 132 133 return keys, nil 134} 135 136func (d *DB) GetPublicKeysPaginated(limit int, cursor string) ([]PublicKey, string, error) { 137 var keys []PublicKey 138 139 offset := 0 140 if cursor != "" { 141 if o, err := strconv.Atoi(cursor); err == nil && o >= 0 { 142 offset = o 143 } 144 } 145 146 query := `select key, did, created from public_keys order by created desc limit ? offset ?` 147 rows, err := d.db.Query(query, limit+1, offset) // +1 to check if there are more results 148 if err != nil { 149 return nil, "", err 150 } 151 defer rows.Close() 152 153 for rows.Next() { 154 var publicKey PublicKey 155 if err := rows.Scan(&publicKey.Key, &publicKey.Did, &publicKey.CreatedAt); err != nil { 156 return nil, "", err 157 } 158 keys = append(keys, publicKey) 159 } 160 161 if err := rows.Err(); err != nil { 162 return nil, "", err 163 } 164 165 // check if there are more results for pagination 166 var nextCursor string 167 if len(keys) > limit { 168 keys = keys[:limit] // remove the extra item 169 nextCursor = strconv.Itoa(offset + limit) 170 } 171 172 return keys, nextCursor, nil 173}