1package server
2
3import (
4 "bytes"
5 "context"
6 "io"
7 "slices"
8 "strings"
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"
16 "github.com/ipfs/go-cid"
17 "github.com/ipld/go-car"
18 "github.com/labstack/echo/v4"
19)
20
21func (s *Server) handleRepoImportRepo(e echo.Context) error {
22 urepo := e.Get("repo").(*models.RepoActor)
23
24 b, err := io.ReadAll(e.Request().Body)
25 if err != nil {
26 s.logger.Error("could not read bytes in import request", "error", err)
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 {
34 s.logger.Error("could not read car in import request", "error", err)
35 return helpers.ServerError(e, nil)
36 }
37
38 orderedBlocks := []blocks.Block{}
39 currBlock, err := cs.Next()
40 if err != nil {
41 s.logger.Error("could not get first block from car", "error", err)
42 return helpers.ServerError(e, nil)
43 }
44 currBlockCt := 1
45
46 for currBlock != nil {
47 s.logger.Info("someone is importing their repo", "block", currBlockCt)
48 orderedBlocks = append(orderedBlocks, currBlock)
49 next, _ := cs.Next()
50 currBlock = next
51 currBlockCt++
52 }
53
54 slices.Reverse(orderedBlocks)
55
56 if err := bs.PutMany(context.TODO(), orderedBlocks); err != nil {
57 s.logger.Error("could not insert blocks", "error", err)
58 return helpers.ServerError(e, nil)
59 }
60
61 r, err := repo.OpenRepo(context.TODO(), bs, cs.Header.Roots[0])
62 if err != nil {
63 s.logger.Error("could not open repo", "error", err)
64 return helpers.ServerError(e, nil)
65 }
66
67 tx := s.db.Begin()
68
69 clock := syntax.NewTIDClock(0)
70
71 if err := r.ForEach(context.TODO(), "", func(key string, cid cid.Cid) error {
72 pts := strings.Split(key, "/")
73 nsid := pts[0]
74 rkey := pts[1]
75 cidStr := cid.String()
76 b, err := bs.Get(context.TODO(), cid)
77 if err != nil {
78 s.logger.Error("record bytes don't exist in blockstore", "error", err)
79 return helpers.ServerError(e, nil)
80 }
81
82 rec := models.Record{
83 Did: urepo.Repo.Did,
84 CreatedAt: clock.Next().String(),
85 Nsid: nsid,
86 Rkey: rkey,
87 Cid: cidStr,
88 Value: b.RawData(),
89 }
90
91 if err := tx.Create(rec).Error; err != nil {
92 return err
93 }
94
95 return nil
96 }); err != nil {
97 tx.Rollback()
98 s.logger.Error("record bytes don't exist in blockstore", "error", err)
99 return helpers.ServerError(e, nil)
100 }
101
102 tx.Commit()
103
104 root, rev, err := r.Commit(context.TODO(), urepo.SignFor)
105 if err != nil {
106 s.logger.Error("error committing", "error", err)
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 }
114
115 return nil
116}