From 91c3d46ceb36c88073cda0502fd3d81626607ebd Mon Sep 17 00:00:00 2001 From: edmand46 Date: Wed, 12 Aug 2026 23:58:31 +0300 Subject: [PATCH] Add ProjectStorageService and generated ProjectStorage models --- ProjectStorage/GetProjectStorageResponse.cs | 16 +++++ ProjectStorage/ProjectStorageItem.cs | 37 +++++++++++ ProjectStorage/ProjectStorageUpdateItem.cs | 16 +++++ ProjectStorage/UpdateProjectStorageRequest.cs | 16 +++++ RudderClient.cs | 4 ++ Services/ProjectStorageService.cs | 64 +++++++++++++++++++ 6 files changed, 153 insertions(+) create mode 100644 ProjectStorage/GetProjectStorageResponse.cs create mode 100644 ProjectStorage/ProjectStorageItem.cs create mode 100644 ProjectStorage/ProjectStorageUpdateItem.cs create mode 100644 ProjectStorage/UpdateProjectStorageRequest.cs create mode 100644 Services/ProjectStorageService.cs diff --git a/ProjectStorage/GetProjectStorageResponse.cs b/ProjectStorage/GetProjectStorageResponse.cs new file mode 100644 index 0000000..33a2b5a --- /dev/null +++ b/ProjectStorage/GetProjectStorageResponse.cs @@ -0,0 +1,16 @@ +// Code generated by apigen. DO NOT EDIT. +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; + +namespace RudderSdk.Core.Models.ProjectStorage; + +public class GetProjectStorageResponse +{ + [JsonProperty("items")] + public List Items { get; set; } + + [JsonProperty("nextCursor")] + public string NextCursor { get; set; } + +} diff --git a/ProjectStorage/ProjectStorageItem.cs b/ProjectStorage/ProjectStorageItem.cs new file mode 100644 index 0000000..3eaea64 --- /dev/null +++ b/ProjectStorage/ProjectStorageItem.cs @@ -0,0 +1,37 @@ +// Code generated by apigen. DO NOT EDIT. +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; + +namespace RudderSdk.Core.Models.ProjectStorage; + +public class ProjectStorageItem +{ + [JsonProperty("data")] + public string Data { get; set; } + + [JsonProperty("expiresAt")] + public string ExpiresAt { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("readPermission")] + public string ReadPermission { get; set; } + + [JsonProperty("size")] + public long Size { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("updatedAt")] + public string UpdatedAt { get; set; } + + [JsonProperty("version")] + public long Version { get; set; } + + [JsonProperty("writePermission")] + public string WritePermission { get; set; } + +} diff --git a/ProjectStorage/ProjectStorageUpdateItem.cs b/ProjectStorage/ProjectStorageUpdateItem.cs new file mode 100644 index 0000000..038201a --- /dev/null +++ b/ProjectStorage/ProjectStorageUpdateItem.cs @@ -0,0 +1,16 @@ +// Code generated by apigen. DO NOT EDIT. +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; + +namespace RudderSdk.Core.Models.ProjectStorage; + +public class ProjectStorageUpdateItem +{ + [JsonProperty("data")] + public string Data { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + +} diff --git a/ProjectStorage/UpdateProjectStorageRequest.cs b/ProjectStorage/UpdateProjectStorageRequest.cs new file mode 100644 index 0000000..7899851 --- /dev/null +++ b/ProjectStorage/UpdateProjectStorageRequest.cs @@ -0,0 +1,16 @@ +// Code generated by apigen. DO NOT EDIT. +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; + +namespace RudderSdk.Core.Models.ProjectStorage; + +public class UpdateProjectStorageRequest +{ + [JsonProperty("idempotencyKey")] + public string IdempotencyKey { get; set; } + + [JsonProperty("items")] + public List Items { get; set; } + +} diff --git a/RudderClient.cs b/RudderClient.cs index b1fe8f6..a1ccfe5 100644 --- a/RudderClient.cs +++ b/RudderClient.cs @@ -29,6 +29,9 @@ public sealed class RudderClient /// Player key-value storage. public StorageService Storage { get; } + /// Project key-value storage (global, shared across players). + public ProjectStorageService ProjectStorage { get; } + /// In-game stores and offer purchases. public StoresService Stores { get; } @@ -86,6 +89,7 @@ public sealed class RudderClient Player = new PlayerService(this); RemoteConfig = new RemoteConfigService(this); Storage = new StorageService(this); + ProjectStorage = new ProjectStorageService(this); Stores = new StoresService(this); Leaderboards = new LeaderboardsService(this); Inventory = new InventoryService(this); diff --git a/Services/ProjectStorageService.cs b/Services/ProjectStorageService.cs new file mode 100644 index 0000000..cf83d3b --- /dev/null +++ b/Services/ProjectStorageService.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using RudderSdk.Core.Models.ProjectStorage; + +namespace RudderSdk.Core; + +/// Project key-value storage (global, shared across players). +public sealed class ProjectStorageService +{ + private readonly RudderClient _client; + + internal ProjectStorageService(RudderClient client) => _client = client; + + /// Fetches one page of project storage items, optionally filtered by type. + public Task GetAsync(string? type = null, int limit = 100, string? cursor = null, CancellationToken cancellationToken = default) + { + var query = Url.Query( + ("types", type), + ("limit", limit > 0 ? limit.ToString() : null), + ("cursor", cursor)); + + return _client.SendAsync("GET", "/sdk/v1/project-storage" + query, cancellationToken); + } + + /// Iterates over all project storage items, following the cursor pagination. + public async IAsyncEnumerable ListAllAsync( + string? type = null, + int limit = 100, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + string? cursor = null; + do + { + var page = await GetAsync(type, limit, cursor, cancellationToken).ConfigureAwait(false); + if (page?.Items != null) + { + foreach (var item in page.Items) + yield return item; + } + + cursor = page?.NextCursor; + } + while (!string.IsNullOrEmpty(cursor)); + } + + /// + /// Saves (upserts) project storage items. When + /// is null, a random one is generated. + /// + public Task SaveAsync(IEnumerable items, string? idempotencyKey = null, CancellationToken cancellationToken = default) + => _client.SendAsync( + "PUT", + "/sdk/v1/project-storage", + new UpdateProjectStorageRequest + { + IdempotencyKey = idempotencyKey ?? Guid.NewGuid().ToString(), + Items = items?.ToList() ?? new List() + }, + cancellationToken); +}