backend for xcvr appview
1package oauth
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "github.com/bluesky-social/indigo/api/atproto"
8 "github.com/bluesky-social/indigo/atproto/client"
9 "github.com/bluesky-social/indigo/lex/util"
10 "os"
11 "rvcx/internal/lex"
12 "rvcx/internal/log"
13)
14
15type PasswordClient struct {
16 logger *log.Logger
17 xrpc *client.APIClient
18 accessjwt *string
19 refreshjwt *string
20 did *string
21}
22
23func NewPasswordClient(did string, host string, l *log.Logger) *PasswordClient {
24 return &PasswordClient{
25 xrpc: client.NewAPIClient(host),
26 did: &did,
27 logger: l,
28 }
29}
30
31func (c *PasswordClient) CreateSession(ctx context.Context) error {
32 c.logger.Deprintln("creating session...")
33 secret := os.Getenv("MY_SECRET")
34 identity := os.Getenv("MY_IDENTITY")
35 input := atproto.ServerCreateSession_Input{
36 Identifier: identity,
37 Password: secret,
38 }
39 var out atproto.ServerCreateSession_Output
40 err := c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.server.createSession", nil, input, &out)
41 if err != nil {
42 return errors.New("I couldn't create a session: " + err.Error())
43 }
44 c.accessjwt = &out.AccessJwt
45 c.refreshjwt = &out.RefreshJwt
46 c.logger.Deprintln("created session!")
47 return nil
48}
49
50func (c *PasswordClient) RefreshSession(ctx context.Context) error {
51 c.logger.Deprintln("refreshing session")
52 c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.refreshjwt))
53 var out atproto.ServerRefreshSession_Output
54 err := c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.server.refreshSession", nil, nil, &out)
55 if err != nil {
56 c.logger.Println("FAILED TO REFRESH RESSION")
57 return errors.New("failed to refresh session! " + err.Error())
58 }
59 c.accessjwt = &out.AccessJwt
60 c.refreshjwt = &out.RefreshJwt
61 c.logger.Deprintln("refreshed session!")
62 return nil
63}
64
65func (c *PasswordClient) CreateXCVRMessage(message *lex.MessageRecord, ctx context.Context) (cid string, uri string, err error) {
66 input := atproto.RepoCreateRecord_Input{
67 Collection: "org.xcvr.lrc.message",
68 Repo: *c.did,
69 Record: &util.LexiconTypeDecoder{Val: message},
70 }
71 return c.createMyRecord(input, ctx)
72}
73
74func (c *PasswordClient) CreateXCVRSignet(signet *lex.SignetRecord, ctx context.Context) (cid string, uri string, err error) {
75 input := atproto.RepoCreateRecord_Input{
76 Collection: "org.xcvr.lrc.signet",
77 Repo: *c.did,
78 Record: &util.LexiconTypeDecoder{Val: signet},
79 }
80 return c.createMyRecord(input, ctx)
81}
82
83func (c *PasswordClient) CreateXCVRChannel(channel *lex.ChannelRecord, ctx context.Context) (cid string, uri string, err error) {
84 input := atproto.RepoCreateRecord_Input{
85 Collection: "org.xcvr.feed.channel",
86 Repo: *c.did,
87 Record: &util.LexiconTypeDecoder{Val: channel},
88 }
89 return c.createMyRecord(input, ctx)
90}
91
92func (c *PasswordClient) createMyRecord(input atproto.RepoCreateRecord_Input, ctx context.Context) (cid string, uri string, err error) {
93 if c.accessjwt == nil {
94 err = errors.New("must create a session first")
95 return
96 }
97 c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.accessjwt))
98 var out atproto.RepoCreateRecord_Output
99 err = c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.repo.createRecord", nil, input, &out)
100 if err != nil {
101 err1 := err.Error()
102 err = c.RefreshSession(ctx)
103 if err != nil {
104 err = errors.New(fmt.Sprintf("failed to refresh session while creating %s! first %s then %s", input.Collection, err1, err.Error()))
105 return
106 }
107 c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.accessjwt))
108 out = atproto.RepoCreateRecord_Output{}
109 err = c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.repo.createRecord", nil, input, &out)
110 if err != nil {
111 err = errors.New(fmt.Sprintf("not good, failed to create %s after failing then refreshing session! first %s then %s", input.Collection, err1, err.Error()))
112 return
113 }
114 cid = out.Cid
115 uri = out.Uri
116 return
117 }
118 cid = out.Cid
119 uri = out.Uri
120 return
121}
122
123func (c *PasswordClient) DeleteXCVRSignet(rkey string, ctx context.Context) (bool, error) {
124 getOut, err := atproto.RepoGetRecord(ctx, c.xrpc, "", "org.xcvr.lrc.signet", *c.did, rkey)
125 if err != nil {
126 return true, errors.New("nothing to delete :3")
127 }
128 input := atproto.RepoDeleteRecord_Input{
129 Repo: *c.did,
130 Collection: "org.xcvr.lrc.signet",
131 Rkey: rkey,
132 SwapRecord: getOut.Cid,
133 }
134 err = c.deleteMyRecord(input, ctx)
135 if err != nil {
136 return false, errors.New("failed to delete")
137 }
138 return true, nil
139}
140
141func (c *PasswordClient) deleteMyRecord(input atproto.RepoDeleteRecord_Input, ctx context.Context) (err error) {
142 if c.accessjwt == nil {
143 err = errors.New("must create a session first")
144 return
145 }
146 c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.accessjwt))
147 var out atproto.RepoDeleteRecord_Output
148 err = c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.repo.deleteRecord", nil, input, &out)
149 if err != nil {
150 err1 := err.Error()
151 err = c.RefreshSession(ctx)
152 if err != nil {
153 err = errors.New(fmt.Sprintf("failed to refresh session while deleting %s! first %s then %s", input.Collection, err1, err.Error()))
154 return
155 }
156 c.xrpc.Headers.Set("Authorization", fmt.Sprintf("Bearer %s", *c.accessjwt))
157 err = c.xrpc.LexDo(ctx, "POST", "application/json", "com.atproto.repo.deleteRecord", nil, input, &out)
158 if err != nil {
159 err = errors.New(fmt.Sprintf("not good, failed to delete %s after failing then refreshing session! first %s then %s", input.Collection, err1, err.Error()))
160 return
161 }
162 }
163 return
164}