add csfloat api usage
This commit is contained in:
86
BlueLaminate/BlueLaminate.EFCore/Entities/Listing.cs
Normal file
86
BlueLaminate/BlueLaminate.EFCore/Entities/Listing.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
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; }
|
||||
}
|
||||
@@ -9,6 +9,19 @@ public class Skin
|
||||
/// <summary>Stable id from the CSGO-API catalogue, e.g. "skin-e757fd7191f9". The natural key.</summary>
|
||||
public string Slug { get; set; } = null!;
|
||||
|
||||
// CSFloat/CS item indexes, sourced from the static catalogue (weapon.weapon_id
|
||||
// and paint_index). Together they identify a skin on CSFloat and let market
|
||||
// listings join back to this catalogue row. Nullable until a sync populates
|
||||
// them, since older catalogue rows predate these columns.
|
||||
public int? DefIndex { get; set; }
|
||||
public int? PaintIndex { get; set; }
|
||||
|
||||
// When the catalogue-driven listing sweep last fully covered this skin. The
|
||||
// sweep processes least-recently-swept skins first (nulls = never swept), so
|
||||
// capped runs chain across the whole catalogue and the stalest data refreshes
|
||||
// first. Null until the first sweep reaches this skin.
|
||||
public DateTimeOffset? ListingsSweptAt { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
public string Rarity { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
|
||||
@@ -1,20 +1,50 @@
|
||||
namespace BlueLaminate.EFCore.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One physical CS2 item, identified by its fingerprint
|
||||
/// (Skin + FloatValue + PaintSeed + StatTrak + Souvenir) rather than its Steam
|
||||
/// asset id, which changes on every trade. Decoupled from Steam inventories on
|
||||
/// purpose: an instance exists from market observation alone, and the optional
|
||||
/// <see cref="InventoryItem"/> bridge ties it to a <c>SteamUser</c> only once we
|
||||
/// crawl inventories.
|
||||
///
|
||||
/// Duping note: a duplicated item is a byte-for-byte copy with an identical
|
||||
/// fingerprint, so a fingerprint is NOT guaranteed unique to one physical item.
|
||||
/// We treat the fingerprint as the item, and flag <see cref="SuspectedDupe"/>
|
||||
/// when the same fingerprint is seen live under two or more different asset ids
|
||||
/// at once (see the sweep's dupe detection).
|
||||
/// </summary>
|
||||
public class SkinInstance
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int SkinId { get; set; }
|
||||
public Skin Skin { get; set; } = null!;
|
||||
public int ConditionId { get; set; }
|
||||
public SkinCondition Condition { get; set; } = null!;
|
||||
|
||||
// FloatValue + PaintSeed form a stable fingerprint across trades; the Steam
|
||||
// asset_id changes on every trade but these do not.
|
||||
// Nullable: market observation gives a float but not a derived wear bucket.
|
||||
// Condition can be backfilled later from the float without blocking ingest.
|
||||
public int? ConditionId { get; set; }
|
||||
public SkinCondition? Condition { get; set; }
|
||||
|
||||
// The fingerprint. FloatValue is stored at full precision (see config) so
|
||||
// that exact-match dupe detection isn't fooled by rounding.
|
||||
public decimal FloatValue { get; set; }
|
||||
public string PaintSeed { get; set; } = null!;
|
||||
public bool StatTrak { get; set; }
|
||||
public bool Souvenir { get; set; }
|
||||
public DateTimeOffset FirstSeenAt { get; set; }
|
||||
public DateTimeOffset LastSeenAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True once this fingerprint was observed live under 2+ distinct asset ids
|
||||
/// simultaneously — the signature of duplication.
|
||||
/// </summary>
|
||||
public bool SuspectedDupe { get; set; }
|
||||
|
||||
/// <summary>When the dupe condition was first detected. Null until then.</summary>
|
||||
public DateTimeOffset? DupeFirstSeenAt { get; set; }
|
||||
|
||||
/// <summary>Every market listing observed for this physical item over time.</summary>
|
||||
public ICollection<Listing> Listings { get; set; } = new List<Listing>();
|
||||
|
||||
public ICollection<InventoryItem> InventoryItems { get; set; } = new List<InventoryItem>();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user