1package main
2
3import (
4 "context"
5 "fmt"
6 "os"
7
8 comatproto "github.com/bluesky-social/indigo/api/atproto"
9 "github.com/bluesky-social/indigo/atproto/identity"
10 "github.com/bluesky-social/indigo/atproto/syntax"
11 "github.com/bluesky-social/indigo/util/cliutil"
12
13 cli "github.com/urfave/cli/v2"
14)
15
16var syncCmd = &cli.Command{
17 Name: "sync",
18 Usage: "sub-commands for repo sync endpoints",
19 Subcommands: []*cli.Command{
20 syncGetRepoCmd,
21 syncGetRootCmd,
22 syncListReposCmd,
23 },
24}
25
26var syncGetRepoCmd = &cli.Command{
27 Name: "get-repo",
28 Usage: "download repo from account's PDS to local file (or '-' for stdout). for hex combine with 'xxd -ps -u -c 0'",
29 ArgsUsage: `<at-identifier> [<car-file-path>]`,
30 Flags: []cli.Flag{
31 &cli.StringFlag{
32 Name: "host",
33 },
34 },
35 Action: func(cctx *cli.Context) error {
36 ctx := context.Background()
37 arg := cctx.Args().First()
38 if arg == "" {
39 return fmt.Errorf("at-identifier arg is required")
40 }
41 atid, err := syntax.ParseAtIdentifier(arg)
42 if err != nil {
43 return err
44 }
45 dir := identity.DefaultDirectory()
46 ident, err := dir.Lookup(ctx, *atid)
47 if err != nil {
48 return err
49 }
50
51 carPath := cctx.Args().Get(1)
52 if carPath == "" {
53 carPath = ident.DID.String() + ".car"
54 }
55
56 xrpcc, err := cliutil.GetXrpcClient(cctx, false)
57 if err != nil {
58 return err
59 }
60 xrpcc.Host = ident.PDSEndpoint()
61 if xrpcc.Host == "" {
62 return fmt.Errorf("no PDS endpoint for identity")
63 }
64
65 if h := cctx.String("host"); h != "" {
66 xrpcc.Host = h
67 }
68
69 log.Info("downloading", "from", xrpcc.Host, "to", carPath)
70 repoBytes, err := comatproto.SyncGetRepo(ctx, xrpcc, ident.DID.String(), "")
71 if err != nil {
72 return err
73 }
74
75 if carPath == "-" {
76 _, err = os.Stdout.Write(repoBytes)
77 return err
78 } else {
79 return os.WriteFile(carPath, repoBytes, 0666)
80 }
81 },
82}
83
84var syncGetRootCmd = &cli.Command{
85 Name: "get-root",
86 ArgsUsage: `<did>`,
87 Action: func(cctx *cli.Context) error {
88 xrpcc, err := cliutil.GetXrpcClient(cctx, false)
89 if err != nil {
90 return err
91 }
92
93 ctx := context.TODO()
94
95 atid, err := syntax.ParseAtIdentifier(cctx.Args().First())
96 if err != nil {
97 return err
98 }
99
100 dir := identity.DefaultDirectory()
101 ident, err := dir.Lookup(ctx, *atid)
102 if err != nil {
103 return err
104 }
105
106 carPath := cctx.Args().Get(1)
107 if carPath == "" {
108 carPath = ident.DID.String() + ".car"
109 }
110
111 xrpcc.Host = ident.PDSEndpoint()
112 if xrpcc.Host == "" {
113 return fmt.Errorf("no PDS endpoint for identity")
114 }
115
116 root, err := comatproto.SyncGetHead(ctx, xrpcc, cctx.Args().First())
117 if err != nil {
118 return err
119 }
120
121 fmt.Println(root.Root)
122
123 return nil
124 },
125}
126
127var syncListReposCmd = &cli.Command{
128 Name: "list-repos",
129 Action: func(cctx *cli.Context) error {
130 xrpcc, err := cliutil.GetXrpcClient(cctx, false)
131 if err != nil {
132 return err
133 }
134
135 var curs string
136 for {
137 out, err := comatproto.SyncListRepos(context.TODO(), xrpcc, curs, 1000)
138 if err != nil {
139 return err
140 }
141
142 if len(out.Repos) == 0 {
143 break
144 }
145
146 for _, r := range out.Repos {
147 fmt.Println(r.Did)
148 }
149
150 if out.Cursor == nil {
151 break
152 }
153
154 curs = *out.Cursor
155 }
156
157 return nil
158 },
159}