Files
DorkNet/DorkNet.Server/Data/Entities/RoomDataBlobEntity.cs
Alexa d471b418b9 Import march-2020-03-10 from private repo (scrubbed 2026-05-27)
Targets Rec Room 2020.03.10 client (also serves 2020.03.06).

Re-import after adding:
- DorkNet.ClientMod/dorknet-clientmod.json.template — config schema
  the launcher's manifest-driven patcher renders into UserData/.
- tools/build-patcher-zip.ps1 — produces dorknet-clientpatch-{key}.zip
  for v1-march-* Release uploads.
- .github/workflows/release.yml — on tag push publishes both
  dorknet-server-march_2020_03_10-win-x64.zip and
  dorknet-clientpatch-march_2020_03_10.zip as Release assets.

Same scrub rules as december; tools/build-patcher-zip.ps1 added to
the maintainer-side allow-list so it survives.
2026-05-27 01:06:12 +03:00

61 lines
2.6 KiB
C#

using System.ComponentModel.DataAnnotations;
namespace DorkNet.Server.Data.Entities;
/// <summary>
/// Metadata for a single saved version of a room's PersistedRoomData
/// protobuf. The actual bytes live in S3 at the canonical
/// (bucket, key) returned by <see cref="Services.BlobRouter.Route"/>;
/// this row only carries the lookup string + provenance.
///
/// One row per save. Visitors fetching the room get the row whose
/// <see cref="BlobName"/> matches the current
/// <c>RoomEntity.CurrentDataBlobName</c>; the CDN controller takes
/// that name, routes it via <see cref="Services.BlobRouter"/>, and
/// streams bytes out of S3.
///
/// Was originally a fat row with a <c>Bytes</c> column; that column
/// was dropped once S3 became the canonical store. Only text columns
/// remain in the DB.
/// </summary>
public class RoomDataBlobEntity
{
public long Id { get; set; }
/// <summary>FK to RoomEntity. Indexed for "give me all versions of
/// this room" queries (history, GC). Set to 0 for shared assets
/// not bound to a specific room (HTRs, PV images, polaroids).</summary>
public long RoomId { get; set; }
/// <summary>The string the client uses as the cdn URL segment.
/// <see cref="Services.BlobRouter.Route"/> converts this into a
/// canonical (bucket, key) deterministically.</summary>
[MaxLength(128)]
public string BlobName { get; set; } = string.Empty;
/// <summary>The player id of the uploader. Audit trail; also used by
/// the GC to keep the room owner's saves longer than visitor saves.</summary>
public long UploadedByPlayerId { get; set; }
public DateTime UploadedAt { get; set; } = DateTime.UtcNow;
/// <summary>Comma-separated list of file names referenced by the
/// PersistedRoomData (e.g. invention thumbnails, audio clips). The
/// client passes these via the upload's referencedFilenames argument;
/// the server uses them later when GC'ing orphaned blobs.</summary>
[MaxLength(2048)]
public string ReferencedFilenamesCsv { get; set; } = string.Empty;
/// <summary>
/// Legacy bytes column. The codebase no longer writes to this — S3
/// is the canonical store — but rows imported / uploaded before the
/// S3-only cutover still hold their bytes here, and the backfill
/// migrator (<c>POST /api/admin/v1/storage/backfill</c>) reads them
/// to upload into S3. After backfill is verified, a follow-up EF
/// migration drops this column entirely and only metadata remains.
/// Nullable so freshly-inserted rows can omit it without breaking
/// SQLite's NOT NULL invariant.
/// </summary>
public byte[]? Bytes { get; set; }
}