this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add get follows and refreshing to api bindings

why 4d7b802a 76b7c985

+313 -6
+24
api/bsky.go
··· 159 159 160 160 return nil 161 161 } 162 + 163 + type GetFollowsResp struct { 164 + Subject *User `json:"subject"` 165 + Cursor string `json:"cursor"` 166 + Follows []User `json:"follows"` 167 + } 168 + 169 + func (b *BskyApp) GraphGetFollows(ctx context.Context, user string, limit int, before *string) (*GetFollowsResp, error) { 170 + params := map[string]interface{}{ 171 + "user": user, 172 + "limit": limit, 173 + } 174 + 175 + if before != nil { 176 + params["before"] = *before 177 + } 178 + 179 + var out GetFollowsResp 180 + if err := b.C.Do(ctx, xrpc.Query, "app.bsky.graph.getFollows", params, nil, &out); err != nil { 181 + return nil, err 182 + } 183 + 184 + return &out, nil 185 + }
+56
cmd/gosky/main.go
··· 35 35 feedGetAuthorCmd, 36 36 actorGetSuggestionsCmd, 37 37 feedSetVoteCmd, 38 + graphGetFollowsCmd, 39 + refreshAuthTokenCmd, 38 40 } 39 41 40 42 app.RunAndExitOnError() ··· 347 349 348 350 }, 349 351 } 352 + 353 + var graphGetFollowsCmd = &cli.Command{ 354 + Name: "graphGetFollows", 355 + Action: func(cctx *cli.Context) error { 356 + bskyc, err := cliutil.GetBskyClient(cctx, true) 357 + if err != nil { 358 + return err 359 + } 360 + 361 + user := cctx.Args().First() 362 + 363 + ctx := context.TODO() 364 + resp, err := bskyc.GraphGetFollows(ctx, user, 100, nil) 365 + if err != nil { 366 + return err 367 + } 368 + 369 + for _, f := range resp.Follows { 370 + fmt.Println(f.Did) 371 + } 372 + 373 + return nil 374 + }, 375 + } 376 + 377 + var refreshAuthTokenCmd = &cli.Command{ 378 + Name: "refresh", 379 + Action: func(cctx *cli.Context) error { 380 + atpc, err := cliutil.GetATPClient(cctx, true) 381 + if err != nil { 382 + return err 383 + } 384 + 385 + a := atpc.C.Auth 386 + a.AccessJwt = a.RefreshJwt 387 + 388 + ctx := context.TODO() 389 + nauth, err := atpc.SessionRefresh(ctx) 390 + if err != nil { 391 + return err 392 + } 393 + 394 + b, err := json.Marshal(nauth) 395 + if err != nil { 396 + return err 397 + } 398 + 399 + if err := os.WriteFile(cctx.String("auth"), b, 0600); err != nil { 400 + return err 401 + } 402 + 403 + return nil 404 + }, 405 + }
+30 -4
cmd/lexgen/main.go
··· 67 67 &cli.StringFlag{ 68 68 Name: "prefix", 69 69 }, 70 + &cli.BoolFlag{ 71 + Name: "gen-server", 72 + }, 73 + &cli.StringSliceFlag{ 74 + Name: "types-import", 75 + }, 76 + &cli.StringFlag{ 77 + Name: "package", 78 + Value: "schemagen", 79 + }, 70 80 } 71 81 app.Action = func(cctx *cli.Context) error { 72 82 outdir := cctx.String("outdir") ··· 91 101 schemas = append(schemas, s) 92 102 } 93 103 94 - for i, s := range schemas { 95 - fname := filepath.Join(outdir, s.Name()+".go") 104 + pkgname := cctx.String("package") 96 105 97 - if err := lex.GenCodeForSchema("schemagen", prefix, fname, true, s); err != nil { 98 - return fmt.Errorf("failed to process schema %q: %w", paths[i], err) 106 + if cctx.Bool("gen-server") { 107 + paths := cctx.StringSlice("types-import") 108 + importmap := make(map[string]string) 109 + for _, p := range paths { 110 + parts := strings.Split(p, ":") 111 + importmap[parts[0]] = parts[1] 112 + } 113 + 114 + if err := lex.CreateHandlerStub(pkgname, importmap, outdir, schemas); err != nil { 115 + return err 116 + } 117 + 118 + } else { 119 + for i, s := range schemas { 120 + fname := filepath.Join(outdir, s.Name()+".go") 121 + 122 + if err := lex.GenCodeForSchema(pkgname, prefix, fname, true, s); err != nil { 123 + return fmt.Errorf("failed to process schema %q: %w", paths[i], err) 124 + } 99 125 } 100 126 } 101 127
+203 -2
lex/gen.go
··· 5 5 "encoding/json" 6 6 "fmt" 7 7 "go/format" 8 + "html/template" 8 9 "io" 9 10 "os" 10 11 "os/exec" 12 + "path/filepath" 11 13 "sort" 12 14 "strings" 13 15 ) ··· 152 154 } 153 155 } 154 156 155 - formatted, err := format.Source(buf.Bytes()) 157 + if err := writeCodeFile(buf.Bytes(), fname); err != nil { 158 + return err 159 + } 160 + 161 + return nil 162 + } 163 + 164 + func writeCodeFile(b []byte, fname string) error { 165 + formatted, err := format.Source(b) 156 166 if err != nil { 167 + fmt.Println(string(b)) 157 168 return fmt.Errorf("failed to format generated file: %w", err) 158 169 } 159 170 ··· 211 222 212 223 } 213 224 225 + func orderedMapIter[T any](m map[string]T, cb func(string, T) error) error { 226 + var keys []string 227 + for k := range m { 228 + keys = append(keys, k) 229 + } 230 + 231 + sort.Strings(keys) 232 + 233 + for _, k := range keys { 234 + if err := cb(k, m[k]); err != nil { 235 + return err 236 + } 237 + } 238 + return nil 239 + } 240 + 214 241 func (s *Schema) WriteRPC(w io.Writer, prefix string) error { 215 242 fname := s.nameFromID(s.ID, s.prefix) 216 243 ··· 221 248 inpvar = "input" 222 249 } 223 250 251 + if s.Parameters != nil { 252 + if err := orderedMapIter[TypeSchema](s.Parameters.Properties, func(name string, t TypeSchema) error { 253 + tn, err := s.typeNameForField(name, "", t) 254 + if err != nil { 255 + return err 256 + } 257 + 258 + // TODO: deal with optional params 259 + params = params + fmt.Sprintf(", %s %s", name, tn) 260 + return nil 261 + }); err != nil { 262 + return err 263 + } 264 + } 265 + 224 266 out := "error" 225 267 if s.Output != nil { 226 268 out = fmt.Sprintf("(*%s_Output, error)", fname) ··· 239 281 } 240 282 241 283 queryparams := "nil" 284 + if s.Parameters != nil { 285 + queryparams = "params" 286 + fmt.Fprintf(w, ` 287 + params := map[string]interface{}{ 288 + `) 289 + if err := orderedMapIter[TypeSchema](s.Parameters.Properties, func(name string, t TypeSchema) error { 290 + fmt.Fprintf(w, `"%s": %s, 291 + `, name, name) 292 + return nil 293 + }); err != nil { 294 + return err 295 + } 296 + fmt.Fprintf(w, "}\n") 297 + } 242 298 243 299 var reqtype string 244 300 switch s.Type { ··· 253 309 fmt.Fprintf(w, "\tif err := c.Do(ctx, %s, \"%s\", %s, %s, %s); err != nil {\n", reqtype, s.ID, queryparams, inpvar, outvar) 254 310 fmt.Fprintf(w, "\t\treturn %s\n", errRet) 255 311 fmt.Fprintf(w, "\t}\n\n") 256 - 257 312 fmt.Fprintf(w, "\treturn %s\n", outRet) 258 313 fmt.Fprintf(w, "}\n\n") 314 + 315 + return nil 316 + } 317 + 318 + func doTemplate(w io.Writer, info interface{}, templ string) error { 319 + t := template.Must(template.New(""). 320 + Funcs(template.FuncMap{ 321 + "TODO": func(thing string) string { 322 + return "//TODO: " + thing 323 + }, 324 + }).Parse(templ)) 325 + 326 + return t.Execute(w, info) 327 + } 328 + 329 + func CreateHandlerStub(pkg string, impmap map[string]string, dir string, schemas []*Schema) error { 330 + buf := new(bytes.Buffer) 331 + 332 + if err := WriteXrpcServer(buf, schemas, pkg, impmap); err != nil { 333 + return err 334 + } 335 + 336 + fname := filepath.Join(dir, "stubs.go") 337 + if err := writeCodeFile(buf.Bytes(), fname); err != nil { 338 + return err 339 + } 340 + 341 + return nil 342 + } 343 + 344 + func importNameForPrefix(prefix string) string { 345 + return strings.Join(strings.Split(prefix, "."), "") + "types" 346 + } 347 + 348 + func WriteXrpcServer(w io.Writer, schemas []*Schema, pkg string, impmap map[string]string) error { 349 + fmt.Fprintf(w, "package %s\n\n", pkg) 350 + fmt.Fprintf(w, "import (\n") 351 + fmt.Fprintf(w, "\t\"context\"\n") 352 + fmt.Fprintf(w, "\t\"fmt\"\n") 353 + fmt.Fprintf(w, "\t\"encoding/json\"\n") 354 + fmt.Fprintf(w, "\t\"github.com/whyrusleeping/gosky/xrpc\"\n") 355 + fmt.Fprintf(w, "\t\"github.com/labstack/echo/v4\"\n") 356 + for k, v := range impmap { 357 + fmt.Fprintf(w, "\t%s\"%s\"\n", importNameForPrefix(k), v) 358 + } 359 + fmt.Fprintf(w, ")\n\n") 360 + 361 + fmt.Fprintf(w, "func (s *Server) RegisterHandlers(e echo.Echo) error {\n") 362 + for _, s := range schemas { 363 + var verb string 364 + switch s.Type { 365 + case "query": 366 + verb = "GET" 367 + case "procedure": 368 + verb = "POST" 369 + default: 370 + continue 371 + } 372 + 373 + fmt.Fprintf(w, "e.%s(\"/xrpc/%s\", s.%s)\n", verb, s.ID, idToTitle(s.ID)) 374 + } 375 + 376 + fmt.Fprintf(w, "return nil\n}\n\n") 377 + 378 + for _, s := range schemas { 379 + var prefix string 380 + for k := range impmap { 381 + if strings.HasPrefix(s.ID, k) { 382 + prefix = k 383 + break 384 + } 385 + } 386 + 387 + if s.Type == "procedure" || s.Type == "query" { 388 + if err := s.WriteRPCHandler(w, prefix); err != nil { 389 + return err 390 + } 391 + } 392 + } 393 + 394 + return nil 395 + } 396 + 397 + func idToTitle(id string) string { 398 + var fname string 399 + for _, p := range strings.Split(id, ".") { 400 + fname += strings.Title(p) 401 + } 402 + return fname 403 + } 404 + 405 + func (s *Schema) WriteRPCHandler(w io.Writer, prefix string) error { 406 + fname := idToTitle(s.ID) 407 + 408 + tname := s.nameFromID(s.ID, prefix) 409 + 410 + fmt.Fprintf(w, "func (s *Server) Handle%s(c echo.Context) error {\n", fname) 411 + 412 + paramtypes := []string{"ctx context.Context"} 413 + params := []string{"ctx"} 414 + if s.Type == "query" { 415 + if s.Parameters != nil { 416 + orderedMapIter[TypeSchema](s.Parameters.Properties, func(k string, t TypeSchema) error { 417 + switch t.Type { 418 + case "string": 419 + params = append(params, k) 420 + paramtypes = append(paramtypes, k+" string") 421 + fmt.Fprintf(w, "%s := c.QueryParam(\"%s\")\n", k, k) 422 + case "number": 423 + params = append(params, k) 424 + paramtypes = append(paramtypes, k+" int") 425 + fmt.Fprintf(w, ` 426 + %s, err := strconv.Atoi(c.QueryParam("%s")) 427 + if err != nil { 428 + return err 429 + } 430 + `, k, k) 431 + default: 432 + return fmt.Errorf("unsupported handler parameter type: %s", t.Type) 433 + } 434 + return nil 435 + }) 436 + } 437 + } else if s.Type == "procedure" { 438 + fmt.Fprintf(w, ` 439 + var body types.%s 440 + if err := e.Bind(&out); err != nil { 441 + return err 442 + } 443 + `, tname+"_Input") 444 + } else { 445 + return fmt.Errorf("can only generate handlers for queries or procedures") 446 + } 447 + 448 + assign := "err" 449 + returndef := "error" 450 + if s.Output != nil { 451 + assign = "out, err" 452 + fmt.Fprintf(w, "var out types.%s\n", tname+"_Output") 453 + returndef = fmt.Sprintf("(*types.%s_Output, error)", tname) 454 + } 455 + fmt.Fprintf(w, "var err error\n") 456 + fmt.Fprintf(w, "// func (s *Server) handle%s(%s) %s\n", fname, strings.Join(paramtypes, ","), returndef) 457 + fmt.Fprintf(w, "%s = s.handle%s(%s)\n", assign, fname, strings.Join(params, ",")) 458 + 459 + fmt.Fprintf(w, "return nil // TODO: implement me\n}\n\n") 259 460 260 461 return nil 261 462 }