87 lines
3.5 KiB
C#
87 lines
3.5 KiB
C#
namespace BlueLaminate.EFCore.Entities;
|
|
|
|
/// <summary>Lifecycle of a CSFloat listing as observed across sweeps.</summary>
|
|
public enum ListingStatus
|
|
{
|
|
/// <summary>Seen in the most recent sweep that covered it.</summary>
|
|
Active = 0,
|
|
|
|
/// <summary>
|
|
/// Previously seen, then absent from a sweep that should have covered it —
|
|
/// i.e. sold or delisted. The disappearance is the signal; we can't tell sold
|
|
/// from delisted with certainty, but <see cref="Listing.LastSeenAt"/> bounds when.
|
|
/// </summary>
|
|
Removed = 1,
|
|
}
|
|
|
|
/// <summary>
|
|
/// One active-market listing observed on CSFloat via the official
|
|
/// <c>GET /api/v1/listings</c> endpoint. Rows are keyed by CSFloat's own listing
|
|
/// id and soft-tracked across sweeps: <see cref="FirstSeenAt"/>/<see cref="LastSeenAt"/>
|
|
/// bound the observation window and <see cref="Status"/> flips to
|
|
/// <see cref="ListingStatus.Removed"/> when a once-seen listing stops appearing,
|
|
/// which approximates a sale/delisting.
|
|
///
|
|
/// A global sweep returns items that may not be in our catalogue, so
|
|
/// <see cref="SkinId"/> is a best-effort nullable link (resolved by
|
|
/// def_index + paint_index); the listing stands on its own without it.
|
|
/// </summary>
|
|
public class Listing
|
|
{
|
|
public int Id { get; set; }
|
|
|
|
/// <summary>CSFloat's listing id (a snowflake string). Natural key for dedup.</summary>
|
|
public string CsFloatListingId { get; set; } = null!;
|
|
|
|
/// <summary>"buy_now" or "auction".</summary>
|
|
public string Type { get; set; } = null!;
|
|
|
|
/// <summary>Asking price in USD.</summary>
|
|
public decimal Price { get; set; }
|
|
|
|
/// <summary>When CSFloat says the listing was created.</summary>
|
|
public DateTimeOffset ListedAt { get; set; }
|
|
|
|
// Item identity. Stored directly (not only via the Skin link) so listings for
|
|
// items outside our catalogue are still fully described.
|
|
public int DefIndex { get; set; }
|
|
public int PaintIndex { get; set; }
|
|
public string MarketHashName { get; set; } = null!;
|
|
public string? WearName { get; set; }
|
|
public decimal FloatValue { get; set; }
|
|
public int PaintSeed { get; set; }
|
|
public bool IsStatTrak { get; set; }
|
|
public bool IsSouvenir { get; set; }
|
|
public int StickerCount { get; set; }
|
|
|
|
public string? SellerSteamId { get; set; }
|
|
public string? InspectLink { get; set; }
|
|
|
|
/// <summary>
|
|
/// Steam asset id of the listed copy. Changes on trade, so not a stable
|
|
/// identity — but the discriminator that distinguishes duped copies which
|
|
/// otherwise share an identical fingerprint.
|
|
/// </summary>
|
|
public string? AssetId { get; set; }
|
|
|
|
/// <summary>Best-effort catalogue link, resolved by def_index + paint_index. Null if unmatched.</summary>
|
|
public int? SkinId { get; set; }
|
|
public Skin? Skin { get; set; }
|
|
|
|
/// <summary>
|
|
/// The physical item (by fingerprint) this listing is for. Many listings over
|
|
/// time roll up to one instance, forming its market-movement history. Nullable
|
|
/// because catalogue-less items can't be fingerprinted to a known skin.
|
|
/// </summary>
|
|
public int? SkinInstanceId { get; set; }
|
|
public SkinInstance? SkinInstance { get; set; }
|
|
|
|
// Soft-tracking across sweeps.
|
|
public DateTimeOffset FirstSeenAt { get; set; }
|
|
public DateTimeOffset LastSeenAt { get; set; }
|
|
public ListingStatus Status { get; set; }
|
|
|
|
/// <summary>When the listing was marked Removed (absent from a sweep). Null while Active.</summary>
|
|
public DateTimeOffset? RemovedAt { get; set; }
|
|
}
|