Skip to content

Commit a19c3f3

Browse files
authored
Merge pull request #387 from csfloat/feat/rank-gateway-service
Implements FloatDB Gateway for Rank Fetching
2 parents 7ae1fea + 8204d10 commit a19c3f3

18 files changed

Lines changed: 522 additions & 111 deletions

src/environment.dev.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export const environment = {
66
loggingLevel: 'Error',
77
},
88
reverse_watch_base_api_url: 'http://localhost:3434/api',
9+
floatdb_gateway_url: 'https://gateway.floatdb.com',
910
};

src/environment.staging.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export const environment = {
66
loggingLevel: 'Error',
77
},
88
reverse_watch_base_api_url: 'https://reverse.watch/api',
9+
floatdb_gateway_url: 'https://gateway.floatdb.com',
910
};

src/environment.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export const environment = {
66
loggingLevel: 'Warn',
77
},
88
reverse_watch_base_api_url: 'https://reverse.watch/api',
9+
floatdb_gateway_url: 'https://gateway.floatdb.com',
910
};

src/lib/bridge/handlers/fetch_inspect_info.ts

Lines changed: 127 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import {decodeLink, CEconItemPreviewDataBlock} from '@csfloat/cs2-inspect-serial
22
import {SimpleHandler} from './main';
33
import {RequestType} from './types';
44
import {gSchemaFetcher} from '../../services/schema_fetcher';
5+
import {gThresholdFetcher} from '../../services/threshold_fetcher';
6+
import {gRankBatcher} from '../../services/rank_batcher';
57
import type {ItemSchema} from '../../types/schema';
68

79
interface Sticker {
@@ -42,95 +44,144 @@ export interface ItemInfo {
4244

4345
export interface FetchInspectInfoRequest {
4446
link: string;
45-
listPrice?: number;
47+
asset_id: string;
4648
}
4749

4850
export interface FetchInspectInfoResponse {
4951
iteminfo: ItemInfo;
5052
error?: string;
5153
}
5254

55+
async function processInspectItem(req: FetchInspectInfoRequest, schema: ItemSchema.Response): Promise<ItemInfo> {
56+
let decoded: CEconItemPreviewDataBlock;
57+
try {
58+
decoded = decodeLink(req.link);
59+
} catch (error) {
60+
throw new Error('Failed to decode inspect link');
61+
}
62+
63+
const defindex = decoded.defindex ?? 0;
64+
const paintindex = decoded.paintindex ?? 0;
65+
const floatvalue = decoded.paintwear ?? 0;
66+
67+
let min = 0;
68+
let max = 1;
69+
let weaponType: string | undefined;
70+
let itemName: string | undefined;
71+
let rarityName: string | undefined;
72+
let stickers: Sticker[] = [];
73+
let keychains: Keychain[] = [];
74+
75+
try {
76+
const weapon = schema.weapons[defindex];
77+
const paint = getSchemaPaint(weapon, paintindex);
78+
79+
weaponType = weapon?.name;
80+
rarityName = schema.rarities.find((rarity) => rarity.value === (paint?.rarity ?? decoded.rarity))?.name;
81+
82+
if (paint) {
83+
itemName = paint.name;
84+
min = paint.min;
85+
max = paint.max;
86+
}
87+
88+
stickers = decoded.stickers.map((sticker) => {
89+
const schemaSticker = schema.stickers[sticker.stickerId?.toString() ?? ''];
90+
return {
91+
slot: sticker.slot ?? 0,
92+
stickerId: sticker.stickerId ?? 0,
93+
wear: sticker.wear,
94+
name: schemaSticker?.market_hash_name,
95+
};
96+
});
97+
98+
keychains = decoded.keychains.map((keychain) => {
99+
const schemaKeychain = schema.keychains[keychain.stickerId?.toString() ?? ''];
100+
return {
101+
slot: keychain.slot ?? 0,
102+
stickerId: keychain.stickerId ?? 0,
103+
wear: keychain.wear,
104+
pattern: keychain.pattern ?? 0,
105+
name: schemaKeychain?.market_hash_name,
106+
};
107+
});
108+
} catch (error) {
109+
console.error('Failed to fetch schema item metadata:', error);
110+
}
111+
112+
const iteminfo: ItemInfo = {
113+
stickers,
114+
keychains,
115+
itemid: decoded.itemid?.toString() ?? '',
116+
defindex,
117+
paintindex,
118+
rarity: decoded.rarity ?? 0,
119+
quality: decoded.quality ?? 0,
120+
paintseed: decoded.paintseed ?? 0,
121+
inventory: decoded.inventory ?? 0,
122+
origin: decoded.origin ?? 0,
123+
floatvalue,
124+
min,
125+
max,
126+
weapon_type: weaponType,
127+
item_name: itemName,
128+
rarity_name: rarityName,
129+
wear_name: getWearName(floatvalue),
130+
};
131+
132+
try {
133+
if (decoded.itemid != null && decoded.paintwear != null) {
134+
const stattrak = decoded.killeaterscoretype !== undefined;
135+
const souvenir = decoded.quality === 12;
136+
137+
if (await gThresholdFetcher.qualifiesForRankCheck(defindex, paintindex, stattrak, souvenir, floatvalue)) {
138+
const rankResult = await gRankBatcher.check(req.link, decoded.itemid.toString());
139+
if (rankResult) {
140+
iteminfo.low_rank = rankResult.low_rank;
141+
iteminfo.high_rank = rankResult.high_rank;
142+
}
143+
}
144+
}
145+
} catch (e) {
146+
console.error('Failed to check rank:', e);
147+
}
148+
149+
return iteminfo;
150+
}
151+
53152
export const FetchInspectInfo = new SimpleHandler<FetchInspectInfoRequest, FetchInspectInfoResponse>(
54153
RequestType.FETCH_INSPECT_INFO,
55154
async (req) => {
56-
let decoded: CEconItemPreviewDataBlock;
57-
try {
58-
decoded = decodeLink(req.link);
59-
} catch (error) {
60-
throw new Error('Failed to decode inspect link');
61-
}
155+
const schema = await gSchemaFetcher.getSchema();
156+
return {iteminfo: await processInspectItem(req, schema)};
157+
}
158+
);
62159

63-
const defindex = decoded.defindex ?? 0;
64-
const paintindex = decoded.paintindex ?? 0;
65-
const floatvalue = decoded.paintwear ?? 0;
66-
67-
let min = 0;
68-
let max = 1;
69-
let weaponType: string | undefined;
70-
let itemName: string | undefined;
71-
let rarityName: string | undefined;
72-
let stickers: Sticker[] = [];
73-
let keychains: Keychain[] = [];
74-
75-
try {
76-
const schema = await gSchemaFetcher.getSchema();
77-
const weapon = schema.weapons[defindex];
78-
const paint = getSchemaPaint(weapon, paintindex);
79-
80-
weaponType = weapon?.name;
81-
rarityName = schema.rarities.find((rarity) => rarity.value === (paint?.rarity ?? decoded.rarity))?.name;
82-
83-
if (paint) {
84-
itemName = paint.name;
85-
min = paint.min;
86-
max = paint.max;
87-
}
160+
export interface FetchInspectInfoBatchRequest {
161+
requests: FetchInspectInfoRequest[];
162+
}
88163

89-
stickers = decoded.stickers.map((sticker) => {
90-
const schemaSticker = schema.stickers[sticker.stickerId?.toString() ?? ''];
91-
return {
92-
slot: sticker.slot ?? 0,
93-
stickerId: sticker.stickerId ?? 0,
94-
wear: sticker.wear,
95-
name: schemaSticker?.market_hash_name,
96-
};
97-
});
98-
99-
keychains = decoded.keychains.map((keychain) => {
100-
const schemaKeychain = schema.keychains[keychain.stickerId?.toString() ?? ''];
101-
return {
102-
slot: keychain.slot ?? 0,
103-
stickerId: keychain.stickerId ?? 0,
104-
wear: keychain.wear,
105-
pattern: keychain.pattern ?? 0,
106-
name: schemaKeychain?.market_hash_name,
107-
};
108-
});
109-
} catch (error) {
110-
console.error('Failed to fetch schema item metadata:', error);
111-
}
164+
export interface FetchInspectInfoBatchResponse {
165+
results: Record<string, FetchInspectInfoResponse>;
166+
}
112167

113-
return {
114-
iteminfo: {
115-
stickers,
116-
keychains,
117-
itemid: decoded.itemid?.toString() ?? '',
118-
defindex,
119-
paintindex,
120-
rarity: decoded.rarity ?? 0,
121-
quality: decoded.quality ?? 0,
122-
paintseed: decoded.paintseed ?? 0,
123-
inventory: decoded.inventory ?? 0,
124-
origin: decoded.origin ?? 0,
125-
floatvalue,
126-
min,
127-
max,
128-
weapon_type: weaponType,
129-
item_name: itemName,
130-
rarity_name: rarityName,
131-
wear_name: getWearName(floatvalue),
132-
},
133-
};
168+
export const FetchInspectInfoBatch = new SimpleHandler<FetchInspectInfoBatchRequest, FetchInspectInfoBatchResponse>(
169+
RequestType.FETCH_INSPECT_INFO_BATCH,
170+
async (req) => {
171+
const schema = await gSchemaFetcher.getSchema();
172+
173+
const results: Record<string, FetchInspectInfoResponse> = {};
174+
await Promise.all(
175+
req.requests.map(async (itemReq) => {
176+
try {
177+
results[itemReq.asset_id] = {iteminfo: await processInspectItem(itemReq, schema)};
178+
} catch (e) {
179+
results[itemReq.asset_id] = {iteminfo: {} as ItemInfo, error: (e as any).toString()};
180+
}
181+
})
182+
);
183+
184+
return {results};
134185
}
135186
);
136187

src/lib/bridge/handlers/handlers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {ExecuteScriptOnPage} from './execute_script';
22
import {FetchStall} from './fetch_stall';
3-
import {FetchInspectInfo} from './fetch_inspect_info';
3+
import {FetchInspectInfo, FetchInspectInfoBatch} from './fetch_inspect_info';
44
import {ExecuteCssOnPage} from './execute_css';
55
import {StorageGet} from './storage_get';
66
import {StorageSet} from './storage_set';
@@ -78,4 +78,5 @@ export const HANDLERS_MAP: {[key in RequestType]: RequestHandler<any, any>} = {
7878
[RequestType.FETCH_NOTARY_TOKEN]: FetchNotaryToken,
7979
[RequestType.FETCH_STEAM_POWERED_INVENTORY]: FetchSteamPoweredInventory,
8080
[RequestType.FETCH_REVERSAL_STATUS]: FetchReversalStatus,
81+
[RequestType.FETCH_INSPECT_INFO_BATCH]: FetchInspectInfoBatch,
8182
};

src/lib/bridge/handlers/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ export enum RequestType {
3737
FETCH_NOTARY_TOKEN = 35,
3838
FETCH_STEAM_POWERED_INVENTORY = 36,
3939
FETCH_REVERSAL_STATUS = 37,
40+
FETCH_INSPECT_INFO_BATCH = 38,
4041
}

src/lib/components/common/item_holder_metadata.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,12 @@ export abstract class ItemHolderMetadata extends FloatElement {
173173
if (!isSkin(this.asset) && !isCharm(this.asset)) return;
174174

175175
// Commodities won't have inspect links
176-
if (!this.inspectLink) return;
176+
if (!this.inspectLink || !this.assetId) return;
177177

178178
try {
179179
this.itemInfo = await gFloatFetcher.fetch({
180180
link: this.inspectLink,
181+
asset_id: this.assetId,
181182
});
182183
} catch (e: any) {
183184
console.error(`Failed to fetch float for ${this.assetId}: ${e.toString()}`);

src/lib/components/inventory/inventory_item_holder_metadata.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import {ContextId} from '../../types/steam_constants';
55
import {isCAppwideInventory} from '../../utils/checkers';
66

77
@CustomElement()
8-
@InjectAppend(
9-
'#active_inventory_page div.inventory_page:not([style*="display: none"]) .itemHolder div.app730',
10-
InjectionMode.CONTINUOUS
11-
)
8+
@InjectAppend('#active_inventory_page div.inventory_page .itemHolder div.app730', InjectionMode.CONTINUOUS)
129
export class InventoryItemHolderMetadata extends ItemHolderMetadata {
1310
get asset(): rgAsset | undefined {
1411
if (!this.assetId) return;

src/lib/components/inventory/selected_item_info.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ export class SelectedItemInfo extends FloatElement {
262262
) {
263263
try {
264264
this.itemInfo = await gFloatFetcher.fetch({
265+
asset_id: this.asset.assetid,
265266
link: this.inspectLink,
266267
});
267268
} catch (e: any) {

src/lib/components/market/item_row_wrapper.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,13 @@ export class ItemRowWrapper extends FloatElement {
8383
}
8484

8585
async fetchFloat(): Promise<ItemInfo> {
86+
if (!this.listingInfo?.asset.id) {
87+
throw new Error('Missing asset ID');
88+
}
89+
8690
return gFloatFetcher.fetch({
8791
link: this.inspectLink!,
88-
listPrice: this.usdPrice,
92+
asset_id: this.listingInfo?.asset.id,
8993
});
9094
}
9195

@@ -111,14 +115,6 @@ export class ItemRowWrapper extends FloatElement {
111115
return (this.listingInfo.converted_price + this.listingInfo.converted_fee) / 100;
112116
}
113117

114-
get usdPrice(): number | undefined {
115-
if (this.listingInfo?.currencyid === Currency.USD) {
116-
return this.listingInfo.price + this.listingInfo.fee;
117-
} else if (this.listingInfo?.converted_currencyid === Currency.USD) {
118-
return this.listingInfo.converted_price! + this.listingInfo.converted_fee!;
119-
}
120-
}
121-
122118
@state()
123119
private itemInfo: ItemInfo | undefined;
124120
@state()

0 commit comments

Comments
 (0)