@@ -2,8 +2,10 @@ package bluesky
2
2
3
3
import (
4
4
"context"
5
+ "errors"
5
6
"fmt"
6
7
"log/slog"
8
+ "net"
7
9
"strings"
8
10
"time"
9
11
@@ -128,7 +130,7 @@ func (c *Client) Post(ctx context.Context, post *bsky.FeedPost) error {
128
130
return c .Client .CustomCall (func (api * xrpc.Client ) error {
129
131
sessionResult , err := atproto .ServerGetSession (ctx , api )
130
132
if err != nil {
131
- return err
133
+ return handleError ( ctx , err )
132
134
}
133
135
134
136
_ , err = atproto .RepoCreateRecord (ctx , api , & atproto.RepoCreateRecord_Input {
@@ -139,6 +141,49 @@ func (c *Client) Post(ctx context.Context, post *bsky.FeedPost) error {
139
141
},
140
142
})
141
143
142
- return err
144
+ return handleError ( ctx , err )
143
145
})
144
146
}
147
+
148
+ func handleError (ctx context.Context , err error ) error {
149
+ if err == nil {
150
+ return nil
151
+ }
152
+
153
+ // handle atproto specific errors
154
+ if rpcErr , ok := err .(* xrpc.Error ); ok {
155
+ switch rpcErr .StatusCode {
156
+ case 400 , 413 :
157
+ slog .WarnContext (ctx , "the record data is invalid" )
158
+ return err
159
+ case 401 , 403 :
160
+ slog .ErrorContext (ctx , "authentication failed; check the credentials" )
161
+ return err
162
+ case 429 :
163
+ slog .InfoContext (ctx , "we got rate limited, let's back off: " + rpcErr .Error ())
164
+ return nil
165
+ default :
166
+ slog .DebugContext (ctx , "unhandled error: " + rpcErr .Error ())
167
+ return err
168
+ }
169
+ }
170
+
171
+ // probably a low-level http/dns error
172
+ var netErr * net.OpError
173
+ if errors .As (err , & netErr ) {
174
+ if netErr .Temporary () {
175
+ return nil
176
+ }
177
+
178
+ if netErr .Timeout () {
179
+ return nil
180
+ }
181
+
182
+ slog .ErrorContext (ctx , netErr .Error ())
183
+ return err
184
+ }
185
+
186
+ // unhandled
187
+ slog .ErrorContext (ctx , err .Error ())
188
+ return err
189
+ }
0 commit comments