Files
2026-08-28 13:36:03 +03:00

237 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# rudder-go-sdk
Серверный Go SDK для LiveOps-платформы Rudder. Покрывает server-admin
поверхность `/game/v1` (auth по `X-API-Key`).
## Install
Модуль раздаётся напрямую с self-hosted Gitea, минуя proxy.golang.org,
поэтому Go должен пропускать его мимо checksum database:
```bash
go env -w GOPRIVATE=hub.rudder.build/*
go get hub.rudder.build/rudder/rudder-go-sdk@latest
```
Требуется Go 1.21+. Токен не нужен — репозиторий публичный.
## Версионирование
Потребители фиксируют версию по git-тегу
(`go get hub.rudder.build/rudder/rudder-go-sdk@vX.Y.Z`). Первый тег `v0.1.0`
будет создан при релизе; до него версионирования нет.
## Доступ
`AdminKey` — это per-project Admin Key: поле «Admin Key» в настройках проекта
в дашборде (app.rudder.build → проект → Settings). Ключ сам определяет
проект, отдельный project ID не нужен. Храните его только на сервере —
никогда не вшивайте в игровые клиенты.
## Usage
```go
client, err := rudder.New(rudder.Config{
AdminKey: os.Getenv("RUDDER_ADMIN_KEY"),
})
if err != nil {
// *rudder.APIError с кодом sdk/invalid-options
}
players, err := client.Players.List(ctx, rudder.ListPlayersParameters{Limit: 100})
```
Публичные типы живут в пакете `rudder`. Пакет `models` — сгенерированный
wire-формат, в прикладном коде его импортировать не нужно.
## Handles
`client.Player(id)` и `client.Leaderboard(slug)` создают handle без
HTTP-запроса. Handles — сахар над batch-методами сервисов: каждая операция
отправляет batch из одного элемента с подставленным playerID/slug.
```go
player := client.Player("p1")
wallet, err := player.Wallet().Adjust(ctx, rudder.AdjustPlayerWalletParameters{
IdempotencyKey: "grant-001",
CurrencyCode: "coins",
Amount: 100,
Reason: "compensation",
})
history, err := player.Wallet().History(ctx, rudder.WalletHistoryParameters{Limit: 50})
item, err := player.Inventory().Adjust(ctx, rudder.AdjustPlayerInventoryParameters{
Slug: "sword",
Amount: 1,
Reason: "quest reward",
})
inventory, err := player.Inventory().List(ctx, rudder.ListInventoryParameters{Limit: 50})
storage, err := player.Storage().Get(ctx, "settings")
updated, err := player.Storage().Upsert(ctx, rudder.UpsertPlayerStorageParameters{
Type: "settings",
Data: `{"lang":"ru"}`,
})
err = player.Storage().Delete(ctx, rudder.DeletePlayerStorageParameters{Type: "settings"})
quests, err := player.Quests().List(ctx)
err = player.Quests().Reset(ctx, rudder.PlayerQuestParameters{QuestID: "daily-1"})
// ForceComplete и ForceClaim — аналогично
updatedPlayer, err := player.Update(ctx, rudder.UpdatePlayerParameters{Nickname: "Neo"})
banned, err := player.Ban(ctx, rudder.BanPlayerParameters{
Reason: "cheating",
BannedUntil: "2030-01-01T00:00:00Z",
})
unbanned, err := player.Unban(ctx, "")
err = player.Delete(ctx, "")
board := client.Leaderboard("weekly")
entries, err := board.List(ctx, rudder.ListLeaderboardEntriesParameters{Limit: 100})
// entries.Entries []rudder.Rank, entries.NextCursor
entry, err := board.Get(ctx, "p1") // *rudder.Rank с rank
around, err := board.GetAround(ctx, "p1", 10) // []rudder.Rank вокруг игрока
err = board.Submit(ctx, []rudder.LeaderboardScore{{PlayerID: "p1", Score: 1500}})
err = board.Update(ctx, []rudder.LeaderboardScore{{PlayerID: "p1", Score: 1600}})
err = board.Delete(ctx, []string{"p1", "p2"})
```
## Batch-first API
Все мутирующие операции верхнего уровня — batch-only: тело
`{idempotencyKey?, items:[...]}` (`playerId` внутри элементов), до 100
элементов, all-or-nothing в одной транзакции, один idempotency key на батч.
```go
wallets, err := client.Wallet.Adjust(ctx, rudder.AdjustWalletParameters{
IdempotencyKey: "grant-001",
Items: []rudder.WalletAdjustment{
{PlayerID: "p1", CurrencyCode: "coins", Amount: 100, Reason: "compensation"},
{PlayerID: "p2", CurrencyCode: "coins", Amount: 100, Reason: "compensation"},
},
})
items, err := client.Inventory.Adjust(ctx, rudder.AdjustInventoryParameters{
Items: []rudder.InventoryAdjustment{
{PlayerID: "p1", Slug: "sword", Amount: 1, Reason: "quest reward"},
},
})
updated, err := client.Players.Update(ctx, rudder.UpdatePlayersParameters{
Items: []rudder.PlayerUpdate{
{PlayerID: "p1", Nickname: "Neo"},
},
})
banned, err := client.Players.Ban(ctx, rudder.BanPlayersParameters{
Items: []rudder.PlayerBan{
{PlayerID: "p2", Reason: "cheating", BannedUntil: "2030-01-01T00:00:00Z"},
},
})
unbanned, err := client.Players.Unban(ctx, rudder.UnbanPlayersParameters{
PlayerIDs: []string{"p2"},
})
err = client.Players.Delete(ctx, rudder.DeletePlayersParameters{
PlayerIDs: []string{"p3"},
})
```
## Верификация авторизации
`Players.VerifyAuth` — одиночный (не batch) вызов `POST /players/auth/verify`:
проверяет access token игрока и возвращает `playerId`, `projectId` и `status`
(`active`/`banned`/`deleted`).
```go
verification, err := client.Players.VerifyAuth(ctx, accessToken)
// verification.PlayerID, verification.ProjectID, verification.Status
```
`VerifyWebhookSignature` — пакетный хелпер для приёма webhook'ов с подписью
`X-Signature` (hex HMAC-SHA256 от сырого тела, ключ — webhook secret проекта):
```go
if !rudder.VerifyWebhookSignature(secret, body, r.Header.Get("X-Signature")) {
// подпись не сошлась — отклонить запрос
}
```
err = client.Quests.Reset(ctx, rudder.PlayerQuestsParameters{
Items: []rudder.PlayerQuestRef{
{PlayerID: "p1", QuestID: "daily-1"},
},
})
// ForceComplete и ForceClaim — аналогично
err = client.Leaderboards.Submit(ctx, "weekly", []rudder.LeaderboardScore{
{PlayerID: "p1", Score: 1500},
})
// Update и Delete — аналогично
err = client.Storage.Upsert(ctx, rudder.UpsertStorageParameters{
Items: []rudder.ProjectStorageInput{
{Type: "config", Data: `{"event":"x2"}`},
},
})
err = client.Storage.Delete(ctx, rudder.DeleteStorageParameters{
Types: []string{"config"},
})
```
## Каталоги и read-операции
Курсорная пагинация: передавайте `Limit`/`Cursor`, следующую страницу
запрашивайте по `NextCursor` из ответа.
```go
boards, err := client.Leaderboards.List(ctx, rudder.ListLeaderboardsParameters{Limit: 100})
// boards.Items []rudder.Leaderboard, boards.NextCursor
quests, err := client.Quests.List(ctx, rudder.ListQuestsParameters{
Status: &status, // "active" или "archived", optional
Limit: 100,
})
// quests.Items []rudder.Quest, quests.NextCursor
history, err := client.Wallet.History(ctx, playerID, rudder.WalletHistoryParameters{
Currency: &currency, // optional
Limit: 50,
})
// history.Entries []rudder.WalletTransaction, history.NextCursor
inventory, err := client.Inventory.List(ctx, playerID, rudder.ListInventoryParameters{
Limit: 50,
})
// inventory.Items []rudder.InventoryItem, inventory.NextCursor
storage, err := client.Storage.List(ctx, rudder.ListStorageParameters{
Limit: 100,
Search: "config", // optional
})
item, err := client.Storage.Get(ctx, "config")
```
## Ошибки
```go
var apiErr *rudder.APIError
if errors.As(err, &apiErr) {
apiErr.Status // HTTP status
apiErr.Code // машинный код из тела ошибки gateway
apiErr.RequestID // корреляция с логами gateway
}
```
## Генерация
`models/` генерируется apigen'ом из `liveops-gateway/openapi.yaml`
(`make generate-openapi` в liveops-gateway). Руками не править.
Публичные имена — aliases в корне пакета `rudder` (`types.go`).