An atproto PDS written in Go
at main 3.0 kB view raw
1package sqlite_blockstore 2 3import ( 4 "context" 5 "fmt" 6 7 "github.com/bluesky-social/indigo/atproto/syntax" 8 "github.com/haileyok/cocoon/internal/db" 9 "github.com/haileyok/cocoon/models" 10 blocks "github.com/ipfs/go-block-format" 11 "github.com/ipfs/go-cid" 12 "gorm.io/gorm/clause" 13) 14 15type SqliteBlockstore struct { 16 db *db.DB 17 did string 18 readonly bool 19 inserts map[cid.Cid]blocks.Block 20} 21 22func New(did string, db *db.DB) *SqliteBlockstore { 23 return &SqliteBlockstore{ 24 did: did, 25 db: db, 26 readonly: false, 27 inserts: map[cid.Cid]blocks.Block{}, 28 } 29} 30 31func NewReadOnly(did string, db *db.DB) *SqliteBlockstore { 32 return &SqliteBlockstore{ 33 did: did, 34 db: db, 35 readonly: true, 36 inserts: map[cid.Cid]blocks.Block{}, 37 } 38} 39 40func (bs *SqliteBlockstore) Get(ctx context.Context, cid cid.Cid) (blocks.Block, error) { 41 var block models.Block 42 43 maybeBlock, ok := bs.inserts[cid] 44 if ok { 45 return maybeBlock, nil 46 } 47 48 if err := bs.db.Raw("SELECT * FROM blocks WHERE did = ? AND cid = ?", nil, bs.did, cid.Bytes()).Scan(&block).Error; err != nil { 49 return nil, err 50 } 51 52 b, err := blocks.NewBlockWithCid(block.Value, cid) 53 if err != nil { 54 return nil, err 55 } 56 57 return b, nil 58} 59 60func (bs *SqliteBlockstore) Put(ctx context.Context, block blocks.Block) error { 61 bs.inserts[block.Cid()] = block 62 63 if bs.readonly { 64 return nil 65 } 66 67 b := models.Block{ 68 Did: bs.did, 69 Cid: block.Cid().Bytes(), 70 Rev: syntax.NewTIDNow(0).String(), // TODO: WARN, this is bad. don't do this 71 Value: block.RawData(), 72 } 73 74 if err := bs.db.Create(&b, []clause.Expression{clause.OnConflict{ 75 Columns: []clause.Column{{Name: "did"}, {Name: "cid"}}, 76 UpdateAll: true, 77 }}).Error; err != nil { 78 return err 79 } 80 81 return nil 82} 83 84func (bs *SqliteBlockstore) DeleteBlock(context.Context, cid.Cid) error { 85 panic("not implemented") 86} 87 88func (bs *SqliteBlockstore) Has(context.Context, cid.Cid) (bool, error) { 89 panic("not implemented") 90} 91 92func (bs *SqliteBlockstore) GetSize(context.Context, cid.Cid) (int, error) { 93 panic("not implemented") 94} 95 96func (bs *SqliteBlockstore) PutMany(ctx context.Context, blocks []blocks.Block) error { 97 tx := bs.db.BeginDangerously() 98 99 for _, block := range blocks { 100 bs.inserts[block.Cid()] = block 101 102 if bs.readonly { 103 continue 104 } 105 106 b := models.Block{ 107 Did: bs.did, 108 Cid: block.Cid().Bytes(), 109 Rev: syntax.NewTIDNow(0).String(), // TODO: WARN, this is bad. don't do this 110 Value: block.RawData(), 111 } 112 113 if err := tx.Clauses(clause.OnConflict{ 114 Columns: []clause.Column{{Name: "did"}, {Name: "cid"}}, 115 UpdateAll: true, 116 }).Create(&b).Error; err != nil { 117 tx.Rollback() 118 return err 119 } 120 } 121 122 if bs.readonly { 123 return nil 124 } 125 126 tx.Commit() 127 128 return nil 129} 130 131func (bs *SqliteBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { 132 return nil, fmt.Errorf("iteration not allowed on sqlite blockstore") 133} 134 135func (bs *SqliteBlockstore) HashOnRead(enabled bool) { 136 panic("not implemented") 137}