Bot Download API #26

Merged
itzaname merged 27 commits from bot-dl into staging 2026-02-26 02:55:30 +00:00
Owner
  • Assumes dev service "Storage" "Read" permission exists
  • Shoves a bunch of new stuff into times.go

Please tell me if there is a different way I should be doing this.

- Assumes dev service "Storage" "Read" permission exists - Shoves a bunch of new stuff into times.go Please tell me if there is a different way I should be doing this.
Quaternions added 3 commits 2026-02-23 17:22:17 +00:00
initialize properly
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
33f55524a8
Quaternions requested review from itzaname 2026-02-23 17:22:17 +00:00
Quaternions added 1 commit 2026-02-23 18:24:14 +00:00
generate
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
03695e773d
Quaternions added 1 commit 2026-02-23 18:25:37 +00:00
fix api
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
010494ed0e
Quaternions added 1 commit 2026-02-24 00:50:16 +00:00
fix comment
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
79016134b6
itzaname requested changes 2026-02-24 02:16:10 +00:00
Dismissed
@@ -44,0 +46,4 @@
Url string `json:"url"`
} // @name BotDownloadUrl
type FileInfo struct {
Owner

DTO is for external interfaces not calling internal services. So basically what the API would receive from a client or respond with to an API client. FileInfo is for an internal service call and does not belong here. I'd honestly just inline the struct like:

var storageResp struct {
    ID      string `json:"ID"`
    Created int64  `json:"Created"`
    Url     string `json:"Url"`
}
DTO is for external interfaces not calling internal services. So basically what the API would receive from a client or respond with to an API client. `FileInfo` is for an internal service call and does not belong here. I'd honestly just inline the struct like: ```go var storageResp struct { ID string `json:"ID"` Created int64 `json:"Created"` Url string `json:"Url"` } ```
Quaternions marked this conversation as resolved
@@ -27,3 +32,4 @@
}
return &TimesHandler{
Handler: baseHandler,
client: http_client,
Owner

Using snake_case while surrounded by camelCase is a war crime.

Using snake_case while surrounded by camelCase is a war crime.
Quaternions marked this conversation as resolved
@@ -320,0 +334,4 @@
// @Success 200 {object} dto.Response[dto.BotDownloadUrl]
// @Failure 404 {object} dto.Error "Time not found"
// @Failure 404 {object} dto.Error "Time does not have a Bot"
// @Failure 404 {object} dto.Error "Bot not found"
Owner

You've got 3 404s but the only one will be used as you can see in the generated docs.

You've got 3 404s but the only one will be used as you can see in the generated docs.
Quaternions marked this conversation as resolved
@@ -320,0 +336,4 @@
// @Failure 404 {object} dto.Error "Time does not have a Bot"
// @Failure 404 {object} dto.Error "Bot not found"
// @Failure default {object} dto.Error "General error response"
// @Router /time/{id}/download-url [get]
Owner

This is an RPC like action not a RESTful url. Do something like this:

  • /time/{id}/bot
  • /time/{id}/bot/replay (if you foresee returning bot metadata in /bot)
This is an RPC like action not a RESTful url. Do something like this: - /time/{id}/bot - /time/{id}/bot/replay (if you foresee returning bot metadata in /bot)
Quaternions marked this conversation as resolved
@@ -320,0 +379,4 @@
ctx.JSON(statusCode, dto.Error{
Error: errorMessage,
})
log.WithError(err).Error(
Owner

You're using WithError but no error was actually set.

You're using `WithError` but no error was actually set.
Quaternions marked this conversation as resolved
@@ -320,0 +410,4 @@
// fetch download url from storage service
// Build the full URL.
fullURL := h.url + botData.FileID
Owner

Use url.JoinPath as it will handle adding / as needed.

Use `url.JoinPath` as it will handle adding `/` as needed.
Quaternions marked this conversation as resolved
@@ -320,0 +451,4 @@
ctx.JSON(statusCode, dto.Error{
Error: errorMessage,
})
log.WithError(err).Error(
Owner

Another error log when err would be nil.

Another error log when err would be nil.
Quaternions marked this conversation as resolved
@@ -320,0 +473,4 @@
}
// Return the download url
ctx.JSON(http.StatusOK, dto.Response[dto.BotDownloadUrl]{
Owner

Simplify things and just 302 to the download url instead.

Simplify things and just 302 to the download url instead.
Quaternions marked this conversation as resolved
@@ -60,0 +67,4 @@
}
}
// WithStorageUrl sets the data gRPC client
Owner

This aint no grpc client

This aint no grpc client
Quaternions marked this conversation as resolved
@@ -76,3 +93,3 @@
// Times handler
timesHandler, err := handlers.NewTimesHandler(handlerOptions...)
timesHandler, err := handlers.NewTimesHandler(cfg.httpClient, cfg.storageUrl, handlerOptions...)
Owner

You added WithStorageUrl and WithHttpClient for the api options but then ignore that pattern when working with the times handler and slapped some new args in front...

You added `WithStorageUrl` and `WithHttpClient` for the api options but then ignore that pattern when working with the times handler and slapped some new args in front...
Author
Owner

The Handler type and HandlerOption is not general enough, I don't understand how to implement the pattern here. Adding httpClient and storageUrl to Handler would pollute the other handlers with irrelevant and unused fields.

The Handler type and HandlerOption is not general enough, I don't understand how to implement the pattern here. Adding httpClient and storageUrl to Handler would pollute the other handlers with irrelevant and unused fields.
Owner

Just add it to the handler it's already getting thrown into RouterConfig and the cli I'm not going to lose sleep over Handler.

Just add it to the handler it's already getting thrown into `RouterConfig` and the cli I'm not going to lose sleep over `Handler`.
Quaternions marked this conversation as resolved
pkg/cmds/api.go Outdated
@@ -53,3 +64,4 @@
api.WithPort(ctx.Int("port")),
api.WithDevClient(devConn),
api.WithDataClient(dataConn),
api.WithHttpClient(&http.Client{}),
Owner

Set a timeout when making the client

Set a timeout when making the client
Quaternions marked this conversation as resolved
Quaternions added 1 commit 2026-02-24 15:51:57 +00:00
use cases consistently
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
31802ac9fc
Quaternions added 1 commit 2026-02-24 15:53:37 +00:00
inline internal storage struct
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
c7c64cd8f7
Quaternions added 1 commit 2026-02-24 15:56:04 +00:00
use most likely error msg in doc
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
1ab40fdc78
Quaternions added 1 commit 2026-02-24 15:58:35 +00:00
there is no err
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
69344551b9
Quaternions added 1 commit 2026-02-24 16:00:04 +00:00
use url.JoinPath
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
5a9bc0ea6c
Quaternions added 1 commit 2026-02-24 16:00:33 +00:00
there is no err
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
af1c35b618
Quaternions added 5 commits 2026-02-24 16:20:15 +00:00
generate
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
a10a18d0a9
Quaternions added 1 commit 2026-02-24 16:21:36 +00:00
set an http timeout
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
c341c881e3
Quaternions added 1 commit 2026-02-24 22:26:29 +00:00
fix comment
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
21a764f298
itzaname requested changes 2026-02-25 00:42:32 +00:00
Dismissed
pkg/cmds/api.go Outdated
@@ -50,1 +58,4 @@
// Storage service http client
storageUrl := ctx.String("storage-host")
httpClient := http.Client{
Owner

Honestly looking at this more I'm not sure why this http client struct is being pre-created instead of just being created in the one function that uses it.

Honestly looking at this more I'm not sure why this http client struct is being pre-created instead of just being created in the one function that uses it.
Quaternions marked this conversation as resolved
pkg/cmds/api.go Outdated
@@ -51,0 +59,4 @@
// Storage service http client
storageUrl := ctx.String("storage-host")
httpClient := http.Client{
Timeout: 10,
Owner

This is 10 nano seconds

10 * time.Second
This is 10 nano seconds ```go 10 * time.Second ```
Quaternions marked this conversation as resolved
Quaternions added 2 commits 2026-02-25 17:17:24 +00:00
use handler pattern for storage url
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
c8d0502616
Quaternions requested review from itzaname 2026-02-25 17:20:06 +00:00
Quaternions changed title from WIP: Bot Download API to Bot Download API 2026-02-25 17:53:39 +00:00
itzaname requested changes 2026-02-26 01:08:51 +00:00
Dismissed
@@ -76,3 +86,3 @@
// Times handler
timesHandler, err := handlers.NewTimesHandler(handlerOptions...)
timesHandler, err := handlers.NewTimesHandler([]handlers.HandlerOption{
Owner
timesHandler, err := handlers.NewTimesHandler(
    handlers.WithDataClient(cfg.dataClient),
    handlers.WithStorageUrl(cfg.storageUrl),
)
```go timesHandler, err := handlers.NewTimesHandler( handlers.WithDataClient(cfg.dataClient), handlers.WithStorageUrl(cfg.storageUrl), ) ```
Quaternions marked this conversation as resolved
Quaternions added 1 commit 2026-02-26 02:14:03 +00:00
omit HandlerOption slice
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
b38ddd2fae
Quaternions requested review from itzaname 2026-02-26 02:14:11 +00:00
itzaname approved these changes 2026-02-26 02:15:33 +00:00
Dismissed
itzaname left a comment
Owner

We got there eventually

We got there eventually
itzaname requested changes 2026-02-26 02:17:44 +00:00
Dismissed
@@ -318,2 +323,4 @@
})
}
// @Summary Get bot download url by time ID
Owner

Actually, probably need to update this since you're not really getting the dl url.

Actually, probably need to update this since you're not really getting the dl url.
Quaternions marked this conversation as resolved
Quaternions added 1 commit 2026-02-26 02:29:26 +00:00
update summary
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
cb86bafa7c
Quaternions added 1 commit 2026-02-26 02:31:27 +00:00
update description
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
d3771a874a
Quaternions requested review from itzaname 2026-02-26 02:33:32 +00:00
Owner

Generate the api docs again and you're good.

Generate the api docs again and you're good.
Author
Owner

Please merge and get staging working, otherwise deploy directly to prod. Reminder that it also needs a new permission category "Storage.Read" on the dev portal.

Please merge and get staging working, otherwise deploy directly to prod. Reminder that it also needs a new permission category "Storage.Read" on the dev portal.
Quaternions added 1 commit 2026-02-26 02:36:19 +00:00
generate
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2ea3808f12
Owner

Please merge and get staging working, otherwise deploy directly to prod. Reminder that it also needs a new permission category "Storage.Read" on the dev portal.

Is "Storage" too generic? Bots.Read?

> Please merge and get staging working, otherwise deploy directly to prod. Reminder that it also needs a new permission category "Storage.Read" on the dev portal. Is "Storage" too generic? Bots.Read?
Author
Owner

The only thing it could be confused with is "Datastore" for playerdata & equipment. Bots are the only thing on storage, but I think being precise is a good idea. I'll change it to Bots. We can change it to Assets or something if we end up hosting maps there too and want them on the same category.

The only thing it could be confused with is "Datastore" for playerdata & equipment. Bots are the only thing on storage, but I think being precise is a good idea. I'll change it to Bots. We can change it to Assets or something if we end up hosting maps there too and want them on the same category.
Quaternions added 1 commit 2026-02-26 02:41:18 +00:00
change permission name to "Bots"
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
46ebb5574e
itzaname reviewed 2026-02-26 02:43:49 +00:00
@@ -123,2 +136,4 @@
v1.GET("/rank", rankHandler.List)
}
v1_bots := r.Group("/api/v1")
Owner

Missed this one sneaky snake_case. I'll note I don't know if duplicate groups can work like this but we will find out.

Missed this one sneaky snake_case. I'll note I don't know if duplicate groups can work like this but we will find out.
Quaternions marked this conversation as resolved
Quaternions added 1 commit 2026-02-26 02:47:41 +00:00
rename variables
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
9df5e4a8dd
itzaname approved these changes 2026-02-26 02:55:18 +00:00
itzaname merged commit 128aaf4c06 into staging 2026-02-26 02:55:30 +00:00
itzaname deleted branch bot-dl 2026-02-26 02:55:30 +00:00
Owner
It's live https://api.staging.strafes.net/docs/index.html
Sign in to join this conversation.