+1
-9
blockstore/blockstore.go
sqlite_blockstore/sqlite_blockstore.go
+1
-9
blockstore/blockstore.go
sqlite_blockstore/sqlite_blockstore.go
···
1
-
package blockstore
2
3
import (
4
"context"
···
134
135
func (bs *SqliteBlockstore) HashOnRead(enabled bool) {
136
panic("not implemented")
137
-
}
138
-
139
-
func (bs *SqliteBlockstore) UpdateRepo(ctx context.Context, root cid.Cid, rev string) error {
140
-
if err := bs.db.Exec("UPDATE repos SET root = ?, rev = ? WHERE did = ?", nil, root.Bytes(), rev, bs.did).Error; err != nil {
141
-
return err
142
-
}
143
-
144
-
return nil
145
}
146
147
func (bs *SqliteBlockstore) Execute(ctx context.Context) error {
+7
cmd/cocoon/main.go
+7
cmd/cocoon/main.go
···
136
EnvVars: []string{"COCOON_DEFAULT_ATPROTO_PROXY"},
137
Value: "did:web:api.bsky.app#bsky_appview",
138
},
139
},
140
Commands: []*cli.Command{
141
runServe,
···
158
Usage: "Start the cocoon PDS",
159
Flags: []cli.Flag{},
160
Action: func(cmd *cli.Context) error {
161
s, err := server.New(&server.Args{
162
Addr: cmd.String("addr"),
163
DbName: cmd.String("db-name"),
···
185
},
186
SessionSecret: cmd.String("session-secret"),
187
DefaultAtprotoProxy: cmd.String("default-atproto-proxy"),
188
})
189
if err != nil {
190
fmt.Printf("error creating cocoon: %v", err)
···
136
EnvVars: []string{"COCOON_DEFAULT_ATPROTO_PROXY"},
137
Value: "did:web:api.bsky.app#bsky_appview",
138
},
139
+
&cli.StringFlag{
140
+
Name: "blockstore-variant",
141
+
EnvVars: []string{"COCOON_BLOCKSTORE_VARIANT"},
142
+
Value: "sqlite",
143
+
},
144
},
145
Commands: []*cli.Command{
146
runServe,
···
163
Usage: "Start the cocoon PDS",
164
Flags: []cli.Flag{},
165
Action: func(cmd *cli.Context) error {
166
+
167
s, err := server.New(&server.Args{
168
Addr: cmd.String("addr"),
169
DbName: cmd.String("db-name"),
···
191
},
192
SessionSecret: cmd.String("session-secret"),
193
DefaultAtprotoProxy: cmd.String("default-atproto-proxy"),
194
+
BlockstoreVariant: server.MustReturnBlockstoreVariant(cmd.String("blockstore-variant")),
195
})
196
if err != nil {
197
fmt.Printf("error creating cocoon: %v", err)
+77
recording_blockstore/recording_blockstore.go
+77
recording_blockstore/recording_blockstore.go
···
···
1
+
package recording_blockstore
2
+
3
+
import (
4
+
"context"
5
+
6
+
blockformat "github.com/ipfs/go-block-format"
7
+
"github.com/ipfs/go-cid"
8
+
blockstore "github.com/ipfs/go-ipfs-blockstore"
9
+
)
10
+
11
+
type RecordingBlockstore struct {
12
+
base blockstore.Blockstore
13
+
14
+
inserts map[cid.Cid]blockformat.Block
15
+
}
16
+
17
+
func New(base blockstore.Blockstore) *RecordingBlockstore {
18
+
return &RecordingBlockstore{
19
+
base: base,
20
+
inserts: make(map[cid.Cid]blockformat.Block),
21
+
}
22
+
}
23
+
24
+
func (bs *RecordingBlockstore) Has(ctx context.Context, c cid.Cid) (bool, error) {
25
+
return bs.base.Has(ctx, c)
26
+
}
27
+
28
+
func (bs *RecordingBlockstore) Get(ctx context.Context, c cid.Cid) (blockformat.Block, error) {
29
+
return bs.base.Get(ctx, c)
30
+
}
31
+
32
+
func (bs *RecordingBlockstore) GetSize(ctx context.Context, c cid.Cid) (int, error) {
33
+
return bs.base.GetSize(ctx, c)
34
+
}
35
+
36
+
func (bs *RecordingBlockstore) DeleteBlock(ctx context.Context, c cid.Cid) error {
37
+
return bs.base.DeleteBlock(ctx, c)
38
+
}
39
+
40
+
func (bs *RecordingBlockstore) Put(ctx context.Context, block blockformat.Block) error {
41
+
if err := bs.base.Put(ctx, block); err != nil {
42
+
return err
43
+
}
44
+
bs.inserts[block.Cid()] = block
45
+
return nil
46
+
}
47
+
48
+
func (bs *RecordingBlockstore) PutMany(ctx context.Context, blocks []blockformat.Block) error {
49
+
if err := bs.base.PutMany(ctx, blocks); err != nil {
50
+
return err
51
+
}
52
+
53
+
for _, b := range blocks {
54
+
bs.inserts[b.Cid()] = b
55
+
}
56
+
57
+
return nil
58
+
}
59
+
60
+
func (bs *RecordingBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
61
+
return bs.AllKeysChan(ctx)
62
+
}
63
+
64
+
func (bs *RecordingBlockstore) HashOnRead(enabled bool) {
65
+
}
66
+
67
+
func (bs *RecordingBlockstore) GetLogMap() map[cid.Cid]blockformat.Block {
68
+
return bs.inserts
69
+
}
70
+
71
+
func (bs *RecordingBlockstore) GetLogArray() []blockformat.Block {
72
+
var blocks []blockformat.Block
73
+
for _, b := range bs.inserts {
74
+
blocks = append(blocks, b)
75
+
}
76
+
return blocks
77
+
}
+30
server/blockstore_variant.go
+30
server/blockstore_variant.go
···
···
1
+
package server
2
+
3
+
import (
4
+
"github.com/haileyok/cocoon/sqlite_blockstore"
5
+
blockstore "github.com/ipfs/go-ipfs-blockstore"
6
+
)
7
+
8
+
type BlockstoreVariant int
9
+
10
+
const (
11
+
BlockstoreVariantSqlite = iota
12
+
)
13
+
14
+
func MustReturnBlockstoreVariant(maybeBsv string) BlockstoreVariant {
15
+
switch maybeBsv {
16
+
case "sqlite":
17
+
return BlockstoreVariantSqlite
18
+
default:
19
+
panic("invalid blockstore variant provided")
20
+
}
21
+
}
22
+
23
+
func (s *Server) getBlockstore(did string) blockstore.Blockstore {
24
+
switch s.config.BlockstoreVariant {
25
+
case BlockstoreVariantSqlite:
26
+
return sqlite_blockstore.New(did, s.db)
27
+
default:
28
+
return sqlite_blockstore.New(did, s.db)
29
+
}
30
+
}
+2
-3
server/handle_import_repo.go
+2
-3
server/handle_import_repo.go
···
9
10
"github.com/bluesky-social/indigo/atproto/syntax"
11
"github.com/bluesky-social/indigo/repo"
12
-
"github.com/haileyok/cocoon/blockstore"
13
"github.com/haileyok/cocoon/internal/helpers"
14
"github.com/haileyok/cocoon/models"
15
blocks "github.com/ipfs/go-block-format"
···
27
return helpers.ServerError(e, nil)
28
}
29
30
-
bs := blockstore.New(urepo.Repo.Did, s.db)
31
32
cs, err := car.NewCarReader(bytes.NewReader(b))
33
if err != nil {
···
107
return helpers.ServerError(e, nil)
108
}
109
110
-
if err := bs.UpdateRepo(context.TODO(), root, rev); err != nil {
111
s.logger.Error("error updating repo after commit", "error", err)
112
return helpers.ServerError(e, nil)
113
}
···
9
10
"github.com/bluesky-social/indigo/atproto/syntax"
11
"github.com/bluesky-social/indigo/repo"
12
"github.com/haileyok/cocoon/internal/helpers"
13
"github.com/haileyok/cocoon/models"
14
blocks "github.com/ipfs/go-block-format"
···
26
return helpers.ServerError(e, nil)
27
}
28
29
+
bs := s.getBlockstore(urepo.Repo.Did)
30
31
cs, err := car.NewCarReader(bytes.NewReader(b))
32
if err != nil {
···
106
return helpers.ServerError(e, nil)
107
}
108
109
+
if err := s.UpdateRepo(context.TODO(), urepo.Repo.Did, root, rev); err != nil {
110
s.logger.Error("error updating repo after commit", "error", err)
111
return helpers.ServerError(e, nil)
112
}
+2
-3
server/handle_server_create_account.go
+2
-3
server/handle_server_create_account.go
···
14
"github.com/bluesky-social/indigo/events"
15
"github.com/bluesky-social/indigo/repo"
16
"github.com/bluesky-social/indigo/util"
17
-
"github.com/haileyok/cocoon/blockstore"
18
"github.com/haileyok/cocoon/internal/helpers"
19
"github.com/haileyok/cocoon/models"
20
"github.com/labstack/echo/v4"
···
177
}
178
179
if customDidHeader == "" {
180
-
bs := blockstore.New(signupDid, s.db)
181
r := repo.NewRepo(context.TODO(), signupDid, bs)
182
183
root, rev, err := r.Commit(context.TODO(), urepo.SignFor)
···
186
return helpers.ServerError(e, nil)
187
}
188
189
-
if err := bs.UpdateRepo(context.TODO(), root, rev); err != nil {
190
s.logger.Error("error updating repo after commit", "error", err)
191
return helpers.ServerError(e, nil)
192
}
···
14
"github.com/bluesky-social/indigo/events"
15
"github.com/bluesky-social/indigo/repo"
16
"github.com/bluesky-social/indigo/util"
17
"github.com/haileyok/cocoon/internal/helpers"
18
"github.com/haileyok/cocoon/models"
19
"github.com/labstack/echo/v4"
···
176
}
177
178
if customDidHeader == "" {
179
+
bs := s.getBlockstore(signupDid)
180
r := repo.NewRepo(context.TODO(), signupDid, bs)
181
182
root, rev, err := r.Commit(context.TODO(), urepo.SignFor)
···
185
return helpers.ServerError(e, nil)
186
}
187
188
+
if err := s.UpdateRepo(context.TODO(), urepo.Did, root, rev); err != nil {
189
s.logger.Error("error updating repo after commit", "error", err)
190
return helpers.ServerError(e, nil)
191
}
+1
-2
server/handle_sync_get_blocks.go
+1
-2
server/handle_sync_get_blocks.go
···
6
"strings"
7
8
"github.com/bluesky-social/indigo/carstore"
9
-
"github.com/haileyok/cocoon/blockstore"
10
"github.com/haileyok/cocoon/internal/helpers"
11
"github.com/ipfs/go-cid"
12
cbor "github.com/ipfs/go-ipld-cbor"
···
54
return helpers.ServerError(e, nil)
55
}
56
57
-
bs := blockstore.New(urepo.Repo.Did, s.db)
58
59
for _, c := range cids {
60
b, err := bs.Get(context.TODO(), c)
···
6
"strings"
7
8
"github.com/bluesky-social/indigo/carstore"
9
"github.com/haileyok/cocoon/internal/helpers"
10
"github.com/ipfs/go-cid"
11
cbor "github.com/ipfs/go-ipld-cbor"
···
53
return helpers.ServerError(e, nil)
54
}
55
56
+
bs := s.getBlockstore(urepo.Repo.Did)
57
58
for _, c := range cids {
59
b, err := bs.Get(context.TODO(), c)
+12
-12
server/repo.go
+12
-12
server/repo.go
···
16
"github.com/bluesky-social/indigo/events"
17
lexutil "github.com/bluesky-social/indigo/lex/util"
18
"github.com/bluesky-social/indigo/repo"
19
-
"github.com/bluesky-social/indigo/util"
20
-
"github.com/haileyok/cocoon/blockstore"
21
"github.com/haileyok/cocoon/internal/db"
22
"github.com/haileyok/cocoon/models"
23
blocks "github.com/ipfs/go-block-format"
24
"github.com/ipfs/go-cid"
25
cbor "github.com/ipfs/go-ipld-cbor"
···
103
return nil, err
104
}
105
106
-
dbs := blockstore.New(urepo.Did, rm.db)
107
r, err := repo.OpenRepo(context.TODO(), dbs, rootcid)
108
109
entries := []models.Record{}
···
274
}
275
}
276
277
-
for _, op := range dbs.GetLog() {
278
if _, err := carstore.LdWrite(buf, op.Cid().Bytes(), op.RawData()); err != nil {
279
return nil, err
280
}
···
324
},
325
})
326
327
-
if err := dbs.UpdateRepo(context.TODO(), newroot, rev); err != nil {
328
return nil, err
329
}
330
···
345
return cid.Undef, nil, err
346
}
347
348
-
dbs := blockstore.New(urepo.Did, rm.db)
349
-
bs := util.NewLoggingBstore(dbs)
350
351
r, err := repo.OpenRepo(context.TODO(), bs, c)
352
if err != nil {
···
358
return cid.Undef, nil, err
359
}
360
361
-
return c, bs.GetLoggedBlocks(), nil
362
}
363
364
func (rm *RepoMan) incrementBlobRefs(urepo models.Repo, cbor []byte) ([]cid.Cid, error) {
···
414
return nil, fmt.Errorf("error unmarshaling cbor: %w", err)
415
}
416
417
-
var deepiter func(interface{}) error
418
-
deepiter = func(item interface{}) error {
419
switch val := item.(type) {
420
-
case map[string]interface{}:
421
if val["$type"] == "blob" {
422
if ref, ok := val["ref"].(string); ok {
423
c, err := cid.Parse(ref)
···
430
return deepiter(v)
431
}
432
}
433
-
case []interface{}:
434
for _, v := range val {
435
deepiter(v)
436
}
···
16
"github.com/bluesky-social/indigo/events"
17
lexutil "github.com/bluesky-social/indigo/lex/util"
18
"github.com/bluesky-social/indigo/repo"
19
"github.com/haileyok/cocoon/internal/db"
20
"github.com/haileyok/cocoon/models"
21
+
"github.com/haileyok/cocoon/recording_blockstore"
22
blocks "github.com/ipfs/go-block-format"
23
"github.com/ipfs/go-cid"
24
cbor "github.com/ipfs/go-ipld-cbor"
···
102
return nil, err
103
}
104
105
+
dbs := rm.s.getBlockstore(urepo.Did)
106
+
bs := recording_blockstore.New(dbs)
107
r, err := repo.OpenRepo(context.TODO(), dbs, rootcid)
108
109
entries := []models.Record{}
···
274
}
275
}
276
277
+
for _, op := range bs.GetLogMap() {
278
if _, err := carstore.LdWrite(buf, op.Cid().Bytes(), op.RawData()); err != nil {
279
return nil, err
280
}
···
324
},
325
})
326
327
+
if err := rm.s.UpdateRepo(context.TODO(), urepo.Did, newroot, rev); err != nil {
328
return nil, err
329
}
330
···
345
return cid.Undef, nil, err
346
}
347
348
+
dbs := rm.s.getBlockstore(urepo.Did)
349
+
bs := recording_blockstore.New(dbs)
350
351
r, err := repo.OpenRepo(context.TODO(), bs, c)
352
if err != nil {
···
358
return cid.Undef, nil, err
359
}
360
361
+
return c, bs.GetLogArray(), nil
362
}
363
364
func (rm *RepoMan) incrementBlobRefs(urepo models.Repo, cbor []byte) ([]cid.Cid, error) {
···
414
return nil, fmt.Errorf("error unmarshaling cbor: %w", err)
415
}
416
417
+
var deepiter func(any) error
418
+
deepiter = func(item any) error {
419
switch val := item.(type) {
420
+
case map[string]any:
421
if val["$type"] == "blob" {
422
if ref, ok := val["ref"].(string); ok {
423
c, err := cid.Parse(ref)
···
430
return deepiter(v)
431
}
432
}
433
+
case []any:
434
for _, v := range val {
435
deepiter(v)
436
}
+13
server/server.go
+13
server/server.go
···
38
"github.com/haileyok/cocoon/oauth/dpop"
39
"github.com/haileyok/cocoon/oauth/provider"
40
"github.com/haileyok/cocoon/plc"
41
echo_session "github.com/labstack/echo-contrib/session"
42
"github.com/labstack/echo/v4"
43
"github.com/labstack/echo/v4/middleware"
···
104
SessionSecret string
105
106
DefaultAtprotoProxy string
107
}
108
109
type config struct {
···
117
SmtpEmail string
118
SmtpName string
119
DefaultAtprotoProxy string
120
}
121
122
type CustomValidator struct {
···
349
SmtpName: args.SmtpName,
350
SmtpEmail: args.SmtpEmail,
351
DefaultAtprotoProxy: args.DefaultAtprotoProxy,
352
},
353
evtman: events.NewEventManager(events.NewMemPersister()),
354
passport: identity.NewPassport(h, identity.NewMemCache(10_000)),
···
641
go s.doBackup()
642
}
643
}
···
38
"github.com/haileyok/cocoon/oauth/dpop"
39
"github.com/haileyok/cocoon/oauth/provider"
40
"github.com/haileyok/cocoon/plc"
41
+
"github.com/ipfs/go-cid"
42
echo_session "github.com/labstack/echo-contrib/session"
43
"github.com/labstack/echo/v4"
44
"github.com/labstack/echo/v4/middleware"
···
105
SessionSecret string
106
107
DefaultAtprotoProxy string
108
+
109
+
BlockstoreVariant BlockstoreVariant
110
}
111
112
type config struct {
···
120
SmtpEmail string
121
SmtpName string
122
DefaultAtprotoProxy string
123
+
BlockstoreVariant BlockstoreVariant
124
}
125
126
type CustomValidator struct {
···
353
SmtpName: args.SmtpName,
354
SmtpEmail: args.SmtpEmail,
355
DefaultAtprotoProxy: args.DefaultAtprotoProxy,
356
+
BlockstoreVariant: args.BlockstoreVariant,
357
},
358
evtman: events.NewEventManager(events.NewMemPersister()),
359
passport: identity.NewPassport(h, identity.NewMemCache(10_000)),
···
646
go s.doBackup()
647
}
648
}
649
+
650
+
func (s *Server) UpdateRepo(ctx context.Context, did string, root cid.Cid, rev string) error {
651
+
if err := s.db.Exec("UPDATE repos SET root = ?, rev = ? WHERE did = ?", nil, root.Bytes(), rev, did).Error; err != nil {
652
+
return err
653
+
}
654
+
655
+
return nil
656
+
}