using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using RudderSdk.Core.Models.Ugc;
namespace RudderSdk.Core;
/// User-generated content: upload, list, download URLs, deletion.
public sealed class UgcService
{
private readonly RudderClient _client;
internal UgcService(RudderClient client) => _client = client;
///
/// Uploads a file in one call: pre-signed URL, PUT of the bytes, submission.
/// Requires an upload transport in .
///
public async Task UploadAsync(
string name,
byte[] data,
string? description = null,
JToken? metadata = null,
CancellationToken cancellationToken = default)
{
var uploadTransport = _client.Options.UploadTransport
?? throw new InvalidOperationException("UploadTransport is not configured.");
var upload = await GetUploadUrlAsync(name, cancellationToken).ConfigureAwait(false);
await uploadTransport.PutAsync(
upload.UploadUrl,
data ?? Array.Empty(),
GetContentType(name),
cancellationToken).ConfigureAwait(false);
return await SubmitAsync(
name,
upload.FileKey,
data?.LongLength ?? 0,
description,
metadata,
cancellationToken).ConfigureAwait(false);
}
/// Fetches one page of the player's submissions.
public Task ListAsync(string? status = null, int limit = 20, string? cursor = null, CancellationToken cancellationToken = default)
=> _client.SendAsync(
"GET",
"/sdk/v1/ugc" + Url.Query(
("status", status),
("limit", limit > 0 ? limit.ToString() : null),
("cursor", cursor)),
cancellationToken);
/// Iterates over all of the player's submissions, following the cursor pagination.
public async IAsyncEnumerable ListAllAsync(
string? status = null,
int limit = 20,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
string? cursor = null;
do
{
var page = await ListAsync(status, 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));
}
/// Returns one submission.
public Task GetAsync(string id, CancellationToken cancellationToken = default)
=> _client.SendAsync("GET", "/sdk/v1/ugc/" + Url.Encode(id), cancellationToken);
/// Deletes a submission; returns false when the server refused.
public async Task DeleteAsync(string id, CancellationToken cancellationToken = default)
{
var response = await _client.SendAsync(
"DELETE",
"/sdk/v1/ugc/" + Url.Encode(id),
cancellationToken).ConfigureAwait(false);
return response == null || response.Success;
}
/// Requests a pre-signed upload URL.
public Task GetUploadUrlAsync(string filename, CancellationToken cancellationToken = default)
=> _client.SendAsync(
"GET",
"/sdk/v1/ugc/upload-url" + Url.Query(("filename", filename)),
cancellationToken);
///
/// Resolves the download URL of a submission.
/// Throws when the server returned none.
///
public async Task GetDownloadUrlAsync(string id, CancellationToken cancellationToken = default)
{
var response = await _client.SendAsync(
"GET",
"/sdk/v1/ugc/" + Url.Encode(id) + "/download",
cancellationToken).ConfigureAwait(false);
if (response == null || string.IsNullOrEmpty(response.DownloadUrl))
throw new InvalidOperationException("The server returned no download URL.");
return response.DownloadUrl;
}
/// Registers an uploaded file as a submission.
public Task SubmitAsync(
string name,
string fileKey,
long fileSize,
string? description = null,
JToken? metadata = null,
CancellationToken cancellationToken = default)
{
return _client.SendAsync(
"POST",
"/sdk/v1/ugc",
new SubmitUgcRequest
{
Name = name,
FileKey = fileKey,
FileSize = fileSize,
Description = description!,
Metadata = metadata!
},
cancellationToken);
}
private static string GetContentType(string filename)
{
var ext = System.IO.Path.GetExtension(filename)?.ToLowerInvariant();
switch (ext)
{
case ".png": return "image/png";
case ".jpg":
case ".jpeg": return "image/jpeg";
case ".gif": return "image/gif";
case ".webp": return "image/webp";
case ".txt": return "text/plain";
default: return "application/octet-stream";
}
}
}